@harvest-profit/npk
Version:
NPK UI Design System
89 lines (82 loc) • 2.4 kB
text/typescript
import { useMemo, useRef, useState } from 'react';
import { autoUpdate, flip, offset, shift } from '@floating-ui/dom';
import { arrow, useClick, useDismiss, useFloating, useInteractions, useMergeRefs, useRole } from '@floating-ui/react';
import { MenuContextType } from './MenuContext';
interface UsePopoverProps {
initialOpen?: boolean;
placement?: any;
modal?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
showArrow?: boolean | null;
initialFocus?: number;
autoDismiss?: boolean | 'menu';
submenu?: boolean;
variant?: string;
offset?: number;
}
function usePopover({
initialOpen = false,
placement = "bottom-start",
modal,
open: controlledOpen,
onOpenChange: setControlledOpen,
showArrow,
initialFocus,
autoDismiss = true,
submenu = false,
variant = 'dialog',
offset: offsetAmount = 5
}: UsePopoverProps): MenuContextType {
const [uncontrolledOpen, setUncontrolledOpen] = useState(initialOpen);
const [labelId, setLabelId] = useState<string | undefined>();
const [descriptionId, setDescriptionId] = useState<string | undefined>();
const arrowRef = useRef<HTMLElement>(null);
const open = controlledOpen ?? uncontrolledOpen;
const setOpen = setControlledOpen ?? setUncontrolledOpen;
const data = useFloating({
placement,
open,
onOpenChange: setOpen,
whileElementsMounted: autoUpdate,
middleware: [
offset(offsetAmount),
flip({
crossAxis: placement.includes("-"),
fallbackAxisSideDirection: "end",
}),
shift({ padding: 5 }),
arrow({
element: arrowRef,
}),
]
});
const click = useClick(data.context, { enabled: controlledOpen == null });
const dismiss = useDismiss(data.context);
const role = useRole(data.context);
const interactions = useInteractions([click, dismiss, role]);
return useMemo<MenuContextType>(
() => ({
menu: true,
open,
setOpen,
initialFocus,
...interactions,
...data,
modal,
submenu,
arrowRef,
labelId,
descriptionId,
setLabelId,
setDescriptionId,
showArrow,
autoDismiss,
useMergeRefs,
placement,
variant
}),
[open, setOpen, interactions, data, modal, labelId, descriptionId, arrowRef, showArrow, autoDismiss, submenu, placement, variant, initialFocus]
);
}
export default usePopover;