@1771technologies/lytenyte-pro
Version:
492 lines (491 loc) • 15 kB
JavaScript
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
};