UNPKG

@veracity/vui

Version:

Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.

105 lines (103 loc) 3.41 kB
import { useCallbackRef } from "../utils/react.js"; import { useCallback, useEffect, useState } from "react"; import { autoUpdate, flip, offset, safePolygon, shift, size, useClick, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, useTransitionStyles } from "@floating-ui/react"; //#region src/popover/usePopover.ts /** * Controls the logic of positioning and managing a floating popover. * Takes multiple configuration props that control closing, placement or behavior. * Exposes functions used for ref callbacks on consuming components, programmatic open/close methods and properties. */ function usePopover(props = {}) { const { closeOnBlur = true, closeOnEsc = true, defaultIsOpen = false, flip: flip$1 = true, isOpen: isOpenProp, matchWidth, offset: offset$1, onClose: onCloseProp, onOpen: onOpenProp, nodeId, placement = "bottom-start", trigger = "click" } = props; const isControlled = isOpenProp !== void 0; const [isOpenState, setIsOpenState] = useState(defaultIsOpen); const isOpen = isControlled ? isOpenProp : isOpenState; const onClose = useCallbackRef(onCloseProp); const onOpen = useCallbackRef(onOpenProp); const setIsOpen = useCallback((open) => { if (!isControlled) setIsOpenState(open); if (open) onOpen(); else onClose(); }, [ isControlled, onOpen, onClose ]); const close = useCallback(() => setIsOpen(false), [setIsOpen]); const open = useCallback(() => setIsOpen(true), [setIsOpen]); const middleware = [ offset({ mainAxis: offset$1?.[1] ?? 4, crossAxis: offset$1?.[0] ?? 0 }), flip$1 && flip(), shift({ padding: 5 }), matchWidth && size({ apply({ rects, elements }) { Object.assign(elements.floating.style, { width: `${rects.reference.width}px` }); } }) ].filter(Boolean); const { refs, floatingStyles, context } = useFloating({ open: isOpen, onOpenChange: setIsOpen, nodeId, placement, middleware, whileElementsMounted: autoUpdate }); const { isMounted, styles: transitionStyles } = useTransitionStyles(context, { duration: 150, initial: { opacity: 0 }, open: { opacity: 1 }, close: { opacity: 0 } }); const clickEnabled = trigger === "click" && !isControlled; const hoverEnabled = trigger === "mouseenter" && !isControlled; const focusEnabled = (trigger === "focus" || trigger === "focusin") && !isControlled; const click = useClick(context, { enabled: clickEnabled }); const hover = useHover(context, { enabled: hoverEnabled, move: false, handleClose: hoverEnabled ? safePolygon() : null, delay: { open: 0, close: 200 } }); const focus = useFocus(context, { enabled: focusEnabled }); const dismiss = useDismiss(context, { enabled: !isControlled, escapeKey: closeOnEsc, outsidePress: closeOnBlur }); const role = useRole(context); const { getReferenceProps, getFloatingProps } = useInteractions([ click, hover, focus, dismiss, role ]); useEffect(() => { if (isControlled) setIsOpenState(isOpenProp); }, [isControlled, isOpenProp]); return { close, context, floatingStyles, getFloatingProps, getReferenceProps, isMounted, isOpen, open, popper: refs.floating.current, reference: refs.reference.current, refs, setPopper: refs.setFloating, setReference: refs.setReference, transitionStyles }; } //#endregion export { usePopover as default }; globalThis.__vuiVersion__ = "5.3.1" //# sourceMappingURL=usePopover.js.map