UNPKG

@1771technologies/lytenyte-pro

Version:

492 lines (491 loc) 15 kB
import { jsx } from "react/jsx-runtime"; import { u as useControlled, a as useTransitionStatus, b as useScrollLock, c as useGrid } from "./useScrollLock-D4UY33Sb.js"; import * as React from "react"; import { useState, useEffect } from "react"; import { A as AnchorProvider } from "./anchor-context-Cqr_oiJt.js"; import { F as FloatingPortal, P as PropTypes, H as HTMLElementType, r as refType, j as useEventCallback, n as useOpenChangeComplete, p as useFloatingRootContext, q as useHover, t as safePolygon, v as useClick, w as useDismiss, x as useRole, y as useListNavigation, z as useTypeahead, A as useInteractions, B as FloatingTree } from "./proptypes-BjYr2nFr.js"; import { u as useDirection } from "./DirectionContext-DIPP5cAe.js"; import * as ReactDOM from "react-dom"; const MenuRootContext = /* @__PURE__ */ React.createContext(void 0); if (process.env.NODE_ENV !== "production") { MenuRootContext.displayName = "MenuRootContext"; } function useMenuRootContext(optional) { const context = React.useContext(MenuRootContext); if (context === void 0 && !optional) { throw new Error("Base UI: MenuRootContext is missing. Menu parts must be placed within <Menu.Root>."); } return context; } const MenuPortalContext = /* @__PURE__ */ React.createContext(void 0); function useMenuPortalContext() { const value = React.useContext(MenuPortalContext); if (value === void 0) { throw new Error("Base UI: <Menu.Portal> is missing."); } return value; } function MenuPortal(props) { const { children, keepMounted = false, container } = props; const { mounted } = useMenuRootContext(); const shouldRender = mounted || keepMounted; if (!shouldRender) { return null; } return /* @__PURE__ */ jsx(MenuPortalContext.Provider, { value: keepMounted, children: /* @__PURE__ */ jsx(FloatingPortal, { root: container, children }) }); } process.env.NODE_ENV !== "production" ? MenuPortal.propTypes = { // ┌────────────────────────────── Warning ──────────────────────────────┐ // │ These PropTypes are generated from the TypeScript type definitions. │ // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ // └─────────────────────────────────────────────────────────────────────┘ /** * @ignore */ children: PropTypes.node, /** * A parent element to render the portal element into. */ container: PropTypes.oneOfType([HTMLElementType, refType]), /** * Whether to keep the portal mounted in the DOM while the popup is hidden. * @default false */ keepMounted: PropTypes.bool } : void 0; const TYPEAHEAD_RESET_MS = 500; const PATIENT_CLICK_THRESHOLD = 500; function translateOpenChangeReason(nativeReason) { if (!nativeReason) { return void 0; } return { // Identical mappings click: "click", hover: "hover", focus: "focus", "focus-out": "focus-out", "escape-key": "escape-key", "outside-press": "outside-press", // New mappings "reference-press": "trigger-press", "safe-polygon": "hover", "ancestor-scroll": void 0, // Not supported "list-navigation": void 0 // Unnecessary to expose currently }[nativeReason]; } const EMPTY_ARRAY = []; function useMenuRoot(parameters) { const { open: openParam, defaultOpen, onOpenChange, onOpenChangeComplete, orientation, direction, disabled, nested, closeParentOnEsc, loop, delay, openOnHover, onTypingChange, modal } = parameters; const [triggerElement, setTriggerElement] = React.useState(null); const [positionerElement, setPositionerElementUnwrapped] = React.useState(null); const [instantType, setInstantType] = React.useState(); const [hoverEnabled, setHoverEnabled] = React.useState(true); const [activeIndex, setActiveIndex] = React.useState(null); const [openReason, setOpenReason] = React.useState(null); const [stickIfOpen, setStickIfOpen] = React.useState(true); const popupRef = React.useRef(null); const positionerRef = React.useRef(null); const stickIfOpenTimeoutRef = React.useRef(-1); const [open, setOpenUnwrapped] = useControlled({ controlled: openParam, default: defaultOpen, name: "useMenuRoot", state: "open" }); const setPositionerElement = React.useCallback((value) => { positionerRef.current = value; setPositionerElementUnwrapped(value); }, []); const allowMouseUpTriggerRef = React.useRef(false); const { mounted, setMounted, transitionStatus } = useTransitionStatus(open); useScrollLock(open && modal && openReason !== "hover", triggerElement); const setOpen = useEventCallback((nextOpen, event, reason) => { onOpenChange?.(nextOpen, event); setOpenUnwrapped(nextOpen); if (nextOpen) { setOpenReason(reason ?? null); } }); if (!open && !hoverEnabled) { setHoverEnabled(true); } const handleUnmount = useEventCallback(() => { setMounted(false); setOpenReason(null); setStickIfOpen(true); onOpenChangeComplete?.(false); }); useOpenChangeComplete({ enabled: !parameters.actionsRef, open, ref: popupRef, onComplete() { if (!open) { handleUnmount(); } } }); React.useImperativeHandle(parameters.actionsRef, () => ({ unmount: handleUnmount }), [handleUnmount]); const clearStickIfOpenTimeout = useEventCallback(() => { clearTimeout(stickIfOpenTimeoutRef.current); }); React.useEffect(() => { if (!open) { clearStickIfOpenTimeout(); } }, [clearStickIfOpenTimeout, open]); React.useEffect(() => { return clearStickIfOpenTimeout; }, [clearStickIfOpenTimeout]); const floatingRootContext = useFloatingRootContext({ elements: { reference: triggerElement, floating: positionerElement }, open, onOpenChange(openValue, eventValue, reasonValue) { const isHover = reasonValue === "hover" || reasonValue === "safe-polygon"; const isKeyboardClick = reasonValue === "click" && eventValue.detail === 0; const isDismissClose = !openValue && (reasonValue === "escape-key" || reasonValue == null); function changeState() { setOpen(openValue, eventValue, translateOpenChangeReason(reasonValue)); } if (isHover) { clearStickIfOpenTimeout(); setStickIfOpen(true); stickIfOpenTimeoutRef.current = window.setTimeout(() => { setStickIfOpen(false); }, PATIENT_CLICK_THRESHOLD); ReactDOM.flushSync(changeState); } else { changeState(); } if (isKeyboardClick || isDismissClose) { setInstantType(isKeyboardClick ? "click" : "dismiss"); } else { setInstantType(void 0); } } }); const hover = useHover(floatingRootContext, { enabled: hoverEnabled && openOnHover && !disabled && openReason !== "click", handleClose: safePolygon({ blockPointerEvents: true }), mouseOnly: true, move: false, delay: { open: delay } }); const click = useClick(floatingRootContext, { enabled: !disabled, event: "mousedown", toggle: !openOnHover || !nested, ignoreMouse: openOnHover && nested, stickIfOpen }); const dismiss = useDismiss(floatingRootContext, { bubbles: closeParentOnEsc && nested, outsidePressEvent: "mousedown" }); const role = useRole(floatingRootContext, { role: "menu" }); const itemDomElements = React.useRef([]); const itemLabels = React.useRef([]); const listNavigation = useListNavigation(floatingRootContext, { enabled: !disabled, listRef: itemDomElements, activeIndex, nested, loop, orientation, rtl: direction === "rtl", disabledIndices: EMPTY_ARRAY, onNavigate: setActiveIndex }); const typeahead = useTypeahead(floatingRootContext, { listRef: itemLabels, activeIndex, resetMs: TYPEAHEAD_RESET_MS, onMatch: (index) => { if (open && index !== activeIndex) { setActiveIndex(index); } }, onTypingChange }); const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([hover, click, dismiss, role, listNavigation, typeahead]); const triggerProps = React.useMemo(() => getReferenceProps({ onMouseEnter() { setHoverEnabled(true); } }), [getReferenceProps]); const popupProps = React.useMemo(() => getFloatingProps({ onMouseEnter() { if (!openOnHover || nested) { setHoverEnabled(false); } }, onClick() { if (openOnHover) { setHoverEnabled(false); } } }), [getFloatingProps, openOnHover, nested]); const itemProps = React.useMemo(() => getItemProps(), [getItemProps]); return React.useMemo(() => ({ activeIndex, allowMouseUpTriggerRef, floatingRootContext, itemProps, popupProps, triggerProps, itemDomElements, itemLabels, mounted, open, popupRef, positionerRef, setOpen, setPositionerElement, setTriggerElement, transitionStatus, openReason, instantType, onOpenChangeComplete, setHoverEnabled }), [activeIndex, floatingRootContext, itemProps, popupProps, triggerProps, itemDomElements, itemLabels, mounted, open, positionerRef, setOpen, transitionStatus, setPositionerElement, openReason, instantType, onOpenChangeComplete]); } const MenuRoot = function MenuRoot2(props) { const { children, defaultOpen = false, disabled = false, closeParentOnEsc = true, loop = true, modal = true, onOpenChange, open, orientation = "vertical", delay = 100, openOnHover: openOnHoverProp, actionsRef, onOpenChangeComplete } = props; const direction = useDirection(); const parentContext = useMenuRootContext(true); const nested = parentContext != null; const openOnHover = openOnHoverProp ?? nested; const typingRef = React.useRef(false); const onTypingChange = React.useCallback((nextTyping) => { typingRef.current = nextTyping; }, []); const menuRoot = useMenuRoot({ direction, disabled, closeParentOnEsc, onOpenChange, loop, defaultOpen, open, orientation, nested, openOnHover, delay, onTypingChange, modal, actionsRef, onOpenChangeComplete }); const context = React.useMemo(() => ({ ...menuRoot, nested, parentContext, disabled, allowMouseUpTriggerRef: parentContext?.allowMouseUpTriggerRef ?? menuRoot.allowMouseUpTriggerRef, typingRef, modal }), [menuRoot, nested, parentContext, disabled, modal]); if (!nested) { return /* @__PURE__ */ jsx(FloatingTree, { children: /* @__PURE__ */ jsx(MenuRootContext.Provider, { value: context, children }) }); } return /* @__PURE__ */ jsx(MenuRootContext.Provider, { value: context, children }); }; process.env.NODE_ENV !== "production" ? MenuRoot.propTypes = { // ┌────────────────────────────── Warning ──────────────────────────────┐ // │ These PropTypes are generated from the TypeScript type definitions. │ // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ // └─────────────────────────────────────────────────────────────────────┘ /** * A ref to imperative actions. */ actionsRef: PropTypes.shape({ current: PropTypes.shape({ unmount: PropTypes.func.isRequired }).isRequired }), /** * @ignore */ children: PropTypes.node, /** * When in a submenu, determines whether pressing the Escape key * closes the entire menu, or only the current child menu. * @default true */ closeParentOnEsc: PropTypes.bool, /** * Whether the menu is initially open. * * To render a controlled menu, use the `open` prop instead. * @default false */ defaultOpen: PropTypes.bool, /** * How long to wait before the menu may be opened on hover. Specified in milliseconds. * * Requires the `openOnHover` prop. * @default 100 */ delay: PropTypes.number, /** * Whether the component should ignore user interaction. * @default false */ disabled: PropTypes.bool, /** * Whether to loop keyboard focus back to the first item * when the end of the list is reached while using the arrow keys. * @default true */ loop: PropTypes.bool, /** * Whether the menu should prevent outside clicks and lock page scroll when open. * @default true */ modal: PropTypes.bool, /** * Event handler called when the menu is opened or closed. */ onOpenChange: PropTypes.func, /** * Event handler called after any animations complete when the menu is closed. */ onOpenChangeComplete: PropTypes.func, /** * Whether the menu is currently open. */ open: PropTypes.bool, /** * Whether the menu should also open when the trigger is hovered. * * Defaults to `true` for nested menus. */ openOnHover: PropTypes.bool, /** * The visual orientation of the menu. * Controls whether roving focus uses up/down or left/right arrow keys. * @default 'vertical' */ orientation: PropTypes.oneOf(["horizontal", "vertical"]) } : void 0; const emptyBB = { getBoundingClientRect: () => ({ x: 0, y: 0, width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0, toJSON: () => "" }) }; function ColumnMenuDriver() { const grid = useGrid(); const menuColumn = grid.state.internal.columnMenuColumn.use(); const target = grid.state.internal.columnMenuTarget.use(); const MenuRenderer = grid.state.columnMenuRenderer.use(); const [open, setOpen] = useState(false); useEffect(() => { if (menuColumn == null || target == null) { setOpen(false); return; } setOpen(true); }, [menuColumn, target]); return /* @__PURE__ */ jsx( MenuRoot, { open, onOpenChange: (c) => { setOpen(c); }, onOpenChangeComplete: (c) => { if (!c) grid.api.columnMenuClose(); }, children: /* @__PURE__ */ jsx(MenuPortal, { children: /* @__PURE__ */ jsx(AnchorProvider, { anchor: target, children: MenuRenderer && menuColumn && /* @__PURE__ */ jsx(MenuRenderer, { api: grid.api, column: menuColumn }) }) }) } ); } export { ColumnMenuDriver as C, MenuRoot as M, PATIENT_CLICK_THRESHOLD as P, MenuPortal as a, useMenuPortalContext as b, emptyBB as e, translateOpenChangeReason as t, useMenuRootContext as u };