弹出框
查看源代码鼠标点击在某个组件时,弹出的气泡式的卡片浮层。可以对卡片上的元素进行操作。
导入
import {
Popover,
PopoverAnchor,
PopoverTrigger,
PopoverContent,
PopoverArrow,
PopoverTitle,
PopoverDescription,
PopoverClose,
} from "@resolid/react-ui";
Popover
: 包含弹出框的所有部分。PopoverTrigger
: 包装将打开弹出框的控件。PopoverAnchor
: 用于包装位置的可选引用元素。PopoverContent
: 包含弹出框打开时要呈现的内容。PopoverArrow
: 一个可选的箭头元素,与弹出框一起渲染。PopoverTitle
: 打开弹出框时要宣布的可访问标题。PopoverDescription
: 打开弹出框时要宣布的可选描述。PopoverClose
: 关闭弹出框的控件。
演示
弹出框默认的样式并不是很多,你可以通过 PopoverContent
、PopoverTitle
和 PopoverDescription
的 className
自定义弹出框的样式。
import {
Button,
Popover,
PopoverArrow,
PopoverClose,
PopoverContent,
PopoverDescription,
PopoverTitle,
PopoverTrigger,
} from "@resolid/react-ui";
export default function App() {
return (
<div className={"flex flex-row gap-3"}>
<Popover>
<PopoverTrigger render={(props) => <Button {...props} />}>打开弹出框</PopoverTrigger>
<PopoverContent className="max-w-96">
<PopoverArrow />
<PopoverTitle className={"p-4"}>弹出框标题</PopoverTitle>
<PopoverDescription className={"p-4 pt-1"}>
这是一个弹出框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
</PopoverDescription>
<div className={"flex justify-end gap-4 p-4 pt-1"}>
<PopoverClose
render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
>
取消
</PopoverClose>
<Button color={"neutral"}>确定</Button>
</div>
</PopoverContent>
</Popover>
</div>
);
}
举例
嵌套
你可以正常的嵌套弹出框。
import {
Button,
Popover,
PopoverTrigger,
PopoverContent,
PopoverArrow,
PopoverTitle,
PopoverDescription,
} from "@resolid/react-ui";
export default function App() {
return (
<div className={"flex flex-row gap-3"}>
<Popover>
<PopoverTrigger render={(props) => <Button {...props} />}>打开弹出框</PopoverTrigger>
<PopoverContent className="max-w-96">
<PopoverArrow />
<PopoverTitle className={"p-4"}>弹出框标题</PopoverTitle>
<PopoverDescription className={"p-4 pt-1"}>
你正在进行一项操作,这可能会影响当前的设置或数据。请确认是否继续?如果不确定,可以先查看相关文档,或者咨询管理员获取更多信息。
</PopoverDescription>
<div className={"flex p-4 pt-1"}>
<Popover>
<PopoverTrigger
render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
>
打开嵌套弹出框
</PopoverTrigger>
<PopoverContent className="max-w-86">
<PopoverArrow />
<PopoverDescription className={"p-4"}>一些嵌套的弹出内容</PopoverDescription>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</div>
);
}
焦点管理
弹出框打开会自动将焦点设置在第一个可用的元素上,关闭时会自动返回焦点,你可以通过设置 initialFocus
和 finalFocus
属性来自定义焦点目标
import {
Button,
Input,
Popover,
PopoverArrow,
PopoverClose,
PopoverContent,
PopoverTitle,
PopoverTrigger,
} from "@resolid/react-ui";
import { useRef } from "react";
export default function App() {
const initialRef = useRef(null);
const finalRef = useRef(null);
return (
<div className={"flex flex-row gap-3"}>
<Popover initialFocus={initialRef} finalFocus={finalRef}>
<PopoverTrigger render={(props) => <Button {...props} />}>打开弹出框</PopoverTrigger>
<Button color={"neutral"} ref={finalRef}>
键盘关闭对话框后获得焦点
</Button>
<PopoverContent className="max-w-128">
<PopoverArrow />
<PopoverTitle className={"p-4"}>弹出框标题</PopoverTitle>
<div className={"flex flex-col gap-4 p-4 pt-1"}>
<div className={"flex flex-col gap-1"}>
<label htmlFor={"username"}>姓名</label>
<Input id={"username"} />
</div>
<div className={"flex flex-col gap-1"}>
<label htmlFor={"email"}>邮件</label>
<Input ref={initialRef} id={"email"} />
</div>
</div>
<div className={"flex justify-end gap-4 p-4 pt-1"}>
<PopoverClose
render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
>
取消
</PopoverClose>
<Button color={"neutral"}>保存</Button>
</div>
</PopoverContent>
</Popover>
</div>
);
}
自定锚点
如果您不想将触发器用作锚点,请使用 PopoverAnchor
组件将内容锚定在另一个元素上。
import {
Button,
CloseButton,
Popover,
PopoverAnchor,
PopoverArrow,
PopoverClose,
PopoverContent,
PopoverDescription,
PopoverTitle,
PopoverTrigger,
} from "@resolid/react-ui";
export default function App() {
return (
<div className={"flex flex-row justify-center gap-3"}>
<Popover placement={"bottom"}>
<PopoverAnchor className={"bg-bg-subtlest rounded-md p-3"}>
<p className={"flex items-center"}>
单击
<PopoverTrigger
render={(props) => (
<Button {...props} size={"xs"} color={"neutral"} variant={"subtle"} />
)}
>
打开弹出框
</PopoverTrigger>
时,弹出窗口将打开。
</p>
<p>但是它固定在整个 Div 上。</p>
</PopoverAnchor>
<PopoverContent className="max-w-96">
<PopoverArrow />
<PopoverTitle className={"p-4"}>弹出框标题</PopoverTitle>
<PopoverDescription className={"p-4 pt-1"}>
这是一个弹出框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
</PopoverDescription>
<PopoverClose
render={(props) => <CloseButton className={"absolute end-2 top-2"} {...props} />}
/>
</PopoverContent>
</Popover>
</div>
);
}
上下文
TooltipProvider
组件为工具提示提供了上下文。接受 useTooltip
挂钩的值。你可以利用它来访问工具提示外部的组件状态和方法。
import {
Button,
PopoverArrow,
PopoverContent,
PopoverProvider,
usePopover,
} from "@resolid/react-ui";
import { useEffect, useRef } from "react";
const usePopoverSelection = () => {
const ref = useRef(null);
const { setOpen, setPositionReference, floatingReference, ...popover } = usePopover({
placement: "top",
inlineMiddleware: true,
});
useEffect(() => {
const node = ref.current;
if (!node) {
return;
}
const doc = node.ownerDocument || document;
const handleMouseUp = (e) => {
if (floatingReference.current?.contains(e.target)) {
return;
}
requestAnimationFrame(() => {
const selection = doc.getSelection();
if (!selection?.rangeCount) {
return null;
}
if (selection?.isCollapsed) {
setOpen(false);
return;
}
const range = selection.getRangeAt(0);
if (range && node.contains(range.commonAncestorContainer)) {
setPositionReference({
getBoundingClientRect: () => range.getBoundingClientRect(),
getClientRects: () => range.getClientRects(),
});
setOpen(true);
}
});
};
const handleMouseDown = (e) => {
if (floatingReference.current?.contains(e.target)) {
return;
}
if (doc.getSelection()?.isCollapsed) {
setOpen(false);
}
};
doc.addEventListener("mouseup", handleMouseUp);
doc.addEventListener("mousedown", handleMouseDown);
return () => {
doc.removeEventListener("mouseup", handleMouseUp);
doc.removeEventListener("mousedown", handleMouseDown);
};
}, [floatingReference]);
return { popover, ref };
};
export default function App() {
const { popover, ref } = usePopoverSelection();
return (
<div className={"flex flex-row justify-center gap-3"}>
<div ref={ref} className={"w-1/2"}>
Resolid React UI 是 React 的开源设计系统。使用 React 和 Tailwind CSS
构建。它提供了一组即用型组件,用于构建具有一致外观的 Web 应用程序。
</div>
<PopoverProvider value={popover}>
<PopoverContent className={"p-1"}>
<PopoverArrow />
<Button variant={"ghost"} size={"sm"} color={"neutral"}>
Save
</Button>
<Button variant={"ghost"} size={"sm"} color={"neutral"}>
Edit
</Button>
<Button variant={"ghost"} size={"sm"} color={"neutral"}>
Share
</Button>
</PopoverContent>
</PopoverProvider>
</div>
);
}
放置位置
通过传递 placement
属性来更改弹出框的放置位置。
import {
Button,
Popover,
PopoverArrow,
PopoverContent,
PopoverDescription,
PopoverTitle,
PopoverTrigger,
} from "@resolid/react-ui";
export default function App() {
return (
<div
className={"mx-auto grid w-fit gap-2"}
style={{
gridTemplateAreas:
'". top-start top top-end . "' +
'"left-start . . . right-start "' +
'"left . center . right "' +
'"left-end . . . right-end "' +
'". bottom-start bottom bottom-end . "',
}}
>
{[
["top-start", "上左"],
["top", "上"],
["top-end", "上右"],
["left-start", "左上"],
["left", "左"],
["left-end", "左下"],
["auto", "自动"],
["right-start", "右上"],
["right", "右"],
["right-end", "右下"],
["bottom-start", "下左"],
["bottom", "下"],
["bottom-end", "下右"],
].map(([placement, name]) => (
<Popover key={placement} placement={placement}>
<PopoverTrigger
render={(props) => <Button variant={"soft"} color={"neutral"} {...props} />}
style={{
gridArea: placement === "auto" ? "center" : placement,
}}
>
{name}
</PopoverTrigger>
<PopoverContent className="max-w-96">
<PopoverArrow />
<PopoverTitle className={"p-4"}>弹出框标题</PopoverTitle>
<PopoverDescription className={"p-4 pt-0"}>
这是一个弹出框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
</PopoverDescription>
</PopoverContent>
</Popover>
))}
</div>
);
}
属性
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性open | 简介 受控打开状态 | 类型boolean | 默认值- | 必须false |
属性defaultOpen | 简介 初始渲染时的默认打开状态 | 类型boolean | 默认值false | 必须false |
属性onOpenChange | 简介 打开状态改变时调用 | 类型(open: boolean) => void | 默认值- | 必须false |
属性initialFocus | 简介 开启后焦点目标 | 类型number | RefObject<HTMLElement> | 默认值- | 必须false |
属性finalFocus | 简介 关闭后焦点目标 | 类型RefObject<HTMLElement> | 默认值- | 必须false |
属性closeOnEscape | 简介 按下 Esc 键时关闭 | 类型boolean | 默认值true | 必须false |
属性closeOnOutsideClick | 简介 单击外部时关闭 | 类型boolean | 默认值true | 必须false |
属性placement | 简介 放置位置 | 类型"auto" | Placement | 默认值"auto" | 必须false |
属性duration | 简介 动画持续时间 | 类型number | 默认值250 | 必须false |
属性inlineMiddleware | 简介 控制是否启用 inline 中间件 | 类型boolean | 默认值false | 必须false |