#Drawer 抽屉
从页面边缘展开内容,查看详情或完成操作。
#基础用法
basic.tsx
import { Button, Drawer, Flex, Form, FormField, Input, Select, Space } from '@ifhover/leaf-ui';
import { useState } from 'react';
export function DrawerBasic() {
const [placement, setPlacement] = useState<'left' | 'right' | 'top' | 'bottom'>('right');
const [open, setOpen] = useState(false);
return (
<Space direction="vertical" align="stretch">
<Flex gap="md" align="center" wrap justify="center">
{(['left', 'right', 'top', 'bottom'] as const).map((side) => (
<Button
key={side}
variant="outline"
onClick={() => {
setPlacement(side);
setOpen(true);
}}
>
{side}
</Button>
))}
</Flex>
<Drawer
open={open}
placement={placement}
title="项目设置"
onClose={() => setOpen(false)}
footer={
<>
<Button variant="outline" onClick={() => setOpen(false)}>
取消
</Button>
<Button type="submit" form="drawer-project">
保存
</Button>
</>
}
>
<Form
id="drawer-project"
onSubmit={(event) => {
event.preventDefault();
setOpen(false);
}}
>
<FormField label="项目名称" required>
<Input name="name" defaultValue="Leaf Garden" />
</FormField>
<FormField label="项目类型">
<Select
name="type"
defaultValue="design"
options={[
{ value: 'design', label: '设计项目' },
{ value: 'development', label: '开发项目' },
]}
/>
</FormField>
</Form>
</Drawer>
</Space>
);
}
#调整宽度与嵌套推移
capabilities.tsx
import { Button, Drawer, Input, Space } from '@ifhover/leaf-ui';
import { useState } from 'react';
export function Capabilities() {
const [open, setOpen] = useState(false),
[child, setChild] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>
{'可调整宽度的工作区'}
</Button>
<Drawer
title={'工作区'}
open={open}
onClose={() => setOpen(false)}
resizable
minSize={260}
maxSize={640}
>
<Space direction="vertical">
<Input aria-label="Project" />
<Button onClick={() => setChild(true)}>{'查看详情'}</Button>
</Space>
<Drawer
open={child}
onClose={() => setChild(false)}
title={'详情'}
width={300}
push={120}
>
Details
</Drawer>
</Drawer>
</>
);
}
#通知偏好
标题、内容与底部操作分区,适合较长的设置流程。
sections.tsx
import { Alert, Button, Drawer, RadioGroup, Space } from '@ifhover/leaf-ui';
import { Bell } from 'lucide-react';
import { useState } from 'react';
export function DrawerSections() {
const [open, setOpen] = useState(false);
const [frequency, setFrequency] = useState('weekly');
return (
<>
<Button variant="outline" startIcon={<Bell />} onClick={() => setOpen(true)}>
{'通知偏好'}
</Button>
<Drawer
open={open}
width={440}
title={'通知偏好'}
description={'选择适合你的更新频率。'}
icon={<Bell />}
onClose={() => setOpen(false)}
footer={
<>
<Button variant="outline" onClick={() => setOpen(false)}>
{'取消'}
</Button>
<Button onClick={() => setOpen(false)}>{'保存'}</Button>
</>
}
>
<Space direction="vertical" align="stretch" size={20}>
<RadioGroup
variant="list"
label={'活动摘要'}
value={frequency}
onChange={(event) => setFrequency(event.target.value)}
options={[
{
value: 'daily',
label: '每日',
description: '每天汇总团队动态',
},
{
value: 'weekly',
label: '每周',
description: '每周一接收一份摘要',
},
{
value: 'off',
label: '关闭摘要',
description: '仅接收重要提醒',
},
]}
/>
<Alert
type="info"
title={'重要提醒始终发送'}
description={'安全事件和需要你处理的事项不会被关闭。'}
/>
</Space>
</Drawer>
</>
);
}
#Drawer API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
initialFocus | RefObject<HTMLElement | null> | (() => HTMLElement | null) | — | 指定打开后的初始焦点。 |
returnFocus | boolean | RefObject<HTMLElement | null> | (() => HTMLElement | null) | — | 关闭后返回原焦点;也可指定目标或设为 false。 |
open | boolean | 必填 | 必需。是否展开 |
title | ReactNode | — | 标题 |
description | ReactNode | — | 补充说明。 |
icon | ReactNode | — | 标题左侧的装饰图标。 |
divided | boolean | true | 用浅分隔线划分标题、内容和底部操作区。 |
footer | ReactNode | — | 底部内容 |
extra | ReactNode | — | 标题旁的操作内容 |
placement | 'left' | 'right' | 'top' | 'bottom' | 'right' | 展开方向 |
width | number | string | 380 | 左右抽屉宽度 |
height | number | string | 300 | 上下抽屉高度 |
closable | boolean | true | 关闭按钮 / 点击遮罩 / Escape 关闭 |
maskClosable | boolean | true | 关闭按钮 / 点击遮罩 / Escape 关闭 |
keyboard | boolean | true | 关闭按钮 / 点击遮罩 / Escape 关闭 |
onClose | () => void | — | 请求关闭,由应用更新 open |
afterClose | () => void | — | 关闭过渡结束后触发 |
forceRender | boolean | false | 打开前也挂载内容,关闭时保持隐藏。 |
destroyOnClose | boolean | false | 关闭过渡完成后卸载内容;默认保留。 |
preserve | boolean | — | 显式控制关闭后是否保留内容,优先于 destroyOnClose。 |
container | Element | DocumentFragment | (() => Element | DocumentFragment) | — | 自定义挂载或滚动容器。 |
push | boolean | number | false | 打开嵌套抽屉时推动父弹层,可指定距离。 |
resizable | boolean | false | 允许拖动和使用方向键调整大小。 |
minSize | number | 240 | 最小尺寸,单位为像素。 |
maxSize | number | 900 | 最大尺寸,单位为像素。 |
onResize | (size: number) => void | — | 大小改变时调用。 |
#类型
定义组件属性或组装列表时可导入相关类型。
import type { DrawerProps } from '@ifhover/leaf-ui';#使用说明
通过 footer 放置取消、提交等操作;表单提交按钮可使用 form 属性关联抽屉内的表单。标题为空时请使用 aria-label 提供名称。支持嵌套弹窗和抽屉,关闭后焦点会回到打开位置。
#外观与丰富内容
description 与 icon 用于说明当前任务。默认标题和底部操作有浅分隔线,底部使用淡灰辅助面;divided={false} 使用留白分区。