@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
JavaScript
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