浮层组件
对话框
带遮罩的模态对话框,支持键盘导航(Esc 关闭)和焦点陷阱,完全符合 WAI-ARIA 规范。
安装
bash
pnpm dlx shadcn@latest add dialog -c packages/react基础用法
tsx
import {
Dialog, DialogContent, DialogHeader,
DialogTitle, DialogDescription, DialogFooter
} from "@polyui/react/dialog"
import { Button } from "@polyui/react/button"
export function DeleteConfirm() {
return (
<Dialog>
<Button>打开对话框</Button>
<DialogContent>
<DialogHeader>
<DialogTitle>确认删除</DialogTitle>
<DialogDescription>
此操作不可撤销,数据将永久删除。
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline">取消</Button>
<Button variant="destructive">删除</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}受控模式
通过 open 和 onOpenChange 完全控制对话框的开关状态。
tsx
const [open, setOpen] = useState(false)
<Dialog open={open} onOpenChange={setOpen}>
<Button onClick={() => setOpen(true)}>
打开
</Button>
<DialogContent>
{/* ... */}
</DialogContent>
</Dialog>基础
Basic Dialogs
vue
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from "@polyui/vue/dialog"
import { Button } from "@polyui/vue/button"
export function DialogBasicDemos() {
return (
<div class="flex flex-wrap gap-3">
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">Basic Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account and remove your data from our
servers.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose as-child>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Continue</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">Destructive</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader class="items-center">
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription class="text-center">
This action cannot be undone. This will permanently delete your account and remove your data from our
servers.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose as-child>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button variant="destructive">Delete</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">Edit Profile</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>Make changes to your profile here. Click save when you're done.</DialogDescription>
</DialogHeader>
<div class="grid gap-4">
<div class="grid gap-2">
<label for="dlg-name-vue">Name</label>
<input id="dlg-name-vue" value="Pedro Duarte" class="border rounded px-3 py-2 text-sm" />
</div>
<div class="grid gap-2">
<label for="dlg-username-vue">Username</label>
<input id="dlg-username-vue" value="@peduarte" class="border rounded px-3 py-2 text-sm" />
</div>
</div>
<DialogFooter>
<DialogClose as-child>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">Terms & Conditions</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-md">
<DialogHeader>
<DialogTitle class="border-b pb-3">Terms and Conditions</DialogTitle>
</DialogHeader>
<div class="text-muted-foreground py-2 text-sm">
<ol class="flex list-decimal flex-col gap-2 pl-4">
<li>
<strong class="text-foreground">Eligibility:</strong> You must be at least 18 years old to use this
service.
</li>
<li>
<strong class="text-foreground">Account Responsibility:</strong> You are responsible for maintaining the
confidentiality of your account and password.
</li>
<li>
<strong class="text-foreground">Usage:</strong> Do not misuse or attempt to disrupt the service.
</li>
<li>
<strong class="text-foreground">Data Collection:</strong> We collect and use your data as described in
our Privacy Policy.
</li>
<li>
<strong class="text-foreground">Modifications:</strong> We reserve the right to update or modify these
terms at any time.
</li>
</ol>
</div>
<DialogFooter>
<DialogClose as-child>
<Button variant="outline">Cancel</Button>
</DialogClose>
<DialogClose as-child>
<Button>I Agree</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
)
}富内容
Rich Content
tsx
export function DialogRichContent() {
return (
<div className="flex flex-col gap-3">
<p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Rich Content</p>
<div className="flex flex-wrap gap-3">
<DialogReferAndEarn />
<DialogRating />
<DialogSignInV2 />
<DialogSignUpV2 />
<DialogInviteV2 />
</div>
</div>
)
}定位
Positioning
tsx
export function DialogPositioning() {
return (
<div className="flex flex-col gap-3">
<p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Positioning</p>
<div className="flex flex-wrap gap-3">
<DialogTopLeft />
<DialogTop />
<DialogTopRight />
<DialogMiddleLeft />
<DialogMiddleRight />
<DialogBottomLeft />
<DialogBottom />
<DialogBottomRight />
</div>
</div>
)
}动画
Animations
tsx
export function DialogAnimations() {
return (
<div className="flex flex-col gap-3">
<p className="text-xs font-mono text-muted-foreground tracking-widest uppercase">Animations</p>
<div className="flex flex-wrap gap-3">
<DialogSlideToTop />
<DialogSlideToRight />
<DialogZoomIn />
</div>
</div>
)
}Props
Dialog
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
open | boolean | — | 受控开关状态 |
onOpenChange | (open: boolean) => void | — | 状态变化回调 |
defaultOpen | boolean | false | 非受控初始状态 |
modal | boolean | true | 是否为模态(阻止背景交互) |
DialogContent
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 自定义样式 |
showCloseButton | boolean | true | 是否显示右上角关闭按钮 |
onEscapeKeyDown | (e: KeyboardEvent) => void | — | Esc 键回调 |
onPointerDownOutside | (e: PointerEvent) => void | — | 点击遮罩回调 |