跳转正文

YDrawer ​

保留拖拽、handle、snap与方向能力的管理端Drawer;适合需要这些交互的任务。

Usage ​

Import / Basic ​

vue
<script setup lang="ts">
import { ref } from 'vue'
import { YDrawer } from '@yoyoboot/ui-patterns/drawer'
const open = ref(false), draft = ref(''), saving = ref(false)
const guard = { dirty: () => !!draft.value, busy: () => saving.value }
</script>
<template>
  <UButton @click="open = true">打开任务</UButton>
  <YDrawer v-model:open="open" title="编辑信息" :guard="guard">
    <template #body><UInput v-model="draft" aria-label="名称" /></template>
    <template #footer="{ close }"><UButton @click="close()">取消</UButton></template>
  </YDrawer>
</template>

Title & description / slots ​

title与description传递到正式primitive。default仍是上游trigger插槽,任务内容使用body;header/title/description/actions/close/footer可按需覆盖,content是完整escape hatch。转发插槽附带安全close方法,不能借自定义取消按钮绕过guard。

direction / handle / snapPoints / nested ​

vue
<YDrawer v-model:open="open" direction="bottom" :handle="true"
  :snap-points="[0.5, 1]" v-model:active-snap-point="snap">
  <template #body>分段高度内容</template>
</YDrawer>

同一组件可用right/top/left/bottom。nested用于真正的Drawer嵌套;不复制vaul的drag/release、snap或closeThreshold算法。第二形态可运行示例见包内Task Surfaces fixture,不为示例强制改变现有业务UX。

Task guard / dirty / busy ​

guard 可省略;只读详情不需要草稿或保存按钮。guard读取业务状态,不复制它:

ts
const guard = { dirty: () => draft.value !== baseline.value, busy: () => saving.value }

关闭按钮、Escape、允许的outside dismiss和slot/exposed close()共享关闭策略:busy拒绝;dirty显示放弃确认;确认返回后再次检查busy。业务保存成功或身份/页面失效时,父组件直接令open=false是权威终止,不再询问放弃;普通取消必须调用安全close,而不是直接写open=false。

Responsive / long content ​

组件类型不会随viewport改变。通过ui.content选择宽度,body滚动,footer保留safe-area。页面自己的提交、验证和回读继续由Feature负责。

Nested / focus ​

子任务应渲染在父任务的body/content插槽内,使用现有YModal或选择组件。上游负责portal/focus trap;父任务guard可把子任务open纳入busy,防止操作绕过。关闭子任务后焦点回到父触发器。focusFirstField()定位首个可编辑输入,focusFirstError()定位aria-invalid字段并滚到可见位置;自定义content完全接管内容结构时,需要自行提供等价焦点接线。

API ​

Props ​

属性合同
open / defaultOpen受控状态 / 非受控初值;defaultOpen默认false
guard可选TaskSurfaceGuard,dirty/busy均为回调
title / description标题与说明
dismissible / modal / overlay默认true;语义沿上游;busy时正常dismiss受保护
close / closeIconclose默认true,可false隐藏或传Button配置;busy叠加disabled
portal默认true;支持false、目标选择器或HTMLElement
inset沿上游默认false
content / ui / class内容事件与布局escape hatch;不会创建新Overlay Runtime
directionbottom默认;可top/left/right
handle / handleOnlyhandle默认true;handleOnly沿上游false
snapPoints / activeSnapPoint保留上游类型和受控更新
nested / closeThreshold保留上游嵌套/关闭阈值
fixed / preventScrollRestoration / noBodyStyles保留上游能力,未传时由上游取默认
shouldScaleBackground / setBackgroundColorOnScale / scrollLockTimeout保留上游能力,非Yoyo自研行为

Models / Events ​

update:open(boolean):受控开关请求;close()事件:通过安全关闭提交后触发;close:prevent:被guard或上游dismiss策略阻止。 Drawer还转发 update:activeSnapPoint(number|string)、drag(number)、release(boolean)、animationEnd(boolean)。

Slots / Exposed methods ​

Slots:default、content、header、title、description、actions、close、body、footer。body/footer及转发插槽得到safe close;不提供业务save。

暴露:close(): Promise<boolean>、focusFirstField(): Promise<void>、focusFirstError(): Promise<void>。父级权威关闭或KeepAlive deactivation使待确认关闭失效,旧确认不得结束新的任务。

Theme / Visual ​

安装 @yoyoboot/ui-patterns/visual/management.css 和 visual/motion.css。header/footer/body由management foundation持有,不要求Feature复制背景色。组件仅显式标记自己的Task Surface,不要求安装Starter外壳;ui可以覆盖具体布局。支持light/dark、既有density和reduced-motion,无Skin runtime。

Accessibility ​

提供有意义的title/description;无障碍关联、遮罩、焦点限制与恢复沿Nuxt UI。busy禁止正常取消但不替业务取消服务端写入;字段错误由Feature标记。Esc在dismissible=false时由上游阻止;close按钮和显式close()仍可在guard许可时取消。

Underlying primitive ​

YDrawer 基于 Nuxt UI UDrawer。官方文档;当前核对版本4.11.2。

Source / Verification ​

  • 源码:packages/ui-patterns/src/drawer/YDrawer.vue。
  • 同源可运行示例:packages/ui-patterns/tests/fixtures/task-surfaces/App.vue,消费正式公开入口。
  • 单测:packages/ui-patterns/tests/task-surfaces.spec.ts;浏览器:Starter tests-e2e/task-surfaces.spec.ts。
  • 本页是该组件的 canonical 文档;VitePress 只投影这份正文,不维护第二份公开副本。可运行示例仍消费正式公开入口。

源码入口 · 共享关闭策略

TypeScript 类型 ​

公开入口同时导出 YDrawerProps 与 YDrawerContent,用于调用方命名 props/content。Content 沿用 Nuxt UI 公开合同,消费者不需要直接依赖 reka-ui 或 vaul-vue。

YoyoBoot · 从真实项目走向可复用能力