@xsolla/xui-context-menu 0.168.0 → 0.168.1-pr328.1780650408
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/native/index.d.mts +6 -0
- package/native/index.d.ts +6 -0
- package/native/index.js +80 -19
- package/native/index.js.map +1 -1
- package/native/index.mjs +84 -20
- package/native/index.mjs.map +1 -1
- package/package.json +9 -9
- package/web/index.d.mts +6 -0
- package/web/index.d.ts +6 -0
- package/web/index.js +80 -19
- package/web/index.js.map +1 -1
- package/web/index.mjs +84 -20
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
CHANGED
|
@@ -96,9 +96,15 @@ interface ContextMenuCellMeta {
|
|
|
96
96
|
}
|
|
97
97
|
interface ContextMenuContextValue {
|
|
98
98
|
size: ContextMenuSize;
|
|
99
|
+
/** Stable id of the owning menu; tags portaled submenus for outside-click. */
|
|
100
|
+
menuId: string;
|
|
99
101
|
closeMenu: () => void;
|
|
100
102
|
registerCell: (id: string, meta: ContextMenuCellMeta) => number;
|
|
101
103
|
unregisterCell: (id: string) => void;
|
|
104
|
+
/** Live position of a cell in the registry (-1 if not registered). */
|
|
105
|
+
getCellIndex: (id: string) => number;
|
|
106
|
+
/** Bumps whenever the cell registry changes; drives index re-derivation. */
|
|
107
|
+
cellsVersion: number;
|
|
102
108
|
activeIndex: number;
|
|
103
109
|
setActiveIndex: (i: number) => void;
|
|
104
110
|
query: string;
|
package/native/index.d.ts
CHANGED
|
@@ -96,9 +96,15 @@ interface ContextMenuCellMeta {
|
|
|
96
96
|
}
|
|
97
97
|
interface ContextMenuContextValue {
|
|
98
98
|
size: ContextMenuSize;
|
|
99
|
+
/** Stable id of the owning menu; tags portaled submenus for outside-click. */
|
|
100
|
+
menuId: string;
|
|
99
101
|
closeMenu: () => void;
|
|
100
102
|
registerCell: (id: string, meta: ContextMenuCellMeta) => number;
|
|
101
103
|
unregisterCell: (id: string) => void;
|
|
104
|
+
/** Live position of a cell in the registry (-1 if not registered). */
|
|
105
|
+
getCellIndex: (id: string) => number;
|
|
106
|
+
/** Bumps whenever the cell registry changes; drives index re-derivation. */
|
|
107
|
+
cellsVersion: number;
|
|
102
108
|
activeIndex: number;
|
|
103
109
|
setActiveIndex: (i: number) => void;
|
|
104
110
|
query: string;
|
package/native/index.js
CHANGED
|
@@ -152,7 +152,9 @@ var OptionCell = ({
|
|
|
152
152
|
const sizing = theme.sizing.contextMenu(size);
|
|
153
153
|
const variants = sizeToVariants[size];
|
|
154
154
|
const id = (0, import_xui_core.useId)();
|
|
155
|
-
const
|
|
155
|
+
const registerCell = ctx?.registerCell;
|
|
156
|
+
const unregisterCell = ctx?.unregisterCell;
|
|
157
|
+
const getCellIndex = ctx?.getCellIndex;
|
|
156
158
|
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
|
|
157
159
|
const [submenuOpen, setSubmenuOpen] = (0, import_react2.useState)(false);
|
|
158
160
|
const [submenuPos, setSubmenuPos] = (0, import_react2.useState)(null);
|
|
@@ -214,15 +216,22 @@ var OptionCell = ({
|
|
|
214
216
|
const onSelectRef = import_react2.default.useRef(onSelect);
|
|
215
217
|
onSelectRef.current = onSelect;
|
|
216
218
|
(0, import_react2.useEffect)(() => {
|
|
217
|
-
if (!
|
|
218
|
-
|
|
219
|
+
if (!registerCell || !unregisterCell) return;
|
|
220
|
+
registerCell(id, {
|
|
221
|
+
type: "option",
|
|
222
|
+
onSelect: () => onSelectRef.current?.()
|
|
223
|
+
});
|
|
224
|
+
return () => unregisterCell(id);
|
|
225
|
+
}, [registerCell, unregisterCell, id]);
|
|
226
|
+
(0, import_react2.useEffect)(() => {
|
|
227
|
+
if (!registerCell) return;
|
|
228
|
+
registerCell(id, {
|
|
219
229
|
type: "option",
|
|
220
230
|
disabled,
|
|
221
231
|
onSelect: () => onSelectRef.current?.()
|
|
222
232
|
});
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}, [ctx, id, disabled]);
|
|
233
|
+
}, [registerCell, id, disabled]);
|
|
234
|
+
const index = getCellIndex ? getCellIndex(id) : -1;
|
|
226
235
|
const isActive = ctx ? index >= 0 && ctx.activeIndex === index : false;
|
|
227
236
|
const inHoverState = isActive || !ctx && isHovered || hasSubmenu && submenuOpen;
|
|
228
237
|
const handleEnter = () => {
|
|
@@ -443,6 +452,7 @@ var OptionCell = ({
|
|
|
443
452
|
"div",
|
|
444
453
|
{
|
|
445
454
|
ref: submenuWrapperRef,
|
|
455
|
+
"data-xui-context-menu-portal": ctx?.menuId,
|
|
446
456
|
onMouseEnter: cancelClose,
|
|
447
457
|
onMouseLeave: scheduleClose,
|
|
448
458
|
style: {
|
|
@@ -475,11 +485,13 @@ var HeadingCell = ({
|
|
|
475
485
|
const sizing = theme.sizing.contextMenu(size);
|
|
476
486
|
const variants = sizeToVariants[size];
|
|
477
487
|
const id = (0, import_xui_core.useId)();
|
|
488
|
+
const registerCell = ctx?.registerCell;
|
|
489
|
+
const unregisterCell = ctx?.unregisterCell;
|
|
478
490
|
(0, import_react2.useEffect)(() => {
|
|
479
|
-
if (!
|
|
480
|
-
|
|
481
|
-
return () =>
|
|
482
|
-
}, [
|
|
491
|
+
if (!registerCell || !unregisterCell) return;
|
|
492
|
+
registerCell(id, { type: "heading" });
|
|
493
|
+
return () => unregisterCell(id);
|
|
494
|
+
}, [registerCell, unregisterCell, id]);
|
|
483
495
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
484
496
|
"div",
|
|
485
497
|
{
|
|
@@ -533,11 +545,13 @@ var SearchCell = ({
|
|
|
533
545
|
const size = propSize ?? ctx?.size ?? "md";
|
|
534
546
|
const sizing = theme.sizing.contextMenu(size);
|
|
535
547
|
const id = (0, import_xui_core.useId)();
|
|
548
|
+
const registerCell = ctx?.registerCell;
|
|
549
|
+
const unregisterCell = ctx?.unregisterCell;
|
|
536
550
|
(0, import_react2.useEffect)(() => {
|
|
537
|
-
if (!
|
|
538
|
-
|
|
539
|
-
return () =>
|
|
540
|
-
}, [
|
|
551
|
+
if (!registerCell || !unregisterCell) return;
|
|
552
|
+
registerCell(id, { type: "search" });
|
|
553
|
+
return () => unregisterCell(id);
|
|
554
|
+
}, [registerCell, unregisterCell, id]);
|
|
541
555
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
542
556
|
"input",
|
|
543
557
|
{
|
|
@@ -570,11 +584,13 @@ var DividerCell = ({ themeMode, themeProductContext, "data-testid": testId }) =>
|
|
|
570
584
|
const { theme } = (0, import_xui_core.useResolvedTheme)({ themeMode, themeProductContext });
|
|
571
585
|
const ctx = useContextMenu();
|
|
572
586
|
const id = (0, import_xui_core.useId)();
|
|
587
|
+
const registerCell = ctx?.registerCell;
|
|
588
|
+
const unregisterCell = ctx?.unregisterCell;
|
|
573
589
|
(0, import_react2.useEffect)(() => {
|
|
574
|
-
if (!
|
|
575
|
-
|
|
576
|
-
return () =>
|
|
577
|
-
}, [
|
|
590
|
+
if (!registerCell || !unregisterCell) return;
|
|
591
|
+
registerCell(id, { type: "divider" });
|
|
592
|
+
return () => unregisterCell(id);
|
|
593
|
+
}, [registerCell, unregisterCell, id]);
|
|
578
594
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
579
595
|
"div",
|
|
580
596
|
{
|
|
@@ -838,6 +854,7 @@ var ContextMenu = (props) => {
|
|
|
838
854
|
const [cellsVersion, setCellsVersion] = (0, import_react5.useState)(0);
|
|
839
855
|
const triggerRef = (0, import_react5.useRef)(null);
|
|
840
856
|
const panelRef = (0, import_react5.useRef)(null);
|
|
857
|
+
const menuId = (0, import_xui_core2.useId)();
|
|
841
858
|
const [query, setQuery] = (0, import_react5.useState)("");
|
|
842
859
|
const [debouncedQuery, setDebouncedQuery] = (0, import_react5.useState)("");
|
|
843
860
|
const debounceTimerRef = (0, import_react5.useRef)(null);
|
|
@@ -861,7 +878,11 @@ var ContextMenu = (props) => {
|
|
|
861
878
|
setCellsVersion((v) => v + 1);
|
|
862
879
|
return cellsRef.current.length - 1;
|
|
863
880
|
}
|
|
881
|
+
const prev = cellsRef.current[existing].meta;
|
|
864
882
|
cellsRef.current[existing] = { id, meta };
|
|
883
|
+
if (prev.disabled !== meta.disabled || prev.type !== meta.type) {
|
|
884
|
+
setCellsVersion((v) => v + 1);
|
|
885
|
+
}
|
|
865
886
|
return existing;
|
|
866
887
|
}, []);
|
|
867
888
|
const unregisterCell = (0, import_react5.useCallback)((id) => {
|
|
@@ -871,18 +892,35 @@ var ContextMenu = (props) => {
|
|
|
871
892
|
setCellsVersion((v) => v + 1);
|
|
872
893
|
}
|
|
873
894
|
}, []);
|
|
895
|
+
const getCellIndex = (0, import_react5.useCallback)(
|
|
896
|
+
(id) => cellsRef.current.findIndex((c) => c.id === id),
|
|
897
|
+
[]
|
|
898
|
+
);
|
|
874
899
|
const ctx = (0, import_react5.useMemo)(
|
|
875
900
|
() => ({
|
|
876
901
|
size,
|
|
902
|
+
menuId,
|
|
877
903
|
closeMenu,
|
|
878
904
|
registerCell,
|
|
879
905
|
unregisterCell,
|
|
906
|
+
getCellIndex,
|
|
907
|
+
cellsVersion,
|
|
880
908
|
activeIndex,
|
|
881
909
|
setActiveIndex,
|
|
882
910
|
query,
|
|
883
911
|
setQuery
|
|
884
912
|
}),
|
|
885
|
-
[
|
|
913
|
+
[
|
|
914
|
+
size,
|
|
915
|
+
menuId,
|
|
916
|
+
closeMenu,
|
|
917
|
+
registerCell,
|
|
918
|
+
unregisterCell,
|
|
919
|
+
getCellIndex,
|
|
920
|
+
cellsVersion,
|
|
921
|
+
activeIndex,
|
|
922
|
+
query
|
|
923
|
+
]
|
|
886
924
|
);
|
|
887
925
|
const triggerNode = (0, import_react5.useMemo)(() => {
|
|
888
926
|
if (!trigger) return null;
|
|
@@ -1120,6 +1158,29 @@ var ContextMenu = (props) => {
|
|
|
1120
1158
|
triggerRef.current?.focus();
|
|
1121
1159
|
}
|
|
1122
1160
|
}, [open]);
|
|
1161
|
+
(0, import_react5.useEffect)(() => {
|
|
1162
|
+
if (!open || !usePortal || typeof document === "undefined") return;
|
|
1163
|
+
const handlePointerDown = (event) => {
|
|
1164
|
+
const target = event.target;
|
|
1165
|
+
if (!target) return;
|
|
1166
|
+
if (panelRef.current?.contains(target)) return;
|
|
1167
|
+
if (triggerRef.current?.contains(target)) return;
|
|
1168
|
+
if (target instanceof Element) {
|
|
1169
|
+
const portals = document.querySelectorAll(
|
|
1170
|
+
"[data-xui-context-menu-portal]"
|
|
1171
|
+
);
|
|
1172
|
+
for (let i = 0; i < portals.length; i += 1) {
|
|
1173
|
+
const portal = portals[i];
|
|
1174
|
+
if (portal.getAttribute("data-xui-context-menu-portal") === menuId && portal.contains(target)) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
closeMenu();
|
|
1180
|
+
};
|
|
1181
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
1182
|
+
return () => document.removeEventListener("mousedown", handlePointerDown);
|
|
1183
|
+
}, [open, usePortal, closeMenu, menuId]);
|
|
1123
1184
|
const resolvedPlacement = position?.placement ?? placement;
|
|
1124
1185
|
const scrollContainerStyle = {
|
|
1125
1186
|
overflowY: "auto",
|
package/native/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.tsx","../../src/ContextMenu.tsx","../../src/ContextMenuContext.tsx","../../src/ContextMenuItem.tsx","../../src/hooks/useContextMenuPosition.ts","../../src/hooks/useKeyboardNavigation.ts"],"sourcesContent":["export { ContextMenu } from \"./ContextMenu\";\nexport { ContextMenuItem } from \"./ContextMenuItem\";\n\nexport {\n useContextMenu,\n useContextMenuRequired,\n ContextMenuContext,\n} from \"./ContextMenuContext\";\n\nexport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nexport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation\";\n\nexport type {\n ContextMenuSize,\n ContextMenuItemType,\n ContextMenuItemLeadingControl,\n ContextMenuOptionItemProps,\n ContextMenuSearchItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuDividerItemProps,\n ContextMenuItemProps,\n ContextMenuPanelType,\n ContextMenuPlacement,\n ContextMenuPosition,\n ContextMenuProps,\n ContextMenuContextValue,\n ContextMenuSizing,\n} from \"./types\";\n","import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n isValidElement,\n cloneElement,\n type ReactElement,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\nimport { ContextMenuContext } from \"./ContextMenuContext\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nimport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation\";\nimport type {\n ContextMenuCellMeta,\n ContextMenuContextValue,\n ContextMenuDividerItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuOptionItemProps,\n ContextMenuProps,\n ContextMenuSize,\n} from \"./types\";\n\ntype Props = ContextMenuProps & ThemeOverrideProps;\n\ninterface CellEntry {\n id: string;\n meta: ContextMenuCellMeta;\n}\n\ntype PresetItem =\n | ContextMenuOptionItemProps\n | ContextMenuHeadingItemProps\n | ContextMenuDividerItemProps;\n\nconst SEARCH_DEBOUNCE_MS = 200;\n\nconst EmptyMessage: React.FC<{ children: React.ReactNode; color: string }> = ({\n children,\n color,\n}) => (\n <div\n style={{\n padding: 12,\n color,\n fontSize: 14,\n textAlign: \"center\",\n }}\n >\n {children}\n </div>\n);\n\nexport const ContextMenu: React.FC<Props> = (props) => {\n const {\n type,\n items,\n children,\n size = \"md\",\n searchable,\n loading,\n emptyMessage,\n empty,\n trigger,\n isOpen,\n onOpenChange,\n closeOnSelect,\n width,\n maxHeight,\n placement = \"bottom-start\",\n onSelect,\n \"aria-label\": ariaLabel,\n \"data-testid\": testId,\n testID,\n themeMode,\n themeProductContext,\n } = props;\n\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const isControlled = isOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const open = isControlled ? !!isOpen : internalOpen;\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const cellsRef = useRef<CellEntry[]>([]);\n const [cellsVersion, setCellsVersion] = useState(0);\n\n const triggerRef = useRef<HTMLElement | null>(null);\n const panelRef = useRef<HTMLDivElement | null>(null);\n\n // Search query state\n const [query, setQuery] = useState(\"\");\n const [debouncedQuery, setDebouncedQuery] = useState(\"\");\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = setTimeout(() => {\n setDebouncedQuery(query);\n }, SEARCH_DEBOUNCE_MS);\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n };\n }, [query]);\n\n const closeMenu = useCallback(() => {\n setOpen(false);\n setActiveIndex(-1);\n }, [setOpen]);\n\n const registerCell = useCallback((id: string, meta: ContextMenuCellMeta) => {\n const existing = cellsRef.current.findIndex((c) => c.id === id);\n if (existing === -1) {\n cellsRef.current.push({ id, meta });\n setCellsVersion((v) => v + 1);\n return cellsRef.current.length - 1;\n }\n cellsRef.current[existing] = { id, meta };\n return existing;\n }, []);\n\n const unregisterCell = useCallback((id: string) => {\n const idx = cellsRef.current.findIndex((c) => c.id === id);\n if (idx !== -1) {\n cellsRef.current.splice(idx, 1);\n setCellsVersion((v) => v + 1);\n }\n }, []);\n\n const ctx: ContextMenuContextValue = useMemo(\n () => ({\n size: size as ContextMenuSize,\n closeMenu,\n registerCell,\n unregisterCell,\n activeIndex,\n setActiveIndex,\n query,\n setQuery,\n }),\n [size, closeMenu, registerCell, unregisterCell, activeIndex, query]\n );\n\n const triggerNode = useMemo(() => {\n if (!trigger) return null;\n const inner = isValidElement(trigger)\n ? cloneElement(\n trigger as ReactElement<{\n \"aria-haspopup\"?: string;\n \"aria-expanded\"?: string | boolean;\n }>,\n {\n \"aria-haspopup\": \"menu\",\n \"aria-expanded\": open ? \"true\" : \"false\",\n }\n )\n : trigger;\n return (\n <span\n ref={(node) => {\n if (!node) {\n triggerRef.current = null;\n return;\n }\n const focusable = node.querySelector<HTMLElement>(\n \"button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])\"\n );\n triggerRef.current = focusable ?? node;\n }}\n onClick={() => setOpen(!open)}\n style={{ display: \"inline-flex\" }}\n >\n {inner}\n </span>\n );\n }, [trigger, open, setOpen]);\n\n const usePortal = !!trigger && typeof document !== \"undefined\";\n\n const position = useContextMenuPosition({\n triggerRef,\n panelRef,\n isOpen: open && usePortal,\n placement,\n });\n\n const cellsForNav = useMemo(\n () => cellsRef.current.map((c) => ({ id: c.id, meta: c.meta })),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [cellsVersion]\n );\n\n const { handleKeyDown } = useKeyboardNavigation({\n isOpen: open,\n cells: cellsForNav,\n activeIndex,\n setActiveIndex,\n onClose: closeMenu,\n triggerRef,\n });\n\n const sizingFn = (theme.sizing as { contextMenu?: (s: string) => unknown })\n .contextMenu;\n const sizing = sizingFn\n ? (sizingFn(size) as {\n panelWidth?: number;\n borderRadius?: number;\n paddingVertical?: number;\n })\n : {};\n const radiusObj = (theme as { radius?: { contextMenu?: number } }).radius;\n const radiusVal = sizing.borderRadius ?? radiusObj?.contextMenu ?? 8;\n const shadowObj = (theme as { shadow?: { contextMenu?: string } }).shadow;\n const shadowVal = shadowObj?.contextMenu ?? \"\";\n const panelPaddingVertical = sizing.paddingVertical ?? 8;\n\n const panelStyle: React.CSSProperties = {\n background: theme.colors.background.primary,\n borderRadius: radiusVal,\n boxShadow: shadowVal,\n width: width ?? sizing.panelWidth,\n maxHeight,\n overflow: \"hidden\",\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n outline: \"none\",\n fontFamily: theme.fonts.body,\n paddingTop: panelPaddingVertical,\n paddingBottom: panelPaddingVertical,\n };\n\n if (usePortal) {\n panelStyle.position = \"fixed\";\n panelStyle.top = position?.top ?? 0;\n panelStyle.left = position?.left ?? 0;\n }\n\n // Filter preset items based on debounced query (only when searchable + items)\n const filteredItems = useMemo<PresetItem[] | undefined>(() => {\n if (!items) return undefined;\n if (!searchable || !debouncedQuery) return items.slice();\n const q = debouncedQuery.toLowerCase();\n const matchedFlags = items.map((item) => {\n if (item.type === \"option\") {\n return String(item.label ?? \"\")\n .toLowerCase()\n .includes(q);\n }\n return false; // headings/dividers themselves never match\n });\n // Now hide headings whose options are all filtered out and trailing dividers\n const result: PresetItem[] = [];\n let pendingHeading: {\n item: ContextMenuHeadingItemProps;\n idx: number;\n } | null = null;\n let lastEmittedWasContent = false; // whether last pushed was option (so divider can follow)\n let groupHasOption = false;\n for (let i = 0; i < items.length; i += 1) {\n const item = items[i];\n if (item.type === \"heading\") {\n // Starting a new group\n pendingHeading = { item, idx: i };\n groupHasOption = false;\n } else if (item.type === \"divider\") {\n // Emit divider only if the previously emitted thing was content\n if (lastEmittedWasContent) {\n result.push(item);\n lastEmittedWasContent = false;\n }\n // dividers also reset pending heading so a heading sits with its group\n pendingHeading = null;\n groupHasOption = false;\n } else if (item.type === \"option\") {\n if (matchedFlags[i]) {\n if (pendingHeading) {\n result.push(pendingHeading.item);\n pendingHeading = null;\n }\n result.push(item);\n lastEmittedWasContent = true;\n groupHasOption = true;\n }\n }\n }\n // Strip trailing divider if any\n while (result.length > 0 && result[result.length - 1].type === \"divider\") {\n result.pop();\n }\n // Suppress unused\n void groupHasOption;\n return result;\n }, [items, searchable, debouncedQuery]);\n\n const effectiveCloseOnSelect =\n closeOnSelect !== undefined ? closeOnSelect : type !== \"checkbox\";\n\n const renderPresetItem = (item: PresetItem, key: number) => {\n if (item.type === \"heading\") {\n return (\n <ContextMenuItem\n key={`h-${key}`}\n {...item}\n size={item.size ?? (size as ContextMenuSize)}\n />\n );\n }\n if (item.type === \"divider\") {\n return (\n <ContextMenuItem\n key={`d-${key}`}\n {...item}\n size={item.size ?? (size as ContextMenuSize)}\n />\n );\n }\n const composed = composeItemForPreset(type, item);\n const originalSelect = composed.onSelect;\n const wrappedSelect = () => {\n originalSelect?.();\n onSelect?.(item);\n if (effectiveCloseOnSelect) closeMenu();\n };\n return (\n <ContextMenuItem\n key={`o-${key}`}\n {...composed}\n size={composed.size ?? (size as ContextMenuSize)}\n onSelect={wrappedSelect}\n />\n );\n };\n\n // Determine what to render in the panel body\n const isLoadingState = loading;\n\n let bodyContent: React.ReactNode = null;\n let isBodyEmpty = false;\n let searchNode: React.ReactNode = null;\n\n if (isLoadingState) {\n bodyContent = (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n }}\n >\n <Spinner size={size === \"xl\" ? \"lg\" : size === \"lg\" ? \"md\" : \"sm\"} />\n </div>\n );\n } else if (children !== undefined && children !== null) {\n // Custom path. Empty when children is falsy/empty array.\n const childArr = React.Children.toArray(children);\n if (childArr.length === 0) {\n isBodyEmpty = true;\n } else {\n bodyContent = children;\n }\n } else if (type && items) {\n // Preset path\n if (searchable) {\n searchNode = (\n <ContextMenuItem\n type=\"search\"\n value={query}\n onValueChange={setQuery}\n size={size as ContextMenuSize}\n />\n );\n }\n const visible = filteredItems ?? [];\n const optionCount = visible.filter((i) => i.type === \"option\").length;\n if (optionCount === 0) {\n isBodyEmpty = true;\n } else {\n bodyContent = visible.map((it, idx) => renderPresetItem(it, idx));\n }\n } else {\n // No children, no items — empty\n isBodyEmpty = true;\n }\n\n if (isBodyEmpty) {\n bodyContent = empty ?? (\n <EmptyMessage color={theme.colors.content.tertiary}>\n {emptyMessage ?? \"No results\"}\n </EmptyMessage>\n );\n }\n\n const hasStickySearch = !!searchNode;\n\n // Focus management on open/close transitions\n const prevOpenRef = useRef(false);\n useEffect(() => {\n const wasOpen = prevOpenRef.current;\n prevOpenRef.current = open;\n if (!wasOpen && open) {\n // open transition: focus search if present, else first option\n // wait for cells to register\n const timer = setTimeout(() => {\n const panel = panelRef.current;\n if (!panel) return;\n const search =\n panel.querySelector<HTMLInputElement>(\"[role='searchbox']\");\n if (search) {\n search.focus();\n return;\n }\n const firstOption = panel.querySelector<HTMLElement>(\n \"[role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio']\"\n );\n if (firstOption) {\n firstOption.focus();\n // Reset activeIndex so keyboard nav starts fresh; onFocus will have\n // set it to the focused option's index, but tests expect ArrowDown\n // to move to the first option from -1.\n setActiveIndex(-1);\n } else {\n panel.focus();\n }\n }, 0);\n return () => clearTimeout(timer);\n }\n if (wasOpen && !open) {\n // close transition: focus the trigger\n triggerRef.current?.focus();\n }\n }, [open]);\n\n const resolvedPlacement = position?.placement ?? placement;\n\n const scrollContainerStyle: React.CSSProperties = {\n overflowY: \"auto\",\n flex: 1,\n minHeight: 0,\n };\n\n const stickyHeaderStyle: React.CSSProperties = {\n position: \"sticky\",\n top: 0,\n zIndex: 1,\n background: theme.colors.background.primary,\n };\n\n const panel = open ? (\n <ContextMenuContext.Provider value={ctx}>\n <div\n ref={panelRef}\n role=\"menu\"\n aria-label={ariaLabel}\n data-testid={testId || testID}\n data-placement={usePortal ? resolvedPlacement : undefined}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n onMouseLeave={() => setActiveIndex(-1)}\n style={panelStyle}\n >\n {hasStickySearch && (\n <div data-sticky=\"top\" style={stickyHeaderStyle}>\n {searchNode}\n </div>\n )}\n <div style={scrollContainerStyle}>{bodyContent}</div>\n </div>\n </ContextMenuContext.Provider>\n ) : null;\n\n return (\n <>\n {triggerNode}\n {usePortal ? panel && createPortal(panel, document.body) : panel}\n </>\n );\n};\n\nContextMenu.displayName = \"ContextMenu\";\n\nfunction composeItemForPreset(\n type: ContextMenuProps[\"type\"],\n item: ContextMenuOptionItemProps\n): ContextMenuOptionItemProps {\n switch (type) {\n case \"checkbox\":\n return { ...item, leadingControl: \"checkbox\" };\n case \"radio\":\n return { ...item, leadingControl: \"radio\" };\n case \"list\":\n case \"phone\":\n case \"status\":\n case \"brandLogo\":\n case \"avatar\":\n default:\n return { ...item };\n }\n}\n","import { createContext, useContext } from \"react\";\nimport type { ContextMenuContextValue } from \"./types\";\n\nexport const ContextMenuContext = createContext<\n ContextMenuContextValue | undefined\n>(undefined);\n\nexport const useContextMenu = () => {\n const context = useContext(ContextMenuContext);\n return context;\n};\n\nexport const useContextMenuRequired = () => {\n const context = useContext(ContextMenuContext);\n if (!context) {\n throw new Error(\n \"useContextMenuRequired must be used within a ContextMenu component\"\n );\n }\n return context;\n};\n","import React, { useEffect, useLayoutEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n useResolvedTheme,\n useId,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport { Typography } from \"@xsolla/xui-typography\";\nimport { Checkbox } from \"@xsolla/xui-checkbox\";\nimport { Radio } from \"@xsolla/xui-radio\";\nimport { useContextMenu } from \"./ContextMenuContext\";\nimport type {\n ContextMenuDividerItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuItemProps,\n ContextMenuOptionItemProps,\n ContextMenuSearchItemProps,\n ContextMenuSize,\n} from \"./types\";\n\ntype BodyVariant = \"bodyLg\" | \"bodyMd\" | \"bodySm\" | \"bodyXs\";\ntype AccentVariant =\n | \"bodyLgAccent\"\n | \"bodyMdAccent\"\n | \"bodySmAccent\"\n | \"bodyXsAccent\";\n\nconst sizeToVariants: Record<\n ContextMenuSize,\n { label: BodyVariant; description: BodyVariant; headingAccent: AccentVariant }\n> = {\n xl: { label: \"bodyLg\", description: \"bodyLg\", headingAccent: \"bodyLgAccent\" },\n lg: { label: \"bodyLg\", description: \"bodyMd\", headingAccent: \"bodyMdAccent\" },\n md: { label: \"bodyMd\", description: \"bodySm\", headingAccent: \"bodySmAccent\" },\n sm: { label: \"bodySm\", description: \"bodyXs\", headingAccent: \"bodyXsAccent\" },\n};\n\nconst sizeLabelOverride: Partial<\n Record<ContextMenuSize, { fontSize: number; lineHeight: string }>\n> = {\n xl: { fontSize: 20, lineHeight: \"26px\" },\n};\n\ntype Props = ContextMenuItemProps & ThemeOverrideProps;\n\nexport const ContextMenuItem: React.FC<Props> = (props) => {\n if (props.type === \"option\") return <OptionCell {...props} />;\n if (props.type === \"heading\") return <HeadingCell {...props} />;\n if (props.type === \"divider\") return <DividerCell {...props} />;\n if (props.type === \"search\") return <SearchCell {...props} />;\n return null;\n};\n\nContextMenuItem.displayName = \"ContextMenuItem\";\n\nconst SubmenuChevron: React.FC<{ color: string; size: number }> = ({\n color,\n size,\n}) => (\n <span\n data-testid=\"ctxmenu-submenu-chevron\"\n aria-hidden=\"true\"\n style={{\n color,\n display: \"inline-flex\",\n alignItems: \"center\",\n width: size,\n height: size,\n }}\n >\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M17.0605 11.6464C17.2558 11.8417 17.2558 12.1583 17.0605 12.3536L9.70703 19.707L8.29297 18.293L14.5859 12L8.29297 5.70703L9.70703 4.29297L17.0605 11.6464Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n);\n\nconst OptionCell: React.FC<ContextMenuOptionItemProps & ThemeOverrideProps> = ({\n size: propSize,\n label,\n description,\n disabled,\n destructive,\n checked,\n leadingControl,\n leadingIcon,\n status,\n iconWrapper,\n slotContent,\n value,\n hint,\n trailingIcon,\n keyboardShortcut,\n hasSubmenu,\n submenu,\n onSelect,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n const variants = sizeToVariants[size];\n\n const id = useId();\n const [index, setIndex] = useState<number>(-1);\n const [isHovered, setIsHovered] = useState(false);\n const [submenuOpen, setSubmenuOpen] = useState(false);\n const [submenuPos, setSubmenuPos] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const optionRef = React.useRef<HTMLDivElement | null>(null);\n const submenuWrapperRef = React.useRef<HTMLDivElement | null>(null);\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n\n const cancelClose = () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n\n const scheduleClose = () => {\n cancelClose();\n closeTimerRef.current = setTimeout(() => setSubmenuOpen(false), 120);\n };\n\n useEffect(() => () => cancelClose(), []);\n\n useEffect(() => {\n if (!hasSubmenu || !submenuOpen) return;\n const onMouseDown = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n const inOption = optionRef.current?.contains(target);\n const inSubmenu = submenuWrapperRef.current?.contains(target);\n if (!inOption && !inSubmenu) {\n setSubmenuOpen(false);\n return;\n }\n if (\n inSubmenu &&\n target.closest(\n '[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"]'\n )\n ) {\n setSubmenuOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [hasSubmenu, submenuOpen]);\n\n useLayoutEffect(() => {\n if (!hasSubmenu || !submenuOpen) {\n setSubmenuPos(null);\n return;\n }\n const update = () => {\n const node = optionRef.current;\n if (!node) return;\n const rect = node.getBoundingClientRect();\n setSubmenuPos({ top: rect.top, left: rect.right });\n };\n update();\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [hasSubmenu, submenuOpen]);\n const onSelectRef = React.useRef(onSelect);\n onSelectRef.current = onSelect;\n useEffect(() => {\n if (!ctx) return;\n const idx = ctx.registerCell(id, {\n type: \"option\",\n disabled,\n onSelect: () => onSelectRef.current?.(),\n });\n setIndex(idx);\n return () => ctx.unregisterCell(id);\n }, [ctx, id, disabled]);\n\n const isActive = ctx ? index >= 0 && ctx.activeIndex === index : false;\n const inHoverState =\n isActive || (!ctx && isHovered) || (hasSubmenu && submenuOpen);\n\n const handleEnter = () => {\n if (disabled) return;\n if (ctx && index >= 0) ctx.setActiveIndex(index);\n if (!ctx) setIsHovered(true);\n if (hasSubmenu) setSubmenuOpen(true);\n };\n\n const handleLeave = () => {\n if (!ctx) setIsHovered(false);\n if (hasSubmenu) scheduleClose();\n };\n\n const labelColor = disabled\n ? theme.colors.control.input.textDisable\n : destructive\n ? theme.colors.content.alert.primary\n : theme.colors.content.primary;\n\n const bg = inHoverState ? theme.colors.control.input.bgHover : \"transparent\";\n\n const role =\n !hasSubmenu && checked !== undefined ? \"menuitemcheckbox\" : \"menuitem\";\n const ariaChecked =\n !hasSubmenu && checked !== undefined\n ? checked\n ? \"true\"\n : \"false\"\n : undefined;\n\n const handleClick = () => {\n if (disabled) return;\n if (hasSubmenu) {\n setSubmenuOpen(true);\n return;\n }\n onSelect?.();\n };\n\n const closeSubmenuAndFocus = () => {\n setSubmenuOpen(false);\n optionRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (disabled) {\n if (e.key === \"Enter\" || e.key === \" \") e.preventDefault();\n return;\n }\n if (hasSubmenu) {\n if (e.key === \"ArrowRight\" || e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n setSubmenuOpen(true);\n return;\n }\n if (e.key === \"ArrowLeft\" || e.key === \"Escape\") {\n if (submenuOpen) {\n e.preventDefault();\n e.stopPropagation();\n closeSubmenuAndFocus();\n return;\n }\n }\n }\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect?.();\n }\n };\n\n return (\n <div\n ref={optionRef}\n role={role}\n aria-checked={ariaChecked}\n aria-disabled={disabled ? \"true\" : undefined}\n aria-haspopup={hasSubmenu ? \"menu\" : undefined}\n aria-expanded={hasSubmenu ? (submenuOpen ? \"true\" : \"false\") : undefined}\n tabIndex={0}\n data-testid={testId || testID}\n data-state={inHoverState ? \"hover\" : undefined}\n data-destructive={destructive ? \"true\" : undefined}\n aria-keyshortcuts={keyboardShortcut}\n onMouseEnter={() => {\n cancelClose();\n handleEnter();\n }}\n onMouseLeave={handleLeave}\n onFocus={handleEnter}\n onBlur={() => {\n if (!ctx) setIsHovered(false);\n }}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n position: \"relative\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: sizing.gap,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n backgroundColor: bg,\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n outline: \"none\",\n }}\n >\n {leadingControl === \"checkbox\" && (\n <span\n data-testid=\"ctxmenu-leading-checkbox\"\n aria-hidden=\"true\"\n style={{ pointerEvents: \"none\", display: \"inline-flex\" }}\n >\n <Checkbox\n size={size}\n checked={!!checked}\n disabled={!!disabled}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </span>\n )}\n {leadingControl === \"radio\" && (\n <span\n data-testid=\"ctxmenu-leading-radio\"\n aria-hidden=\"true\"\n style={{ pointerEvents: \"none\", display: \"inline-flex\" }}\n >\n <Radio\n size={size}\n checked={!!checked}\n disabled={!!disabled}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </span>\n )}\n {leadingIcon}\n {status}\n {iconWrapper}\n {slotContent}\n <span\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2,\n minWidth: 0,\n }}\n >\n <Typography\n variant={variants.label}\n color={labelColor}\n noWrap={description === undefined}\n style={{\n ...(description === undefined\n ? { display: \"block\", minWidth: 0 }\n : {}),\n ...(sizeLabelOverride[size] ?? {}),\n }}\n >\n {label}\n </Typography>\n {description !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {description}\n </Typography>\n )}\n </span>\n {(value !== undefined || hint !== undefined) && (\n <span\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"flex-end\",\n }}\n >\n {value !== undefined && (\n <Typography\n variant={variants.label}\n color={theme.colors.content.secondary}\n style={sizeLabelOverride[size]}\n >\n {value}\n </Typography>\n )}\n {hint !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {hint}\n </Typography>\n )}\n </span>\n )}\n {keyboardShortcut && (\n <Typography\n as=\"kbd\"\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {keyboardShortcut}\n </Typography>\n )}\n {hasSubmenu && (\n <SubmenuChevron\n color={theme.colors.content.tertiary}\n size={sizing.iconSize}\n />\n )}\n {trailingIcon}\n {hasSubmenu &&\n submenuOpen &&\n submenu &&\n submenuPos &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n ref={submenuWrapperRef}\n onMouseEnter={cancelClose}\n onMouseLeave={scheduleClose}\n style={{\n position: \"fixed\",\n top: submenuPos.top,\n left: submenuPos.left,\n zIndex: 2000,\n }}\n >\n {submenu}\n </div>,\n document.body\n )}\n </div>\n );\n};\n\nconst HeadingCell: React.FC<\n ContextMenuHeadingItemProps & ThemeOverrideProps\n> = ({\n size: propSize,\n label,\n description,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n const variants = sizeToVariants[size];\n\n const id = useId();\n useEffect(() => {\n if (!ctx) return;\n ctx.registerCell(id, { type: \"heading\" });\n return () => ctx.unregisterCell(id);\n }, [ctx, id]);\n\n return (\n <div\n role=\"presentation\"\n data-testid={testId || testID}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n }}\n >\n <Typography\n variant={variants.headingAccent}\n color={theme.colors.content.secondary}\n style={{ textTransform: \"uppercase\", letterSpacing: 0.5 }}\n >\n {label}\n </Typography>\n {description !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {description}\n </Typography>\n )}\n </div>\n );\n};\n\nconst SearchCell: React.FC<ContextMenuSearchItemProps & ThemeOverrideProps> = ({\n size: propSize,\n value,\n onValueChange,\n placeholder = \"Search\",\n autoFocus,\n \"aria-label\": ariaLabel = \"Search options\",\n \"data-testid\": testId,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n\n const id = useId();\n useEffect(() => {\n if (!ctx) return;\n ctx.registerCell(id, { type: \"search\" });\n return () => ctx.unregisterCell(id);\n }, [ctx, id]);\n\n return (\n <input\n type=\"search\"\n role=\"searchbox\"\n aria-label={ariaLabel}\n placeholder={placeholder}\n value={value}\n autoFocus={autoFocus}\n onChange={(e) => onValueChange(e.target.value)}\n data-testid={testId || testID}\n style={{\n width: \"100%\",\n boxSizing: \"border-box\",\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n color: theme.colors.content.primary,\n fontSize: sizing.fontSize,\n lineHeight: `${sizing.fontSize + 2}px`,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n }}\n />\n );\n};\n\nconst DividerCell: React.FC<\n ContextMenuDividerItemProps & ThemeOverrideProps\n> = ({ themeMode, themeProductContext, \"data-testid\": testId }) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const id = useId();\n useEffect(() => {\n if (!ctx) return;\n ctx.registerCell(id, { type: \"divider\" });\n return () => ctx.unregisterCell(id);\n }, [ctx, id]);\n return (\n <div\n role=\"separator\"\n data-testid={testId}\n style={{\n height: 1,\n backgroundColor: theme.colors.border.secondary,\n margin: \"4px 0\",\n }}\n />\n );\n};\n","import { useEffect, useState, type RefObject } from \"react\";\nimport type { ContextMenuPlacement } from \"../types\";\n\ninterface UseContextMenuPositionOptions {\n triggerRef: RefObject<HTMLElement | null>;\n panelRef: RefObject<HTMLElement | null>;\n isOpen: boolean;\n placement?: ContextMenuPlacement;\n offset?: number;\n}\n\ninterface ResolvedPosition {\n top: number;\n left: number;\n placement: ContextMenuPlacement;\n}\n\nconst splitPlacement = (\n placement: ContextMenuPlacement\n): { vertical: \"top\" | \"bottom\"; horizontal: \"start\" | \"end\" } => {\n const [vertical, horizontal] = placement.split(\"-\") as [\n \"top\" | \"bottom\",\n \"start\" | \"end\",\n ];\n return { vertical, horizontal };\n};\n\nconst joinPlacement = (\n vertical: \"top\" | \"bottom\",\n horizontal: \"start\" | \"end\"\n): ContextMenuPlacement => `${vertical}-${horizontal}` as ContextMenuPlacement;\n\nexport const useContextMenuPosition = ({\n triggerRef,\n panelRef,\n isOpen,\n placement = \"bottom-start\",\n offset = 4,\n}: UseContextMenuPositionOptions): ResolvedPosition | undefined => {\n const [resolved, setResolved] = useState<ResolvedPosition | undefined>();\n\n useEffect(() => {\n if (!isOpen) {\n setResolved(undefined);\n return;\n }\n\n const compute = () => {\n const trigger = triggerRef.current;\n const panel = panelRef.current;\n if (!trigger || !panel) return;\n\n const triggerRect = trigger.getBoundingClientRect();\n const panelRect = panel.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let { vertical, horizontal } = splitPlacement(placement);\n\n const computeTop = (v: \"top\" | \"bottom\") =>\n v === \"bottom\"\n ? triggerRect.bottom + offset\n : triggerRect.top - panelRect.height - offset;\n\n const computeLeft = (h: \"start\" | \"end\") =>\n h === \"start\" ? triggerRect.left : triggerRect.right - panelRect.width;\n\n let top = computeTop(vertical);\n const wantedBottom = top + panelRect.height;\n if (top < 0 || wantedBottom > viewportHeight) {\n const flipped = vertical === \"bottom\" ? \"top\" : \"bottom\";\n const flippedTop = computeTop(flipped);\n const flippedBottom = flippedTop + panelRect.height;\n if (flippedTop >= 0 && flippedBottom <= viewportHeight) {\n vertical = flipped;\n top = flippedTop;\n }\n }\n\n let left = computeLeft(horizontal);\n const wantedRight = left + panelRect.width;\n if (left < 0 || wantedRight > viewportWidth) {\n const flipped = horizontal === \"start\" ? \"end\" : \"start\";\n const flippedLeft = computeLeft(flipped);\n const flippedRight = flippedLeft + panelRect.width;\n if (flippedLeft >= 0 && flippedRight <= viewportWidth) {\n horizontal = flipped;\n left = flippedLeft;\n }\n }\n\n setResolved({\n top,\n left,\n placement: joinPlacement(vertical, horizontal),\n });\n };\n\n const rafId = window.requestAnimationFrame(compute);\n const onResize = () => compute();\n window.addEventListener(\"resize\", onResize);\n\n return () => {\n window.cancelAnimationFrame(rafId);\n window.removeEventListener(\"resize\", onResize);\n };\n }, [isOpen, placement, offset, triggerRef, panelRef]);\n\n return resolved;\n};\n","import { useCallback, type RefObject } from \"react\";\n\nexport type CellType = \"option\" | \"search\" | \"heading\" | \"divider\";\n\nexport interface CellMeta {\n type: CellType;\n onSelect?: () => void;\n disabled?: boolean;\n}\n\ninterface UseKeyboardNavigationOptions {\n isOpen: boolean;\n cells: Array<{ id: string; meta: CellMeta }>;\n activeIndex: number;\n setActiveIndex: (index: number) => void;\n onClose: () => void;\n triggerRef?: RefObject<HTMLElement | null>;\n}\n\nconst isNavigableOption = (meta: CellMeta) =>\n meta.type === \"option\" && !meta.disabled;\n\nconst isTextInputTarget = (target: EventTarget | null): boolean => {\n if (!(target instanceof HTMLElement)) return false;\n if (target.tagName === \"INPUT\" || target.tagName === \"TEXTAREA\") return true;\n return target.getAttribute(\"role\") === \"searchbox\";\n};\n\nexport const useKeyboardNavigation = ({\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose,\n triggerRef,\n}: UseKeyboardNavigationOptions) => {\n const findFirstOption = useCallback(() => {\n for (let i = 0; i < cells.length; i += 1) {\n if (isNavigableOption(cells[i].meta)) return i;\n }\n return -1;\n }, [cells]);\n\n const findLastOption = useCallback(() => {\n for (let i = cells.length - 1; i >= 0; i -= 1) {\n if (isNavigableOption(cells[i].meta)) return i;\n }\n return -1;\n }, [cells]);\n\n const findNextOption = useCallback(\n (from: number) => {\n const len = cells.length;\n if (len === 0) return -1;\n for (let step = 1; step <= len; step += 1) {\n const idx = (from + step + len) % len;\n if (isNavigableOption(cells[idx].meta)) return idx;\n }\n return -1;\n },\n [cells]\n );\n\n const findPrevOption = useCallback(\n (from: number) => {\n const len = cells.length;\n if (len === 0) return -1;\n for (let step = 1; step <= len; step += 1) {\n const idx = (from - step + len * 2) % len;\n if (isNavigableOption(cells[idx].meta)) return idx;\n }\n return -1;\n },\n [cells]\n );\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n const next =\n activeIndex < 0 ? findFirstOption() : findNextOption(activeIndex);\n if (next >= 0) setActiveIndex(next);\n break;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n const prev =\n activeIndex < 0 ? findLastOption() : findPrevOption(activeIndex);\n if (prev >= 0) setActiveIndex(prev);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n const first = findFirstOption();\n if (first >= 0) setActiveIndex(first);\n break;\n }\n case \"End\": {\n event.preventDefault();\n const last = findLastOption();\n if (last >= 0) setActiveIndex(last);\n break;\n }\n case \"Enter\":\n case \" \": {\n if (event.defaultPrevented) break;\n if (event.key === \" \" && isTextInputTarget(event.target)) break;\n if (event.key === \" \") event.preventDefault();\n if (activeIndex >= 0 && activeIndex < cells.length) {\n const meta = cells[activeIndex].meta;\n if (isNavigableOption(meta)) meta.onSelect?.();\n }\n break;\n }\n case \"Escape\": {\n event.preventDefault();\n onClose();\n triggerRef?.current?.focus();\n break;\n }\n case \"Tab\": {\n onClose();\n break;\n }\n default:\n break;\n }\n },\n [\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose,\n triggerRef,\n findFirstOption,\n findLastOption,\n findNextOption,\n findPrevOption,\n ]\n );\n\n return { handleKeyDown };\n};\n"],"mappings":"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","names":["import_react","import_react_dom","import_xui_core","import_react","React","import_react","import_react","import_jsx_runtime","React","panel"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.tsx","../../src/ContextMenu.tsx","../../src/ContextMenuContext.tsx","../../src/ContextMenuItem.tsx","../../src/hooks/useContextMenuPosition.ts","../../src/hooks/useKeyboardNavigation.ts"],"sourcesContent":["export { ContextMenu } from \"./ContextMenu\";\nexport { ContextMenuItem } from \"./ContextMenuItem\";\n\nexport {\n useContextMenu,\n useContextMenuRequired,\n ContextMenuContext,\n} from \"./ContextMenuContext\";\n\nexport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nexport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation\";\n\nexport type {\n ContextMenuSize,\n ContextMenuItemType,\n ContextMenuItemLeadingControl,\n ContextMenuOptionItemProps,\n ContextMenuSearchItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuDividerItemProps,\n ContextMenuItemProps,\n ContextMenuPanelType,\n ContextMenuPlacement,\n ContextMenuPosition,\n ContextMenuProps,\n ContextMenuContextValue,\n ContextMenuSizing,\n} from \"./types\";\n","import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n isValidElement,\n cloneElement,\n type ReactElement,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n useResolvedTheme,\n useId,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\nimport { ContextMenuContext } from \"./ContextMenuContext\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nimport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation\";\nimport type {\n ContextMenuCellMeta,\n ContextMenuContextValue,\n ContextMenuDividerItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuOptionItemProps,\n ContextMenuProps,\n ContextMenuSize,\n} from \"./types\";\n\ntype Props = ContextMenuProps & ThemeOverrideProps;\n\ninterface CellEntry {\n id: string;\n meta: ContextMenuCellMeta;\n}\n\ntype PresetItem =\n | ContextMenuOptionItemProps\n | ContextMenuHeadingItemProps\n | ContextMenuDividerItemProps;\n\nconst SEARCH_DEBOUNCE_MS = 200;\n\nconst EmptyMessage: React.FC<{ children: React.ReactNode; color: string }> = ({\n children,\n color,\n}) => (\n <div\n style={{\n padding: 12,\n color,\n fontSize: 14,\n textAlign: \"center\",\n }}\n >\n {children}\n </div>\n);\n\nexport const ContextMenu: React.FC<Props> = (props) => {\n const {\n type,\n items,\n children,\n size = \"md\",\n searchable,\n loading,\n emptyMessage,\n empty,\n trigger,\n isOpen,\n onOpenChange,\n closeOnSelect,\n width,\n maxHeight,\n placement = \"bottom-start\",\n onSelect,\n \"aria-label\": ariaLabel,\n \"data-testid\": testId,\n testID,\n themeMode,\n themeProductContext,\n } = props;\n\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const isControlled = isOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const open = isControlled ? !!isOpen : internalOpen;\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const cellsRef = useRef<CellEntry[]>([]);\n const [cellsVersion, setCellsVersion] = useState(0);\n\n const triggerRef = useRef<HTMLElement | null>(null);\n const panelRef = useRef<HTMLDivElement | null>(null);\n const menuId = useId();\n\n // Search query state\n const [query, setQuery] = useState(\"\");\n const [debouncedQuery, setDebouncedQuery] = useState(\"\");\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = setTimeout(() => {\n setDebouncedQuery(query);\n }, SEARCH_DEBOUNCE_MS);\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n };\n }, [query]);\n\n const closeMenu = useCallback(() => {\n setOpen(false);\n setActiveIndex(-1);\n }, [setOpen]);\n\n const registerCell = useCallback((id: string, meta: ContextMenuCellMeta) => {\n const existing = cellsRef.current.findIndex((c) => c.id === id);\n if (existing === -1) {\n cellsRef.current.push({ id, meta });\n setCellsVersion((v) => v + 1);\n return cellsRef.current.length - 1;\n }\n // Update metadata in place — keep registry order stable. Only bump the\n // version when nav-relevant metadata (disabled) actually changes.\n const prev = cellsRef.current[existing].meta;\n cellsRef.current[existing] = { id, meta };\n if (prev.disabled !== meta.disabled || prev.type !== meta.type) {\n setCellsVersion((v) => v + 1);\n }\n return existing;\n }, []);\n\n const unregisterCell = useCallback((id: string) => {\n const idx = cellsRef.current.findIndex((c) => c.id === id);\n if (idx !== -1) {\n // splice keeps survivors contiguous; consumers derive their index live\n // via getCellIndex so they reindex automatically.\n cellsRef.current.splice(idx, 1);\n setCellsVersion((v) => v + 1);\n }\n }, []);\n\n const getCellIndex = useCallback(\n (id: string) => cellsRef.current.findIndex((c) => c.id === id),\n []\n );\n\n const ctx: ContextMenuContextValue = useMemo(\n () => ({\n size: size as ContextMenuSize,\n menuId,\n closeMenu,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n activeIndex,\n setActiveIndex,\n query,\n setQuery,\n }),\n [\n size,\n menuId,\n closeMenu,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n activeIndex,\n query,\n ]\n );\n\n const triggerNode = useMemo(() => {\n if (!trigger) return null;\n const inner = isValidElement(trigger)\n ? cloneElement(\n trigger as ReactElement<{\n \"aria-haspopup\"?: string;\n \"aria-expanded\"?: string | boolean;\n }>,\n {\n \"aria-haspopup\": \"menu\",\n \"aria-expanded\": open ? \"true\" : \"false\",\n }\n )\n : trigger;\n return (\n <span\n ref={(node) => {\n if (!node) {\n triggerRef.current = null;\n return;\n }\n const focusable = node.querySelector<HTMLElement>(\n \"button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])\"\n );\n triggerRef.current = focusable ?? node;\n }}\n onClick={() => setOpen(!open)}\n style={{ display: \"inline-flex\" }}\n >\n {inner}\n </span>\n );\n }, [trigger, open, setOpen]);\n\n const usePortal = !!trigger && typeof document !== \"undefined\";\n\n const position = useContextMenuPosition({\n triggerRef,\n panelRef,\n isOpen: open && usePortal,\n placement,\n });\n\n const cellsForNav = useMemo(\n () => cellsRef.current.map((c) => ({ id: c.id, meta: c.meta })),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [cellsVersion]\n );\n\n const { handleKeyDown } = useKeyboardNavigation({\n isOpen: open,\n cells: cellsForNav,\n activeIndex,\n setActiveIndex,\n onClose: closeMenu,\n triggerRef,\n });\n\n const sizingFn = (theme.sizing as { contextMenu?: (s: string) => unknown })\n .contextMenu;\n const sizing = sizingFn\n ? (sizingFn(size) as {\n panelWidth?: number;\n borderRadius?: number;\n paddingVertical?: number;\n })\n : {};\n const radiusObj = (theme as { radius?: { contextMenu?: number } }).radius;\n const radiusVal = sizing.borderRadius ?? radiusObj?.contextMenu ?? 8;\n const shadowObj = (theme as { shadow?: { contextMenu?: string } }).shadow;\n const shadowVal = shadowObj?.contextMenu ?? \"\";\n const panelPaddingVertical = sizing.paddingVertical ?? 8;\n\n const panelStyle: React.CSSProperties = {\n background: theme.colors.background.primary,\n borderRadius: radiusVal,\n boxShadow: shadowVal,\n width: width ?? sizing.panelWidth,\n maxHeight,\n overflow: \"hidden\",\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n outline: \"none\",\n fontFamily: theme.fonts.body,\n paddingTop: panelPaddingVertical,\n paddingBottom: panelPaddingVertical,\n };\n\n if (usePortal) {\n panelStyle.position = \"fixed\";\n panelStyle.top = position?.top ?? 0;\n panelStyle.left = position?.left ?? 0;\n }\n\n // Filter preset items based on debounced query (only when searchable + items)\n const filteredItems = useMemo<PresetItem[] | undefined>(() => {\n if (!items) return undefined;\n if (!searchable || !debouncedQuery) return items.slice();\n const q = debouncedQuery.toLowerCase();\n const matchedFlags = items.map((item) => {\n if (item.type === \"option\") {\n return String(item.label ?? \"\")\n .toLowerCase()\n .includes(q);\n }\n return false; // headings/dividers themselves never match\n });\n // Now hide headings whose options are all filtered out and trailing dividers\n const result: PresetItem[] = [];\n let pendingHeading: {\n item: ContextMenuHeadingItemProps;\n idx: number;\n } | null = null;\n let lastEmittedWasContent = false; // whether last pushed was option (so divider can follow)\n let groupHasOption = false;\n for (let i = 0; i < items.length; i += 1) {\n const item = items[i];\n if (item.type === \"heading\") {\n // Starting a new group\n pendingHeading = { item, idx: i };\n groupHasOption = false;\n } else if (item.type === \"divider\") {\n // Emit divider only if the previously emitted thing was content\n if (lastEmittedWasContent) {\n result.push(item);\n lastEmittedWasContent = false;\n }\n // dividers also reset pending heading so a heading sits with its group\n pendingHeading = null;\n groupHasOption = false;\n } else if (item.type === \"option\") {\n if (matchedFlags[i]) {\n if (pendingHeading) {\n result.push(pendingHeading.item);\n pendingHeading = null;\n }\n result.push(item);\n lastEmittedWasContent = true;\n groupHasOption = true;\n }\n }\n }\n // Strip trailing divider if any\n while (result.length > 0 && result[result.length - 1].type === \"divider\") {\n result.pop();\n }\n // Suppress unused\n void groupHasOption;\n return result;\n }, [items, searchable, debouncedQuery]);\n\n const effectiveCloseOnSelect =\n closeOnSelect !== undefined ? closeOnSelect : type !== \"checkbox\";\n\n const renderPresetItem = (item: PresetItem, key: number) => {\n if (item.type === \"heading\") {\n return (\n <ContextMenuItem\n key={`h-${key}`}\n {...item}\n size={item.size ?? (size as ContextMenuSize)}\n />\n );\n }\n if (item.type === \"divider\") {\n return (\n <ContextMenuItem\n key={`d-${key}`}\n {...item}\n size={item.size ?? (size as ContextMenuSize)}\n />\n );\n }\n const composed = composeItemForPreset(type, item);\n const originalSelect = composed.onSelect;\n const wrappedSelect = () => {\n originalSelect?.();\n onSelect?.(item);\n if (effectiveCloseOnSelect) closeMenu();\n };\n return (\n <ContextMenuItem\n key={`o-${key}`}\n {...composed}\n size={composed.size ?? (size as ContextMenuSize)}\n onSelect={wrappedSelect}\n />\n );\n };\n\n // Determine what to render in the panel body\n const isLoadingState = loading;\n\n let bodyContent: React.ReactNode = null;\n let isBodyEmpty = false;\n let searchNode: React.ReactNode = null;\n\n if (isLoadingState) {\n bodyContent = (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n }}\n >\n <Spinner size={size === \"xl\" ? \"lg\" : size === \"lg\" ? \"md\" : \"sm\"} />\n </div>\n );\n } else if (children !== undefined && children !== null) {\n // Custom path. Empty when children is falsy/empty array.\n const childArr = React.Children.toArray(children);\n if (childArr.length === 0) {\n isBodyEmpty = true;\n } else {\n bodyContent = children;\n }\n } else if (type && items) {\n // Preset path\n if (searchable) {\n searchNode = (\n <ContextMenuItem\n type=\"search\"\n value={query}\n onValueChange={setQuery}\n size={size as ContextMenuSize}\n />\n );\n }\n const visible = filteredItems ?? [];\n const optionCount = visible.filter((i) => i.type === \"option\").length;\n if (optionCount === 0) {\n isBodyEmpty = true;\n } else {\n bodyContent = visible.map((it, idx) => renderPresetItem(it, idx));\n }\n } else {\n // No children, no items — empty\n isBodyEmpty = true;\n }\n\n if (isBodyEmpty) {\n bodyContent = empty ?? (\n <EmptyMessage color={theme.colors.content.tertiary}>\n {emptyMessage ?? \"No results\"}\n </EmptyMessage>\n );\n }\n\n const hasStickySearch = !!searchNode;\n\n // Focus management on open/close transitions\n const prevOpenRef = useRef(false);\n useEffect(() => {\n const wasOpen = prevOpenRef.current;\n prevOpenRef.current = open;\n if (!wasOpen && open) {\n // open transition: focus search if present, else first option\n // wait for cells to register\n const timer = setTimeout(() => {\n const panel = panelRef.current;\n if (!panel) return;\n const search =\n panel.querySelector<HTMLInputElement>(\"[role='searchbox']\");\n if (search) {\n search.focus();\n return;\n }\n const firstOption = panel.querySelector<HTMLElement>(\n \"[role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio']\"\n );\n if (firstOption) {\n firstOption.focus();\n // Reset activeIndex so keyboard nav starts fresh; onFocus will have\n // set it to the focused option's index, but tests expect ArrowDown\n // to move to the first option from -1.\n setActiveIndex(-1);\n } else {\n panel.focus();\n }\n }, 0);\n return () => clearTimeout(timer);\n }\n if (wasOpen && !open) {\n // close transition: focus the trigger\n triggerRef.current?.focus();\n }\n }, [open]);\n\n // Dismiss on outside press. Per-instance + DOM-guarded so multiple open\n // menus each close only themselves, native builds no-op, and React <18 is\n // unaffected (plain document listener, no concurrent APIs). Only for\n // portal-anchored (trigger) menus; inline/controlled menus stay\n // consumer-managed.\n useEffect(() => {\n if (!open || !usePortal || typeof document === \"undefined\") return;\n const handlePointerDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target) return;\n if (panelRef.current?.contains(target)) return;\n if (triggerRef.current?.contains(target)) return;\n // This menu's submenus render in a separate DOM subtree (document.body);\n // treat clicks inside them as inside this menu.\n if (target instanceof Element) {\n const portals = document.querySelectorAll(\n \"[data-xui-context-menu-portal]\"\n );\n for (let i = 0; i < portals.length; i += 1) {\n const portal = portals[i];\n if (\n portal.getAttribute(\"data-xui-context-menu-portal\") === menuId &&\n portal.contains(target)\n ) {\n return;\n }\n }\n }\n closeMenu();\n };\n document.addEventListener(\"mousedown\", handlePointerDown);\n return () => document.removeEventListener(\"mousedown\", handlePointerDown);\n }, [open, usePortal, closeMenu, menuId]);\n\n const resolvedPlacement = position?.placement ?? placement;\n\n const scrollContainerStyle: React.CSSProperties = {\n overflowY: \"auto\",\n flex: 1,\n minHeight: 0,\n };\n\n const stickyHeaderStyle: React.CSSProperties = {\n position: \"sticky\",\n top: 0,\n zIndex: 1,\n background: theme.colors.background.primary,\n };\n\n const panel = open ? (\n <ContextMenuContext.Provider value={ctx}>\n <div\n ref={panelRef}\n role=\"menu\"\n aria-label={ariaLabel}\n data-testid={testId || testID}\n data-placement={usePortal ? resolvedPlacement : undefined}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n onMouseLeave={() => setActiveIndex(-1)}\n style={panelStyle}\n >\n {hasStickySearch && (\n <div data-sticky=\"top\" style={stickyHeaderStyle}>\n {searchNode}\n </div>\n )}\n <div style={scrollContainerStyle}>{bodyContent}</div>\n </div>\n </ContextMenuContext.Provider>\n ) : null;\n\n return (\n <>\n {triggerNode}\n {usePortal ? panel && createPortal(panel, document.body) : panel}\n </>\n );\n};\n\nContextMenu.displayName = \"ContextMenu\";\n\nfunction composeItemForPreset(\n type: ContextMenuProps[\"type\"],\n item: ContextMenuOptionItemProps\n): ContextMenuOptionItemProps {\n switch (type) {\n case \"checkbox\":\n return { ...item, leadingControl: \"checkbox\" };\n case \"radio\":\n return { ...item, leadingControl: \"radio\" };\n case \"list\":\n case \"phone\":\n case \"status\":\n case \"brandLogo\":\n case \"avatar\":\n default:\n return { ...item };\n }\n}\n","import { createContext, useContext } from \"react\";\nimport type { ContextMenuContextValue } from \"./types\";\n\nexport const ContextMenuContext = createContext<\n ContextMenuContextValue | undefined\n>(undefined);\n\nexport const useContextMenu = () => {\n const context = useContext(ContextMenuContext);\n return context;\n};\n\nexport const useContextMenuRequired = () => {\n const context = useContext(ContextMenuContext);\n if (!context) {\n throw new Error(\n \"useContextMenuRequired must be used within a ContextMenu component\"\n );\n }\n return context;\n};\n","import React, { useEffect, useLayoutEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n useResolvedTheme,\n useId,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport { Typography } from \"@xsolla/xui-typography\";\nimport { Checkbox } from \"@xsolla/xui-checkbox\";\nimport { Radio } from \"@xsolla/xui-radio\";\nimport { useContextMenu } from \"./ContextMenuContext\";\nimport type {\n ContextMenuDividerItemProps,\n ContextMenuHeadingItemProps,\n ContextMenuItemProps,\n ContextMenuOptionItemProps,\n ContextMenuSearchItemProps,\n ContextMenuSize,\n} from \"./types\";\n\ntype BodyVariant = \"bodyLg\" | \"bodyMd\" | \"bodySm\" | \"bodyXs\";\ntype AccentVariant =\n | \"bodyLgAccent\"\n | \"bodyMdAccent\"\n | \"bodySmAccent\"\n | \"bodyXsAccent\";\n\nconst sizeToVariants: Record<\n ContextMenuSize,\n { label: BodyVariant; description: BodyVariant; headingAccent: AccentVariant }\n> = {\n xl: { label: \"bodyLg\", description: \"bodyLg\", headingAccent: \"bodyLgAccent\" },\n lg: { label: \"bodyLg\", description: \"bodyMd\", headingAccent: \"bodyMdAccent\" },\n md: { label: \"bodyMd\", description: \"bodySm\", headingAccent: \"bodySmAccent\" },\n sm: { label: \"bodySm\", description: \"bodyXs\", headingAccent: \"bodyXsAccent\" },\n};\n\nconst sizeLabelOverride: Partial<\n Record<ContextMenuSize, { fontSize: number; lineHeight: string }>\n> = {\n xl: { fontSize: 20, lineHeight: \"26px\" },\n};\n\ntype Props = ContextMenuItemProps & ThemeOverrideProps;\n\nexport const ContextMenuItem: React.FC<Props> = (props) => {\n if (props.type === \"option\") return <OptionCell {...props} />;\n if (props.type === \"heading\") return <HeadingCell {...props} />;\n if (props.type === \"divider\") return <DividerCell {...props} />;\n if (props.type === \"search\") return <SearchCell {...props} />;\n return null;\n};\n\nContextMenuItem.displayName = \"ContextMenuItem\";\n\nconst SubmenuChevron: React.FC<{ color: string; size: number }> = ({\n color,\n size,\n}) => (\n <span\n data-testid=\"ctxmenu-submenu-chevron\"\n aria-hidden=\"true\"\n style={{\n color,\n display: \"inline-flex\",\n alignItems: \"center\",\n width: size,\n height: size,\n }}\n >\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M17.0605 11.6464C17.2558 11.8417 17.2558 12.1583 17.0605 12.3536L9.70703 19.707L8.29297 18.293L14.5859 12L8.29297 5.70703L9.70703 4.29297L17.0605 11.6464Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n);\n\nconst OptionCell: React.FC<ContextMenuOptionItemProps & ThemeOverrideProps> = ({\n size: propSize,\n label,\n description,\n disabled,\n destructive,\n checked,\n leadingControl,\n leadingIcon,\n status,\n iconWrapper,\n slotContent,\n value,\n hint,\n trailingIcon,\n keyboardShortcut,\n hasSubmenu,\n submenu,\n onSelect,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n const variants = sizeToVariants[size];\n\n const id = useId();\n const registerCell = ctx?.registerCell;\n const unregisterCell = ctx?.unregisterCell;\n const getCellIndex = ctx?.getCellIndex;\n const [isHovered, setIsHovered] = useState(false);\n const [submenuOpen, setSubmenuOpen] = useState(false);\n const [submenuPos, setSubmenuPos] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const optionRef = React.useRef<HTMLDivElement | null>(null);\n const submenuWrapperRef = React.useRef<HTMLDivElement | null>(null);\n const closeTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n\n const cancelClose = () => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n\n const scheduleClose = () => {\n cancelClose();\n closeTimerRef.current = setTimeout(() => setSubmenuOpen(false), 120);\n };\n\n useEffect(() => () => cancelClose(), []);\n\n useEffect(() => {\n if (!hasSubmenu || !submenuOpen) return;\n const onMouseDown = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n const inOption = optionRef.current?.contains(target);\n const inSubmenu = submenuWrapperRef.current?.contains(target);\n if (!inOption && !inSubmenu) {\n setSubmenuOpen(false);\n return;\n }\n if (\n inSubmenu &&\n target.closest(\n '[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"]'\n )\n ) {\n setSubmenuOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [hasSubmenu, submenuOpen]);\n\n useLayoutEffect(() => {\n if (!hasSubmenu || !submenuOpen) {\n setSubmenuPos(null);\n return;\n }\n const update = () => {\n const node = optionRef.current;\n if (!node) return;\n const rect = node.getBoundingClientRect();\n setSubmenuPos({ top: rect.top, left: rect.right });\n };\n update();\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [hasSubmenu, submenuOpen]);\n const onSelectRef = React.useRef(onSelect);\n onSelectRef.current = onSelect;\n // Register on mount / unregister on unmount. Deps are the stable registry\n // callbacks + id only — NOT `ctx`, whose identity changes on every hover\n // (activeIndex). Depending on `ctx` here churned register/unregister and, on\n // React <18 (interleaved passive-effect flush), collapsed every row to the\n // same index so one hover highlighted all rows (FEP-764).\n useEffect(() => {\n if (!registerCell || !unregisterCell) return;\n registerCell(id, {\n type: \"option\",\n onSelect: () => onSelectRef.current?.(),\n });\n return () => unregisterCell(id);\n }, [registerCell, unregisterCell, id]);\n\n // Keep registry metadata (disabled) in sync without reordering the cell.\n useEffect(() => {\n if (!registerCell) return;\n registerCell(id, {\n type: \"option\",\n disabled,\n onSelect: () => onSelectRef.current?.(),\n });\n }, [registerCell, id, disabled]);\n\n // Derive index live from the registry instead of caching it in state, so it\n // is always correct after dynamic add/remove without per-item re-registration.\n const index = getCellIndex ? getCellIndex(id) : -1;\n const isActive = ctx ? index >= 0 && ctx.activeIndex === index : false;\n const inHoverState =\n isActive || (!ctx && isHovered) || (hasSubmenu && submenuOpen);\n\n const handleEnter = () => {\n if (disabled) return;\n if (ctx && index >= 0) ctx.setActiveIndex(index);\n if (!ctx) setIsHovered(true);\n if (hasSubmenu) setSubmenuOpen(true);\n };\n\n const handleLeave = () => {\n if (!ctx) setIsHovered(false);\n if (hasSubmenu) scheduleClose();\n };\n\n const labelColor = disabled\n ? theme.colors.control.input.textDisable\n : destructive\n ? theme.colors.content.alert.primary\n : theme.colors.content.primary;\n\n const bg = inHoverState ? theme.colors.control.input.bgHover : \"transparent\";\n\n const role =\n !hasSubmenu && checked !== undefined ? \"menuitemcheckbox\" : \"menuitem\";\n const ariaChecked =\n !hasSubmenu && checked !== undefined\n ? checked\n ? \"true\"\n : \"false\"\n : undefined;\n\n const handleClick = () => {\n if (disabled) return;\n if (hasSubmenu) {\n setSubmenuOpen(true);\n return;\n }\n onSelect?.();\n };\n\n const closeSubmenuAndFocus = () => {\n setSubmenuOpen(false);\n optionRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (disabled) {\n if (e.key === \"Enter\" || e.key === \" \") e.preventDefault();\n return;\n }\n if (hasSubmenu) {\n if (e.key === \"ArrowRight\" || e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n setSubmenuOpen(true);\n return;\n }\n if (e.key === \"ArrowLeft\" || e.key === \"Escape\") {\n if (submenuOpen) {\n e.preventDefault();\n e.stopPropagation();\n closeSubmenuAndFocus();\n return;\n }\n }\n }\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onSelect?.();\n }\n };\n\n return (\n <div\n ref={optionRef}\n role={role}\n aria-checked={ariaChecked}\n aria-disabled={disabled ? \"true\" : undefined}\n aria-haspopup={hasSubmenu ? \"menu\" : undefined}\n aria-expanded={hasSubmenu ? (submenuOpen ? \"true\" : \"false\") : undefined}\n tabIndex={0}\n data-testid={testId || testID}\n data-state={inHoverState ? \"hover\" : undefined}\n data-destructive={destructive ? \"true\" : undefined}\n aria-keyshortcuts={keyboardShortcut}\n onMouseEnter={() => {\n cancelClose();\n handleEnter();\n }}\n onMouseLeave={handleLeave}\n onFocus={handleEnter}\n onBlur={() => {\n if (!ctx) setIsHovered(false);\n }}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n position: \"relative\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: sizing.gap,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n backgroundColor: bg,\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n outline: \"none\",\n }}\n >\n {leadingControl === \"checkbox\" && (\n <span\n data-testid=\"ctxmenu-leading-checkbox\"\n aria-hidden=\"true\"\n style={{ pointerEvents: \"none\", display: \"inline-flex\" }}\n >\n <Checkbox\n size={size}\n checked={!!checked}\n disabled={!!disabled}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </span>\n )}\n {leadingControl === \"radio\" && (\n <span\n data-testid=\"ctxmenu-leading-radio\"\n aria-hidden=\"true\"\n style={{ pointerEvents: \"none\", display: \"inline-flex\" }}\n >\n <Radio\n size={size}\n checked={!!checked}\n disabled={!!disabled}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </span>\n )}\n {leadingIcon}\n {status}\n {iconWrapper}\n {slotContent}\n <span\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2,\n minWidth: 0,\n }}\n >\n <Typography\n variant={variants.label}\n color={labelColor}\n noWrap={description === undefined}\n style={{\n ...(description === undefined\n ? { display: \"block\", minWidth: 0 }\n : {}),\n ...(sizeLabelOverride[size] ?? {}),\n }}\n >\n {label}\n </Typography>\n {description !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {description}\n </Typography>\n )}\n </span>\n {(value !== undefined || hint !== undefined) && (\n <span\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"flex-end\",\n }}\n >\n {value !== undefined && (\n <Typography\n variant={variants.label}\n color={theme.colors.content.secondary}\n style={sizeLabelOverride[size]}\n >\n {value}\n </Typography>\n )}\n {hint !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {hint}\n </Typography>\n )}\n </span>\n )}\n {keyboardShortcut && (\n <Typography\n as=\"kbd\"\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {keyboardShortcut}\n </Typography>\n )}\n {hasSubmenu && (\n <SubmenuChevron\n color={theme.colors.content.tertiary}\n size={sizing.iconSize}\n />\n )}\n {trailingIcon}\n {hasSubmenu &&\n submenuOpen &&\n submenu &&\n submenuPos &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n ref={submenuWrapperRef}\n data-xui-context-menu-portal={ctx?.menuId}\n onMouseEnter={cancelClose}\n onMouseLeave={scheduleClose}\n style={{\n position: \"fixed\",\n top: submenuPos.top,\n left: submenuPos.left,\n zIndex: 2000,\n }}\n >\n {submenu}\n </div>,\n document.body\n )}\n </div>\n );\n};\n\nconst HeadingCell: React.FC<\n ContextMenuHeadingItemProps & ThemeOverrideProps\n> = ({\n size: propSize,\n label,\n description,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n const variants = sizeToVariants[size];\n\n const id = useId();\n const registerCell = ctx?.registerCell;\n const unregisterCell = ctx?.unregisterCell;\n useEffect(() => {\n if (!registerCell || !unregisterCell) return;\n registerCell(id, { type: \"heading\" });\n return () => unregisterCell(id);\n }, [registerCell, unregisterCell, id]);\n\n return (\n <div\n role=\"presentation\"\n data-testid={testId || testID}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n }}\n >\n <Typography\n variant={variants.headingAccent}\n color={theme.colors.content.secondary}\n style={{ textTransform: \"uppercase\", letterSpacing: 0.5 }}\n >\n {label}\n </Typography>\n {description !== undefined && (\n <Typography\n variant={variants.description}\n color={theme.colors.content.tertiary}\n >\n {description}\n </Typography>\n )}\n </div>\n );\n};\n\nconst SearchCell: React.FC<ContextMenuSearchItemProps & ThemeOverrideProps> = ({\n size: propSize,\n value,\n onValueChange,\n placeholder = \"Search\",\n autoFocus,\n \"aria-label\": ariaLabel = \"Search options\",\n \"data-testid\": testId,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const size: ContextMenuSize = propSize ?? ctx?.size ?? \"md\";\n const sizing = theme.sizing.contextMenu(size);\n\n const id = useId();\n const registerCell = ctx?.registerCell;\n const unregisterCell = ctx?.unregisterCell;\n useEffect(() => {\n if (!registerCell || !unregisterCell) return;\n registerCell(id, { type: \"search\" });\n return () => unregisterCell(id);\n }, [registerCell, unregisterCell, id]);\n\n return (\n <input\n type=\"search\"\n role=\"searchbox\"\n aria-label={ariaLabel}\n placeholder={placeholder}\n value={value}\n autoFocus={autoFocus}\n onChange={(e) => onValueChange(e.target.value)}\n data-testid={testId || testID}\n style={{\n width: \"100%\",\n boxSizing: \"border-box\",\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n color: theme.colors.content.primary,\n fontSize: sizing.fontSize,\n lineHeight: `${sizing.fontSize + 2}px`,\n paddingLeft: sizing.itemPaddingHorizontal,\n paddingRight: sizing.itemPaddingHorizontal,\n paddingTop: sizing.itemPaddingVertical,\n paddingBottom: sizing.itemPaddingVertical,\n }}\n />\n );\n};\n\nconst DividerCell: React.FC<\n ContextMenuDividerItemProps & ThemeOverrideProps\n> = ({ themeMode, themeProductContext, \"data-testid\": testId }) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const ctx = useContextMenu();\n const id = useId();\n const registerCell = ctx?.registerCell;\n const unregisterCell = ctx?.unregisterCell;\n useEffect(() => {\n if (!registerCell || !unregisterCell) return;\n registerCell(id, { type: \"divider\" });\n return () => unregisterCell(id);\n }, [registerCell, unregisterCell, id]);\n return (\n <div\n role=\"separator\"\n data-testid={testId}\n style={{\n height: 1,\n backgroundColor: theme.colors.border.secondary,\n margin: \"4px 0\",\n }}\n />\n );\n};\n","import { useEffect, useState, type RefObject } from \"react\";\nimport type { ContextMenuPlacement } from \"../types\";\n\ninterface UseContextMenuPositionOptions {\n triggerRef: RefObject<HTMLElement | null>;\n panelRef: RefObject<HTMLElement | null>;\n isOpen: boolean;\n placement?: ContextMenuPlacement;\n offset?: number;\n}\n\ninterface ResolvedPosition {\n top: number;\n left: number;\n placement: ContextMenuPlacement;\n}\n\nconst splitPlacement = (\n placement: ContextMenuPlacement\n): { vertical: \"top\" | \"bottom\"; horizontal: \"start\" | \"end\" } => {\n const [vertical, horizontal] = placement.split(\"-\") as [\n \"top\" | \"bottom\",\n \"start\" | \"end\",\n ];\n return { vertical, horizontal };\n};\n\nconst joinPlacement = (\n vertical: \"top\" | \"bottom\",\n horizontal: \"start\" | \"end\"\n): ContextMenuPlacement => `${vertical}-${horizontal}` as ContextMenuPlacement;\n\nexport const useContextMenuPosition = ({\n triggerRef,\n panelRef,\n isOpen,\n placement = \"bottom-start\",\n offset = 4,\n}: UseContextMenuPositionOptions): ResolvedPosition | undefined => {\n const [resolved, setResolved] = useState<ResolvedPosition | undefined>();\n\n useEffect(() => {\n if (!isOpen) {\n setResolved(undefined);\n return;\n }\n\n const compute = () => {\n const trigger = triggerRef.current;\n const panel = panelRef.current;\n if (!trigger || !panel) return;\n\n const triggerRect = trigger.getBoundingClientRect();\n const panelRect = panel.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let { vertical, horizontal } = splitPlacement(placement);\n\n const computeTop = (v: \"top\" | \"bottom\") =>\n v === \"bottom\"\n ? triggerRect.bottom + offset\n : triggerRect.top - panelRect.height - offset;\n\n const computeLeft = (h: \"start\" | \"end\") =>\n h === \"start\" ? triggerRect.left : triggerRect.right - panelRect.width;\n\n let top = computeTop(vertical);\n const wantedBottom = top + panelRect.height;\n if (top < 0 || wantedBottom > viewportHeight) {\n const flipped = vertical === \"bottom\" ? \"top\" : \"bottom\";\n const flippedTop = computeTop(flipped);\n const flippedBottom = flippedTop + panelRect.height;\n if (flippedTop >= 0 && flippedBottom <= viewportHeight) {\n vertical = flipped;\n top = flippedTop;\n }\n }\n\n let left = computeLeft(horizontal);\n const wantedRight = left + panelRect.width;\n if (left < 0 || wantedRight > viewportWidth) {\n const flipped = horizontal === \"start\" ? \"end\" : \"start\";\n const flippedLeft = computeLeft(flipped);\n const flippedRight = flippedLeft + panelRect.width;\n if (flippedLeft >= 0 && flippedRight <= viewportWidth) {\n horizontal = flipped;\n left = flippedLeft;\n }\n }\n\n setResolved({\n top,\n left,\n placement: joinPlacement(vertical, horizontal),\n });\n };\n\n const rafId = window.requestAnimationFrame(compute);\n const onResize = () => compute();\n window.addEventListener(\"resize\", onResize);\n\n return () => {\n window.cancelAnimationFrame(rafId);\n window.removeEventListener(\"resize\", onResize);\n };\n }, [isOpen, placement, offset, triggerRef, panelRef]);\n\n return resolved;\n};\n","import { useCallback, type RefObject } from \"react\";\n\nexport type CellType = \"option\" | \"search\" | \"heading\" | \"divider\";\n\nexport interface CellMeta {\n type: CellType;\n onSelect?: () => void;\n disabled?: boolean;\n}\n\ninterface UseKeyboardNavigationOptions {\n isOpen: boolean;\n cells: Array<{ id: string; meta: CellMeta }>;\n activeIndex: number;\n setActiveIndex: (index: number) => void;\n onClose: () => void;\n triggerRef?: RefObject<HTMLElement | null>;\n}\n\nconst isNavigableOption = (meta: CellMeta) =>\n meta.type === \"option\" && !meta.disabled;\n\nconst isTextInputTarget = (target: EventTarget | null): boolean => {\n if (!(target instanceof HTMLElement)) return false;\n if (target.tagName === \"INPUT\" || target.tagName === \"TEXTAREA\") return true;\n return target.getAttribute(\"role\") === \"searchbox\";\n};\n\nexport const useKeyboardNavigation = ({\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose,\n triggerRef,\n}: UseKeyboardNavigationOptions) => {\n const findFirstOption = useCallback(() => {\n for (let i = 0; i < cells.length; i += 1) {\n if (isNavigableOption(cells[i].meta)) return i;\n }\n return -1;\n }, [cells]);\n\n const findLastOption = useCallback(() => {\n for (let i = cells.length - 1; i >= 0; i -= 1) {\n if (isNavigableOption(cells[i].meta)) return i;\n }\n return -1;\n }, [cells]);\n\n const findNextOption = useCallback(\n (from: number) => {\n const len = cells.length;\n if (len === 0) return -1;\n for (let step = 1; step <= len; step += 1) {\n const idx = (from + step + len) % len;\n if (isNavigableOption(cells[idx].meta)) return idx;\n }\n return -1;\n },\n [cells]\n );\n\n const findPrevOption = useCallback(\n (from: number) => {\n const len = cells.length;\n if (len === 0) return -1;\n for (let step = 1; step <= len; step += 1) {\n const idx = (from - step + len * 2) % len;\n if (isNavigableOption(cells[idx].meta)) return idx;\n }\n return -1;\n },\n [cells]\n );\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (!isOpen) return;\n\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n const next =\n activeIndex < 0 ? findFirstOption() : findNextOption(activeIndex);\n if (next >= 0) setActiveIndex(next);\n break;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n const prev =\n activeIndex < 0 ? findLastOption() : findPrevOption(activeIndex);\n if (prev >= 0) setActiveIndex(prev);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n const first = findFirstOption();\n if (first >= 0) setActiveIndex(first);\n break;\n }\n case \"End\": {\n event.preventDefault();\n const last = findLastOption();\n if (last >= 0) setActiveIndex(last);\n break;\n }\n case \"Enter\":\n case \" \": {\n if (event.defaultPrevented) break;\n if (event.key === \" \" && isTextInputTarget(event.target)) break;\n if (event.key === \" \") event.preventDefault();\n if (activeIndex >= 0 && activeIndex < cells.length) {\n const meta = cells[activeIndex].meta;\n if (isNavigableOption(meta)) meta.onSelect?.();\n }\n break;\n }\n case \"Escape\": {\n event.preventDefault();\n onClose();\n triggerRef?.current?.focus();\n break;\n }\n case \"Tab\": {\n onClose();\n break;\n }\n default:\n break;\n }\n },\n [\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose,\n triggerRef,\n findFirstOption,\n findLastOption,\n findNextOption,\n findPrevOption,\n ]\n );\n\n return { handleKeyDown };\n};\n"],"mappings":"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","names":["import_react","import_react_dom","import_xui_core","import_react","React","import_react","import_react","import_jsx_runtime","React","panel"]}
|