1448 lines
57 KiB
JavaScript
1448 lines
57 KiB
JavaScript
"use client";
|
|
import {
|
|
Combination_default,
|
|
FocusScope,
|
|
hideOthers,
|
|
useFocusGuards
|
|
} from "./chunk-KCU5VMPK.js";
|
|
import {
|
|
useDirection
|
|
} from "./chunk-5HDB4YN4.js";
|
|
import {
|
|
Anchor,
|
|
Arrow,
|
|
Content,
|
|
Root2,
|
|
createPopperScope
|
|
} from "./chunk-ZPHTTZ5Y.js";
|
|
import {
|
|
DismissableLayer,
|
|
Portal,
|
|
useControllableState,
|
|
useId
|
|
} from "./chunk-NQHNXVMS.js";
|
|
import {
|
|
Presence,
|
|
composeEventHandlers
|
|
} from "./chunk-KWKVM5C6.js";
|
|
import {
|
|
Primitive,
|
|
createContextScope,
|
|
dispatchDiscreteCustomEvent,
|
|
useCallbackRef
|
|
} from "./chunk-LMM3RUZD.js";
|
|
import "./chunk-PJEEZAML.js";
|
|
import {
|
|
Slot,
|
|
composeRefs,
|
|
useComposedRefs
|
|
} from "./chunk-7CEJWY55.js";
|
|
import {
|
|
require_jsx_runtime
|
|
} from "./chunk-6PXSGDAH.js";
|
|
import {
|
|
require_react
|
|
} from "./chunk-DRWLMN53.js";
|
|
import {
|
|
__toESM
|
|
} from "./chunk-G3PMV62Z.js";
|
|
|
|
// node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
|
|
var React4 = __toESM(require_react(), 1);
|
|
|
|
// node_modules/@radix-ui/react-menu/dist/index.mjs
|
|
var React3 = __toESM(require_react(), 1);
|
|
|
|
// node_modules/@radix-ui/react-collection/dist/index.mjs
|
|
var import_react = __toESM(require_react(), 1);
|
|
var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
function createCollection(name) {
|
|
const PROVIDER_NAME = name + "CollectionProvider";
|
|
const [createCollectionContext, createCollectionScope3] = createContextScope(PROVIDER_NAME);
|
|
const [CollectionProviderImpl, useCollectionContext] = createCollectionContext(
|
|
PROVIDER_NAME,
|
|
{ collectionRef: { current: null }, itemMap: /* @__PURE__ */ new Map() }
|
|
);
|
|
const CollectionProvider = (props) => {
|
|
const { scope, children } = props;
|
|
const ref = import_react.default.useRef(null);
|
|
const itemMap = import_react.default.useRef(/* @__PURE__ */ new Map()).current;
|
|
return (0, import_jsx_runtime.jsx)(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
|
|
};
|
|
CollectionProvider.displayName = PROVIDER_NAME;
|
|
const COLLECTION_SLOT_NAME = name + "CollectionSlot";
|
|
const CollectionSlot = import_react.default.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { scope, children } = props;
|
|
const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
|
|
const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
|
|
return (0, import_jsx_runtime.jsx)(Slot, { ref: composedRefs, children });
|
|
}
|
|
);
|
|
CollectionSlot.displayName = COLLECTION_SLOT_NAME;
|
|
const ITEM_SLOT_NAME = name + "CollectionItemSlot";
|
|
const ITEM_DATA_ATTR = "data-radix-collection-item";
|
|
const CollectionItemSlot = import_react.default.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { scope, children, ...itemData } = props;
|
|
const ref = import_react.default.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
const context = useCollectionContext(ITEM_SLOT_NAME, scope);
|
|
import_react.default.useEffect(() => {
|
|
context.itemMap.set(ref, { ref, ...itemData });
|
|
return () => void context.itemMap.delete(ref);
|
|
});
|
|
return (0, import_jsx_runtime.jsx)(Slot, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
|
|
}
|
|
);
|
|
CollectionItemSlot.displayName = ITEM_SLOT_NAME;
|
|
function useCollection3(scope) {
|
|
const context = useCollectionContext(name + "CollectionConsumer", scope);
|
|
const getItems = import_react.default.useCallback(() => {
|
|
const collectionNode = context.collectionRef.current;
|
|
if (!collectionNode) return [];
|
|
const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
|
|
const items = Array.from(context.itemMap.values());
|
|
const orderedItems = items.sort(
|
|
(a, b) => orderedNodes.indexOf(a.ref.current) - orderedNodes.indexOf(b.ref.current)
|
|
);
|
|
return orderedItems;
|
|
}, [context.collectionRef, context.itemMap]);
|
|
return getItems;
|
|
}
|
|
return [
|
|
{ Provider: CollectionProvider, Slot: CollectionSlot, ItemSlot: CollectionItemSlot },
|
|
useCollection3,
|
|
createCollectionScope3
|
|
];
|
|
}
|
|
|
|
// node_modules/@radix-ui/react-roving-focus/dist/index.mjs
|
|
var React2 = __toESM(require_react(), 1);
|
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
var ENTRY_FOCUS = "rovingFocusGroup.onEntryFocus";
|
|
var EVENT_OPTIONS = { bubbles: false, cancelable: true };
|
|
var GROUP_NAME = "RovingFocusGroup";
|
|
var [Collection, useCollection, createCollectionScope] = createCollection(GROUP_NAME);
|
|
var [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(
|
|
GROUP_NAME,
|
|
[createCollectionScope]
|
|
);
|
|
var [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);
|
|
var RovingFocusGroup = React2.forwardRef(
|
|
(props, forwardedRef) => {
|
|
return (0, import_jsx_runtime2.jsx)(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: (0, import_jsx_runtime2.jsx)(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: (0, import_jsx_runtime2.jsx)(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });
|
|
}
|
|
);
|
|
RovingFocusGroup.displayName = GROUP_NAME;
|
|
var RovingFocusGroupImpl = React2.forwardRef((props, forwardedRef) => {
|
|
const {
|
|
__scopeRovingFocusGroup,
|
|
orientation,
|
|
loop = false,
|
|
dir,
|
|
currentTabStopId: currentTabStopIdProp,
|
|
defaultCurrentTabStopId,
|
|
onCurrentTabStopIdChange,
|
|
onEntryFocus,
|
|
preventScrollOnEntryFocus = false,
|
|
...groupProps
|
|
} = props;
|
|
const ref = React2.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
const direction = useDirection(dir);
|
|
const [currentTabStopId = null, setCurrentTabStopId] = useControllableState({
|
|
prop: currentTabStopIdProp,
|
|
defaultProp: defaultCurrentTabStopId,
|
|
onChange: onCurrentTabStopIdChange
|
|
});
|
|
const [isTabbingBackOut, setIsTabbingBackOut] = React2.useState(false);
|
|
const handleEntryFocus = useCallbackRef(onEntryFocus);
|
|
const getItems = useCollection(__scopeRovingFocusGroup);
|
|
const isClickFocusRef = React2.useRef(false);
|
|
const [focusableItemsCount, setFocusableItemsCount] = React2.useState(0);
|
|
React2.useEffect(() => {
|
|
const node = ref.current;
|
|
if (node) {
|
|
node.addEventListener(ENTRY_FOCUS, handleEntryFocus);
|
|
return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);
|
|
}
|
|
}, [handleEntryFocus]);
|
|
return (0, import_jsx_runtime2.jsx)(
|
|
RovingFocusProvider,
|
|
{
|
|
scope: __scopeRovingFocusGroup,
|
|
orientation,
|
|
dir: direction,
|
|
loop,
|
|
currentTabStopId,
|
|
onItemFocus: React2.useCallback(
|
|
(tabStopId) => setCurrentTabStopId(tabStopId),
|
|
[setCurrentTabStopId]
|
|
),
|
|
onItemShiftTab: React2.useCallback(() => setIsTabbingBackOut(true), []),
|
|
onFocusableItemAdd: React2.useCallback(
|
|
() => setFocusableItemsCount((prevCount) => prevCount + 1),
|
|
[]
|
|
),
|
|
onFocusableItemRemove: React2.useCallback(
|
|
() => setFocusableItemsCount((prevCount) => prevCount - 1),
|
|
[]
|
|
),
|
|
children: (0, import_jsx_runtime2.jsx)(
|
|
Primitive.div,
|
|
{
|
|
tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
|
|
"data-orientation": orientation,
|
|
...groupProps,
|
|
ref: composedRefs,
|
|
style: { outline: "none", ...props.style },
|
|
onMouseDown: composeEventHandlers(props.onMouseDown, () => {
|
|
isClickFocusRef.current = true;
|
|
}),
|
|
onFocus: composeEventHandlers(props.onFocus, (event) => {
|
|
const isKeyboardFocus = !isClickFocusRef.current;
|
|
if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
|
|
const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);
|
|
event.currentTarget.dispatchEvent(entryFocusEvent);
|
|
if (!entryFocusEvent.defaultPrevented) {
|
|
const items = getItems().filter((item) => item.focusable);
|
|
const activeItem = items.find((item) => item.active);
|
|
const currentItem = items.find((item) => item.id === currentTabStopId);
|
|
const candidateItems = [activeItem, currentItem, ...items].filter(
|
|
Boolean
|
|
);
|
|
const candidateNodes = candidateItems.map((item) => item.ref.current);
|
|
focusFirst(candidateNodes, preventScrollOnEntryFocus);
|
|
}
|
|
}
|
|
isClickFocusRef.current = false;
|
|
}),
|
|
onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))
|
|
}
|
|
)
|
|
}
|
|
);
|
|
});
|
|
var ITEM_NAME = "RovingFocusGroupItem";
|
|
var RovingFocusGroupItem = React2.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const {
|
|
__scopeRovingFocusGroup,
|
|
focusable = true,
|
|
active = false,
|
|
tabStopId,
|
|
...itemProps
|
|
} = props;
|
|
const autoId = useId();
|
|
const id = tabStopId || autoId;
|
|
const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);
|
|
const isCurrentTabStop = context.currentTabStopId === id;
|
|
const getItems = useCollection(__scopeRovingFocusGroup);
|
|
const { onFocusableItemAdd, onFocusableItemRemove } = context;
|
|
React2.useEffect(() => {
|
|
if (focusable) {
|
|
onFocusableItemAdd();
|
|
return () => onFocusableItemRemove();
|
|
}
|
|
}, [focusable, onFocusableItemAdd, onFocusableItemRemove]);
|
|
return (0, import_jsx_runtime2.jsx)(
|
|
Collection.ItemSlot,
|
|
{
|
|
scope: __scopeRovingFocusGroup,
|
|
id,
|
|
focusable,
|
|
active,
|
|
children: (0, import_jsx_runtime2.jsx)(
|
|
Primitive.span,
|
|
{
|
|
tabIndex: isCurrentTabStop ? 0 : -1,
|
|
"data-orientation": context.orientation,
|
|
...itemProps,
|
|
ref: forwardedRef,
|
|
onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {
|
|
if (!focusable) event.preventDefault();
|
|
else context.onItemFocus(id);
|
|
}),
|
|
onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),
|
|
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
if (event.key === "Tab" && event.shiftKey) {
|
|
context.onItemShiftTab();
|
|
return;
|
|
}
|
|
if (event.target !== event.currentTarget) return;
|
|
const focusIntent = getFocusIntent(event, context.orientation, context.dir);
|
|
if (focusIntent !== void 0) {
|
|
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
|
|
event.preventDefault();
|
|
const items = getItems().filter((item) => item.focusable);
|
|
let candidateNodes = items.map((item) => item.ref.current);
|
|
if (focusIntent === "last") candidateNodes.reverse();
|
|
else if (focusIntent === "prev" || focusIntent === "next") {
|
|
if (focusIntent === "prev") candidateNodes.reverse();
|
|
const currentIndex = candidateNodes.indexOf(event.currentTarget);
|
|
candidateNodes = context.loop ? wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);
|
|
}
|
|
setTimeout(() => focusFirst(candidateNodes));
|
|
}
|
|
})
|
|
}
|
|
)
|
|
}
|
|
);
|
|
}
|
|
);
|
|
RovingFocusGroupItem.displayName = ITEM_NAME;
|
|
var MAP_KEY_TO_FOCUS_INTENT = {
|
|
ArrowLeft: "prev",
|
|
ArrowUp: "prev",
|
|
ArrowRight: "next",
|
|
ArrowDown: "next",
|
|
PageUp: "first",
|
|
Home: "first",
|
|
PageDown: "last",
|
|
End: "last"
|
|
};
|
|
function getDirectionAwareKey(key, dir) {
|
|
if (dir !== "rtl") return key;
|
|
return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
|
|
}
|
|
function getFocusIntent(event, orientation, dir) {
|
|
const key = getDirectionAwareKey(event.key, dir);
|
|
if (orientation === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key)) return void 0;
|
|
if (orientation === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key)) return void 0;
|
|
return MAP_KEY_TO_FOCUS_INTENT[key];
|
|
}
|
|
function focusFirst(candidates, preventScroll = false) {
|
|
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
|
|
for (const candidate of candidates) {
|
|
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
|
|
candidate.focus({ preventScroll });
|
|
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
|
|
}
|
|
}
|
|
function wrapArray(array, startIndex) {
|
|
return array.map((_, index) => array[(startIndex + index) % array.length]);
|
|
}
|
|
var Root = RovingFocusGroup;
|
|
var Item = RovingFocusGroupItem;
|
|
|
|
// node_modules/@radix-ui/react-menu/dist/index.mjs
|
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
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 [Collection2, useCollection2, createCollectionScope2] = createCollection(MENU_NAME);
|
|
var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, [
|
|
createCollectionScope2,
|
|
createPopperScope,
|
|
createRovingFocusGroupScope
|
|
]);
|
|
var usePopperScope = createPopperScope();
|
|
var useRovingFocusGroupScope = 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] = React3.useState(null);
|
|
const isUsingKeyboardRef = React3.useRef(false);
|
|
const handleOpenChange = useCallbackRef(onOpenChange);
|
|
const direction = useDirection(dir);
|
|
React3.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 (0, import_jsx_runtime3.jsx)(Root2, { ...popperScope, children: (0, import_jsx_runtime3.jsx)(
|
|
MenuProvider,
|
|
{
|
|
scope: __scopeMenu,
|
|
open,
|
|
onOpenChange: handleOpenChange,
|
|
content,
|
|
onContentChange: setContent,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
MenuRootProvider,
|
|
{
|
|
scope: __scopeMenu,
|
|
onClose: React3.useCallback(() => handleOpenChange(false), [handleOpenChange]),
|
|
isUsingKeyboardRef,
|
|
dir: direction,
|
|
modal,
|
|
children
|
|
}
|
|
)
|
|
}
|
|
) });
|
|
};
|
|
Menu.displayName = MENU_NAME;
|
|
var ANCHOR_NAME = "MenuAnchor";
|
|
var MenuAnchor = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, ...anchorProps } = props;
|
|
const popperScope = usePopperScope(__scopeMenu);
|
|
return (0, import_jsx_runtime3.jsx)(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 (0, import_jsx_runtime3.jsx)(PortalProvider, { scope: __scopeMenu, forceMount, children: (0, import_jsx_runtime3.jsx)(Presence, { present: forceMount || context.open, children: (0, import_jsx_runtime3.jsx)(Portal, { asChild: true, container, children }) }) });
|
|
};
|
|
MenuPortal.displayName = PORTAL_NAME;
|
|
var CONTENT_NAME = "MenuContent";
|
|
var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME);
|
|
var MenuContent = React3.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 (0, import_jsx_runtime3.jsx)(Collection2.Provider, { scope: props.__scopeMenu, children: (0, import_jsx_runtime3.jsx)(Presence, { present: forceMount || context.open, children: (0, import_jsx_runtime3.jsx)(Collection2.Slot, { scope: props.__scopeMenu, children: rootContext.modal ? (0, import_jsx_runtime3.jsx)(MenuRootContentModal, { ...contentProps, ref: forwardedRef }) : (0, import_jsx_runtime3.jsx)(MenuRootContentNonModal, { ...contentProps, ref: forwardedRef }) }) }) });
|
|
}
|
|
);
|
|
var MenuRootContentModal = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
|
|
const ref = React3.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
React3.useEffect(() => {
|
|
const content = ref.current;
|
|
if (content) return hideOthers(content);
|
|
}, []);
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
MenuContentImpl,
|
|
{
|
|
...props,
|
|
ref: composedRefs,
|
|
trapFocus: context.open,
|
|
disableOutsidePointerEvents: context.open,
|
|
disableOutsideScroll: true,
|
|
onFocusOutside: composeEventHandlers(
|
|
props.onFocusOutside,
|
|
(event) => event.preventDefault(),
|
|
{ checkForDefaultPrevented: false }
|
|
),
|
|
onDismiss: () => context.onOpenChange(false)
|
|
}
|
|
);
|
|
}
|
|
);
|
|
var MenuRootContentNonModal = React3.forwardRef((props, forwardedRef) => {
|
|
const context = useMenuContext(CONTENT_NAME, props.__scopeMenu);
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
MenuContentImpl,
|
|
{
|
|
...props,
|
|
ref: forwardedRef,
|
|
trapFocus: false,
|
|
disableOutsidePointerEvents: false,
|
|
disableOutsideScroll: false,
|
|
onDismiss: () => context.onOpenChange(false)
|
|
}
|
|
);
|
|
});
|
|
var MenuContentImpl = React3.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 = useCollection2(__scopeMenu);
|
|
const [currentItemId, setCurrentItemId] = React3.useState(null);
|
|
const contentRef = React3.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, contentRef, context.onContentChange);
|
|
const timerRef = React3.useRef(0);
|
|
const searchRef = React3.useRef("");
|
|
const pointerGraceTimerRef = React3.useRef(0);
|
|
const pointerGraceIntentRef = React3.useRef(null);
|
|
const pointerDirRef = React3.useRef("right");
|
|
const lastPointerXRef = React3.useRef(0);
|
|
const ScrollLockWrapper = disableOutsideScroll ? Combination_default : React3.Fragment;
|
|
const scrollLockWrapperProps = disableOutsideScroll ? { as: Slot, allowPinchZoom: true } : void 0;
|
|
const handleTypeaheadSearch = (key) => {
|
|
var _a, _b;
|
|
const search = searchRef.current + key;
|
|
const items = getItems().filter((item) => !item.disabled);
|
|
const currentItem = document.activeElement;
|
|
const currentMatch = (_a = items.find((item) => item.ref.current === currentItem)) == null ? void 0 : _a.textValue;
|
|
const values = items.map((item) => item.textValue);
|
|
const nextMatch = getNextMatch(values, search, currentMatch);
|
|
const newItem = (_b = items.find((item) => item.textValue === nextMatch)) == null ? void 0 : _b.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());
|
|
}
|
|
};
|
|
React3.useEffect(() => {
|
|
return () => window.clearTimeout(timerRef.current);
|
|
}, []);
|
|
useFocusGuards();
|
|
const isPointerMovingToSubmenu = React3.useCallback((event) => {
|
|
var _a, _b;
|
|
const isMovingTowards = pointerDirRef.current === ((_a = pointerGraceIntentRef.current) == null ? void 0 : _a.side);
|
|
return isMovingTowards && isPointerInGraceArea(event, (_b = pointerGraceIntentRef.current) == null ? void 0 : _b.area);
|
|
}, []);
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
MenuContentProvider,
|
|
{
|
|
scope: __scopeMenu,
|
|
searchRef,
|
|
onItemEnter: React3.useCallback(
|
|
(event) => {
|
|
if (isPointerMovingToSubmenu(event)) event.preventDefault();
|
|
},
|
|
[isPointerMovingToSubmenu]
|
|
),
|
|
onItemLeave: React3.useCallback(
|
|
(event) => {
|
|
var _a;
|
|
if (isPointerMovingToSubmenu(event)) return;
|
|
(_a = contentRef.current) == null ? void 0 : _a.focus();
|
|
setCurrentItemId(null);
|
|
},
|
|
[isPointerMovingToSubmenu]
|
|
),
|
|
onTriggerLeave: React3.useCallback(
|
|
(event) => {
|
|
if (isPointerMovingToSubmenu(event)) event.preventDefault();
|
|
},
|
|
[isPointerMovingToSubmenu]
|
|
),
|
|
pointerGraceTimerRef,
|
|
onPointerGraceIntentChange: React3.useCallback((intent) => {
|
|
pointerGraceIntentRef.current = intent;
|
|
}, []),
|
|
children: (0, import_jsx_runtime3.jsx)(ScrollLockWrapper, { ...scrollLockWrapperProps, children: (0, import_jsx_runtime3.jsx)(
|
|
FocusScope,
|
|
{
|
|
asChild: true,
|
|
trapped: trapFocus,
|
|
onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, (event) => {
|
|
var _a;
|
|
event.preventDefault();
|
|
(_a = contentRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
|
|
}),
|
|
onUnmountAutoFocus: onCloseAutoFocus,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
DismissableLayer,
|
|
{
|
|
asChild: true,
|
|
disableOutsidePointerEvents,
|
|
onEscapeKeyDown,
|
|
onPointerDownOutside,
|
|
onFocusOutside,
|
|
onInteractOutside,
|
|
onDismiss,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
Root,
|
|
{
|
|
asChild: true,
|
|
...rovingFocusGroupScope,
|
|
dir: rootContext.dir,
|
|
orientation: "vertical",
|
|
loop,
|
|
currentTabStopId: currentItemId,
|
|
onCurrentTabStopIdChange: setCurrentItemId,
|
|
onEntryFocus: composeEventHandlers(onEntryFocus, (event) => {
|
|
if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
|
|
}),
|
|
preventScrollOnEntryFocus: true,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
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: 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();
|
|
focusFirst2(candidateNodes);
|
|
}),
|
|
onBlur: composeEventHandlers(props.onBlur, (event) => {
|
|
if (!event.currentTarget.contains(event.target)) {
|
|
window.clearTimeout(timerRef.current);
|
|
searchRef.current = "";
|
|
}
|
|
}),
|
|
onPointerMove: 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_NAME2 = "MenuGroup";
|
|
var MenuGroup = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, ...groupProps } = props;
|
|
return (0, import_jsx_runtime3.jsx)(Primitive.div, { role: "group", ...groupProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
MenuGroup.displayName = GROUP_NAME2;
|
|
var LABEL_NAME = "MenuLabel";
|
|
var MenuLabel = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, ...labelProps } = props;
|
|
return (0, import_jsx_runtime3.jsx)(Primitive.div, { ...labelProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
MenuLabel.displayName = LABEL_NAME;
|
|
var ITEM_NAME2 = "MenuItem";
|
|
var ITEM_SELECT = "menu.itemSelect";
|
|
var MenuItem = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { disabled = false, onSelect, ...itemProps } = props;
|
|
const ref = React3.useRef(null);
|
|
const rootContext = useMenuRootContext(ITEM_NAME2, props.__scopeMenu);
|
|
const contentContext = useMenuContentContext(ITEM_NAME2, props.__scopeMenu);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
const isPointerDownRef = React3.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 == null ? void 0 : onSelect(event), { once: true });
|
|
dispatchDiscreteCustomEvent(menuItem, itemSelectEvent);
|
|
if (itemSelectEvent.defaultPrevented) {
|
|
isPointerDownRef.current = false;
|
|
} else {
|
|
rootContext.onClose();
|
|
}
|
|
}
|
|
};
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
MenuItemImpl,
|
|
{
|
|
...itemProps,
|
|
ref: composedRefs,
|
|
disabled,
|
|
onClick: composeEventHandlers(props.onClick, handleSelect),
|
|
onPointerDown: (event) => {
|
|
var _a;
|
|
(_a = props.onPointerDown) == null ? void 0 : _a.call(props, event);
|
|
isPointerDownRef.current = true;
|
|
},
|
|
onPointerUp: composeEventHandlers(props.onPointerUp, (event) => {
|
|
var _a;
|
|
if (!isPointerDownRef.current) (_a = event.currentTarget) == null ? void 0 : _a.click();
|
|
}),
|
|
onKeyDown: 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_NAME2;
|
|
var MenuItemImpl = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, disabled = false, textValue, ...itemProps } = props;
|
|
const contentContext = useMenuContentContext(ITEM_NAME2, __scopeMenu);
|
|
const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
|
|
const ref = React3.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
const [isFocused, setIsFocused] = React3.useState(false);
|
|
const [textContent, setTextContent] = React3.useState("");
|
|
React3.useEffect(() => {
|
|
const menuItem = ref.current;
|
|
if (menuItem) {
|
|
setTextContent((menuItem.textContent ?? "").trim());
|
|
}
|
|
}, [itemProps.children]);
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
Collection2.ItemSlot,
|
|
{
|
|
scope: __scopeMenu,
|
|
disabled,
|
|
textValue: textValue ?? textContent,
|
|
children: (0, import_jsx_runtime3.jsx)(Item, { asChild: true, ...rovingFocusGroupScope, focusable: !disabled, children: (0, import_jsx_runtime3.jsx)(
|
|
Primitive.div,
|
|
{
|
|
role: "menuitem",
|
|
"data-highlighted": isFocused ? "" : void 0,
|
|
"aria-disabled": disabled || void 0,
|
|
"data-disabled": disabled ? "" : void 0,
|
|
...itemProps,
|
|
ref: composedRefs,
|
|
onPointerMove: 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: composeEventHandlers(
|
|
props.onPointerLeave,
|
|
whenMouse((event) => contentContext.onItemLeave(event))
|
|
),
|
|
onFocus: composeEventHandlers(props.onFocus, () => setIsFocused(true)),
|
|
onBlur: composeEventHandlers(props.onBlur, () => setIsFocused(false))
|
|
}
|
|
) })
|
|
}
|
|
);
|
|
}
|
|
);
|
|
var CHECKBOX_ITEM_NAME = "MenuCheckboxItem";
|
|
var MenuCheckboxItem = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
|
|
return (0, import_jsx_runtime3.jsx)(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: (0, import_jsx_runtime3.jsx)(
|
|
MenuItem,
|
|
{
|
|
role: "menuitemcheckbox",
|
|
"aria-checked": isIndeterminate(checked) ? "mixed" : checked,
|
|
...checkboxItemProps,
|
|
ref: forwardedRef,
|
|
"data-state": getCheckedState(checked),
|
|
onSelect: composeEventHandlers(
|
|
checkboxItemProps.onSelect,
|
|
() => onCheckedChange == null ? void 0 : 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 = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { value, onValueChange, ...groupProps } = props;
|
|
const handleValueChange = useCallbackRef(onValueChange);
|
|
return (0, import_jsx_runtime3.jsx)(RadioGroupProvider, { scope: props.__scopeMenu, value, onValueChange: handleValueChange, children: (0, import_jsx_runtime3.jsx)(MenuGroup, { ...groupProps, ref: forwardedRef }) });
|
|
}
|
|
);
|
|
MenuRadioGroup.displayName = RADIO_GROUP_NAME;
|
|
var RADIO_ITEM_NAME = "MenuRadioItem";
|
|
var MenuRadioItem = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { value, ...radioItemProps } = props;
|
|
const context = useRadioGroupContext(RADIO_ITEM_NAME, props.__scopeMenu);
|
|
const checked = value === context.value;
|
|
return (0, import_jsx_runtime3.jsx)(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: (0, import_jsx_runtime3.jsx)(
|
|
MenuItem,
|
|
{
|
|
role: "menuitemradio",
|
|
"aria-checked": checked,
|
|
...radioItemProps,
|
|
ref: forwardedRef,
|
|
"data-state": getCheckedState(checked),
|
|
onSelect: composeEventHandlers(
|
|
radioItemProps.onSelect,
|
|
() => {
|
|
var _a;
|
|
return (_a = context.onValueChange) == null ? void 0 : _a.call(context, value);
|
|
},
|
|
{ checkForDefaultPrevented: false }
|
|
)
|
|
}
|
|
) });
|
|
}
|
|
);
|
|
MenuRadioItem.displayName = RADIO_ITEM_NAME;
|
|
var ITEM_INDICATOR_NAME = "MenuItemIndicator";
|
|
var [ItemIndicatorProvider, useItemIndicatorContext] = createMenuContext(
|
|
ITEM_INDICATOR_NAME,
|
|
{ checked: false }
|
|
);
|
|
var MenuItemIndicator = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, forceMount, ...itemIndicatorProps } = props;
|
|
const indicatorContext = useItemIndicatorContext(ITEM_INDICATOR_NAME, __scopeMenu);
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
Presence,
|
|
{
|
|
present: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
Primitive.span,
|
|
{
|
|
...itemIndicatorProps,
|
|
ref: forwardedRef,
|
|
"data-state": getCheckedState(indicatorContext.checked)
|
|
}
|
|
)
|
|
}
|
|
);
|
|
}
|
|
);
|
|
MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
|
|
var SEPARATOR_NAME = "MenuSeparator";
|
|
var MenuSeparator = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, ...separatorProps } = props;
|
|
return (0, import_jsx_runtime3.jsx)(
|
|
Primitive.div,
|
|
{
|
|
role: "separator",
|
|
"aria-orientation": "horizontal",
|
|
...separatorProps,
|
|
ref: forwardedRef
|
|
}
|
|
);
|
|
}
|
|
);
|
|
MenuSeparator.displayName = SEPARATOR_NAME;
|
|
var ARROW_NAME = "MenuArrow";
|
|
var MenuArrow = React3.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeMenu, ...arrowProps } = props;
|
|
const popperScope = usePopperScope(__scopeMenu);
|
|
return (0, import_jsx_runtime3.jsx)(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] = React3.useState(null);
|
|
const [content, setContent] = React3.useState(null);
|
|
const handleOpenChange = useCallbackRef(onOpenChange);
|
|
React3.useEffect(() => {
|
|
if (parentMenuContext.open === false) handleOpenChange(false);
|
|
return () => handleOpenChange(false);
|
|
}, [parentMenuContext.open, handleOpenChange]);
|
|
return (0, import_jsx_runtime3.jsx)(Root2, { ...popperScope, children: (0, import_jsx_runtime3.jsx)(
|
|
MenuProvider,
|
|
{
|
|
scope: __scopeMenu,
|
|
open,
|
|
onOpenChange: handleOpenChange,
|
|
content,
|
|
onContentChange: setContent,
|
|
children: (0, import_jsx_runtime3.jsx)(
|
|
MenuSubProvider,
|
|
{
|
|
scope: __scopeMenu,
|
|
contentId: useId(),
|
|
triggerId: useId(),
|
|
trigger,
|
|
onTriggerChange: setTrigger,
|
|
children
|
|
}
|
|
)
|
|
}
|
|
) });
|
|
};
|
|
MenuSub.displayName = SUB_NAME;
|
|
var SUB_TRIGGER_NAME = "MenuSubTrigger";
|
|
var MenuSubTrigger = React3.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 = React3.useRef(null);
|
|
const { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext;
|
|
const scope = { __scopeMenu: props.__scopeMenu };
|
|
const clearOpenTimer = React3.useCallback(() => {
|
|
if (openTimerRef.current) window.clearTimeout(openTimerRef.current);
|
|
openTimerRef.current = null;
|
|
}, []);
|
|
React3.useEffect(() => clearOpenTimer, [clearOpenTimer]);
|
|
React3.useEffect(() => {
|
|
const pointerGraceTimer = pointerGraceTimerRef.current;
|
|
return () => {
|
|
window.clearTimeout(pointerGraceTimer);
|
|
onPointerGraceIntentChange(null);
|
|
};
|
|
}, [pointerGraceTimerRef, onPointerGraceIntentChange]);
|
|
return (0, import_jsx_runtime3.jsx)(MenuAnchor, { asChild: true, ...scope, children: (0, import_jsx_runtime3.jsx)(
|
|
MenuItemImpl,
|
|
{
|
|
id: subContext.triggerId,
|
|
"aria-haspopup": "menu",
|
|
"aria-expanded": context.open,
|
|
"aria-controls": subContext.contentId,
|
|
"data-state": getOpenState(context.open),
|
|
...props,
|
|
ref: composeRefs(forwardedRef, subContext.onTriggerChange),
|
|
onClick: (event) => {
|
|
var _a;
|
|
(_a = props.onClick) == null ? void 0 : _a.call(props, event);
|
|
if (props.disabled || event.defaultPrevented) return;
|
|
event.currentTarget.focus();
|
|
if (!context.open) context.onOpenChange(true);
|
|
},
|
|
onPointerMove: 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: composeEventHandlers(
|
|
props.onPointerLeave,
|
|
whenMouse((event) => {
|
|
var _a, _b;
|
|
clearOpenTimer();
|
|
const contentRect = (_a = context.content) == null ? void 0 : _a.getBoundingClientRect();
|
|
if (contentRect) {
|
|
const side = (_b = context.content) == null ? void 0 : _b.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: composeEventHandlers(props.onKeyDown, (event) => {
|
|
var _a;
|
|
const isTypingAhead = contentContext.searchRef.current !== "";
|
|
if (props.disabled || isTypingAhead && event.key === " ") return;
|
|
if (SUB_OPEN_KEYS[rootContext.dir].includes(event.key)) {
|
|
context.onOpenChange(true);
|
|
(_a = context.content) == null ? void 0 : _a.focus();
|
|
event.preventDefault();
|
|
}
|
|
})
|
|
}
|
|
) });
|
|
}
|
|
);
|
|
MenuSubTrigger.displayName = SUB_TRIGGER_NAME;
|
|
var SUB_CONTENT_NAME = "MenuSubContent";
|
|
var MenuSubContent = React3.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 = React3.useRef(null);
|
|
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
return (0, import_jsx_runtime3.jsx)(Collection2.Provider, { scope: props.__scopeMenu, children: (0, import_jsx_runtime3.jsx)(Presence, { present: forceMount || context.open, children: (0, import_jsx_runtime3.jsx)(Collection2.Slot, { scope: props.__scopeMenu, children: (0, import_jsx_runtime3.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) => {
|
|
var _a;
|
|
if (rootContext.isUsingKeyboardRef.current) (_a = ref.current) == null ? void 0 : _a.focus();
|
|
event.preventDefault();
|
|
},
|
|
onCloseAutoFocus: (event) => event.preventDefault(),
|
|
onFocusOutside: composeEventHandlers(props.onFocusOutside, (event) => {
|
|
if (event.target !== subContext.trigger) context.onOpenChange(false);
|
|
}),
|
|
onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, (event) => {
|
|
rootContext.onClose();
|
|
event.preventDefault();
|
|
}),
|
|
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
var _a;
|
|
const isKeyDownInside = event.currentTarget.contains(event.target);
|
|
const isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
|
|
if (isKeyDownInside && isCloseKey) {
|
|
context.onOpenChange(false);
|
|
(_a = subContext.trigger) == null ? void 0 : _a.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 focusFirst2(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 wrapArray2(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 = wrapArray2(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 Portal2 = 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;
|
|
|
|
// node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
|
|
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
var DROPDOWN_MENU_NAME = "DropdownMenu";
|
|
var [createDropdownMenuContext, createDropdownMenuScope] = createContextScope(
|
|
DROPDOWN_MENU_NAME,
|
|
[createMenuScope]
|
|
);
|
|
var useMenuScope = createMenuScope();
|
|
var [DropdownMenuProvider, useDropdownMenuContext] = createDropdownMenuContext(DROPDOWN_MENU_NAME);
|
|
var DropdownMenu = (props) => {
|
|
const {
|
|
__scopeDropdownMenu,
|
|
children,
|
|
dir,
|
|
open: openProp,
|
|
defaultOpen,
|
|
onOpenChange,
|
|
modal = true
|
|
} = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
const triggerRef = React4.useRef(null);
|
|
const [open = false, setOpen] = useControllableState({
|
|
prop: openProp,
|
|
defaultProp: defaultOpen,
|
|
onChange: onOpenChange
|
|
});
|
|
return (0, import_jsx_runtime4.jsx)(
|
|
DropdownMenuProvider,
|
|
{
|
|
scope: __scopeDropdownMenu,
|
|
triggerId: useId(),
|
|
triggerRef,
|
|
contentId: useId(),
|
|
open,
|
|
onOpenChange: setOpen,
|
|
onOpenToggle: React4.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
|
|
modal,
|
|
children: (0, import_jsx_runtime4.jsx)(Root3, { ...menuScope, open, onOpenChange: setOpen, dir, modal, children })
|
|
}
|
|
);
|
|
};
|
|
DropdownMenu.displayName = DROPDOWN_MENU_NAME;
|
|
var TRIGGER_NAME = "DropdownMenuTrigger";
|
|
var DropdownMenuTrigger = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
|
|
const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Anchor2, { asChild: true, ...menuScope, children: (0, import_jsx_runtime4.jsx)(
|
|
Primitive.button,
|
|
{
|
|
type: "button",
|
|
id: context.triggerId,
|
|
"aria-haspopup": "menu",
|
|
"aria-expanded": context.open,
|
|
"aria-controls": context.open ? context.contentId : void 0,
|
|
"data-state": context.open ? "open" : "closed",
|
|
"data-disabled": disabled ? "" : void 0,
|
|
disabled,
|
|
...triggerProps,
|
|
ref: composeRefs(forwardedRef, context.triggerRef),
|
|
onPointerDown: composeEventHandlers(props.onPointerDown, (event) => {
|
|
if (!disabled && event.button === 0 && event.ctrlKey === false) {
|
|
context.onOpenToggle();
|
|
if (!context.open) event.preventDefault();
|
|
}
|
|
}),
|
|
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
if (disabled) return;
|
|
if (["Enter", " "].includes(event.key)) context.onOpenToggle();
|
|
if (event.key === "ArrowDown") context.onOpenChange(true);
|
|
if (["Enter", " ", "ArrowDown"].includes(event.key)) event.preventDefault();
|
|
})
|
|
}
|
|
) });
|
|
}
|
|
);
|
|
DropdownMenuTrigger.displayName = TRIGGER_NAME;
|
|
var PORTAL_NAME2 = "DropdownMenuPortal";
|
|
var DropdownMenuPortal = (props) => {
|
|
const { __scopeDropdownMenu, ...portalProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Portal2, { ...menuScope, ...portalProps });
|
|
};
|
|
DropdownMenuPortal.displayName = PORTAL_NAME2;
|
|
var CONTENT_NAME2 = "DropdownMenuContent";
|
|
var DropdownMenuContent = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...contentProps } = props;
|
|
const context = useDropdownMenuContext(CONTENT_NAME2, __scopeDropdownMenu);
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
const hasInteractedOutsideRef = React4.useRef(false);
|
|
return (0, import_jsx_runtime4.jsx)(
|
|
Content2,
|
|
{
|
|
id: context.contentId,
|
|
"aria-labelledby": context.triggerId,
|
|
...menuScope,
|
|
...contentProps,
|
|
ref: forwardedRef,
|
|
onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
var _a;
|
|
if (!hasInteractedOutsideRef.current) (_a = context.triggerRef.current) == null ? void 0 : _a.focus();
|
|
hasInteractedOutsideRef.current = false;
|
|
event.preventDefault();
|
|
}),
|
|
onInteractOutside: composeEventHandlers(props.onInteractOutside, (event) => {
|
|
const originalEvent = event.detail.originalEvent;
|
|
const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
|
|
const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
|
|
if (!context.modal || isRightClick) hasInteractedOutsideRef.current = true;
|
|
}),
|
|
style: {
|
|
...props.style,
|
|
// re-namespace exposed content custom properties
|
|
...{
|
|
"--radix-dropdown-menu-content-transform-origin": "var(--radix-popper-transform-origin)",
|
|
"--radix-dropdown-menu-content-available-width": "var(--radix-popper-available-width)",
|
|
"--radix-dropdown-menu-content-available-height": "var(--radix-popper-available-height)",
|
|
"--radix-dropdown-menu-trigger-width": "var(--radix-popper-anchor-width)",
|
|
"--radix-dropdown-menu-trigger-height": "var(--radix-popper-anchor-height)"
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
);
|
|
DropdownMenuContent.displayName = CONTENT_NAME2;
|
|
var GROUP_NAME3 = "DropdownMenuGroup";
|
|
var DropdownMenuGroup = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...groupProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Group, { ...menuScope, ...groupProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
DropdownMenuGroup.displayName = GROUP_NAME3;
|
|
var LABEL_NAME2 = "DropdownMenuLabel";
|
|
var DropdownMenuLabel = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...labelProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Label, { ...menuScope, ...labelProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
DropdownMenuLabel.displayName = LABEL_NAME2;
|
|
var ITEM_NAME3 = "DropdownMenuItem";
|
|
var DropdownMenuItem = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...itemProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
DropdownMenuItem.displayName = ITEM_NAME3;
|
|
var CHECKBOX_ITEM_NAME2 = "DropdownMenuCheckboxItem";
|
|
var DropdownMenuCheckboxItem = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...checkboxItemProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME2;
|
|
var RADIO_GROUP_NAME2 = "DropdownMenuRadioGroup";
|
|
var DropdownMenuRadioGroup = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...radioGroupProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(RadioGroup, { ...menuScope, ...radioGroupProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuRadioGroup.displayName = RADIO_GROUP_NAME2;
|
|
var RADIO_ITEM_NAME2 = "DropdownMenuRadioItem";
|
|
var DropdownMenuRadioItem = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...radioItemProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(RadioItem, { ...menuScope, ...radioItemProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuRadioItem.displayName = RADIO_ITEM_NAME2;
|
|
var INDICATOR_NAME = "DropdownMenuItemIndicator";
|
|
var DropdownMenuItemIndicator = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...itemIndicatorProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(ItemIndicator, { ...menuScope, ...itemIndicatorProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuItemIndicator.displayName = INDICATOR_NAME;
|
|
var SEPARATOR_NAME2 = "DropdownMenuSeparator";
|
|
var DropdownMenuSeparator = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...separatorProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Separator, { ...menuScope, ...separatorProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuSeparator.displayName = SEPARATOR_NAME2;
|
|
var ARROW_NAME2 = "DropdownMenuArrow";
|
|
var DropdownMenuArrow = React4.forwardRef(
|
|
(props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...arrowProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(Arrow2, { ...menuScope, ...arrowProps, ref: forwardedRef });
|
|
}
|
|
);
|
|
DropdownMenuArrow.displayName = ARROW_NAME2;
|
|
var DropdownMenuSub = (props) => {
|
|
const { __scopeDropdownMenu, children, open: openProp, onOpenChange, defaultOpen } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
const [open = false, setOpen] = useControllableState({
|
|
prop: openProp,
|
|
defaultProp: defaultOpen,
|
|
onChange: onOpenChange
|
|
});
|
|
return (0, import_jsx_runtime4.jsx)(Sub, { ...menuScope, open, onOpenChange: setOpen, children });
|
|
};
|
|
var SUB_TRIGGER_NAME2 = "DropdownMenuSubTrigger";
|
|
var DropdownMenuSubTrigger = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...subTriggerProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(SubTrigger, { ...menuScope, ...subTriggerProps, ref: forwardedRef });
|
|
});
|
|
DropdownMenuSubTrigger.displayName = SUB_TRIGGER_NAME2;
|
|
var SUB_CONTENT_NAME2 = "DropdownMenuSubContent";
|
|
var DropdownMenuSubContent = React4.forwardRef((props, forwardedRef) => {
|
|
const { __scopeDropdownMenu, ...subContentProps } = props;
|
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
return (0, import_jsx_runtime4.jsx)(
|
|
SubContent,
|
|
{
|
|
...menuScope,
|
|
...subContentProps,
|
|
ref: forwardedRef,
|
|
style: {
|
|
...props.style,
|
|
// re-namespace exposed content custom properties
|
|
...{
|
|
"--radix-dropdown-menu-content-transform-origin": "var(--radix-popper-transform-origin)",
|
|
"--radix-dropdown-menu-content-available-width": "var(--radix-popper-available-width)",
|
|
"--radix-dropdown-menu-content-available-height": "var(--radix-popper-available-height)",
|
|
"--radix-dropdown-menu-trigger-width": "var(--radix-popper-anchor-width)",
|
|
"--radix-dropdown-menu-trigger-height": "var(--radix-popper-anchor-height)"
|
|
}
|
|
}
|
|
}
|
|
);
|
|
});
|
|
DropdownMenuSubContent.displayName = SUB_CONTENT_NAME2;
|
|
var Root22 = DropdownMenu;
|
|
var Trigger = DropdownMenuTrigger;
|
|
var Portal22 = DropdownMenuPortal;
|
|
var Content22 = DropdownMenuContent;
|
|
var Group2 = DropdownMenuGroup;
|
|
var Label2 = DropdownMenuLabel;
|
|
var Item22 = DropdownMenuItem;
|
|
var CheckboxItem2 = DropdownMenuCheckboxItem;
|
|
var RadioGroup2 = DropdownMenuRadioGroup;
|
|
var RadioItem2 = DropdownMenuRadioItem;
|
|
var ItemIndicator2 = DropdownMenuItemIndicator;
|
|
var Separator2 = DropdownMenuSeparator;
|
|
var Arrow22 = DropdownMenuArrow;
|
|
var Sub2 = DropdownMenuSub;
|
|
var SubTrigger2 = DropdownMenuSubTrigger;
|
|
var SubContent2 = DropdownMenuSubContent;
|
|
export {
|
|
Arrow22 as Arrow,
|
|
CheckboxItem2 as CheckboxItem,
|
|
Content22 as Content,
|
|
DropdownMenu,
|
|
DropdownMenuArrow,
|
|
DropdownMenuCheckboxItem,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuItemIndicator,
|
|
DropdownMenuLabel,
|
|
DropdownMenuPortal,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuSub,
|
|
DropdownMenuSubContent,
|
|
DropdownMenuSubTrigger,
|
|
DropdownMenuTrigger,
|
|
Group2 as Group,
|
|
Item22 as Item,
|
|
ItemIndicator2 as ItemIndicator,
|
|
Label2 as Label,
|
|
Portal22 as Portal,
|
|
RadioGroup2 as RadioGroup,
|
|
RadioItem2 as RadioItem,
|
|
Root22 as Root,
|
|
Separator2 as Separator,
|
|
Sub2 as Sub,
|
|
SubContent2 as SubContent,
|
|
SubTrigger2 as SubTrigger,
|
|
Trigger,
|
|
createDropdownMenuScope
|
|
};
|
|
//# sourceMappingURL=@radix-ui_react-dropdown-menu.js.map
|