Popover 基于 Floating UI 实现. 可以完全自定义弹出的内容.
Tooltip,Combobox等组件都是基于Popover实现
默认点击target时打开.
Popover的withArrow属性控制着是否显示箭头
withArrow为true时
当Popover的position属性设置为*-start和*-end值时, 并且arrowPosition属性为side时, 箭头会被定位在目标元素的边, arrowOffset属性可以对其进行偏移.
其它情况下, 箭头会被定位在目标元素的中心。arrowOffset属性会被忽略.
opened为受控属性, defaultOpened为非受控属性. 不提供opened属性则在非受控模式下, 此时点击Target内孩子则会打开弹出框.
当提供了opened属性则在受控模式下, 此时不会自动打开弹出框, 必须使用手动设置受控属性值为true才会打开弹出框
import { Popover, Button } from "@rtdui/core";
export default function Demo() {
const [open, setOpen] = React.useState(false);
return (
<Popover opened={open} onChange={setOpen}>
<Popover.Target>
<Button onClick={(e) => setOpen(true)}>popover</Button>
</Popover.Target>
<Popover.Dropdown>
<div className="w-80 h-40 bg-base-200 p-8 rounded-box">abcdefg</div>
</Popover.Dropdown>
</Popover>
);
}
Popover的trapFocus属性控制是否启用焦点围栏, 默认为false.
焦点围栏是指当弹出框显示时, 键盘Tab键的焦点跳转范围限定在弹出框内. 对于弹出框中带有输入控件时尤其有用.
Popover支持Transition组件提供的预置过渡效果和自定义效果, 默认为"fade"
Popover的disabled属性控 制着是否禁止弹出.
Popover的keepMounted属性控制着弹出框关闭时是否保持挂载, 默认为false, 表示弹出框关闭时卸载组件. 如果为true,表示弹出框关闭时不卸载组件,但不可见.
Popover是基于Floating UI实现的, Popover支持的Floating UI中间件:
Popover的width属性为target自动启用, 否则未启用.启用或禁用中间件:
import { Popover } from "@rtdui/core";
function Demo() {
return (
<Popover
middlewares={{ flip: false, shift: { padding: 20 } }} // 禁用flip中间件, 设置shift中间件的自定义选项.
position="bottom"
>
{/* Popover content */}
</Popover>
);
}
嵌套Popover要求子Popover必须禁用withPortal属性. 如果子Portal没有被禁用, 点击子Popover外部会关闭嵌套的所有Popover
所有基于Combobox的组件(间接基于Popover), 如AutoComplete,Select,MultiSelect, TagsInput内部都使用了Popover, 以及直接基于Popover构建的组件, 如Tooltip组件, 这些组件用在Popover组件内, 必须设置它们的withPortal属性为false
import { Button, Popover, Select } from "@rtdui/core";
function Demo() {
return (
<Popover width={300} position="bottom" withArrow shadow="md">
<Popover.Target>
<Button>Toggle popover</Button>
</Popover.Target>
<Popover.Dropdown>
<AutoComplete
comboboxProps={{ withinPortal: false }} // 基于Combobox的通过comboboxProps.withinPortal禁用
label="DatePickerInput within Popover"
placeholder="DatePickerInput within Popover"
data={["React", "Angular", "Svelte", "Vue"]}
/>
<Select
comboboxProps={{ withinPortal: false }} // 基于Combobox的通过comboboxProps.withinPortal禁用
label="Select within Popover"
placeholder="Select within Popover"
data={["React", "Angular", "Svelte", "Vue"]}
/>
<MultiSelect
comboboxProps={{ withinPortal: false }} // 基于Combobox的通过comboboxProps.withinPortal禁用
label="Select within Popover"
placeholder="Select within Popover"
data={["React", "Angular", "Svelte", "Vue"]}
/>
<TagsInput
comboboxProps={{ withinPortal: false }} // 基于Combobox的通过comboboxProps.withinPortal禁用
label="Select within Popover"
placeholder="Select within Popover"
data={["React", "Angular", "Svelte", "Vue"]}
/>
<Tooltip
withinPortal={false} // 直接基于Popover的通过withinPortal禁用
tip="click me"
>
<button></button>
</Tooltip>
</Popover.Dropdown>
</Popover>
);
}| 属性名 | 类型 | 是否必须 | 默认值 | 说明 |
|---|---|---|---|---|
| arrowOffset | number | undefined | no | 10 | Arrow offset in px |
| arrowPosition | ArrowPosition | undefined | no | "side" | Arrow position |
| arrowRadius | number | undefined | no | 0 | Arrow <code>border-radius</code> in px |
| arrowSize | number | undefined | no | 7 | Arrow size in px |
| children | React.ReactNode | no | <code>Popover.Target</code> and <code>Popover.Dropdown</code> components | |
| clickOutsideEvents | string[] | undefined | no | ["mousedown", "touchstart"] | Events that trigger outside clicks |
| closeOnClickOutside | boolean | undefined | no | true | Determines whether dropdown should be closed on outside clicks |
| closeOnEscape | boolean | undefined | no | true | Determines whether dropdown should be closed when <code>Escape</code> key is pressed |
| defaultOpened | boolean | undefined | no | Initial opened state for uncontrolled component | |
| disabled | boolean | undefined | no | If set, popover dropdown will not be rendered | |
| dropdownColor | string | undefined | no | background color of dropdown and arrow, default 'bg-base-100' | |
| floatingStrategy | FloatingStrategy | undefined | no | "absolute" | Changes floating ui [position strategy](https://floating-ui.com/docs/usefloating#strategy) |
| id | string | undefined | no | id base to create accessibility connections | |
| keepMounted | boolean | undefined | no | If set dropdown will not be unmounted from the DOM when it is hidden, <code>display: none</code> styles will be added instead | |
| middlewares | PopoverMiddlewares | undefined | no | { flip: true, shift: true, inline: false } | Floating ui middlewares to configure position handling |
| offset | number | FloatingAxesOffsets | undefined | no | 8 | Offset of the dropdown element |
| onChange | ((opened: boolean) => void) | undefined | no | Called with current state when dropdown opens or closes | |
| onClose | (() => void) | undefined | no | Called when dropdown closes | |
| onOpen | (() => void) | undefined | no | Called when dropdown opens | |
| onPositionChange | ((position: FloatingPosition) => void) | undefined | no | Called when dropdown position changes | |
| opened | boolean | undefined | no | Controlled dropdown opened state | |
| portalProps | Omit<PortalProps, "children"> | undefined | no | Props to pass down to the <code>Portal</code> when <code>withinPortal</code> is true | |
| position | FloatingPosition | undefined | no | "bottom" | Dropdown position relative to the target element |
| positionDependencies | any[] | undefined | no | [] | <code>useEffect</code> dependencies to force update dropdown position |
| radius | string | undefined | no | "md" | Key of <code>theme.radius</code> or any valid CSS value to set border-radius |
| returnFocus | boolean | undefined | no | false | Determines whether focus should be automatically returned to control when dropdown closes |
| shadow | ThemeShadow | undefined | no | "md" | Key of <code>theme.shadows</code> or any other valid CSS <code>box-shadow</code> value |
| transitionProps | Omit<TransitionProps, "children"> | undefined | no | {duration: 150, transition: 'fade'} | Props passed down to the <code>Transition</code> component that used to animate dropdown presence, use to configure duration and animation type |
| trapFocus | boolean | undefined | no | false | Determines whether focus should be trapped within dropdown |
| width | PopoverWidth | no | "max-content" | Dropdown width, or <code>'target'</code> to make dropdown width the same as target element |
| withArrow | boolean | undefined | no | false | Determines whether component should have an arrow |
| withRoles | boolean | undefined | no | true | Determines whether dropdown and target elements should have accessible roles |
| withinPortal | boolean | undefined | no | true | Determines whether dropdown should be rendered within the <code>Portal</code> |
| zIndex | string | number | undefined | no | 50 | Dropdown <code>z-index</code> |