import { useState } from 'react'; import { autoPlacement, autoUpdate, flip, offset, shift, useClick, useDismiss, useFloating, useFloatingNodeId, useHover, useInteractions, useRole, type AutoPlacementOptions, type OffsetOptions, type Placement, type UseClickProps, type UseDismissProps, type UseHoverProps, type UseRoleProps, } from '@floating-ui/react'; export function usePopover( props: { hover?: boolean | UseHoverProps; role?: boolean | UseRoleProps; click?: boolean | UseClickProps; dismiss?: boolean | UseDismissProps; placement?: Placement; autoPlacement?: AutoPlacementOptions; offset?: OffsetOptions; // boundary?: Boundary; } = {}, ) { // let { container } = useContainer(); const [open, setOpen] = useState(false); const nodeId = useFloatingNodeId(); const { refs, floatingStyles, context } = useFloating({ nodeId, placement: props.placement, open: open, onOpenChange: setOpen, middleware: [ offset(props.offset ?? 10), !props.placement && autoPlacement({ // boundary: props.boundary, ...props.autoPlacement, }), // 至少确保在视窗内 props.placement && flip(), shift(), ], whileElementsMounted: autoUpdate, }); const list = []; if (props.dismiss ?? true) { const dismiss = useDismiss(context, typeof props.dismiss === 'object' ? props.dismiss : {}); list.push(dismiss); } if (props.click ?? true) { const click = useClick(context, typeof props.click === 'object' ? props.click : {}); list.push(click); } if (props.role ?? true) { const role = useRole(context, typeof props.role === 'object' ? props.role : {}); list.push(role); } if (props.hover) { const opts = typeof props.hover === 'object' ? props.hover : { move: false }; const hover = useHover(context, opts); list.push(hover); } // Merge all the interactions into prop getters const { getReferenceProps, getFloatingProps } = useInteractions(list); return { nodeId, refs, open, setOpen, getReferenceProps, getFloatingProps, floatingStyles, context, }; }