Popover
Popover 从 HeroUI v2 到 v3 的迁移指南。
完整的 API 参考、样式指南与高级示例请参阅 v3 Popover 文档。本指南只关注从 HeroUI v2 的迁移。
结构变化
在 v2 中,Popover 由独立的多个组件组成:
import { Popover, PopoverTrigger, PopoverContent, Button } from "@lenso/ui";
export default function App() { return ( <Popover placement="right"> <PopoverTrigger> <Button>Open</Button> </PopoverTrigger> <PopoverContent> <div>Content</div> </PopoverContent> </Popover> );}在 v3 中,Popover 改为复合组件:
import { Popover, Button } from "@lenso/ui";
export default function App() { return ( <Popover> <Button>Open</Button> <Popover.Content> <Popover.Dialog> <Popover.Heading>Title</Popover.Heading> <div>Content</div> </Popover.Dialog> </Popover.Content> </Popover> );}主要变化
1. 组件结构
v2: 独立的多个组件(Popover、PopoverTrigger、PopoverContent)
v3: 复合组件(Popover、Popover.Trigger、Popover.Content、Popover.Dialog、Popover.Heading、Popover.Arrow)
2. Prop 变更
| v2 prop | v3 位置 | 说明 |
|---|---|---|
placement | placement(在 Content 上) | 移至 Popover.Content |
offset | offset(在 Content 上) | 移至 Popover.Content |
shouldFlip | shouldFlip(在 Content 上) | 移至 Popover.Content |
isOpen / defaultOpen / onOpenChange | 同名(在根上) | 受控状态仍保留在根 Popover 上 |
showArrow | — | 改用 Popover.Arrow 子组件 |
size | — | 已移除(请改用 Tailwind CSS) |
color | — | 已移除(请改用 Tailwind CSS) |
radius | — | 已移除(请改用 Tailwind CSS) |
shadow | — | 已移除(请改用 Tailwind CSS) |
backdrop | — | 已移除 |
motionProps | — | 已移除(动画机制已不同) |
classNames | — | 改在各子组件上使用 className |
onClose | — | 改用 onOpenChange((open) => { if (!open) { ... } }) |
迁移示例
内容配置
{/* With arrow */}<Popover showArrow> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent></Popover>
{/* With placement */}<Popover placement="top"> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent></Popover>
{/* With offset */}<Popover offset={10}> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent></Popover>带标题
<PopoverContent> <div className="px-1 py-2"> <div className="text-small font-bold">Title</div> <div className="text-tiny">Content</div> </div></PopoverContent>受控
import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
<Popover isOpen={isOpen} onOpenChange={setIsOpen}> <PopoverTrigger> <Button>Open</Button> </PopoverTrigger> <PopoverContent> <div>Content</div> </PopoverContent></Popover>自定义触发器
<PopoverTrigger> <CustomButton>Custom</CustomButton></PopoverTrigger>组件结构
v3 Popover 遵循以下结构:
Popover (Root) ├── Popover.Trigger (optional, or use Button directly) └── Popover.Content └── Popover.Dialog ├── Popover.Arrow (optional) ├── Popover.Heading (optional) └── Contentv3 中的新功能
Popover.Arrow 组件
在 v2 中,箭头通过根 Popover 上的 showArrow 布尔 prop 控制。在 v3 中,Popover.Arrow 是一个放置在 Popover.Content 内部的专用组件,让你可以完全控制其渲染:
<Popover> <Button>Open</Button> <Popover.Content> <Popover.Arrow className="custom-arrow" /> <Popover.Dialog> <div>Content</div> </Popover.Dialog> </Popover.Content></Popover>Popover.Arrow 也接受 render prop,可完全自定义箭头的渲染。
受控打开状态
受控的打开状态仍保留在根 Popover 组件上,prop 名称与 v2 一致:
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
isOpen | boolean | - | 控制 Popover 的可见性(受控) |
defaultOpen | boolean | false | 初始打开状态(非受控) |
onOpenChange | (isOpen: boolean) => void | - | 打开状态变化时触发 |
自定义渲染函数
Popover.Content 与 Popover.Arrow 都支持 render prop,让你可以在高级场景下用自定义渲染函数覆盖默认 DOM 元素。
总结
- 组件结构:必须使用复合组件(
Popover.Content、Popover.Dialog等) - 触发器:可以使用
Popover.Trigger,或直接将 Button 作为子节点 - 内容包装:内容必须放在
Popover.Dialog中 - 箭头:移除
showArrowprop——改用Popover.Arrow子组件 - 标题:改用
Popover.Heading组件 - prop 移动位置:
placement、offset、shouldFlip移到Popover.Content上 - 移除样式 prop:
size、color、radius、shadow—— 请改用 Tailwind CSS - 移除 backdrop:
backdropprop 已移除 - 移除 motion:
motionProps已移除,动画机制已不同 - 移除 classNames:改在各子组件上使用
classNameprop