跳到主要内容

Sheet (Drawer)

  • 组件说明:侧边面板,用于表单、详情视图或辅助内容展示。支持四个方向:上、右(默认)、下、左。基于 Radix Dialog。别名 Drawer。
  • 当前状态:支持声明式(trigger 作为 children)和配置式(title/content/footer)两种模式,以及命令式 Sheet.open() API。
  • 实现约定:ui/sheet 封装 Radix Dialog primitive,design 层提供配置式 API、方向/宽度控制与命令式弹层能力。

基础用法​

通过 props 传入 title、content、footer,触发器作为 children 传入。

结果
Loading...
实时编辑器
render(
  <div style={{ padding: '40px 0' }}>
    <Sheet
      title="个人资料"
      content={
        <div style={{ padding: '0 16px', flex: 1 }}>
          <p style={{ fontSize: 14, color: '#6b7280', marginBottom: 8 }}>查看和编辑个人信息。</p>
          <p>姓名:张三</p>
          <p>邮箱:zhangsan@example.com</p>
        </div>
      }
      footer={
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <Button variant="secondary">取消</Button>
          <Button>保存</Button>
        </div>
      }
    >
      <Button>打开面板</Button>
    </Sheet>
  </div>,
)

方向变体​

通过 side 控制面板滑出方向,默认为 right。

结果
Loading...
实时编辑器
render(
  <div style={{ display: 'flex', gap: 12, padding: '40px 0', flexWrap: 'wrap' }}>
    <Sheet side="right" title="右侧面板" content={<div style={{ padding: '0 16px', flex: 1 }}>从右侧滑出(默认)。</div>}>
      <Button variant="secondary">右</Button>
    </Sheet>
    <Sheet side="left" title="左侧面板" content={<div style={{ padding: '0 16px', flex: 1 }}>从左侧滑出。</div>}>
      <Button variant="secondary">左</Button>
    </Sheet>
    <Sheet side="top" title="顶部面板" content={<div style={{ padding: '0 16px' }}>从顶部滑出。</div>}>
      <Button variant="secondary">上</Button>
    </Sheet>
    <Sheet side="bottom" title="底部面板" content={<div style={{ padding: '0 16px' }}>从底部滑出。</div>}>
      <Button variant="secondary">下</Button>
    </Sheet>
  </div>,
)

自定义宽度​

左右方向的面板可通过 width 设置宽度,接受数字(px)或字符串。

结果
Loading...
实时编辑器
render(
  <div style={{ display: 'flex', gap: 12, padding: '40px 0' }}>
    <Sheet width={400} title="窄面板" content={<div style={{ padding: '0 16px', flex: 1 }}>宽度:400px</div>}>
      <Button variant="secondary">400px</Button>
    </Sheet>
    <Sheet width="80vw" title="宽面板" content={<div style={{ padding: '0 16px', flex: 1 }}>宽度:80vw</div>}>
      <Button variant="secondary">80vw</Button>
    </Sheet>
  </div>,
)

受控模式​

结果
Loading...
实时编辑器
const Demo = () => {
  const [open, setOpen] = useState(false)
  return (
    <div style={{ display: 'flex', gap: 12, alignItems: 'center', padding: '40px 0' }}>
      <Button onClick={() => setOpen(true)}>打开受控面板</Button>
      <span style={{ fontSize: 14, color: '#999' }}>open: {String(open)}</span>
      <Sheet
        open={open}
        onOpenChange={setOpen}
        title="受控面板"
        content={
          <div style={{ padding: '0 16px', flex: 1 }}>
            <p>此面板由外部状态控制。</p>
            <Button variant="secondary" onClick={() => setOpen(false)}>从内部关闭</Button>
          </div>
        }
      />
    </div>
  )
}
render(<Demo />)

命令式 API​

Sheet.open() 提供命令式调用,适合异步回调、快捷键、表格 action 等非 JSX trigger 场景。需要在应用根部挂载 DesignProvider 或 OverlayHost。

import { Sheet } from '@plaud/design'

Sheet.open({
title: '编辑资料',
content: ({ close }) => (
<div>
<p>内容区域。</p>
<Button onClick={close}>关闭</Button>
</div>
),
})

更新已打开的面板​

open() 返回控制器,可在打开后更新配置:

const controller = Sheet.open({
title: '加载中...',
content: <div>请稍候。</div>,
})

setTimeout(() => {
controller.update({
title: '完成',
content: <div>数据已加载。</div>,
})
}, 1000)

控制器​

interface ImperativeOverlayController<TOptions> {
id: string
close: () => void
update: (updater: Partial<TOptions> | ((prev: TOptions) => TOptions)) => void
afterClosed: Promise<void>
}

Props​

属性类型默认值说明
titleReactNode—标题
contentReactNode—主体内容
footerReactNode—底部区域
childrenReactNode—触发器(非受控模式)
openboolean—受控打开状态
onOpenChange(open: boolean) => void—打开状态变更回调
side'top' | 'right' | 'bottom' | 'left''right'滑出方向
widthnumber | string560左右方向内容宽度(px 或 CSS 值)
showClosebooleantrue是否显示关闭按钮
destroyOnClosebooleantrue关闭后是否销毁内容
contentClassNamestring—内容区域自定义 class
closeOnOverlayClickbooleantrue点击蒙层是否关闭面板。只有 pointerdown 落在蒙层元素本身上才会触发关闭,浮在面板之上的其他元素(如全局悬浮组件)不会触发;传 false 则点击外部一律不关闭。默认 true(与 Dialog 的默认值 false 不同),是为了保持 Sheet 既有的「点外部即关」行为;非模态面板(modal={false})不渲染蒙层,此时该 prop 退回旧语义——除非传 false,否则点击任意外部区域都会关闭

使用约束​

  • 左右方向默认宽度 560px。
  • 命令式 API 需要在应用根部挂载 DesignProvider 或 OverlayHost。