@xsolla/xui-context-menu 0.183.0 → 0.185.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ContextMenu.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/ContextMenuContext.tsx","../../src/ContextMenuItem.tsx","../../src/ContextMenuSubmenu.tsx","../../src/hooks/useContextMenuPosition.ts","../../src/hooks/useKeyboardNavigation.ts"],"sourcesContent":["import React, {\n cloneElement,\n forwardRef,\n isValidElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId } from \"@xsolla/xui-core\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\nimport { ContextMenuContext } from \"./ContextMenuContext\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { ContextMenuSubmenu } from \"./ContextMenuSubmenu\";\nimport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nimport {\n useKeyboardNavigation,\n type CellMeta,\n} from \"./hooks/useKeyboardNavigation\";\nimport type {\n ContextMenuContextValue,\n ContextMenuItemProps,\n ContextMenuOptionItemProps,\n ContextMenuPlacement,\n ContextMenuProps,\n ContextMenuSizing,\n} from \"./types\";\n\ntype CellEntry = { id: string; meta: CellMeta };\n\ntype ContextMenuTheme = {\n sizing: {\n contextMenu: (\n size: NonNullable<ContextMenuProps[\"size\"]>\n ) => ContextMenuSizing;\n };\n shape?: {\n contextMenu?: Partial<\n Record<\n NonNullable<ContextMenuProps[\"size\"]>,\n {\n borderRadius?: number | string;\n }\n >\n >;\n };\n colors: {\n background: {\n secondary: string;\n };\n border: {\n secondary: string;\n };\n control: {\n brand: {\n primary: {\n bg: string;\n };\n };\n };\n };\n};\n\nconst DEFAULT_EMPTY_MESSAGE = \"No results\";\nconst SEARCH_DEBOUNCE_MS = 200;\nconst ARROW_SIZE = 10;\nconst ARROW_HALF = ARROW_SIZE / 2;\nconst ARROW_EDGE_OFFSET = 12;\nconst PANEL_SHADOW = \"0 4px 12px rgba(0,0,0,0.15)\";\n\nconst textFromNode = (node: React.ReactNode): string => {\n if (node === null || node === undefined || typeof node === \"boolean\")\n return \"\";\n if (typeof node === \"string\" || typeof node === \"number\") return String(node);\n if (Array.isArray(node)) return node.map(textFromNode).join(\" \");\n if (isValidElement(node)) return textFromNode(node.props.children);\n return \"\";\n};\n\nconst filterItems = (\n items: ReadonlyArray<ContextMenuItemProps>,\n query: string\n): ContextMenuItemProps[] => {\n const normalized = query.trim().toLowerCase();\n if (!normalized) return [...items];\n\n const result: ContextMenuItemProps[] = [];\n let pendingStructural: ContextMenuItemProps[] = [];\n\n for (const item of items) {\n if (item.type === \"option\") {\n const label = textFromNode(item.label).toLowerCase();\n if (label.includes(normalized)) {\n result.push(...pendingStructural, item);\n pendingStructural = [];\n }\n continue;\n }\n\n if (item.type === \"heading\") {\n pendingStructural = [item];\n continue;\n }\n\n if (item.type === \"divider\") {\n if (result.length > 0) pendingStructural.push(item);\n continue;\n }\n }\n\n return result;\n};\n\nconst isOption = (\n item: ContextMenuItemProps\n): item is ContextMenuOptionItemProps => item.type === \"option\";\n\nconst ContextMenuRoot = forwardRef<HTMLElement, ContextMenuProps>(\n (\n {\n children,\n type = \"list\",\n items = [],\n size = \"md\",\n searchable,\n loading,\n isLoading,\n emptyMessage = DEFAULT_EMPTY_MESSAGE,\n empty,\n isOpen: propIsOpen,\n onOpenChange,\n trigger,\n placement = \"bottom-start\",\n position,\n width,\n maxHeight = 300,\n withArrow = false,\n onSelect,\n closeOnSelect,\n \"aria-label\": ariaLabel,\n testID,\n \"data-testid\": dataTestId,\n themeMode,\n themeProductContext,\n style,\n },\n ref\n ) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const xuiTheme = rawTheme as ContextMenuTheme;\n const menuId = useId();\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [cellsVersion, setCellsVersion] = useState(0);\n const [query, setQuery] = useState(\"\");\n const [debouncedQuery, setDebouncedQuery] = useState(\"\");\n const [activeSubmenuId, setActiveSubmenuId] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const panelRef = useRef<HTMLElement | null>(null);\n const cellsRef = useRef<CellEntry[]>([]);\n\n const isOpen = propIsOpen !== undefined ? propIsOpen : internalIsOpen;\n const sizeStyles = xuiTheme.sizing.contextMenu(size);\n const borderRadius = xuiTheme.shape?.contextMenu?.[size]?.borderRadius ?? 8;\n const shouldCloseOnSelect =\n closeOnSelect ?? (type === \"checkbox\" ? false : true);\n\n const positioned = useContextMenuPosition({\n triggerRef,\n panelRef,\n isOpen: isOpen && !!trigger && !position,\n placement,\n });\n\n const resolvedPlacement: ContextMenuPlacement =\n positioned?.placement ?? placement;\n\n const getArrowStyle = (\n arrowPlacement: ContextMenuPlacement\n ): React.CSSProperties => {\n const isTop = arrowPlacement.startsWith(\"top\");\n const arrowStyle: React.CSSProperties = {\n position: \"absolute\",\n width: ARROW_SIZE,\n height: ARROW_SIZE,\n backgroundColor: xuiTheme.colors.background.secondary,\n borderStyle: \"solid\",\n borderColor: xuiTheme.colors.border.secondary,\n // 1px outline only on the two outward-facing edges of the rotated square\n borderWidth: isTop ? \"0 1px 1px 0\" : \"1px 0 0 1px\",\n transform: \"rotate(45deg)\",\n pointerEvents: \"none\",\n };\n // Cross axis: sit half outside the panel edge nearest the trigger.\n if (isTop) arrowStyle.bottom = -ARROW_HALF;\n else arrowStyle.top = -ARROW_HALF;\n // Main axis: align toward the trigger side.\n if (arrowPlacement.endsWith(\"center\")) {\n arrowStyle.left = \"50%\";\n arrowStyle.marginLeft = -ARROW_HALF;\n } else if (arrowPlacement.endsWith(\"end\")) {\n arrowStyle.right = ARROW_EDGE_OFFSET;\n } else {\n arrowStyle.left = ARROW_EDGE_OFFSET;\n }\n return arrowStyle;\n };\n\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if (propIsOpen === undefined) setInternalIsOpen(nextOpen);\n onOpenChange?.(nextOpen);\n if (!nextOpen) setActiveIndex(-1);\n },\n [propIsOpen, onOpenChange]\n );\n\n const closeMenu = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const toggleMenu = useCallback(() => {\n setOpen(!isOpen);\n }, [isOpen, setOpen]);\n\n const registerCell = useCallback((id: string, meta: CellMeta) => {\n const existingIndex = cellsRef.current.findIndex(\n (cell) => cell.id === id\n );\n if (existingIndex >= 0) {\n cellsRef.current[existingIndex] = { id, meta };\n setCellsVersion((version) => version + 1);\n return existingIndex;\n }\n cellsRef.current.push({ id, meta });\n setCellsVersion((version) => version + 1);\n return cellsRef.current.length - 1;\n }, []);\n\n const unregisterCell = useCallback((id: string) => {\n const index = cellsRef.current.findIndex((cell) => cell.id === id);\n if (index >= 0) {\n cellsRef.current.splice(index, 1);\n setCellsVersion((version) => version + 1);\n }\n }, []);\n\n const getCellIndex = useCallback((id: string) => {\n return cellsRef.current.findIndex((cell) => cell.id === id);\n }, []);\n\n const cells = useMemo(() => [...cellsRef.current], [cellsVersion]);\n const keyboard = useKeyboardNavigation({\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose: closeMenu,\n triggerRef,\n });\n\n useEffect(() => {\n if (!isOpen) {\n cellsRef.current = [];\n setCellsVersion((version) => version + 1);\n setQuery(\"\");\n setDebouncedQuery(\"\");\n setActiveSubmenuId(null);\n }\n }, [isOpen]);\n\n useEffect(() => {\n const timer = setTimeout(\n () => setDebouncedQuery(query),\n SEARCH_DEBOUNCE_MS\n );\n return () => clearTimeout(timer);\n }, [query]);\n\n useEffect(() => {\n if (!isOpen || !trigger) return;\n\n const onMouseDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target || containerRef.current?.contains(target)) return;\n closeMenu();\n };\n\n const onScroll = () => closeMenu();\n\n document.addEventListener(\"mousedown\", onMouseDown);\n window.addEventListener(\"scroll\", onScroll);\n return () => {\n document.removeEventListener(\"mousedown\", onMouseDown);\n window.removeEventListener(\"scroll\", onScroll);\n };\n }, [isOpen, trigger, closeMenu]);\n\n useLayoutEffect(() => {\n if (!isOpen || !panelRef.current) return;\n const searchbox =\n panelRef.current.querySelector<HTMLElement>('[role=\"searchbox\"]');\n const firstOption = panelRef.current.querySelector<HTMLElement>(\n '[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"]'\n );\n (searchbox ?? firstOption)?.focus();\n }, [isOpen]);\n\n useLayoutEffect(() => {\n if (!isOpen || !panelRef.current) return;\n const activeElement = document.activeElement;\n if (activeElement && panelRef.current.contains(activeElement)) return;\n panelRef.current.focus();\n }, [isOpen, cellsVersion]);\n\n useEffect(() => {\n if (isOpen) return;\n triggerRef.current?.focus();\n }, [isOpen]);\n\n const contextValue: ContextMenuContextValue = useMemo(\n () => ({\n size,\n menuId,\n closeMenu,\n activeIndex,\n setActiveIndex,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n query,\n setQuery,\n activeSubmenuId,\n setActiveSubmenuId,\n }),\n [\n size,\n menuId,\n closeMenu,\n activeIndex,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n query,\n activeSubmenuId,\n ]\n );\n\n const renderPresetItem = (item: ContextMenuItemProps, index: number) => {\n if (!isOption(item)) {\n return (\n <ContextMenuItem\n key={`context-menu-item-${index}`}\n {...item}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n );\n }\n\n const leadingControl =\n item.leadingControl ??\n (type === \"checkbox\"\n ? \"checkbox\"\n : type === \"radio\"\n ? \"radio\"\n : undefined);\n\n return (\n <ContextMenuItem\n key={`context-menu-item-${index}`}\n {...item}\n leadingControl={leadingControl}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n onSelect={() => {\n item.onSelect?.();\n onSelect?.(item);\n if (shouldCloseOnSelect) closeMenu();\n }}\n />\n );\n };\n\n const renderedItems = searchable\n ? filterItems(items, debouncedQuery)\n : [...items];\n\n const renderContent = () => {\n if (loading || isLoading || type === \"loading\") {\n const brandColor = xuiTheme.colors.control.brand.primary.bg;\n return (\n <Box\n padding={16}\n alignItems=\"center\"\n justifyContent=\"center\"\n minHeight={60}\n >\n <Spinner size=\"md\" color={brandColor} />\n </Box>\n );\n }\n\n if (children) return children;\n\n const content = renderedItems.map(renderPresetItem);\n if (searchable) {\n content.unshift(\n <div\n key=\"context-menu-search\"\n data-sticky=\"top\"\n style={{\n position: \"sticky\",\n top: 0,\n zIndex: 1,\n backgroundColor: xuiTheme.colors.background.secondary,\n }}\n >\n <ContextMenuItem\n type=\"search\"\n value={query}\n onValueChange={setQuery}\n placeholder=\"Search\"\n autoFocus\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </div>\n );\n }\n\n if (content.length > (searchable ? 1 : 0)) return content;\n return empty ?? <div style={{ padding: 16 }}>{emptyMessage}</div>;\n };\n\n const assignPanelRef = (node: HTMLElement | null) => {\n panelRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n };\n\n const assignTriggerRef = (node: HTMLElement | null) => {\n triggerRef.current = node;\n };\n\n const assignTriggerWrapperRef = (node: HTMLSpanElement | null) => {\n if (!node) {\n assignTriggerRef(null);\n return;\n }\n const firstChild = node.firstElementChild;\n assignTriggerRef(\n firstChild instanceof HTMLElement ? firstChild : (node as HTMLElement)\n );\n };\n\n const triggerNode =\n trigger && isValidElement(trigger) ? (\n <span\n ref={assignTriggerWrapperRef}\n onClick={(event) => {\n if (!event.defaultPrevented) toggleMenu();\n }}\n style={{ display: \"inline-flex\" }}\n >\n {cloneElement(trigger as React.ReactElement<any>, {\n \"aria-haspopup\": \"menu\",\n \"aria-expanded\": isOpen ? \"true\" : \"false\",\n })}\n </span>\n ) : trigger ? (\n <span\n ref={assignTriggerRef}\n role=\"button\"\n tabIndex={0}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen ? \"true\" : \"false\"}\n onClick={toggleMenu}\n >\n {trigger}\n </span>\n ) : null;\n\n const positionStyle = position\n ? {\n position: \"fixed\" as const,\n left: position.x,\n top: position.y,\n }\n : trigger\n ? {\n position: \"fixed\" as const,\n left: positioned?.left ?? 0,\n top: positioned?.top ?? 0,\n }\n : undefined;\n\n return (\n <ContextMenuContext.Provider value={contextValue}>\n <div\n ref={containerRef}\n style={{\n position: trigger || position ? \"relative\" : undefined,\n display: trigger ? \"inline-block\" : undefined,\n }}\n >\n {triggerNode}\n {isOpen && (\n <Box\n ref={assignPanelRef}\n role=\"menu\"\n aria-label={ariaLabel}\n data-testid={dataTestId ?? testID ?? \"context-menu\"}\n data-placement={resolvedPlacement}\n backgroundColor={xuiTheme.colors.background.secondary}\n borderColor={xuiTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={borderRadius}\n paddingVertical={sizeStyles.paddingVertical}\n width={width}\n minWidth={sizeStyles.minWidth}\n tabIndex={-1}\n onKeyDown={keyboard.handleKeyDown}\n onMouseLeave={() => setActiveIndex(-1)}\n style={{\n ...positionStyle,\n ...style,\n zIndex: 1000,\n boxShadow: PANEL_SHADOW,\n ...(withArrow\n ? {\n overflow: \"visible\",\n }\n : {\n maxHeight,\n overflowY: \"auto\",\n }),\n outline: \"none\",\n }}\n >\n {withArrow ? (\n <>\n <span\n aria-hidden=\"true\"\n data-testid=\"context-menu-arrow\"\n style={getArrowStyle(resolvedPlacement)}\n />\n <div style={{ maxHeight, overflowY: \"auto\", borderRadius }}>\n {renderContent()}\n </div>\n </>\n ) : (\n renderContent()\n )}\n </Box>\n )}\n </div>\n </ContextMenuContext.Provider>\n );\n }\n);\n\nContextMenuRoot.displayName = \"ContextMenu\";\n\nexport const ContextMenu = Object.assign(ContextMenuRoot, {\n Item: ContextMenuItem,\n Submenu: ContextMenuSubmenu,\n});\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\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 { Search } from \"@xsolla/xui-icons-base\";\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\nconst SUBMENU_GAP = 8;\nconst SUBMENU_VIEWPORT_PADDING = 8;\n\nconst clipsOverflow = (style: CSSStyleDeclaration) => {\n return /(auto|scroll|hidden|clip)/.test(\n `${style.overflow}${style.overflowX}${style.overflowY}`\n );\n};\n\nconst getSubmenuBoundary = (node: HTMLElement) => {\n const viewport = {\n top: SUBMENU_VIEWPORT_PADDING,\n right: window.innerWidth - SUBMENU_VIEWPORT_PADDING,\n bottom: window.innerHeight - SUBMENU_VIEWPORT_PADDING,\n left: SUBMENU_VIEWPORT_PADDING,\n };\n\n let current = node.parentElement;\n while (current && current !== document.body) {\n const style = window.getComputedStyle(current);\n if (clipsOverflow(style) && current.getAttribute(\"role\") !== \"menu\") {\n const rect = current.getBoundingClientRect();\n return {\n top: Math.max(viewport.top, rect.top + SUBMENU_VIEWPORT_PADDING),\n right: Math.min(viewport.right, rect.right - SUBMENU_VIEWPORT_PADDING),\n bottom: Math.min(\n viewport.bottom,\n rect.bottom - SUBMENU_VIEWPORT_PADDING\n ),\n left: Math.max(viewport.left, rect.left + SUBMENU_VIEWPORT_PADDING),\n };\n }\n current = current.parentElement;\n }\n\n return viewport;\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 slot,\n slotContent,\n value,\n hint,\n trailingIcon,\n keyboardShortcut,\n hasSubmenu,\n submenu,\n onSelect,\n onCheckedChange,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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\n const update = () => {\n const node = optionRef.current;\n if (!node) return;\n const rect = node.getBoundingClientRect();\n const submenuRect = submenuWrapperRef.current?.getBoundingClientRect();\n const submenuWidth = submenuRect?.width ?? 0;\n const submenuHeight = submenuRect?.height ?? 0;\n const boundary = getSubmenuBoundary(node);\n\n const rightSideLeft = rect.right + SUBMENU_GAP;\n const leftSideLeft = rect.left - SUBMENU_GAP - submenuWidth;\n const opensLeft =\n submenuWidth > 0 && rightSideLeft + submenuWidth > boundary.right;\n\n let left = opensLeft ? leftSideLeft : rightSideLeft;\n\n if (submenuWidth > 0) {\n if (opensLeft) {\n left = Math.max(SUBMENU_VIEWPORT_PADDING, left);\n } else {\n left = Math.min(\n Math.max(boundary.left, left),\n Math.max(boundary.left, boundary.right - submenuWidth)\n );\n }\n }\n\n let top = rect.top;\n if (submenuHeight > 0 && top + submenuHeight > boundary.bottom) {\n top = boundary.bottom - submenuHeight;\n }\n top = Math.max(boundary.top, top);\n\n setSubmenuPos((prev) =>\n prev?.top === top && prev.left === left ? prev : { top, left }\n );\n };\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 });\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\n ? leadingControl === \"radio\"\n ? \"menuitemradio\"\n : \"menuitemcheckbox\"\n : \"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 if (checked !== undefined) {\n onCheckedChange?.(!checked);\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 if (checked !== undefined) {\n onCheckedChange?.(!checked);\n }\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 {slot}\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: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 onChange,\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: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 <div\n style={{\n boxSizing: \"border-box\",\n paddingLeft: sizing.searchPaddingHorizontal,\n paddingRight: sizing.searchPaddingHorizontal,\n paddingTop: sizing.searchPaddingVertical,\n paddingBottom: sizing.searchPaddingVertical,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n paddingBottom: 6,\n borderBottom: `1px solid ${theme.colors.border.secondary}`,\n }}\n >\n <Search\n variant=\"line\"\n size={sizing.searchIconSize}\n color={theme.colors.control.input.placeholder}\n aria-hidden\n />\n <input\n type=\"search\"\n role=\"searchbox\"\n aria-label={ariaLabel}\n placeholder={placeholder}\n value={value ?? \"\"}\n autoFocus={autoFocus}\n onChange={(e) => {\n onChange?.(e);\n onValueChange?.(e.target.value);\n }}\n data-testid={testId || testID}\n style={{\n flex: 1,\n minWidth: 0,\n boxSizing: \"border-box\",\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n padding: 0,\n color: theme.colors.content.primary,\n fontSize: sizing.searchFontSize,\n lineHeight: `${sizing.searchLineHeight}px`,\n }}\n />\n </div>\n </div>\n );\n};\n\nconst DividerCell: React.FC<\n ContextMenuDividerItemProps & ThemeOverrideProps\n> = ({ themeMode, themeProductContext, \"data-testid\": testId }) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 React, {\n useState,\n useRef,\n useEffect,\n useLayoutEffect,\n useCallback,\n} from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useDesignSystem } from \"@xsolla/xui-core\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { useContextMenu } from \"./ContextMenuContext\";\nimport type { ContextMenuSubmenuProps } from \"./types\";\n\n/** Gap (px) between the parent menu panel and the submenu panel */\nconst SUBMENU_GAP = 4;\n/** Delay (ms) before the submenu opens on hover */\nconst OPEN_DELAY_MS = 200;\n/** Grace period (ms) before the submenu closes after the pointer leaves */\nconst CLOSE_GRACE_MS = 100;\n\n/** Module-level counter for stable, unique submenu IDs (React 16 compatible) */\nlet _submenuIdCounter = 0;\n\nexport const ContextMenuSubmenu: React.FC<ContextMenuSubmenuProps> = ({\n label,\n icon,\n disabled,\n children,\n size: propSize,\n \"data-testid\": testId = \"context-menu-submenu\",\n}) => {\n const { theme } = useDesignSystem();\n const xuiTheme = theme as any;\n const context = useContextMenu();\n const size = propSize || context?.size || \"md\";\n const sizeStyles = xuiTheme.sizing.contextMenu(size);\n const borderRadius =\n xuiTheme.shape?.contextMenu?.[size]?.borderRadius ??\n xuiTheme.radius?.button ??\n 8;\n\n const submenuIdRef = useRef<string | null>(null);\n if (submenuIdRef.current === null) {\n submenuIdRef.current = `xui-cm-submenu-${(_submenuIdCounter += 1)}`;\n }\n const submenuId = submenuIdRef.current;\n\n const [isOpen, setIsOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const [openLeft, setOpenLeft] = useState(false);\n const [topOffset, setTopOffset] = useState(0);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const openTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimers = useCallback(() => {\n if (openTimerRef.current) clearTimeout(openTimerRef.current);\n if (closeTimerRef.current) clearTimeout(closeTimerRef.current);\n }, []);\n\n // Close this submenu when a sibling submenu becomes active (Bug #3 fix)\n useEffect(() => {\n if (!context?.activeSubmenuId) return;\n if (context.activeSubmenuId !== submenuId) {\n setIsOpen(false);\n }\n }, [context?.activeSubmenuId, submenuId]);\n\n const calculatePlacement = useCallback(() => {\n if (!triggerRef.current) return;\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const estimatedWidth = sizeStyles.minWidth + 32;\n const wouldOverflowRight =\n triggerRect.right + estimatedWidth + SUBMENU_GAP > window.innerWidth - 8;\n // Bug #1/#2 fix: only flip left when there is actually space on the left\n const hasSpaceOnLeft =\n triggerRect.left - SUBMENU_GAP - estimatedWidth >= 8;\n setOpenLeft(wouldOverflowRight && hasSpaceOnLeft);\n setTopOffset(0);\n }, [sizeStyles.minWidth]);\n\n useLayoutEffect(() => {\n if (!isOpen || !submenuRef.current || !triggerRef.current) return;\n\n const submenuRect = submenuRef.current.getBoundingClientRect();\n const triggerRect = triggerRef.current.getBoundingClientRect();\n\n const wouldOverflowRight =\n triggerRect.right + submenuRect.width + SUBMENU_GAP >\n window.innerWidth - 8;\n const hasSpaceOnLeft =\n triggerRect.left - SUBMENU_GAP - submenuRect.width >= 8;\n setOpenLeft(wouldOverflowRight && hasSpaceOnLeft);\n\n const overflowBottom =\n triggerRect.top + submenuRect.height - (window.innerHeight - 8);\n if (overflowBottom > 0) {\n setTopOffset(-Math.min(overflowBottom, triggerRect.top - 8));\n } else {\n setTopOffset(0);\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) {\n setVisible(false);\n return;\n }\n const raf = requestAnimationFrame(() => setVisible(true));\n return () => cancelAnimationFrame(raf);\n }, [isOpen]);\n\n useEffect(() => () => clearTimers(), [clearTimers]);\n\n const handleTriggerEnter = () => {\n if (disabled) return;\n clearTimers();\n openTimerRef.current = setTimeout(() => {\n calculatePlacement();\n setIsOpen(true);\n context?.setActiveSubmenuId(submenuId);\n }, OPEN_DELAY_MS);\n };\n\n const handleTriggerLeave = () => {\n clearTimers();\n closeTimerRef.current = setTimeout(() => {\n setIsOpen(false);\n if (context?.activeSubmenuId === submenuId) {\n context.setActiveSubmenuId(null);\n }\n }, CLOSE_GRACE_MS);\n };\n\n const handleSubmenuEnter = () => clearTimers();\n\n const handleSubmenuLeave = () => {\n clearTimers();\n closeTimerRef.current = setTimeout(() => {\n setIsOpen(false);\n if (context?.activeSubmenuId === submenuId) {\n context.setActiveSubmenuId(null);\n }\n }, CLOSE_GRACE_MS);\n };\n\n const submenuPositionStyle = openLeft\n ? { right: `calc(100% + ${SUBMENU_GAP}px)` }\n : { left: `calc(100% + ${SUBMENU_GAP}px)` };\n\n return (\n <div\n ref={triggerRef}\n style={{ position: \"relative\" }}\n onMouseEnter={handleTriggerEnter}\n onMouseLeave={handleTriggerLeave}\n data-testid={testId}\n >\n <ContextMenuItem\n type=\"option\"\n label={label}\n leadingIcon={icon}\n disabled={disabled}\n hasSubmenu\n size={size}\n data-testid={`${testId}-trigger`}\n />\n\n {isOpen && (\n <div\n ref={submenuRef}\n onMouseEnter={handleSubmenuEnter}\n onMouseLeave={handleSubmenuLeave}\n style={{\n position: \"absolute\",\n top: topOffset,\n ...submenuPositionStyle,\n zIndex: 1001,\n opacity: visible ? 1 : 0,\n transform: visible\n ? \"translateX(0)\"\n : openLeft\n ? \"translateX(4px)\"\n : \"translateX(-4px)\",\n transition: \"opacity 100ms ease, transform 100ms ease\",\n }}\n data-testid={`${testId}-content`}\n >\n <Box\n role=\"menu\"\n backgroundColor={xuiTheme.colors.background.secondary}\n borderColor={xuiTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={borderRadius}\n paddingVertical={sizeStyles.paddingVertical}\n style={{\n boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\",\n minWidth: sizeStyles.minWidth,\n }}\n >\n {children}\n </Box>\n </div>\n )}\n </div>\n );\n};\n\nContextMenuSubmenu.displayName = \"ContextMenuSubmenu\";\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\" | \"center\" } => {\n const [vertical, horizontal] = placement.split(\"-\") as [\n \"top\" | \"bottom\",\n \"start\" | \"end\" | \"center\",\n ];\n return { vertical, horizontal };\n};\n\nconst joinPlacement = (\n vertical: \"top\" | \"bottom\",\n horizontal: \"start\" | \"end\" | \"center\"\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\" | \"center\") => {\n if (h === \"center\")\n return triggerRect.left + triggerRect.width / 2 - panelRect.width / 2;\n return h === \"start\"\n ? triggerRect.left\n : triggerRect.right - panelRect.width;\n };\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 if (horizontal === \"center\") {\n // Center can't flip; clamp into the viewport instead.\n const maxLeft = viewportWidth - panelRect.width;\n left = maxLeft >= 0 ? Math.min(Math.max(left, 0), maxLeft) : 0;\n } else {\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\n const next = {\n top,\n left,\n placement: joinPlacement(vertical, horizontal),\n };\n setResolved((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.placement === next.placement\n ? prev\n : next\n );\n };\n\n const rafId = window.requestAnimationFrame(compute);\n // No scroll listener: the menu dismisses on scroll (see ContextMenu), so\n // following the trigger would be dead work. Resize still repositions an\n // open menu.\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":["useCallback","useEffect","useLayoutEffect","useRef","useState","useResolvedTheme","useId","jsx","useState","useEffect","useLayoutEffect","jsx","jsxs","SUBMENU_GAP","useState","useEffect","useLayoutEffect","useEffect","useState","useCallback","jsx","jsxs","useResolvedTheme","useId","useState","useRef","useCallback","useEffect","useLayoutEffect"]}
1
+ {"version":3,"sources":["../../src/ContextMenu.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/ContextMenuContext.tsx","../../src/ContextMenuItem.tsx","../../src/ContextMenuSubmenu.tsx","../../src/hooks/useContextMenuPosition.ts","../../src/hooks/useKeyboardNavigation.ts"],"sourcesContent":["import React, {\n cloneElement,\n forwardRef,\n isValidElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, useId } from \"@xsolla/xui-core\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\nimport { ContextMenuContext } from \"./ContextMenuContext\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { ContextMenuSubmenu } from \"./ContextMenuSubmenu\";\nimport { useContextMenuPosition } from \"./hooks/useContextMenuPosition\";\nimport {\n useKeyboardNavigation,\n type CellMeta,\n} from \"./hooks/useKeyboardNavigation\";\nimport type {\n ContextMenuContextValue,\n ContextMenuItemProps,\n ContextMenuOptionItemProps,\n ContextMenuPlacement,\n ContextMenuProps,\n ContextMenuSizing,\n} from \"./types\";\n\ntype CellEntry = { id: string; meta: CellMeta };\n\ntype ContextMenuTheme = {\n sizing: {\n contextMenu: (\n size: NonNullable<ContextMenuProps[\"size\"]>\n ) => ContextMenuSizing;\n };\n shape?: {\n contextMenu?: Partial<\n Record<\n NonNullable<ContextMenuProps[\"size\"]>,\n {\n borderRadius?: number | string;\n }\n >\n >;\n };\n colors: {\n background: {\n secondary: string;\n };\n border: {\n secondary: string;\n };\n control: {\n brand: {\n primary: {\n bg: string;\n };\n };\n };\n };\n};\n\nconst DEFAULT_EMPTY_MESSAGE = \"No results\";\nconst SEARCH_DEBOUNCE_MS = 200;\nconst ARROW_SIZE = 10;\nconst ARROW_HALF = ARROW_SIZE / 2;\nconst ARROW_EDGE_OFFSET = 12;\n// Distance the rotated arrow's tip protrudes past the panel edge toward the\n// trigger. The square is rotated 45deg about its center (pinned to the edge),\n// so its corner sits ARROW_HALF * √2 beyond it. Folded into the position\n// offset when `withArrow` is set so `offset` measures to the arrow tip.\nconst ARROW_TIP_PROTRUSION = ARROW_HALF * Math.SQRT2;\nconst PANEL_SHADOW = \"0 4px 12px rgba(0,0,0,0.15)\";\n\nconst textFromNode = (node: React.ReactNode): string => {\n if (node === null || node === undefined || typeof node === \"boolean\")\n return \"\";\n if (typeof node === \"string\" || typeof node === \"number\") return String(node);\n if (Array.isArray(node)) return node.map(textFromNode).join(\" \");\n if (isValidElement(node)) return textFromNode(node.props.children);\n return \"\";\n};\n\nconst filterItems = (\n items: ReadonlyArray<ContextMenuItemProps>,\n query: string\n): ContextMenuItemProps[] => {\n const normalized = query.trim().toLowerCase();\n if (!normalized) return [...items];\n\n const result: ContextMenuItemProps[] = [];\n let pendingStructural: ContextMenuItemProps[] = [];\n\n for (const item of items) {\n if (item.type === \"option\") {\n const label = textFromNode(item.label).toLowerCase();\n if (label.includes(normalized)) {\n result.push(...pendingStructural, item);\n pendingStructural = [];\n }\n continue;\n }\n\n if (item.type === \"heading\") {\n pendingStructural = [item];\n continue;\n }\n\n if (item.type === \"divider\") {\n if (result.length > 0) pendingStructural.push(item);\n continue;\n }\n }\n\n return result;\n};\n\nconst isOption = (\n item: ContextMenuItemProps\n): item is ContextMenuOptionItemProps => item.type === \"option\";\n\nconst ContextMenuRoot = forwardRef<HTMLElement, ContextMenuProps>(\n (\n {\n children,\n type = \"list\",\n items = [],\n size = \"md\",\n searchable,\n loading,\n isLoading,\n emptyMessage = DEFAULT_EMPTY_MESSAGE,\n empty,\n isOpen: propIsOpen,\n onOpenChange,\n trigger,\n triggerFullWidth = false,\n placement = \"bottom-start\",\n offset = 4,\n position,\n width,\n maxHeight = 300,\n withArrow = false,\n onSelect,\n closeOnSelect,\n \"aria-label\": ariaLabel,\n testID,\n \"data-testid\": dataTestId,\n themeMode,\n themeProductContext,\n style,\n },\n ref\n ) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const xuiTheme = rawTheme as ContextMenuTheme;\n const menuId = useId();\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [cellsVersion, setCellsVersion] = useState(0);\n const [query, setQuery] = useState(\"\");\n const [debouncedQuery, setDebouncedQuery] = useState(\"\");\n const [activeSubmenuId, setActiveSubmenuId] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const panelRef = useRef<HTMLElement | null>(null);\n const cellsRef = useRef<CellEntry[]>([]);\n\n const isOpen = propIsOpen !== undefined ? propIsOpen : internalIsOpen;\n const sizeStyles = xuiTheme.sizing.contextMenu(size);\n const borderRadius = xuiTheme.shape?.contextMenu?.[size]?.borderRadius ?? 8;\n const shouldCloseOnSelect =\n closeOnSelect ?? (type === \"checkbox\" ? false : true);\n\n // With an arrow, the tip protrudes past the panel edge, so push the panel\n // out by that amount to keep `offset` measured to the visible arrow tip.\n const positionOffset = withArrow ? offset + ARROW_TIP_PROTRUSION : offset;\n\n const positioned = useContextMenuPosition({\n triggerRef,\n panelRef,\n containerRef,\n isOpen: isOpen && !!trigger && !position,\n placement,\n offset: positionOffset,\n });\n\n const resolvedPlacement: ContextMenuPlacement =\n positioned?.placement ?? placement;\n\n const getArrowStyle = (\n arrowPlacement: ContextMenuPlacement\n ): React.CSSProperties => {\n const isTop = arrowPlacement.startsWith(\"top\");\n const arrowStyle: React.CSSProperties = {\n position: \"absolute\",\n width: ARROW_SIZE,\n height: ARROW_SIZE,\n backgroundColor: xuiTheme.colors.background.secondary,\n borderStyle: \"solid\",\n borderColor: xuiTheme.colors.border.secondary,\n // 1px outline only on the two outward-facing edges of the rotated square\n borderWidth: isTop ? \"0 1px 1px 0\" : \"1px 0 0 1px\",\n transform: \"rotate(45deg)\",\n pointerEvents: \"none\",\n };\n // Cross axis: sit half outside the panel edge nearest the trigger.\n if (isTop) arrowStyle.bottom = -ARROW_HALF;\n else arrowStyle.top = -ARROW_HALF;\n // Main axis: align toward the trigger side.\n if (arrowPlacement.endsWith(\"center\")) {\n arrowStyle.left = \"50%\";\n arrowStyle.marginLeft = -ARROW_HALF;\n } else if (arrowPlacement.endsWith(\"end\")) {\n arrowStyle.right = ARROW_EDGE_OFFSET;\n } else {\n arrowStyle.left = ARROW_EDGE_OFFSET;\n }\n return arrowStyle;\n };\n\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if (propIsOpen === undefined) setInternalIsOpen(nextOpen);\n onOpenChange?.(nextOpen);\n if (!nextOpen) setActiveIndex(-1);\n },\n [propIsOpen, onOpenChange]\n );\n\n const closeMenu = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const toggleMenu = useCallback(() => {\n setOpen(!isOpen);\n }, [isOpen, setOpen]);\n\n const registerCell = useCallback((id: string, meta: CellMeta) => {\n const existingIndex = cellsRef.current.findIndex(\n (cell) => cell.id === id\n );\n if (existingIndex >= 0) {\n cellsRef.current[existingIndex] = { id, meta };\n setCellsVersion((version) => version + 1);\n return existingIndex;\n }\n cellsRef.current.push({ id, meta });\n setCellsVersion((version) => version + 1);\n return cellsRef.current.length - 1;\n }, []);\n\n const unregisterCell = useCallback((id: string) => {\n const index = cellsRef.current.findIndex((cell) => cell.id === id);\n if (index >= 0) {\n cellsRef.current.splice(index, 1);\n setCellsVersion((version) => version + 1);\n }\n }, []);\n\n const getCellIndex = useCallback((id: string) => {\n return cellsRef.current.findIndex((cell) => cell.id === id);\n }, []);\n\n const cells = useMemo(() => [...cellsRef.current], [cellsVersion]);\n const keyboard = useKeyboardNavigation({\n isOpen,\n cells,\n activeIndex,\n setActiveIndex,\n onClose: closeMenu,\n triggerRef,\n });\n\n useEffect(() => {\n if (!isOpen) {\n cellsRef.current = [];\n setCellsVersion((version) => version + 1);\n setQuery(\"\");\n setDebouncedQuery(\"\");\n setActiveSubmenuId(null);\n }\n }, [isOpen]);\n\n useEffect(() => {\n const timer = setTimeout(\n () => setDebouncedQuery(query),\n SEARCH_DEBOUNCE_MS\n );\n return () => clearTimeout(timer);\n }, [query]);\n\n useEffect(() => {\n if (!isOpen || !trigger) return;\n\n const onMouseDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target || containerRef.current?.contains(target)) return;\n closeMenu();\n };\n\n const onScroll = () => closeMenu();\n\n document.addEventListener(\"mousedown\", onMouseDown);\n window.addEventListener(\"scroll\", onScroll);\n return () => {\n document.removeEventListener(\"mousedown\", onMouseDown);\n window.removeEventListener(\"scroll\", onScroll);\n };\n }, [isOpen, trigger, closeMenu]);\n\n useLayoutEffect(() => {\n if (!isOpen || !panelRef.current) return;\n const searchbox =\n panelRef.current.querySelector<HTMLElement>('[role=\"searchbox\"]');\n const firstOption = panelRef.current.querySelector<HTMLElement>(\n '[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"]'\n );\n (searchbox ?? firstOption)?.focus();\n }, [isOpen]);\n\n useLayoutEffect(() => {\n if (!isOpen || !panelRef.current) return;\n const activeElement = document.activeElement;\n if (activeElement && panelRef.current.contains(activeElement)) return;\n panelRef.current.focus();\n }, [isOpen, cellsVersion]);\n\n useEffect(() => {\n if (isOpen) return;\n triggerRef.current?.focus();\n }, [isOpen]);\n\n const contextValue: ContextMenuContextValue = useMemo(\n () => ({\n size,\n menuId,\n closeMenu,\n activeIndex,\n setActiveIndex,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n query,\n setQuery,\n activeSubmenuId,\n setActiveSubmenuId,\n }),\n [\n size,\n menuId,\n closeMenu,\n activeIndex,\n registerCell,\n unregisterCell,\n getCellIndex,\n cellsVersion,\n query,\n activeSubmenuId,\n ]\n );\n\n const renderPresetItem = (item: ContextMenuItemProps, index: number) => {\n if (!isOption(item)) {\n return (\n <ContextMenuItem\n key={`context-menu-item-${index}`}\n {...item}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n );\n }\n\n const leadingControl =\n item.leadingControl ??\n (type === \"checkbox\"\n ? \"checkbox\"\n : type === \"radio\"\n ? \"radio\"\n : undefined);\n\n return (\n <ContextMenuItem\n key={`context-menu-item-${index}`}\n {...item}\n leadingControl={leadingControl}\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n onSelect={() => {\n item.onSelect?.();\n onSelect?.(item);\n if (shouldCloseOnSelect) closeMenu();\n }}\n />\n );\n };\n\n const renderedItems = searchable\n ? filterItems(items, debouncedQuery)\n : [...items];\n\n const renderContent = () => {\n if (loading || isLoading || type === \"loading\") {\n const brandColor = xuiTheme.colors.control.brand.primary.bg;\n return (\n <Box\n padding={16}\n alignItems=\"center\"\n justifyContent=\"center\"\n minHeight={60}\n >\n <Spinner size=\"md\" color={brandColor} />\n </Box>\n );\n }\n\n if (children) return children;\n\n const content = renderedItems.map(renderPresetItem);\n if (searchable) {\n content.unshift(\n <div\n key=\"context-menu-search\"\n data-sticky=\"top\"\n style={{\n position: \"sticky\",\n top: 0,\n zIndex: 1,\n backgroundColor: xuiTheme.colors.background.secondary,\n }}\n >\n <ContextMenuItem\n type=\"search\"\n value={query}\n onValueChange={setQuery}\n placeholder=\"Search\"\n autoFocus\n themeMode={themeMode}\n themeProductContext={themeProductContext}\n />\n </div>\n );\n }\n\n if (content.length > (searchable ? 1 : 0)) return content;\n return empty ?? <div style={{ padding: 16 }}>{emptyMessage}</div>;\n };\n\n const assignPanelRef = (node: HTMLElement | null) => {\n panelRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n };\n\n const assignTriggerRef = (node: HTMLElement | null) => {\n triggerRef.current = node;\n };\n\n const assignTriggerWrapperRef = (node: HTMLSpanElement | null) => {\n if (!node) {\n assignTriggerRef(null);\n return;\n }\n const firstChild = node.firstElementChild;\n assignTriggerRef(\n firstChild instanceof HTMLElement ? firstChild : (node as HTMLElement)\n );\n };\n\n const triggerNode =\n trigger && isValidElement(trigger) ? (\n <span\n ref={assignTriggerWrapperRef}\n onClick={(event) => {\n if (!event.defaultPrevented) toggleMenu();\n }}\n style={{\n display: \"inline-flex\",\n width: triggerFullWidth ? \"100%\" : \"auto\",\n }}\n >\n {cloneElement(trigger as React.ReactElement<any>, {\n \"aria-haspopup\": \"menu\",\n \"aria-expanded\": isOpen ? \"true\" : \"false\",\n })}\n </span>\n ) : trigger ? (\n <span\n ref={assignTriggerRef}\n role=\"button\"\n tabIndex={0}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen ? \"true\" : \"false\"}\n onClick={toggleMenu}\n >\n {trigger}\n </span>\n ) : null;\n\n const positionStyle: React.CSSProperties | undefined = position\n ? {\n position: \"fixed\" as const,\n left: position.x,\n top: position.y,\n }\n : trigger\n ? positioned\n ? {\n position: \"absolute\" as const,\n left: positioned.left,\n top: positioned.top,\n }\n : {\n position: \"absolute\" as const,\n visibility: \"hidden\" as const,\n }\n : undefined;\n\n return (\n <ContextMenuContext.Provider value={contextValue}>\n <div\n ref={containerRef}\n style={{\n position: trigger || position ? \"relative\" : undefined,\n display: trigger ? \"inline-block\" : undefined,\n }}\n >\n {triggerNode}\n {isOpen && (\n <Box\n ref={assignPanelRef}\n role=\"menu\"\n aria-label={ariaLabel}\n data-testid={dataTestId ?? testID ?? \"context-menu\"}\n data-placement={resolvedPlacement}\n backgroundColor={xuiTheme.colors.background.secondary}\n borderColor={xuiTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={borderRadius}\n paddingVertical={sizeStyles.paddingVertical}\n width={width}\n minWidth={sizeStyles.minWidth}\n tabIndex={-1}\n onKeyDown={keyboard.handleKeyDown}\n onMouseLeave={() => setActiveIndex(-1)}\n style={{\n ...positionStyle,\n ...style,\n zIndex: 1000,\n boxShadow: PANEL_SHADOW,\n ...(withArrow\n ? {\n overflow: \"visible\",\n }\n : {\n maxHeight,\n overflowY: \"auto\",\n }),\n outline: \"none\",\n }}\n >\n {withArrow ? (\n <>\n <span\n aria-hidden=\"true\"\n data-testid=\"context-menu-arrow\"\n style={getArrowStyle(resolvedPlacement)}\n />\n <div style={{ maxHeight, overflowY: \"auto\", borderRadius }}>\n {renderContent()}\n </div>\n </>\n ) : (\n renderContent()\n )}\n </Box>\n )}\n </div>\n </ContextMenuContext.Provider>\n );\n }\n);\n\nContextMenuRoot.displayName = \"ContextMenu\";\n\nexport const ContextMenu = Object.assign(ContextMenuRoot, {\n Item: ContextMenuItem,\n Submenu: ContextMenuSubmenu,\n});\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\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 { Search } from \"@xsolla/xui-icons-base\";\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\nconst SUBMENU_GAP = 8;\nconst SUBMENU_VIEWPORT_PADDING = 8;\n\nconst clipsOverflow = (style: CSSStyleDeclaration) => {\n return /(auto|scroll|hidden|clip)/.test(\n `${style.overflow}${style.overflowX}${style.overflowY}`\n );\n};\n\nconst getSubmenuBoundary = (node: HTMLElement) => {\n const viewport = {\n top: SUBMENU_VIEWPORT_PADDING,\n right: window.innerWidth - SUBMENU_VIEWPORT_PADDING,\n bottom: window.innerHeight - SUBMENU_VIEWPORT_PADDING,\n left: SUBMENU_VIEWPORT_PADDING,\n };\n\n let current = node.parentElement;\n while (current && current !== document.body) {\n const style = window.getComputedStyle(current);\n if (clipsOverflow(style) && current.getAttribute(\"role\") !== \"menu\") {\n const rect = current.getBoundingClientRect();\n return {\n top: Math.max(viewport.top, rect.top + SUBMENU_VIEWPORT_PADDING),\n right: Math.min(viewport.right, rect.right - SUBMENU_VIEWPORT_PADDING),\n bottom: Math.min(\n viewport.bottom,\n rect.bottom - SUBMENU_VIEWPORT_PADDING\n ),\n left: Math.max(viewport.left, rect.left + SUBMENU_VIEWPORT_PADDING),\n };\n }\n current = current.parentElement;\n }\n\n return viewport;\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 slot,\n slotContent,\n value,\n hint,\n trailingIcon,\n keyboardShortcut,\n hasSubmenu,\n submenu,\n onSelect,\n onCheckedChange,\n testID,\n themeMode,\n themeProductContext,\n \"data-testid\": testId,\n}) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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\n const update = () => {\n const node = optionRef.current;\n if (!node) return;\n const rect = node.getBoundingClientRect();\n const submenuRect = submenuWrapperRef.current?.getBoundingClientRect();\n const submenuWidth = submenuRect?.width ?? 0;\n const submenuHeight = submenuRect?.height ?? 0;\n const boundary = getSubmenuBoundary(node);\n\n const rightSideLeft = rect.right + SUBMENU_GAP;\n const leftSideLeft = rect.left - SUBMENU_GAP - submenuWidth;\n const opensLeft =\n submenuWidth > 0 && rightSideLeft + submenuWidth > boundary.right;\n\n let left = opensLeft ? leftSideLeft : rightSideLeft;\n\n if (submenuWidth > 0) {\n if (opensLeft) {\n left = Math.max(SUBMENU_VIEWPORT_PADDING, left);\n } else {\n left = Math.min(\n Math.max(boundary.left, left),\n Math.max(boundary.left, boundary.right - submenuWidth)\n );\n }\n }\n\n let top = rect.top;\n if (submenuHeight > 0 && top + submenuHeight > boundary.bottom) {\n top = boundary.bottom - submenuHeight;\n }\n top = Math.max(boundary.top, top);\n\n setSubmenuPos((prev) =>\n prev?.top === top && prev.left === left ? prev : { top, left }\n );\n };\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 });\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\n ? leadingControl === \"radio\"\n ? \"menuitemradio\"\n : \"menuitemcheckbox\"\n : \"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 if (checked !== undefined) {\n onCheckedChange?.(!checked);\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 if (checked !== undefined) {\n onCheckedChange?.(!checked);\n }\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 {slot}\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: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 onChange,\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: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 <div\n style={{\n boxSizing: \"border-box\",\n paddingLeft: sizing.searchPaddingHorizontal,\n paddingRight: sizing.searchPaddingHorizontal,\n paddingTop: sizing.searchPaddingVertical,\n paddingBottom: sizing.searchPaddingVertical,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n paddingBottom: 6,\n borderBottom: `1px solid ${theme.colors.border.secondary}`,\n }}\n >\n <Search\n variant=\"line\"\n size={sizing.searchIconSize}\n color={theme.colors.control.input.placeholder}\n aria-hidden\n />\n <input\n type=\"search\"\n role=\"searchbox\"\n aria-label={ariaLabel}\n placeholder={placeholder}\n value={value ?? \"\"}\n autoFocus={autoFocus}\n onChange={(e) => {\n onChange?.(e);\n onValueChange?.(e.target.value);\n }}\n data-testid={testId || testID}\n style={{\n flex: 1,\n minWidth: 0,\n boxSizing: \"border-box\",\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n padding: 0,\n color: theme.colors.content.primary,\n fontSize: sizing.searchFontSize,\n lineHeight: `${sizing.searchLineHeight}px`,\n }}\n />\n </div>\n </div>\n );\n};\n\nconst DividerCell: React.FC<\n ContextMenuDividerItemProps & ThemeOverrideProps\n> = ({ themeMode, themeProductContext, \"data-testid\": testId }) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\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 React, {\n useState,\n useRef,\n useEffect,\n useLayoutEffect,\n useCallback,\n} from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useDesignSystem } from \"@xsolla/xui-core\";\nimport { ContextMenuItem } from \"./ContextMenuItem\";\nimport { useContextMenu } from \"./ContextMenuContext\";\nimport type { ContextMenuSubmenuProps } from \"./types\";\n\n/** Gap (px) between the parent menu panel and the submenu panel */\nconst SUBMENU_GAP = 4;\n/** Delay (ms) before the submenu opens on hover */\nconst OPEN_DELAY_MS = 200;\n/** Grace period (ms) before the submenu closes after the pointer leaves */\nconst CLOSE_GRACE_MS = 100;\n\n/** Module-level counter for stable, unique submenu IDs (React 16 compatible) */\nlet _submenuIdCounter = 0;\n\nexport const ContextMenuSubmenu: React.FC<ContextMenuSubmenuProps> = ({\n label,\n icon,\n disabled,\n children,\n size: propSize,\n \"data-testid\": testId = \"context-menu-submenu\",\n}) => {\n const { theme } = useDesignSystem();\n const xuiTheme = theme as any;\n const context = useContextMenu();\n const size = propSize || context?.size || \"md\";\n const sizeStyles = xuiTheme.sizing.contextMenu(size);\n const borderRadius =\n xuiTheme.shape?.contextMenu?.[size]?.borderRadius ??\n xuiTheme.radius?.button ??\n 8;\n\n const submenuIdRef = useRef<string | null>(null);\n if (submenuIdRef.current === null) {\n submenuIdRef.current = `xui-cm-submenu-${(_submenuIdCounter += 1)}`;\n }\n const submenuId = submenuIdRef.current;\n\n const [isOpen, setIsOpen] = useState(false);\n const [visible, setVisible] = useState(false);\n const [openLeft, setOpenLeft] = useState(false);\n const [topOffset, setTopOffset] = useState(0);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const openTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimers = useCallback(() => {\n if (openTimerRef.current) clearTimeout(openTimerRef.current);\n if (closeTimerRef.current) clearTimeout(closeTimerRef.current);\n }, []);\n\n // Close this submenu when a sibling submenu becomes active (Bug #3 fix)\n useEffect(() => {\n if (!context?.activeSubmenuId) return;\n if (context.activeSubmenuId !== submenuId) {\n setIsOpen(false);\n }\n }, [context?.activeSubmenuId, submenuId]);\n\n const calculatePlacement = useCallback(() => {\n if (!triggerRef.current) return;\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const estimatedWidth = sizeStyles.minWidth + 32;\n const wouldOverflowRight =\n triggerRect.right + estimatedWidth + SUBMENU_GAP > window.innerWidth - 8;\n // Bug #1/#2 fix: only flip left when there is actually space on the left\n const hasSpaceOnLeft =\n triggerRect.left - SUBMENU_GAP - estimatedWidth >= 8;\n setOpenLeft(wouldOverflowRight && hasSpaceOnLeft);\n setTopOffset(0);\n }, [sizeStyles.minWidth]);\n\n useLayoutEffect(() => {\n if (!isOpen || !submenuRef.current || !triggerRef.current) return;\n\n const submenuRect = submenuRef.current.getBoundingClientRect();\n const triggerRect = triggerRef.current.getBoundingClientRect();\n\n const wouldOverflowRight =\n triggerRect.right + submenuRect.width + SUBMENU_GAP >\n window.innerWidth - 8;\n const hasSpaceOnLeft =\n triggerRect.left - SUBMENU_GAP - submenuRect.width >= 8;\n setOpenLeft(wouldOverflowRight && hasSpaceOnLeft);\n\n const overflowBottom =\n triggerRect.top + submenuRect.height - (window.innerHeight - 8);\n if (overflowBottom > 0) {\n setTopOffset(-Math.min(overflowBottom, triggerRect.top - 8));\n } else {\n setTopOffset(0);\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) {\n setVisible(false);\n return;\n }\n const raf = requestAnimationFrame(() => setVisible(true));\n return () => cancelAnimationFrame(raf);\n }, [isOpen]);\n\n useEffect(() => () => clearTimers(), [clearTimers]);\n\n const handleTriggerEnter = () => {\n if (disabled) return;\n clearTimers();\n openTimerRef.current = setTimeout(() => {\n calculatePlacement();\n setIsOpen(true);\n context?.setActiveSubmenuId(submenuId);\n }, OPEN_DELAY_MS);\n };\n\n const handleTriggerLeave = () => {\n clearTimers();\n closeTimerRef.current = setTimeout(() => {\n setIsOpen(false);\n if (context?.activeSubmenuId === submenuId) {\n context.setActiveSubmenuId(null);\n }\n }, CLOSE_GRACE_MS);\n };\n\n const handleSubmenuEnter = () => clearTimers();\n\n const handleSubmenuLeave = () => {\n clearTimers();\n closeTimerRef.current = setTimeout(() => {\n setIsOpen(false);\n if (context?.activeSubmenuId === submenuId) {\n context.setActiveSubmenuId(null);\n }\n }, CLOSE_GRACE_MS);\n };\n\n const submenuPositionStyle = openLeft\n ? { right: `calc(100% + ${SUBMENU_GAP}px)` }\n : { left: `calc(100% + ${SUBMENU_GAP}px)` };\n\n return (\n <div\n ref={triggerRef}\n style={{ position: \"relative\" }}\n onMouseEnter={handleTriggerEnter}\n onMouseLeave={handleTriggerLeave}\n data-testid={testId}\n >\n <ContextMenuItem\n type=\"option\"\n label={label}\n leadingIcon={icon}\n disabled={disabled}\n hasSubmenu\n size={size}\n data-testid={`${testId}-trigger`}\n />\n\n {isOpen && (\n <div\n ref={submenuRef}\n onMouseEnter={handleSubmenuEnter}\n onMouseLeave={handleSubmenuLeave}\n style={{\n position: \"absolute\",\n top: topOffset,\n ...submenuPositionStyle,\n zIndex: 1001,\n opacity: visible ? 1 : 0,\n transform: visible\n ? \"translateX(0)\"\n : openLeft\n ? \"translateX(4px)\"\n : \"translateX(-4px)\",\n transition: \"opacity 100ms ease, transform 100ms ease\",\n }}\n data-testid={`${testId}-content`}\n >\n <Box\n role=\"menu\"\n backgroundColor={xuiTheme.colors.background.secondary}\n borderColor={xuiTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={borderRadius}\n paddingVertical={sizeStyles.paddingVertical}\n style={{\n boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\",\n minWidth: sizeStyles.minWidth,\n }}\n >\n {children}\n </Box>\n </div>\n )}\n </div>\n );\n};\n\nContextMenuSubmenu.displayName = \"ContextMenuSubmenu\";\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\nimport type { ContextMenuPlacement } from \"../types\";\n\ninterface UseContextMenuPositionOptions {\n triggerRef: RefObject<HTMLElement | null>;\n panelRef: RefObject<HTMLElement | null>;\n containerRef: 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\" | \"center\" } => {\n const [vertical, horizontal] = placement.split(\"-\") as [\n \"top\" | \"bottom\",\n \"start\" | \"end\" | \"center\",\n ];\n return { vertical, horizontal };\n};\n\nconst joinPlacement = (\n vertical: \"top\" | \"bottom\",\n horizontal: \"start\" | \"end\" | \"center\"\n): ContextMenuPlacement => `${vertical}-${horizontal}` as ContextMenuPlacement;\n\nexport const useContextMenuPosition = ({\n triggerRef,\n panelRef,\n containerRef,\n isOpen,\n placement = \"bottom-start\",\n offset = 4,\n}: UseContextMenuPositionOptions): ResolvedPosition | undefined => {\n const [resolved, setResolved] = useState<ResolvedPosition | undefined>();\n\n useLayoutEffect(() => {\n if (!isOpen) {\n setResolved(undefined);\n return;\n }\n\n const compute = () => {\n const trigger = triggerRef.current;\n const panel = panelRef.current;\n const container = containerRef.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\" | \"center\") => {\n if (h === \"center\")\n return triggerRect.left + triggerRect.width / 2 - panelRect.width / 2;\n return h === \"start\"\n ? triggerRect.left\n : triggerRect.right - panelRect.width;\n };\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 if (horizontal === \"center\") {\n const maxLeft = viewportWidth - panelRect.width;\n left = maxLeft >= 0 ? Math.min(Math.max(left, 0), maxLeft) : 0;\n } else {\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\n // Convert viewport coordinates to local (absolute-positioning) coords\n // relative to the container. Reading containerRect here (inside the\n // layout effect) guarantees we measure at the same time as the trigger\n // and panel, avoiding stale-rect issues from intermediate renders.\n if (container) {\n const containerRect = container.getBoundingClientRect();\n const cOffsetW = container.offsetWidth;\n const cOffsetH = container.offsetHeight;\n const scaleX = cOffsetW > 0 ? containerRect.width / cOffsetW : 1;\n const scaleY = cOffsetH > 0 ? containerRect.height / cOffsetH : 1;\n left = (left - containerRect.left) / (scaleX || 1);\n top = (top - containerRect.top) / (scaleY || 1);\n }\n\n const next = {\n top,\n left,\n placement: joinPlacement(vertical, horizontal),\n };\n setResolved((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.placement === next.placement\n ? prev\n : next\n );\n };\n\n compute();\n // No scroll listener: the menu dismisses on scroll (see ContextMenu), so\n // following the trigger would be dead work. Resize still repositions an\n // open menu.\n const onResize = () => compute();\n window.addEventListener(\"resize\", onResize);\n\n return () => {\n window.removeEventListener(\"resize\", onResize);\n };\n }, [isOpen, placement, offset, triggerRef, panelRef, containerRef]);\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":["useCallback","useEffect","useLayoutEffect","useRef","useState","useResolvedTheme","useId","jsx","useState","useEffect","useLayoutEffect","jsx","jsxs","SUBMENU_GAP","useState","useEffect","useLayoutEffect","useLayoutEffect","useState","useCallback","jsx","jsxs","useResolvedTheme","useId","useState","useRef","useCallback","useEffect","useLayoutEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-context-menu",
3
- "version": "0.183.0",
3
+ "version": "0.185.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,15 +13,15 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-checkbox": "0.183.0",
17
- "@xsolla/xui-core": "0.183.0",
18
- "@xsolla/xui-divider": "0.183.0",
19
- "@xsolla/xui-icons": "0.183.0",
20
- "@xsolla/xui-icons-base": "0.183.0",
21
- "@xsolla/xui-primitives-core": "0.183.0",
22
- "@xsolla/xui-radio": "0.183.0",
23
- "@xsolla/xui-spinner": "0.183.0",
24
- "@xsolla/xui-typography": "0.183.0"
16
+ "@xsolla/xui-checkbox": "0.185.0",
17
+ "@xsolla/xui-core": "0.185.0",
18
+ "@xsolla/xui-divider": "0.185.0",
19
+ "@xsolla/xui-icons": "0.185.0",
20
+ "@xsolla/xui-icons-base": "0.185.0",
21
+ "@xsolla/xui-primitives-core": "0.185.0",
22
+ "@xsolla/xui-radio": "0.185.0",
23
+ "@xsolla/xui-spinner": "0.185.0",
24
+ "@xsolla/xui-typography": "0.185.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": ">=16.8.0",
package/web/index.d.mts CHANGED
@@ -87,6 +87,11 @@ interface ContextMenuProps extends ThemeOverrideProps {
87
87
  emptyMessage?: string;
88
88
  empty?: ReactNode;
89
89
  trigger?: ReactNode;
90
+ /**
91
+ * When `true`, the trigger fills the full width of its parent instead of
92
+ * shrinking to its content width. Defaults to `false`.
93
+ */
94
+ triggerFullWidth?: boolean;
90
95
  /**
91
96
  * Menu placement relative to the trigger element. The `*-center` variants
92
97
  * horizontally center the panel on the trigger; every variant auto-flips on
@@ -95,6 +100,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
95
100
  * when `position` is set). Defaults to `"bottom-start"`.
96
101
  */
97
102
  placement?: ContextMenuPlacement;
103
+ /**
104
+ * Gap in pixels between the trigger and the menu. When `withArrow` is set
105
+ * this is measured to the arrow's tip; otherwise to the panel edge. Only
106
+ * applies to trigger-anchored menus (ignored when `position` is set).
107
+ * Defaults to `4`.
108
+ */
109
+ offset?: number;
98
110
  position?: ContextMenuPosition;
99
111
  isOpen?: boolean;
100
112
  onOpenChange?: (open: boolean) => void;
@@ -174,6 +186,7 @@ declare const useContextMenuRequired: () => ContextMenuContextValue;
174
186
  interface UseContextMenuPositionOptions {
175
187
  triggerRef: RefObject<HTMLElement | null>;
176
188
  panelRef: RefObject<HTMLElement | null>;
189
+ containerRef: RefObject<HTMLElement | null>;
177
190
  isOpen: boolean;
178
191
  placement?: ContextMenuPlacement;
179
192
  offset?: number;
@@ -183,6 +196,6 @@ interface ResolvedPosition {
183
196
  left: number;
184
197
  placement: ContextMenuPlacement;
185
198
  }
186
- declare const useContextMenuPosition: ({ triggerRef, panelRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
199
+ declare const useContextMenuPosition: ({ triggerRef, panelRef, containerRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
187
200
 
188
201
  export { ContextMenu, ContextMenuContext, type ContextMenuContextValue, type ContextMenuDividerItemProps, type ContextMenuHeadingItemProps, ContextMenuItem, type ContextMenuItemProps, type ContextMenuOptionItemProps, type ContextMenuPlacement, type ContextMenuPosition, type ContextMenuPresetType, type ContextMenuProps, type ContextMenuSearchItemProps, type ContextMenuSize, type ContextMenuSizing, ContextMenuSubmenu, type ContextMenuSubmenuProps, useContextMenu, useContextMenuPosition, useContextMenuRequired, useKeyboardNavigation };
package/web/index.d.ts CHANGED
@@ -87,6 +87,11 @@ interface ContextMenuProps extends ThemeOverrideProps {
87
87
  emptyMessage?: string;
88
88
  empty?: ReactNode;
89
89
  trigger?: ReactNode;
90
+ /**
91
+ * When `true`, the trigger fills the full width of its parent instead of
92
+ * shrinking to its content width. Defaults to `false`.
93
+ */
94
+ triggerFullWidth?: boolean;
90
95
  /**
91
96
  * Menu placement relative to the trigger element. The `*-center` variants
92
97
  * horizontally center the panel on the trigger; every variant auto-flips on
@@ -95,6 +100,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
95
100
  * when `position` is set). Defaults to `"bottom-start"`.
96
101
  */
97
102
  placement?: ContextMenuPlacement;
103
+ /**
104
+ * Gap in pixels between the trigger and the menu. When `withArrow` is set
105
+ * this is measured to the arrow's tip; otherwise to the panel edge. Only
106
+ * applies to trigger-anchored menus (ignored when `position` is set).
107
+ * Defaults to `4`.
108
+ */
109
+ offset?: number;
98
110
  position?: ContextMenuPosition;
99
111
  isOpen?: boolean;
100
112
  onOpenChange?: (open: boolean) => void;
@@ -174,6 +186,7 @@ declare const useContextMenuRequired: () => ContextMenuContextValue;
174
186
  interface UseContextMenuPositionOptions {
175
187
  triggerRef: RefObject<HTMLElement | null>;
176
188
  panelRef: RefObject<HTMLElement | null>;
189
+ containerRef: RefObject<HTMLElement | null>;
177
190
  isOpen: boolean;
178
191
  placement?: ContextMenuPlacement;
179
192
  offset?: number;
@@ -183,6 +196,6 @@ interface ResolvedPosition {
183
196
  left: number;
184
197
  placement: ContextMenuPlacement;
185
198
  }
186
- declare const useContextMenuPosition: ({ triggerRef, panelRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
199
+ declare const useContextMenuPosition: ({ triggerRef, panelRef, containerRef, isOpen, placement, offset, }: UseContextMenuPositionOptions) => ResolvedPosition | undefined;
187
200
 
188
201
  export { ContextMenu, ContextMenuContext, type ContextMenuContextValue, type ContextMenuDividerItemProps, type ContextMenuHeadingItemProps, ContextMenuItem, type ContextMenuItemProps, type ContextMenuOptionItemProps, type ContextMenuPlacement, type ContextMenuPosition, type ContextMenuPresetType, type ContextMenuProps, type ContextMenuSearchItemProps, type ContextMenuSize, type ContextMenuSizing, ContextMenuSubmenu, type ContextMenuSubmenuProps, useContextMenu, useContextMenuPosition, useContextMenuRequired, useKeyboardNavigation };