114 lines
3.5 KiB
Plaintext
114 lines
3.5 KiB
Plaintext
|
|
---
|
||
|
|
title: 浮层与定位
|
||
|
|
description: 使用 Base UI 的 render 组合 Dialog、Popover 与本地 AnchoredSurface。
|
||
|
|
order: 12
|
||
|
|
toc:
|
||
|
|
- id: dialog
|
||
|
|
title: Dialog
|
||
|
|
- id: popover
|
||
|
|
title: Popover
|
||
|
|
- id: anchored-surface
|
||
|
|
title: 连续尾巴
|
||
|
|
- id: positioning
|
||
|
|
title: 自定义定位
|
||
|
|
- id: choosing-an-overlay
|
||
|
|
title: 选择浮层
|
||
|
|
---
|
||
|
|
|
||
|
|
## Dialog {#dialog}
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import { Button } from "@workspace/ui/components/button"
|
||
|
|
import {
|
||
|
|
Dialog,
|
||
|
|
DialogContent,
|
||
|
|
DialogDescription,
|
||
|
|
DialogFooter,
|
||
|
|
DialogHeader,
|
||
|
|
DialogTitle,
|
||
|
|
DialogTrigger,
|
||
|
|
} from "@workspace/ui/components/dialog"
|
||
|
|
|
||
|
|
export function ProfileDialog() {
|
||
|
|
return (
|
||
|
|
<Dialog>
|
||
|
|
<DialogTrigger render={<Button variant="outline" />}>
|
||
|
|
编辑资料
|
||
|
|
</DialogTrigger>
|
||
|
|
<DialogContent>
|
||
|
|
<DialogHeader>
|
||
|
|
<DialogTitle>编辑资料</DialogTitle>
|
||
|
|
<DialogDescription>更新公开显示的信息。</DialogDescription>
|
||
|
|
</DialogHeader>
|
||
|
|
<div>表单内容</div>
|
||
|
|
<DialogFooter>
|
||
|
|
<Button type="submit">保存</Button>
|
||
|
|
</DialogFooter>
|
||
|
|
</DialogContent>
|
||
|
|
</Dialog>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
`DialogContent` 已包含 Portal、Overlay 和默认关闭按钮。标题与说明会连接到底层可访问性属性,不要只用无语义的 `div` 替代。
|
||
|
|
|
||
|
|
## Popover {#popover}
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import { Button } from "@workspace/ui/components/button"
|
||
|
|
import {
|
||
|
|
Popover,
|
||
|
|
PopoverContent,
|
||
|
|
PopoverDescription,
|
||
|
|
PopoverTitle,
|
||
|
|
PopoverTrigger,
|
||
|
|
} from "@workspace/ui/components/popover"
|
||
|
|
|
||
|
|
;<Popover>
|
||
|
|
<PopoverTrigger render={<Button variant="outline" />}>
|
||
|
|
打开设置
|
||
|
|
</PopoverTrigger>
|
||
|
|
<PopoverContent align="end">
|
||
|
|
<PopoverTitle>显示设置</PopoverTitle>
|
||
|
|
<PopoverDescription>选择列表密度。</PopoverDescription>
|
||
|
|
</PopoverContent>
|
||
|
|
</Popover>
|
||
|
|
```
|
||
|
|
|
||
|
|
本地 API 继续转发 Base UI Popup 与 Positioner 的 props。需要受控状态时给 `Popover` 传入 `open` 和 `onOpenChange`。
|
||
|
|
|
||
|
|
## 连续尾巴 {#anchored-surface}
|
||
|
|
|
||
|
|
本仓库的 `showArrow` 不是普通三角 SVG。它让 `PopoverContent` 用 `AnchoredSurface` 渲染一个圆角表面与连续曲线尾巴:
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
<PopoverContent
|
||
|
|
side="bottom"
|
||
|
|
showArrow={{ cornerRadius: "2xl", tailSize: "sm" }}
|
||
|
|
className="w-80 p-0"
|
||
|
|
viewportClassName="max-h-72 p-4"
|
||
|
|
>
|
||
|
|
{content}
|
||
|
|
</PopoverContent>
|
||
|
|
```
|
||
|
|
|
||
|
|
外层表面保持 `overflow: visible`,避免尾巴被裁剪;滚动发生在内部 `data-slot="popover-viewport"`。因此要限制内容高度或设置 padding 时,优先使用 `viewportClassName`。
|
||
|
|
|
||
|
|
`AnchoredSurface` 也可以独立使用,但它只负责视觉表面,不负责测量锚点、碰撞检测、焦点或 Portal。
|
||
|
|
|
||
|
|
## 自定义定位 {#positioning}
|
||
|
|
|
||
|
|
`PopoverContent` 额外暴露 `anchor`、`positionMethod`、`arrowPadding`、`alignOffset` 和 `sideOffset`。虚拟锚点或自定义锚点应通过这些参数传给共享组件,不需要绕过它重新拼装 Base UI primitives。
|
||
|
|
|
||
|
|
需要从非 React 代码控制弹层时,可使用 `createPopoverHandle<Payload>()` 创建 handle,再按 Base UI 的 handle 模式传给 Root。
|
||
|
|
|
||
|
|
## 选择浮层 {#choosing-an-overlay}
|
||
|
|
|
||
|
|
- 必须阻止背景交互:`Dialog` 或 `AlertDialog`。
|
||
|
|
- 从屏幕边缘进入的任务面板:`Sheet`;强调触摸拖拽的移动面板:`Drawer`。
|
||
|
|
- 与一个触发点关联的交互内容:`Popover`。
|
||
|
|
- 只在悬停或聚焦时补充预览:`HoverCard`。
|
||
|
|
- 简短、非交互说明:`Tooltip`。
|
||
|
|
|
||
|
|
基础用法可与 [shadcn Popover 文档](https://ui.shadcn.com/docs/components/base/popover)对照;组合语法必须使用 Base UI 版本的 `render`。
|