Files
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

902 lines
38 KiB
JavaScript

"use strict";
"use client";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/react/menu/src/index.ts
var src_exports = {};
__export(src_exports, {
Anchor: () => Anchor2,
Arrow: () => Arrow2,
CheckboxItem: () => CheckboxItem,
Content: () => Content2,
Group: () => Group,
Item: () => Item2,
ItemIndicator: () => ItemIndicator,
Label: () => Label,
Menu: () => Menu,
MenuAnchor: () => MenuAnchor,
MenuArrow: () => MenuArrow,
MenuCheckboxItem: () => MenuCheckboxItem,
MenuContent: () => MenuContent,
MenuGroup: () => MenuGroup,
MenuItem: () => MenuItem,
MenuItemIndicator: () => MenuItemIndicator,
MenuLabel: () => MenuLabel,
MenuPortal: () => MenuPortal,
MenuRadioGroup: () => MenuRadioGroup,
MenuRadioItem: () => MenuRadioItem,
MenuSeparator: () => MenuSeparator,
MenuSub: () => MenuSub,
MenuSubContent: () => MenuSubContent,
MenuSubTrigger: () => MenuSubTrigger,
Portal: () => Portal,
RadioGroup: () => RadioGroup,
RadioItem: () => RadioItem,
Root: () => Root3,
Separator: () => Separator,
Sub: () => Sub,
SubContent: () => SubContent,
SubTrigger: () => SubTrigger,
createMenuScope: () => createMenuScope
});
module.exports = __toCommonJS(src_exports);
// packages/react/menu/src/Menu.tsx
var React = __toESM(require("react"));
var import_primitive = require("@radix-ui/primitive");
var import_react_collection = require("@radix-ui/react-collection");
var import_react_compose_refs = require("@radix-ui/react-compose-refs");
var import_react_context = require("@radix-ui/react-context");
var import_react_direction = require("@radix-ui/react-direction");
var import_react_dismissable_layer = require("@radix-ui/react-dismissable-layer");
var import_react_focus_guards = require("@radix-ui/react-focus-guards");
var import_react_focus_scope = require("@radix-ui/react-focus-scope");
var import_react_id = require("@radix-ui/react-id");
var PopperPrimitive = __toESM(require("@radix-ui/react-popper"));
var import_react_popper = require("@radix-ui/react-popper");
var import_react_portal = require("@radix-ui/react-portal");
var import_react_presence = require("@radix-ui/react-presence");
var import_react_primitive = require("@radix-ui/react-primitive");
var RovingFocusGroup = __toESM(require("@radix-ui/react-roving-focus"));
var import_react_roving_focus = require("@radix-ui/react-roving-focus");
var import_react_slot = require("@radix-ui/react-slot");
var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
var import_aria_hidden = require("aria-hidden");
var import_react_remove_scroll = require("react-remove-scroll");
var import_jsx_runtime = require("react/jsx-runtime");
var SELECTION_KEYS = ["Enter", " "];
var FIRST_KEYS = ["ArrowDown", "PageUp", "Home"];
var LAST_KEYS = ["ArrowUp", "PageDown", "End"];
var FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
var SUB_OPEN_KEYS = {
ltr: [...SELECTION_KEYS, "ArrowRight"],
rtl: [...SELECTION_KEYS, "ArrowLeft"]
};
var SUB_CLOSE_KEYS = {
ltr: ["ArrowLeft"],
rtl: ["ArrowRight"]
};
var MENU_NAME = "Menu";
var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(MENU_NAME);
var [createMenuContext, createMenuScope] = (0, import_react_context.createContextScope)(MENU_NAME, [
createCollectionScope,
import_react_popper.createPopperScope,
import_react_roving_focus.createRovingFocusGroupScope
]);
var usePopperScope = (0, import_react_popper.createPopperScope)();
var useRovingFocusGroupScope = (0, import_react_roving_focus.createRovingFocusGroupScope)();
var [MenuProvider, useMenuContext] = createMenuContext(MENU_NAME);
var [MenuRootProvider, useMenuRootContext] = createMenuContext(MENU_NAME);
var Menu = (props) => {
const { __scopeMenu, open = false, children, dir, onOpenChange, modal = true } = props;
const popperScope = usePopperScope(__scopeMenu);
const [content, setContent] = React.useState(null);
const isUsingKeyboardRef = React.useRef(false);
const handleOpenChange = (0, import_react_use_callback_ref.useCallbackRef)(onOpenChange);
const direction = (0, import_react_direction.useDirection)(dir);
React.useEffect(() => {
const handleKeyDown = () => {
isUsingKeyboardRef.current = true;
document.addEventListener("pointerdown", handlePointer, { capture: true, once: true });
document.addEventListener("pointermove", handlePointer, { capture: true, once: true });
};
const handlePointer = () => isUsingKeyboardRef.current = false;
document.addEventListener("keydown", handleKeyDown, { capture: true });
return () => {
document.removeEventListener("keydown", handleKeyDown, { capture: true });
document.removeEventListener("pointerdown", handlePointer, { capture: true });
document.removeEventListener("pointermove", handlePointer, { capture: true });
};
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuProvider,
{
scope: __scopeMenu,
open,
onOpenChange: handleOpenChange,
content,
onContentChange: setContent,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuRootProvider,
{
scope: __scopeMenu,
onClose: React.useCallback(() => handleOpenChange(false), [handleOpenChange]),
isUsingKeyboardRef,
dir: direction,
modal,
children
}
)
}
) });
};
Menu.displayName = MENU_NAME;
var ANCHOR_NAME = "MenuAnchor";
var MenuAnchor = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, ...anchorProps } = props;
const popperScope = usePopperScope(__scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });
}
);
MenuAnchor.displayName = ANCHOR_NAME;
var PORTAL_NAME = "MenuPortal";
var [PortalProvider, usePortalContext] = createMenuContext(PORTAL_NAME, {
forceMount: void 0
});
var MenuPortal = (props) => {
const { __scopeMenu, forceMount, children, container } = props;
const context = useMenuContext(PORTAL_NAME, __scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PortalProvider, { scope: __scopeMenu, forceMount, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || context.open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_portal.Portal, { asChild: true, container, children }) }) });
};
MenuPortal.displayName = PORTAL_NAME;
var CONTENT_NAME = "MenuContent";
var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME);
var MenuContent = React.forwardRef(
(props, forwardedRef) => {
const portalContext = usePortalContext(CONTENT_NAME, props.__scopeMenu);
const { forceMount = portalContext.forceMount, ...contentProps } = props;
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
const rootContext = useMenuRootContext(CONTENT_NAME, props.__scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || context.open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: props.__scopeMenu, children: rootContext.modal ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) }) });
}
);
var MenuRootContentModal = React.forwardRef(
(props, forwardedRef) => {
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
const ref = React.useRef(null);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
React.useEffect(() => {
const content = ref.current;
if (content) return (0, import_aria_hidden.hideOthers)(content);
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuContentImpl,
{
...props,
ref: composedRefs,
trapFocus: context.open,
disableOutsidePointerEvents: context.open,
disableOutsideScroll: true,
onFocusOutside: (0, import_primitive.composeEventHandlers)(
props.onFocusOutside,
(event) => event.preventDefault(),
{ checkForDefaultPrevented: false }
),
onDismiss: () => context.onOpenChange(false)
}
);
}
);
var MenuRootContentNonModal = React.forwardRef((props, forwardedRef) => {
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuContentImpl,
{
...props,
ref: forwardedRef,
trapFocus: false,
disableOutsidePointerEvents: false,
disableOutsideScroll: false,
onDismiss: () => context.onOpenChange(false)
}
);
});
var MenuContentImpl = React.forwardRef(
(props, forwardedRef) => {
const {
__scopeMenu,
loop = false,
trapFocus,
onOpenAutoFocus,
onCloseAutoFocus,
disableOutsidePointerEvents,
onEntryFocus,
onEscapeKeyDown,
onPointerDownOutside,
onFocusOutside,
onInteractOutside,
onDismiss,
disableOutsideScroll,
...contentProps
} = props;
const context = useMenuContext(CONTENT_NAME, __scopeMenu);
const rootContext = useMenuRootContext(CONTENT_NAME, __scopeMenu);
const popperScope = usePopperScope(__scopeMenu);
const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
const getItems = useCollection(__scopeMenu);
const [currentItemId, setCurrentItemId] = React.useState(null);
const contentRef = React.useRef(null);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, contentRef, context.onContentChange);
const timerRef = React.useRef(0);
const searchRef = React.useRef("");
const pointerGraceTimerRef = React.useRef(0);
const pointerGraceIntentRef = React.useRef(null);
const pointerDirRef = React.useRef("right");
const lastPointerXRef = React.useRef(0);
const ScrollLockWrapper = disableOutsideScroll ? import_react_remove_scroll.RemoveScroll : React.Fragment;
const scrollLockWrapperProps = disableOutsideScroll ? { as: import_react_slot.Slot, allowPinchZoom: true } : void 0;
const handleTypeaheadSearch = (key) => {
const search = searchRef.current + key;
const items = getItems().filter((item) => !item.disabled);
const currentItem = document.activeElement;
const currentMatch = items.find((item) => item.ref.current === currentItem)?.textValue;
const values = items.map((item) => item.textValue);
const nextMatch = getNextMatch(values, search, currentMatch);
const newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
(function updateSearch(value) {
searchRef.current = value;
window.clearTimeout(timerRef.current);
if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
})(search);
if (newItem) {
setTimeout(() => newItem.focus());
}
};
React.useEffect(() => {
return () => window.clearTimeout(timerRef.current);
}, []);
(0, import_react_focus_guards.useFocusGuards)();
const isPointerMovingToSubmenu = React.useCallback((event) => {
const isMovingTowards = pointerDirRef.current === pointerGraceIntentRef.current?.side;
return isMovingTowards && isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuContentProvider,
{
scope: __scopeMenu,
searchRef,
onItemEnter: React.useCallback(
(event) => {
if (isPointerMovingToSubmenu(event)) event.preventDefault();
},
[isPointerMovingToSubmenu]
),
onItemLeave: React.useCallback(
(event) => {
if (isPointerMovingToSubmenu(event)) return;
contentRef.current?.focus();
setCurrentItemId(null);
},
[isPointerMovingToSubmenu]
),
onTriggerLeave: React.useCallback(
(event) => {
if (isPointerMovingToSubmenu(event)) event.preventDefault();
},
[isPointerMovingToSubmenu]
),
pointerGraceTimerRef,
onPointerGraceIntentChange: React.useCallback((intent) => {
pointerGraceIntentRef.current = intent;
}, []),
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollLockWrapper, { ...scrollLockWrapperProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_focus_scope.FocusScope,
{
asChild: true,
trapped: trapFocus,
onMountAutoFocus: (0, import_primitive.composeEventHandlers)(onOpenAutoFocus, (event) => {
event.preventDefault();
contentRef.current?.focus({ preventScroll: true });
}),
onUnmountAutoFocus: onCloseAutoFocus,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_dismissable_layer.DismissableLayer,
{
asChild: true,
disableOutsidePointerEvents,
onEscapeKeyDown,
onPointerDownOutside,
onFocusOutside,
onInteractOutside,
onDismiss,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
RovingFocusGroup.Root,
{
asChild: true,
...rovingFocusGroupScope,
dir: rootContext.dir,
orientation: "vertical",
loop,
currentTabStopId: currentItemId,
onCurrentTabStopIdChange: setCurrentItemId,
onEntryFocus: (0, import_primitive.composeEventHandlers)(onEntryFocus, (event) => {
if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
}),
preventScrollOnEntryFocus: true,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
PopperPrimitive.Content,
{
role: "menu",
"aria-orientation": "vertical",
"data-state": getOpenState(context.open),
"data-radix-menu-content": "",
dir: rootContext.dir,
...popperScope,
...contentProps,
ref: composedRefs,
style: { outline: "none", ...contentProps.style },
onKeyDown: (0, import_primitive.composeEventHandlers)(contentProps.onKeyDown, (event) => {
const target = event.target;
const isKeyDownInside = target.closest("[data-radix-menu-content]") === event.currentTarget;
const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
const isCharacterKey = event.key.length === 1;
if (isKeyDownInside) {
if (event.key === "Tab") event.preventDefault();
if (!isModifierKey && isCharacterKey) handleTypeaheadSearch(event.key);
}
const content = contentRef.current;
if (event.target !== content) return;
if (!FIRST_LAST_KEYS.includes(event.key)) return;
event.preventDefault();
const items = getItems().filter((item) => !item.disabled);
const candidateNodes = items.map((item) => item.ref.current);
if (LAST_KEYS.includes(event.key)) candidateNodes.reverse();
focusFirst(candidateNodes);
}),
onBlur: (0, import_primitive.composeEventHandlers)(props.onBlur, (event) => {
if (!event.currentTarget.contains(event.target)) {
window.clearTimeout(timerRef.current);
searchRef.current = "";
}
}),
onPointerMove: (0, import_primitive.composeEventHandlers)(
props.onPointerMove,
whenMouse((event) => {
const target = event.target;
const pointerXHasChanged = lastPointerXRef.current !== event.clientX;
if (event.currentTarget.contains(target) && pointerXHasChanged) {
const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
pointerDirRef.current = newDir;
lastPointerXRef.current = event.clientX;
}
})
)
}
)
}
)
}
)
}
) })
}
);
}
);
MenuContent.displayName = CONTENT_NAME;
var GROUP_NAME = "MenuGroup";
var MenuGroup = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, ...groupProps } = props;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { role: "group", ...groupProps, ref: forwardedRef });
}
);
MenuGroup.displayName = GROUP_NAME;
var LABEL_NAME = "MenuLabel";
var MenuLabel = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, ...labelProps } = props;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { ...labelProps, ref: forwardedRef });
}
);
MenuLabel.displayName = LABEL_NAME;
var ITEM_NAME = "MenuItem";
var ITEM_SELECT = "menu.itemSelect";
var MenuItem = React.forwardRef(
(props, forwardedRef) => {
const { disabled = false, onSelect, ...itemProps } = props;
const ref = React.useRef(null);
const rootContext = useMenuRootContext(ITEM_NAME, props.__scopeMenu);
const contentContext = useMenuContentContext(ITEM_NAME, props.__scopeMenu);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
const isPointerDownRef = React.useRef(false);
const handleSelect = () => {
const menuItem = ref.current;
if (!disabled && menuItem) {
const itemSelectEvent = new CustomEvent(ITEM_SELECT, { bubbles: true, cancelable: true });
menuItem.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), { once: true });
(0, import_react_primitive.dispatchDiscreteCustomEvent)(menuItem, itemSelectEvent);
if (itemSelectEvent.defaultPrevented) {
isPointerDownRef.current = false;
} else {
rootContext.onClose();
}
}
};
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuItemImpl,
{
...itemProps,
ref: composedRefs,
disabled,
onClick: (0, import_primitive.composeEventHandlers)(props.onClick, handleSelect),
onPointerDown: (event) => {
props.onPointerDown?.(event);
isPointerDownRef.current = true;
},
onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, (event) => {
if (!isPointerDownRef.current) event.currentTarget?.click();
}),
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => {
const isTypingAhead = contentContext.searchRef.current !== "";
if (disabled || isTypingAhead && event.key === " ") return;
if (SELECTION_KEYS.includes(event.key)) {
event.currentTarget.click();
event.preventDefault();
}
})
}
);
}
);
MenuItem.displayName = ITEM_NAME;
var MenuItemImpl = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, disabled = false, textValue, ...itemProps } = props;
const contentContext = useMenuContentContext(ITEM_NAME, __scopeMenu);
const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
const ref = React.useRef(null);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
const [isFocused, setIsFocused] = React.useState(false);
const [textContent, setTextContent] = React.useState("");
React.useEffect(() => {
const menuItem = ref.current;
if (menuItem) {
setTextContent((menuItem.textContent ?? "").trim());
}
}, [itemProps.children]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
Collection.ItemSlot,
{
scope: __scopeMenu,
disabled,
textValue: textValue ?? textContent,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RovingFocusGroup.Item, { asChild: true, ...rovingFocusGroupScope, focusable: !disabled, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_primitive.Primitive.div,
{
role: "menuitem",
"data-highlighted": isFocused ? "" : void 0,
"aria-disabled": disabled || void 0,
"data-disabled": disabled ? "" : void 0,
...itemProps,
ref: composedRefs,
onPointerMove: (0, import_primitive.composeEventHandlers)(
props.onPointerMove,
whenMouse((event) => {
if (disabled) {
contentContext.onItemLeave(event);
} else {
contentContext.onItemEnter(event);
if (!event.defaultPrevented) {
const item = event.currentTarget;
item.focus({ preventScroll: true });
}
}
})
),
onPointerLeave: (0, import_primitive.composeEventHandlers)(
props.onPointerLeave,
whenMouse((event) => contentContext.onItemLeave(event))
),
onFocus: (0, import_primitive.composeEventHandlers)(props.onFocus, () => setIsFocused(true)),
onBlur: (0, import_primitive.composeEventHandlers)(props.onBlur, () => setIsFocused(false))
}
) })
}
);
}
);
var CHECKBOX_ITEM_NAME = "MenuCheckboxItem";
var MenuCheckboxItem = React.forwardRef(
(props, forwardedRef) => {
const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuItem,
{
role: "menuitemcheckbox",
"aria-checked": isIndeterminate(checked) ? "mixed" : checked,
...checkboxItemProps,
ref: forwardedRef,
"data-state": getCheckedState(checked),
onSelect: (0, import_primitive.composeEventHandlers)(
checkboxItemProps.onSelect,
() => onCheckedChange?.(isIndeterminate(checked) ? true : !checked),
{ checkForDefaultPrevented: false }
)
}
) });
}
);
MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
var RADIO_GROUP_NAME = "MenuRadioGroup";
var [RadioGroupProvider, useRadioGroupContext] = createMenuContext(
RADIO_GROUP_NAME,
{ value: void 0, onValueChange: () => {
} }
);
var MenuRadioGroup = React.forwardRef(
(props, forwardedRef) => {
const { value, onValueChange, ...groupProps } = props;
const handleValueChange = (0, import_react_use_callback_ref.useCallbackRef)(onValueChange);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RadioGroupProvider, { scope: props.__scopeMenu, value, onValueChange: handleValueChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuGroup, { ...groupProps, ref: forwardedRef }) });
}
);
MenuRadioGroup.displayName = RADIO_GROUP_NAME;
var RADIO_ITEM_NAME = "MenuRadioItem";
var MenuRadioItem = React.forwardRef(
(props, forwardedRef) => {
const { value, ...radioItemProps } = props;
const context = useRadioGroupContext(RADIO_ITEM_NAME, props.__scopeMenu);
const checked = value === context.value;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuItem,
{
role: "menuitemradio",
"aria-checked": checked,
...radioItemProps,
ref: forwardedRef,
"data-state": getCheckedState(checked),
onSelect: (0, import_primitive.composeEventHandlers)(
radioItemProps.onSelect,
() => context.onValueChange?.(value),
{ checkForDefaultPrevented: false }
)
}
) });
}
);
MenuRadioItem.displayName = RADIO_ITEM_NAME;
var ITEM_INDICATOR_NAME = "MenuItemIndicator";
var [ItemIndicatorProvider, useItemIndicatorContext] = createMenuContext(
ITEM_INDICATOR_NAME,
{ checked: false }
);
var MenuItemIndicator = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, forceMount, ...itemIndicatorProps } = props;
const indicatorContext = useItemIndicatorContext(ITEM_INDICATOR_NAME, __scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_presence.Presence,
{
present: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_primitive.Primitive.span,
{
...itemIndicatorProps,
ref: forwardedRef,
"data-state": getCheckedState(indicatorContext.checked)
}
)
}
);
}
);
MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
var SEPARATOR_NAME = "MenuSeparator";
var MenuSeparator = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, ...separatorProps } = props;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_primitive.Primitive.div,
{
role: "separator",
"aria-orientation": "horizontal",
...separatorProps,
ref: forwardedRef
}
);
}
);
MenuSeparator.displayName = SEPARATOR_NAME;
var ARROW_NAME = "MenuArrow";
var MenuArrow = React.forwardRef(
(props, forwardedRef) => {
const { __scopeMenu, ...arrowProps } = props;
const popperScope = usePopperScope(__scopeMenu);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Arrow, { ...popperScope, ...arrowProps, ref: forwardedRef });
}
);
MenuArrow.displayName = ARROW_NAME;
var SUB_NAME = "MenuSub";
var [MenuSubProvider, useMenuSubContext] = createMenuContext(SUB_NAME);
var MenuSub = (props) => {
const { __scopeMenu, children, open = false, onOpenChange } = props;
const parentMenuContext = useMenuContext(SUB_NAME, __scopeMenu);
const popperScope = usePopperScope(__scopeMenu);
const [trigger, setTrigger] = React.useState(null);
const [content, setContent] = React.useState(null);
const handleOpenChange = (0, import_react_use_callback_ref.useCallbackRef)(onOpenChange);
React.useEffect(() => {
if (parentMenuContext.open === false) handleOpenChange(false);
return () => handleOpenChange(false);
}, [parentMenuContext.open, handleOpenChange]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuProvider,
{
scope: __scopeMenu,
open,
onOpenChange: handleOpenChange,
content,
onContentChange: setContent,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuSubProvider,
{
scope: __scopeMenu,
contentId: (0, import_react_id.useId)(),
triggerId: (0, import_react_id.useId)(),
trigger,
onTriggerChange: setTrigger,
children
}
)
}
) });
};
MenuSub.displayName = SUB_NAME;
var SUB_TRIGGER_NAME = "MenuSubTrigger";
var MenuSubTrigger = React.forwardRef(
(props, forwardedRef) => {
const context = useMenuContext(SUB_TRIGGER_NAME, props.__scopeMenu);
const rootContext = useMenuRootContext(SUB_TRIGGER_NAME, props.__scopeMenu);
const subContext = useMenuSubContext(SUB_TRIGGER_NAME, props.__scopeMenu);
const contentContext = useMenuContentContext(SUB_TRIGGER_NAME, props.__scopeMenu);
const openTimerRef = React.useRef(null);
const { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext;
const scope = { __scopeMenu: props.__scopeMenu };
const clearOpenTimer = React.useCallback(() => {
if (openTimerRef.current) window.clearTimeout(openTimerRef.current);
openTimerRef.current = null;
}, []);
React.useEffect(() => clearOpenTimer, [clearOpenTimer]);
React.useEffect(() => {
const pointerGraceTimer = pointerGraceTimerRef.current;
return () => {
window.clearTimeout(pointerGraceTimer);
onPointerGraceIntentChange(null);
};
}, [pointerGraceTimerRef, onPointerGraceIntentChange]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuAnchor, { asChild: true, ...scope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuItemImpl,
{
id: subContext.triggerId,
"aria-haspopup": "menu",
"aria-expanded": context.open,
"aria-controls": subContext.contentId,
"data-state": getOpenState(context.open),
...props,
ref: (0, import_react_compose_refs.composeRefs)(forwardedRef, subContext.onTriggerChange),
onClick: (event) => {
props.onClick?.(event);
if (props.disabled || event.defaultPrevented) return;
event.currentTarget.focus();
if (!context.open) context.onOpenChange(true);
},
onPointerMove: (0, import_primitive.composeEventHandlers)(
props.onPointerMove,
whenMouse((event) => {
contentContext.onItemEnter(event);
if (event.defaultPrevented) return;
if (!props.disabled && !context.open && !openTimerRef.current) {
contentContext.onPointerGraceIntentChange(null);
openTimerRef.current = window.setTimeout(() => {
context.onOpenChange(true);
clearOpenTimer();
}, 100);
}
})
),
onPointerLeave: (0, import_primitive.composeEventHandlers)(
props.onPointerLeave,
whenMouse((event) => {
clearOpenTimer();
const contentRect = context.content?.getBoundingClientRect();
if (contentRect) {
const side = context.content?.dataset.side;
const rightSide = side === "right";
const bleed = rightSide ? -5 : 5;
const contentNearEdge = contentRect[rightSide ? "left" : "right"];
const contentFarEdge = contentRect[rightSide ? "right" : "left"];
contentContext.onPointerGraceIntentChange({
area: [
// Apply a bleed on clientX to ensure that our exit point is
// consistently within polygon bounds
{ x: event.clientX + bleed, y: event.clientY },
{ x: contentNearEdge, y: contentRect.top },
{ x: contentFarEdge, y: contentRect.top },
{ x: contentFarEdge, y: contentRect.bottom },
{ x: contentNearEdge, y: contentRect.bottom }
],
side
});
window.clearTimeout(pointerGraceTimerRef.current);
pointerGraceTimerRef.current = window.setTimeout(
() => contentContext.onPointerGraceIntentChange(null),
300
);
} else {
contentContext.onTriggerLeave(event);
if (event.defaultPrevented) return;
contentContext.onPointerGraceIntentChange(null);
}
})
),
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => {
const isTypingAhead = contentContext.searchRef.current !== "";
if (props.disabled || isTypingAhead && event.key === " ") return;
if (SUB_OPEN_KEYS[rootContext.dir].includes(event.key)) {
context.onOpenChange(true);
context.content?.focus();
event.preventDefault();
}
})
}
) });
}
);
MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
var SUB_CONTENT_NAME = "MenuSubContent";
var MenuSubContent = React.forwardRef(
(props, forwardedRef) => {
const portalContext = usePortalContext(CONTENT_NAME, props.__scopeMenu);
const { forceMount = portalContext.forceMount, ...subContentProps } = props;
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
const rootContext = useMenuRootContext(CONTENT_NAME, props.__scopeMenu);
const subContext = useMenuSubContext(SUB_CONTENT_NAME, props.__scopeMenu);
const ref = React.useRef(null);
const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: props.__scopeMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || context.open, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Slot, { scope: props.__scopeMenu, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuContentImpl,
{
id: subContext.contentId,
"aria-labelledby": subContext.triggerId,
...subContentProps,
ref: composedRefs,
align: "start",
side: rootContext.dir === "rtl" ? "left" : "right",
disableOutsidePointerEvents: false,
disableOutsideScroll: false,
trapFocus: false,
onOpenAutoFocus: (event) => {
if (rootContext.isUsingKeyboardRef.current) ref.current?.focus();
event.preventDefault();
},
onCloseAutoFocus: (event) => event.preventDefault(),
onFocusOutside: (0, import_primitive.composeEventHandlers)(props.onFocusOutside, (event) => {
if (event.target !== subContext.trigger) context.onOpenChange(false);
}),
onEscapeKeyDown: (0, import_primitive.composeEventHandlers)(props.onEscapeKeyDown, (event) => {
rootContext.onClose();
event.preventDefault();
}),
onKeyDown: (0, import_primitive.composeEventHandlers)(props.onKeyDown, (event) => {
const isKeyDownInside = event.currentTarget.contains(event.target);
const isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
if (isKeyDownInside && isCloseKey) {
context.onOpenChange(false);
subContext.trigger?.focus();
event.preventDefault();
}
})
}
) }) }) });
}
);
MenuSubContent.displayName = SUB_CONTENT_NAME;
function getOpenState(open) {
return open ? "open" : "closed";
}
function isIndeterminate(checked) {
return checked === "indeterminate";
}
function getCheckedState(checked) {
return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
}
function focusFirst(candidates) {
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
for (const candidate of candidates) {
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
candidate.focus();
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
}
}
function wrapArray(array, startIndex) {
return array.map((_, index) => array[(startIndex + index) % array.length]);
}
function getNextMatch(values, search, currentMatch) {
const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
const normalizedSearch = isRepeated ? search[0] : search;
const currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
const excludeCurrentMatch = normalizedSearch.length === 1;
if (excludeCurrentMatch) wrappedValues = wrappedValues.filter((v) => v !== currentMatch);
const nextMatch = wrappedValues.find(
(value) => value.toLowerCase().startsWith(normalizedSearch.toLowerCase())
);
return nextMatch !== currentMatch ? nextMatch : void 0;
}
function isPointInPolygon(point, polygon) {
const { x, y } = point;
let inside = false;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].x;
const yi = polygon[i].y;
const xj = polygon[j].x;
const yj = polygon[j].y;
const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
function isPointerInGraceArea(event, area) {
if (!area) return false;
const cursorPos = { x: event.clientX, y: event.clientY };
return isPointInPolygon(cursorPos, area);
}
function whenMouse(handler) {
return (event) => event.pointerType === "mouse" ? handler(event) : void 0;
}
var Root3 = Menu;
var Anchor2 = MenuAnchor;
var Portal = MenuPortal;
var Content2 = MenuContent;
var Group = MenuGroup;
var Label = MenuLabel;
var Item2 = MenuItem;
var CheckboxItem = MenuCheckboxItem;
var RadioGroup = MenuRadioGroup;
var RadioItem = MenuRadioItem;
var ItemIndicator = MenuItemIndicator;
var Separator = MenuSeparator;
var Arrow2 = MenuArrow;
var Sub = MenuSub;
var SubTrigger = MenuSubTrigger;
var SubContent = MenuSubContent;
//# sourceMappingURL=index.js.map