@xsolla/xui-context-menu 0.181.0 → 0.182.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 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;\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 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 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 triggerNode =\n trigger && isValidElement(trigger) ? (\n cloneElement(trigger as React.ReactElement<any>, {\n ref: assignTriggerRef,\n \"aria-haspopup\": \"menu\",\n \"aria-expanded\": isOpen ? \"true\" : \"false\",\n onClick: (event: React.MouseEvent) => {\n trigger.props.onClick?.(event);\n if (!event.defaultPrevented) toggleMenu();\n },\n })\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={positioned?.placement ?? placement}\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: \"0 4px 12px rgba(0,0,0,0.15)\",\n maxHeight,\n overflowY: \"auto\",\n outline: \"none\",\n }}\n >\n {renderContent()}\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\" } => {\n const [vertical, horizontal] = placement.split(\"-\") as [\n \"top\" | \"bottom\",\n \"start\" | \"end\",\n ];\n return { vertical, horizontal };\n};\n\nconst joinPlacement = (\n vertical: \"top\" | \"bottom\",\n horizontal: \"start\" | \"end\"\n): ContextMenuPlacement => `${vertical}-${horizontal}` as ContextMenuPlacement;\n\nexport const useContextMenuPosition = ({\n triggerRef,\n panelRef,\n isOpen,\n placement = \"bottom-start\",\n offset = 4,\n}: UseContextMenuPositionOptions): ResolvedPosition | undefined => {\n const [resolved, setResolved] = useState<ResolvedPosition | undefined>();\n\n useEffect(() => {\n if (!isOpen) {\n setResolved(undefined);\n return;\n }\n\n const compute = () => {\n const trigger = triggerRef.current;\n const panel = panelRef.current;\n if (!trigger || !panel) return;\n\n const triggerRect = trigger.getBoundingClientRect();\n const panelRect = panel.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let { vertical, horizontal } = splitPlacement(placement);\n\n const computeTop = (v: \"top\" | \"bottom\") =>\n v === \"bottom\"\n ? triggerRect.bottom + offset\n : triggerRect.top - panelRect.height - offset;\n\n const computeLeft = (h: \"start\" | \"end\") =>\n h === \"start\" ? triggerRect.left : triggerRect.right - panelRect.width;\n\n let top = computeTop(vertical);\n const wantedBottom = top + panelRect.height;\n if (top < 0 || wantedBottom > viewportHeight) {\n const flipped = vertical === \"bottom\" ? \"top\" : \"bottom\";\n const flippedTop = computeTop(flipped);\n const flippedBottom = flippedTop + panelRect.height;\n if (flippedTop >= 0 && flippedBottom <= viewportHeight) {\n vertical = flipped;\n top = flippedTop;\n }\n }\n\n let left = computeLeft(horizontal);\n const wantedRight = left + panelRect.width;\n if (left < 0 || wantedRight > viewportWidth) {\n const flipped = horizontal === \"start\" ? \"end\" : \"start\";\n const flippedLeft = computeLeft(flipped);\n const flippedRight = flippedLeft + panelRect.width;\n if (flippedLeft >= 0 && flippedRight <= viewportWidth) {\n horizontal = flipped;\n left = flippedLeft;\n }\n }\n\n 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;\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":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAAA;AAAA,EACA,aAAAC;AAAA,EACA,mBAAAC;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;;;ACTP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AA2ID;AAxIC,IAAM,MAA0B,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,oBAAoB,CAAC,aAAkC;AAAA,IAC3D,iBACE,WAAW,YAAY,kBACnB,WAAW,kBACX;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI;AAAA,EACN;AAEA,QAAM,cAAc,cAAc;AAIlC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb;AAAA,IACA,eAAe;AAAA,IACf,GAAG;AAAA,EACL,IAAI;AAGJ,MAAI,OAAO,SAAS,KAAK;AACvB,UAAM,aAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI;AAAA,IACN;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,EAAE,KAAK,IAAI;AAAA,QACnB,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,YAAW;AAAA,QACV,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,CAAC,EAAE,QAAQ,MAAM,kBAAkB,OAAO;AAAA,QACjD,QAAQ;AAAA,QACP,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,kBAAkB;AAAA,MACzB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;;;ADnLA,SAAS,oBAAAC,mBAAkB,SAAAC,cAAa;AACxC,SAAS,eAAe;;;AEdxB,SAAS,eAAe,kBAAkB;AAGnC,IAAM,qBAAqB,cAEhC,MAAS;AAEJ,IAAM,iBAAiB,MAAM;AAClC,QAAM,UAAU,WAAW,kBAAkB;AAC7C,SAAO;AACT;AAEO,IAAM,yBAAyB,MAAM;AAC1C,QAAM,UAAU,WAAW,kBAAkB;AAC7C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;ACpBA,OAAO,SAAS,WAAW,iBAAiB,gBAAgB;AAC5D,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,cAAc;AA2Ee,gBAAAC,MAgXhC,YAhXgC;AAzDtC,IAAM,iBAGF;AAAA,EACF,IAAI,EAAE,OAAO,UAAU,aAAa,UAAU,eAAe,eAAe;AAAA,EAC5E,IAAI,EAAE,OAAO,UAAU,aAAa,UAAU,eAAe,eAAe;AAAA,EAC5E,IAAI,EAAE,OAAO,UAAU,aAAa,UAAU,eAAe,eAAe;AAAA,EAC5E,IAAI,EAAE,OAAO,UAAU,aAAa,UAAU,eAAe,eAAe;AAC9E;AAEA,IAAM,oBAEF;AAAA,EACF,IAAI,EAAE,UAAU,IAAI,YAAY,OAAO;AACzC;AAEA,IAAM,cAAc;AACpB,IAAM,2BAA2B;AAEjC,IAAM,gBAAgB,CAAC,UAA+B;AACpD,SAAO,4BAA4B;AAAA,IACjC,GAAG,MAAM,QAAQ,GAAG,MAAM,SAAS,GAAG,MAAM,SAAS;AAAA,EACvD;AACF;AAEA,IAAM,qBAAqB,CAAC,SAAsB;AAChD,QAAM,WAAW;AAAA,IACf,KAAK;AAAA,IACL,OAAO,OAAO,aAAa;AAAA,IAC3B,QAAQ,OAAO,cAAc;AAAA,IAC7B,MAAM;AAAA,EACR;AAEA,MAAI,UAAU,KAAK;AACnB,SAAO,WAAW,YAAY,SAAS,MAAM;AAC3C,UAAM,QAAQ,OAAO,iBAAiB,OAAO;AAC7C,QAAI,cAAc,KAAK,KAAK,QAAQ,aAAa,MAAM,MAAM,QAAQ;AACnE,YAAM,OAAO,QAAQ,sBAAsB;AAC3C,aAAO;AAAA,QACL,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,MAAM,wBAAwB;AAAA,QAC/D,OAAO,KAAK,IAAI,SAAS,OAAO,KAAK,QAAQ,wBAAwB;AAAA,QACrE,QAAQ,KAAK;AAAA,UACX,SAAS;AAAA,UACT,KAAK,SAAS;AAAA,QAChB;AAAA,QACA,MAAM,KAAK,IAAI,SAAS,MAAM,KAAK,OAAO,wBAAwB;AAAA,MACpE;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;AAIO,IAAM,kBAAmC,CAAC,UAAU;AACzD,MAAI,MAAM,SAAS,SAAU,QAAO,gBAAAA,KAAC,cAAY,GAAG,OAAO;AAC3D,MAAI,MAAM,SAAS,UAAW,QAAO,gBAAAA,KAAC,eAAa,GAAG,OAAO;AAC7D,MAAI,MAAM,SAAS,UAAW,QAAO,gBAAAA,KAAC,eAAa,GAAG,OAAO;AAC7D,MAAI,MAAM,SAAS,SAAU,QAAO,gBAAAA,KAAC,cAAY,GAAG,OAAO;AAC3D,SAAO;AACT;AAEA,gBAAgB,cAAc;AAE9B,IAAM,iBAA4D,CAAC;AAAA,EACjE;AAAA,EACA;AACF,MACE,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC,eAAY;AAAA,IACZ,eAAY;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,IAEA,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,OAAM;AAAA,QAEN,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA,IACF;AAAA;AACF;AAGF,IAAM,aAAwE,CAAC;AAAA,EAC7E,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MAAM;AACJ,QAAM,EAAE,OAAO,SAAS,IAAI,iBAAiB;AAAA,IAC3C;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,QAAQ;AACd,QAAM,MAAM,eAAe;AAC3B,QAAM,OAAwB,YAAY,KAAK,QAAQ;AACvD,QAAM,SAAS,MAAM,OAAO,YAAY,IAAI;AAC5C,QAAM,WAAW,eAAe,IAAI;AAEpC,QAAM,KAAK,MAAM;AACjB,QAAM,eAAe,KAAK;AAC1B,QAAM,iBAAiB,KAAK;AAC5B,QAAM,eAAe,KAAK;AAC1B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,CAAC,YAAY,aAAa,IAAI,SAG1B,IAAI;AACd,QAAM,YAAY,MAAM,OAA8B,IAAI;AAC1D,QAAM,oBAAoB,MAAM,OAA8B,IAAI;AAClE,QAAM,gBAAgB,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,cAAc,SAAS;AACzB,mBAAa,cAAc,OAAO;AAClC,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM;AAC1B,gBAAY;AACZ,kBAAc,UAAU,WAAW,MAAM,eAAe,KAAK,GAAG,GAAG;AAAA,EACrE;AAEA,YAAU,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvC,YAAU,MAAM;AACd,QAAI,CAAC,cAAc,CAAC,YAAa;AACjC,UAAM,cAAc,CAAC,MAAkB;AACrC,YAAM,SAAS,EAAE;AACjB,UAAI,CAAC,OAAQ;AACb,YAAM,WAAW,UAAU,SAAS,SAAS,MAAM;AACnD,YAAM,YAAY,kBAAkB,SAAS,SAAS,MAAM;AAC5D,UAAI,CAAC,YAAY,CAAC,WAAW;AAC3B,uBAAe,KAAK;AACpB;AAAA,MACF;AACA,UACE,aACA,OAAO;AAAA,QACL;AAAA,MACF,GACA;AACA,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AACA,aAAS,iBAAiB,aAAa,WAAW;AAClD,WAAO,MAAM,SAAS,oBAAoB,aAAa,WAAW;AAAA,EACpE,GAAG,CAAC,YAAY,WAAW,CAAC;AAE5B,kBAAgB,MAAM;AACpB,QAAI,CAAC,cAAc,CAAC,aAAa;AAC/B,oBAAc,IAAI;AAClB;AAAA,IACF;AAEA,UAAM,SAAS,MAAM;AACnB,YAAM,OAAO,UAAU;AACvB,UAAI,CAAC,KAAM;AACX,YAAM,OAAO,KAAK,sBAAsB;AACxC,YAAM,cAAc,kBAAkB,SAAS,sBAAsB;AACrE,YAAM,eAAe,aAAa,SAAS;AAC3C,YAAM,gBAAgB,aAAa,UAAU;AAC7C,YAAM,WAAW,mBAAmB,IAAI;AAExC,YAAM,gBAAgB,KAAK,QAAQ;AACnC,YAAM,eAAe,KAAK,OAAO,cAAc;AAC/C,YAAM,YACJ,eAAe,KAAK,gBAAgB,eAAe,SAAS;AAE9D,UAAI,OAAO,YAAY,eAAe;AAEtC,UAAI,eAAe,GAAG;AACpB,YAAI,WAAW;AACb,iBAAO,KAAK,IAAI,0BAA0B,IAAI;AAAA,QAChD,OAAO;AACL,iBAAO,KAAK;AAAA,YACV,KAAK,IAAI,SAAS,MAAM,IAAI;AAAA,YAC5B,KAAK,IAAI,SAAS,MAAM,SAAS,QAAQ,YAAY;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,KAAK;AACf,UAAI,gBAAgB,KAAK,MAAM,gBAAgB,SAAS,QAAQ;AAC9D,cAAM,SAAS,SAAS;AAAA,MAC1B;AACA,YAAM,KAAK,IAAI,SAAS,KAAK,GAAG;AAEhC;AAAA,QAAc,CAAC,SACb,MAAM,QAAQ,OAAO,KAAK,SAAS,OAAO,OAAO,EAAE,KAAK,KAAK;AAAA,MAC/D;AAAA,IACF;AAEA,WAAO;AACP,WAAO,iBAAiB,UAAU,QAAQ,IAAI;AAC9C,WAAO,iBAAiB,UAAU,MAAM;AACxC,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,QAAQ,IAAI;AACjD,aAAO,oBAAoB,UAAU,MAAM;AAAA,IAC7C;AAAA,EACF,CAAC;AACD,QAAM,cAAc,MAAM,OAAO,QAAQ;AACzC,cAAY,UAAU;AAMtB,YAAU,MAAM;AACd,QAAI,CAAC,gBAAgB,CAAC,eAAgB;AACtC,iBAAa,IAAI;AAAA,MACf,MAAM;AAAA,MACN,UAAU,MAAM,YAAY,UAAU;AAAA,IACxC,CAAC;AACD,WAAO,MAAM,eAAe,EAAE;AAAA,EAChC,GAAG,CAAC,cAAc,gBAAgB,EAAE,CAAC;AAGrC,YAAU,MAAM;AACd,QAAI,CAAC,aAAc;AACnB,iBAAa,IAAI;AAAA,MACf,MAAM;AAAA,MACN;AAAA,MACA,UAAU,MAAM,YAAY,UAAU;AAAA,IACxC,CAAC;AAAA,EACH,GAAG,CAAC,cAAc,IAAI,QAAQ,CAAC;AAI/B,QAAM,QAAQ,eAAe,aAAa,EAAE,IAAI;AAChD,QAAM,WAAW,MAAM,SAAS,KAAK,IAAI,gBAAgB,QAAQ;AACjE,QAAM,eACJ,YAAa,CAAC,OAAO,aAAe,cAAc;AAEpD,QAAM,cAAc,MAAM;AACxB,QAAI,SAAU;AACd,QAAI,OAAO,SAAS,EAAG,KAAI,eAAe,KAAK;AAC/C,QAAI,CAAC,IAAK,cAAa,IAAI;AAC3B,QAAI,WAAY,gBAAe,IAAI;AAAA,EACrC;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,CAAC,IAAK,cAAa,KAAK;AAC5B,QAAI,WAAY,eAAc;AAAA,EAChC;AAEA,QAAM,aAAa,WACf,MAAM,OAAO,QAAQ,MAAM,cAC3B,cACE,MAAM,OAAO,QAAQ,MAAM,UAC3B,MAAM,OAAO,QAAQ;AAE3B,QAAM,KAAK,eAAe,MAAM,OAAO,QAAQ,MAAM,UAAU;AAE/D,QAAM,OACJ,CAAC,cAAc,YAAY,SACvB,mBAAmB,UACjB,kBACA,qBACF;AACN,QAAM,cACJ,CAAC,cAAc,YAAY,SACvB,UACE,SACA,UACF;AAEN,QAAM,cAAc,MAAM;AACxB,QAAI,SAAU;AACd,QAAI,YAAY;AACd,qBAAe,IAAI;AACnB;AAAA,IACF;AACA,QAAI,YAAY,QAAW;AACzB,wBAAkB,CAAC,OAAO;AAAA,IAC5B;AACA,eAAW;AAAA,EACb;AAEA,QAAM,uBAAuB,MAAM;AACjC,mBAAe,KAAK;AACpB,cAAU,SAAS,MAAM;AAAA,EAC3B;AAEA,QAAM,gBAAgB,CAAC,MAA2B;AAChD,QAAI,UAAU;AACZ,UAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,IAAK,GAAE,eAAe;AACzD;AAAA,IACF;AACA,QAAI,YAAY;AACd,UAAI,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,SAAS;AAC/C,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,uBAAe,IAAI;AACnB;AAAA,MACF;AACA,UAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,UAAU;AAC/C,YAAI,aAAa;AACf,YAAE,eAAe;AACjB,YAAE,gBAAgB;AAClB,+BAAqB;AACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,UAAI,YAAY,QAAW;AACzB,0BAAkB,CAAC,OAAO;AAAA,MAC5B;AACA,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,gBAAc;AAAA,MACd,iBAAe,WAAW,SAAS;AAAA,MACnC,iBAAe,aAAa,SAAS;AAAA,MACrC,iBAAe,aAAc,cAAc,SAAS,UAAW;AAAA,MAC/D,UAAU;AAAA,MACV,eAAa,UAAU;AAAA,MACvB,cAAY,eAAe,UAAU;AAAA,MACrC,oBAAkB,cAAc,SAAS;AAAA,MACzC,qBAAmB;AAAA,MACnB,cAAc,MAAM;AAClB,oBAAY;AACZ,oBAAY;AAAA,MACd;AAAA,MACA,cAAc;AAAA,MACd,SAAS;AAAA,MACT,QAAQ,MAAM;AACZ,YAAI,CAAC,IAAK,cAAa,KAAK;AAAA,MAC9B;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,OAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,KAAK,OAAO;AAAA,QACZ,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,eAAe,OAAO;AAAA,QACtB,iBAAiB;AAAA,QACjB,QAAQ,WAAW,gBAAgB;AAAA,QACnC,SAAS;AAAA,MACX;AAAA,MAEC;AAAA,2BAAmB,cAClB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,eAAY;AAAA,YACZ,OAAO,EAAE,eAAe,QAAQ,SAAS,cAAc;AAAA,YAEvD,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,SAAS,CAAC,CAAC;AAAA,gBACX,UAAU,CAAC,CAAC;AAAA,gBACZ;AAAA,gBACA;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA,QAED,mBAAmB,WAClB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,eAAY;AAAA,YACZ,OAAO,EAAE,eAAe,QAAQ,SAAS,cAAc;AAAA,YAEvD,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,SAAS,CAAC,CAAC;AAAA,gBACX,UAAU,CAAC,CAAC;AAAA,gBACZ;AAAA,gBACA;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA,QAED;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACD;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,cACT,eAAe;AAAA,cACf,KAAK;AAAA,cACL,UAAU;AAAA,YACZ;AAAA,YAEA;AAAA,8BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,SAAS;AAAA,kBAClB,OAAO;AAAA,kBACP,QAAQ,gBAAgB;AAAA,kBACxB,OAAO;AAAA,oBACL,GAAI,gBAAgB,SAChB,EAAE,SAAS,SAAS,UAAU,EAAE,IAChC,CAAC;AAAA,oBACL,GAAI,kBAAkB,IAAI,KAAK,CAAC;AAAA,kBAClC;AAAA,kBAEC;AAAA;AAAA,cACH;AAAA,cACC,gBAAgB,UACf,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,SAAS;AAAA,kBAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,kBAE3B;AAAA;AAAA,cACH;AAAA;AAAA;AAAA,QAEJ;AAAA,SACE,UAAU,UAAa,SAAS,WAChC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,eAAe;AAAA,cACf,YAAY;AAAA,YACd;AAAA,YAEC;AAAA,wBAAU,UACT,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,SAAS;AAAA,kBAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,kBAC5B,OAAO,kBAAkB,IAAI;AAAA,kBAE5B;AAAA;AAAA,cACH;AAAA,cAED,SAAS,UACR,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,SAAS;AAAA,kBAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,kBAE3B;AAAA;AAAA,cACH;AAAA;AAAA;AAAA,QAEJ;AAAA,QAED,oBACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,SAAS,SAAS;AAAA,YAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,YAE3B;AAAA;AAAA,QACH;AAAA,QAED,cACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,MAAM,OAAO,QAAQ;AAAA,YAC5B,MAAM,OAAO;AAAA;AAAA,QACf;AAAA,QAED;AAAA,QACA,cACC,eACA,WACA,cACA,OAAO,aAAa,eACpB;AAAA,UACE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,gCAA8B,KAAK;AAAA,cACnC,cAAc;AAAA,cACd,cAAc;AAAA,cACd,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK,WAAW;AAAA,gBAChB,MAAM,WAAW;AAAA,gBACjB,QAAQ;AAAA,cACV;AAAA,cAEC;AAAA;AAAA,UACH;AAAA,UACA,SAAS;AAAA,QACX;AAAA;AAAA;AAAA,EACJ;AAEJ;AAEA,IAAM,cAEF,CAAC;AAAA,EACH,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MAAM;AACJ,QAAM,EAAE,OAAO,SAAS,IAAI,iBAAiB;AAAA,IAC3C;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,QAAQ;AACd,QAAM,MAAM,eAAe;AAC3B,QAAM,OAAwB,YAAY,KAAK,QAAQ;AACvD,QAAM,SAAS,MAAM,OAAO,YAAY,IAAI;AAC5C,QAAM,WAAW,eAAe,IAAI;AAEpC,QAAM,KAAK,MAAM;AACjB,QAAM,eAAe,KAAK;AAC1B,QAAM,iBAAiB,KAAK;AAC5B,YAAU,MAAM;AACd,QAAI,CAAC,gBAAgB,CAAC,eAAgB;AACtC,iBAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AACpC,WAAO,MAAM,eAAe,EAAE;AAAA,EAChC,GAAG,CAAC,cAAc,gBAAgB,EAAE,CAAC;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,eAAa,UAAU;AAAA,MACvB,OAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe;AAAA,QACf,KAAK;AAAA,QACL,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,eAAe,OAAO;AAAA,MACxB;AAAA,MAEA;AAAA,wBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,SAAS;AAAA,YAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,YAC5B,OAAO,EAAE,eAAe,aAAa,eAAe,IAAI;AAAA,YAEvD;AAAA;AAAA,QACH;AAAA,QACC,gBAAgB,UACf,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,SAAS;AAAA,YAClB,OAAO,MAAM,OAAO,QAAQ;AAAA,YAE3B;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,IAAM,aAAwE,CAAC;AAAA,EAC7E,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,cAAc,YAAY;AAAA,EAC1B,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,OAAO,SAAS,IAAI,iBAAiB;AAAA,IAC3C;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,QAAQ;AACd,QAAM,MAAM,eAAe;AAC3B,QAAM,OAAwB,YAAY,KAAK,QAAQ;AACvD,QAAM,SAAS,MAAM,OAAO,YAAY,IAAI;AAE5C,QAAM,KAAK,MAAM;AACjB,QAAM,eAAe,KAAK;AAC1B,QAAM,iBAAiB,KAAK;AAC5B,YAAU,MAAM;AACd,QAAI,CAAC,gBAAgB,CAAC,eAAgB;AACtC,iBAAa,IAAI,EAAE,MAAM,SAAS,CAAC;AACnC,WAAO,MAAM,eAAe,EAAE;AAAA,EAChC,GAAG,CAAC,cAAc,gBAAgB,EAAE,CAAC;AAErC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,WAAW;AAAA,QACX,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,YAAY,OAAO;AAAA,QACnB,eAAe,OAAO;AAAA,MACxB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,KAAK;AAAA,YACL,eAAe;AAAA,YACf,cAAc,aAAa,MAAM,OAAO,OAAO,SAAS;AAAA,UAC1D;AAAA,UAEA;AAAA,4BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAM,OAAO;AAAA,gBACb,OAAO,MAAM,OAAO,QAAQ,MAAM;AAAA,gBAClC,eAAW;AAAA;AAAA,YACb;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,cAAY;AAAA,gBACZ;AAAA,gBACA,OAAO,SAAS;AAAA,gBAChB;AAAA,gBACA,UAAU,CAAC,MAAM;AACf,6BAAW,CAAC;AACZ,kCAAgB,EAAE,OAAO,KAAK;AAAA,gBAChC;AAAA,gBACA,eAAa,UAAU;AAAA,gBACvB,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,UAAU;AAAA,kBACV,WAAW;AAAA,kBACX,QAAQ;AAAA,kBACR,SAAS;AAAA,kBACT,YAAY;AAAA,kBACZ,SAAS;AAAA,kBACT,OAAO,MAAM,OAAO,QAAQ;AAAA,kBAC5B,UAAU,OAAO;AAAA,kBACjB,YAAY,GAAG,OAAO,gBAAgB;AAAA,gBACxC;AAAA;AAAA,YACF;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,cAEF,CAAC,EAAE,WAAW,qBAAqB,eAAe,OAAO,MAAM;AACjE,QAAM,EAAE,OAAO,SAAS,IAAI,iBAAiB;AAAA,IAC3C;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,QAAQ;AACd,QAAM,MAAM,eAAe;AAC3B,QAAM,KAAK,MAAM;AACjB,QAAM,eAAe,KAAK;AAC1B,QAAM,iBAAiB,KAAK;AAC5B,YAAU,MAAM;AACd,QAAI,CAAC,gBAAgB,CAAC,eAAgB;AACtC,iBAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AACpC,WAAO,MAAM,eAAe,EAAE;AAAA,EAChC,GAAG,CAAC,cAAc,gBAAgB,EAAE,CAAC;AACrC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,eAAa;AAAA,MACb,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,iBAAiB,MAAM,OAAO,OAAO;AAAA,QACrC,QAAQ;AAAA,MACV;AAAA;AAAA,EACF;AAEJ;;;AC1tBA;AAAA,EACE,YAAAC;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,mBAAAC;AAAA,EACA;AAAA,OACK;AAGP,SAAS,uBAAuB;AAiJ5B,SAOE,OAAAC,MAPF,QAAAC,aAAA;AA3IJ,IAAMC,eAAc;AAEpB,IAAM,gBAAgB;AAEtB,IAAM,iBAAiB;AAGvB,IAAI,oBAAoB;AAEjB,IAAM,qBAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN,eAAe,SAAS;AAC1B,MAAM;AACJ,QAAM,EAAE,MAAM,IAAI,gBAAgB;AAClC,QAAM,WAAW;AACjB,QAAM,UAAU,eAAe;AAC/B,QAAM,OAAO,YAAY,SAAS,QAAQ;AAC1C,QAAM,aAAa,SAAS,OAAO,YAAY,IAAI;AACnD,QAAM,eACJ,SAAS,OAAO,cAAc,IAAI,GAAG,gBACrC,SAAS,QAAQ,UACjB;AAEF,QAAM,eAAe,OAAsB,IAAI;AAC/C,MAAI,aAAa,YAAY,MAAM;AACjC,iBAAa,UAAU,kBAAmB,qBAAqB,CAAE;AAAA,EACnE;AACA,QAAM,YAAY,aAAa;AAE/B,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,KAAK;AAC1C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,CAAC;AAE5C,QAAM,aAAa,OAAuB,IAAI;AAC9C,QAAM,aAAa,OAAuB,IAAI;AAC9C,QAAM,eAAe,OAA6C,IAAI;AACtE,QAAM,gBAAgB,OAA6C,IAAI;AAEvE,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,aAAa,QAAS,cAAa,aAAa,OAAO;AAC3D,QAAI,cAAc,QAAS,cAAa,cAAc,OAAO;AAAA,EAC/D,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,SAAS,gBAAiB;AAC/B,QAAI,QAAQ,oBAAoB,WAAW;AACzC,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,SAAS,iBAAiB,SAAS,CAAC;AAExC,QAAM,qBAAqB,YAAY,MAAM;AAC3C,QAAI,CAAC,WAAW,QAAS;AACzB,UAAM,cAAc,WAAW,QAAQ,sBAAsB;AAC7D,UAAM,iBAAiB,WAAW,WAAW;AAC7C,UAAM,qBACJ,YAAY,QAAQ,iBAAiBF,eAAc,OAAO,aAAa;AAEzE,UAAM,iBACJ,YAAY,OAAOA,eAAc,kBAAkB;AACrD,gBAAY,sBAAsB,cAAc;AAChD,iBAAa,CAAC;AAAA,EAChB,GAAG,CAAC,WAAW,QAAQ,CAAC;AAExB,EAAAG,iBAAgB,MAAM;AACpB,QAAI,CAAC,UAAU,CAAC,WAAW,WAAW,CAAC,WAAW,QAAS;AAE3D,UAAM,cAAc,WAAW,QAAQ,sBAAsB;AAC7D,UAAM,cAAc,WAAW,QAAQ,sBAAsB;AAE7D,UAAM,qBACJ,YAAY,QAAQ,YAAY,QAAQH,eACxC,OAAO,aAAa;AACtB,UAAM,iBACJ,YAAY,OAAOA,eAAc,YAAY,SAAS;AACxD,gBAAY,sBAAsB,cAAc;AAEhD,UAAM,iBACJ,YAAY,MAAM,YAAY,UAAU,OAAO,cAAc;AAC/D,QAAI,iBAAiB,GAAG;AACtB,mBAAa,CAAC,KAAK,IAAI,gBAAgB,YAAY,MAAM,CAAC,CAAC;AAAA,IAC7D,OAAO;AACL,mBAAa,CAAC;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,EAAAE,WAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,UAAM,MAAM,sBAAsB,MAAM,WAAW,IAAI,CAAC;AACxD,WAAO,MAAM,qBAAqB,GAAG;AAAA,EACvC,GAAG,CAAC,MAAM,CAAC;AAEX,EAAAA,WAAU,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,CAAC;AAElD,QAAM,qBAAqB,MAAM;AAC/B,QAAI,SAAU;AACd,gBAAY;AACZ,iBAAa,UAAU,WAAW,MAAM;AACtC,yBAAmB;AACnB,gBAAU,IAAI;AACd,eAAS,mBAAmB,SAAS;AAAA,IACvC,GAAG,aAAa;AAAA,EAClB;AAEA,QAAM,qBAAqB,MAAM;AAC/B,gBAAY;AACZ,kBAAc,UAAU,WAAW,MAAM;AACvC,gBAAU,KAAK;AACf,UAAI,SAAS,oBAAoB,WAAW;AAC1C,gBAAQ,mBAAmB,IAAI;AAAA,MACjC;AAAA,IACF,GAAG,cAAc;AAAA,EACnB;AAEA,QAAM,qBAAqB,MAAM,YAAY;AAE7C,QAAM,qBAAqB,MAAM;AAC/B,gBAAY;AACZ,kBAAc,UAAU,WAAW,MAAM;AACvC,gBAAU,KAAK;AACf,UAAI,SAAS,oBAAoB,WAAW;AAC1C,gBAAQ,mBAAmB,IAAI;AAAA,MACjC;AAAA,IACF,GAAG,cAAc;AAAA,EACnB;AAEA,QAAM,uBAAuB,WACzB,EAAE,OAAO,eAAeF,YAAW,MAAM,IACzC,EAAE,MAAM,eAAeA,YAAW,MAAM;AAE5C,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO,EAAE,UAAU,WAAW;AAAA,MAC9B,cAAc;AAAA,MACd,cAAc;AAAA,MACd,eAAa;AAAA,MAEb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL;AAAA,YACA,aAAa;AAAA,YACb;AAAA,YACA,YAAU;AAAA,YACV;AAAA,YACA,eAAa,GAAG,MAAM;AAAA;AAAA,QACxB;AAAA,QAEC,UACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,cAAc;AAAA,YACd,cAAc;AAAA,YACd,OAAO;AAAA,cACL,UAAU;AAAA,cACV,KAAK;AAAA,cACL,GAAG;AAAA,cACH,QAAQ;AAAA,cACR,SAAS,UAAU,IAAI;AAAA,cACvB,WAAW,UACP,kBACA,WACE,oBACA;AAAA,cACN,YAAY;AAAA,YACd;AAAA,YACA,eAAa,GAAG,MAAM;AAAA,YAEtB,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,iBAAiB,SAAS,OAAO,WAAW;AAAA,gBAC5C,aAAa,SAAS,OAAO,OAAO;AAAA,gBACpC,aAAa;AAAA,gBACb;AAAA,gBACA,iBAAiB,WAAW;AAAA,gBAC5B,OAAO;AAAA,kBACL,WAAW;AAAA,kBACX,UAAU,WAAW;AAAA,gBACvB;AAAA,gBAEC;AAAA;AAAA,YACH;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,mBAAmB,cAAc;;;ACnNjC,SAAS,aAAAM,YAAW,YAAAC,iBAAgC;AAiBpD,IAAM,iBAAiB,CACrB,cAC2E;AAC3E,QAAM,CAAC,UAAU,UAAU,IAAI,UAAU,MAAM,GAAG;AAIlD,SAAO,EAAE,UAAU,WAAW;AAChC;AAEA,IAAM,gBAAgB,CACpB,UACA,eACyB,GAAG,QAAQ,IAAI,UAAU;AAE7C,IAAM,yBAAyB,CAAC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AACX,MAAmE;AACjE,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAuC;AAEvE,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,kBAAY,MAAS;AACrB;AAAA,IACF;AAEA,UAAM,UAAU,MAAM;AACpB,YAAM,UAAU,WAAW;AAC3B,YAAM,QAAQ,SAAS;AACvB,UAAI,CAAC,WAAW,CAAC,MAAO;AAExB,YAAM,cAAc,QAAQ,sBAAsB;AAClD,YAAM,YAAY,MAAM,sBAAsB;AAC9C,YAAM,gBAAgB,OAAO;AAC7B,YAAM,iBAAiB,OAAO;AAE9B,UAAI,EAAE,UAAU,WAAW,IAAI,eAAe,SAAS;AAEvD,YAAM,aAAa,CAAC,MAClB,MAAM,WACF,YAAY,SAAS,SACrB,YAAY,MAAM,UAAU,SAAS;AAE3C,YAAM,cAAc,CAAC,MAAkC;AACrD,YAAI,MAAM;AACR,iBAAO,YAAY,OAAO,YAAY,QAAQ,IAAI,UAAU,QAAQ;AACtE,eAAO,MAAM,UACT,YAAY,OACZ,YAAY,QAAQ,UAAU;AAAA,MACpC;AAEA,UAAI,MAAM,WAAW,QAAQ;AAC7B,YAAM,eAAe,MAAM,UAAU;AACrC,UAAI,MAAM,KAAK,eAAe,gBAAgB;AAC5C,cAAM,UAAU,aAAa,WAAW,QAAQ;AAChD,cAAM,aAAa,WAAW,OAAO;AACrC,cAAM,gBAAgB,aAAa,UAAU;AAC7C,YAAI,cAAc,KAAK,iBAAiB,gBAAgB;AACtD,qBAAW;AACX,gBAAM;AAAA,QACR;AAAA,MACF;AAEA,UAAI,OAAO,YAAY,UAAU;AACjC,UAAI,eAAe,UAAU;AAE3B,cAAM,UAAU,gBAAgB,UAAU;AAC1C,eAAO,WAAW,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,CAAC,GAAG,OAAO,IAAI;AAAA,MAC/D,OAAO;AACL,cAAM,cAAc,OAAO,UAAU;AACrC,YAAI,OAAO,KAAK,cAAc,eAAe;AAC3C,gBAAM,UAAU,eAAe,UAAU,QAAQ;AACjD,gBAAM,cAAc,YAAY,OAAO;AACvC,gBAAM,eAAe,cAAc,UAAU;AAC7C,cAAI,eAAe,KAAK,gBAAgB,eAAe;AACrD,yBAAa;AACb,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAEA,YAAM,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA,WAAW,cAAc,UAAU,UAAU;AAAA,MAC/C;AACA;AAAA,QAAY,CAAC,SACX,QACA,KAAK,QAAQ,KAAK,OAClB,KAAK,SAAS,KAAK,QACnB,KAAK,cAAc,KAAK,YACpB,OACA;AAAA,MACN;AAAA,IACF;AAEA,UAAM,QAAQ,OAAO,sBAAsB,OAAO;AAIlD,UAAM,WAAW,MAAM,QAAQ;AAC/B,WAAO,iBAAiB,UAAU,QAAQ;AAE1C,WAAO,MAAM;AACX,aAAO,qBAAqB,KAAK;AACjC,aAAO,oBAAoB,UAAU,QAAQ;AAAA,IAC/C;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,QAAQ,YAAY,QAAQ,CAAC;AAEpD,SAAO;AACT;;;ACnIA,SAAS,eAAAE,oBAAmC;AAmB5C,IAAM,oBAAoB,CAAC,SACzB,KAAK,SAAS,YAAY,CAAC,KAAK;AAElC,IAAM,oBAAoB,CAAC,WAAwC;AACjE,MAAI,EAAE,kBAAkB,aAAc,QAAO;AAC7C,MAAI,OAAO,YAAY,WAAW,OAAO,YAAY,WAAY,QAAO;AACxE,SAAO,OAAO,aAAa,MAAM,MAAM;AACzC;AAEO,IAAM,wBAAwB,CAAC;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAoC;AAClC,QAAM,kBAAkBA,aAAY,MAAM;AACxC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,UAAI,kBAAkB,MAAM,CAAC,EAAE,IAAI,EAAG,QAAO;AAAA,IAC/C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBAAiBA,aAAY,MAAM;AACvC,aAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;AAC7C,UAAI,kBAAkB,MAAM,CAAC,EAAE,IAAI,EAAG,QAAO;AAAA,IAC/C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,iBAAiBA;AAAA,IACrB,CAAC,SAAiB;AAChB,YAAM,MAAM,MAAM;AAClB,UAAI,QAAQ,EAAG,QAAO;AACtB,eAAS,OAAO,GAAG,QAAQ,KAAK,QAAQ,GAAG;AACzC,cAAM,OAAO,OAAO,OAAO,OAAO;AAClC,YAAI,kBAAkB,MAAM,GAAG,EAAE,IAAI,EAAG,QAAO;AAAA,MACjD;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,iBAAiBA;AAAA,IACrB,CAAC,SAAiB;AAChB,YAAM,MAAM,MAAM;AAClB,UAAI,QAAQ,EAAG,QAAO;AACtB,eAAS,OAAO,GAAG,QAAQ,KAAK,QAAQ,GAAG;AACzC,cAAM,OAAO,OAAO,OAAO,MAAM,KAAK;AACtC,YAAI,kBAAkB,MAAM,GAAG,EAAE,IAAI,EAAG,QAAO;AAAA,MACjD;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,gBAAgBA;AAAA,IACpB,CAAC,UAA+B;AAC9B,UAAI,CAAC,OAAQ;AAEb,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,eAAe;AACrB,gBAAM,OACJ,cAAc,IAAI,gBAAgB,IAAI,eAAe,WAAW;AAClE,cAAI,QAAQ,EAAG,gBAAe,IAAI;AAClC;AAAA,QACF;AAAA,QACA,KAAK,WAAW;AACd,gBAAM,eAAe;AACrB,gBAAM,OACJ,cAAc,IAAI,eAAe,IAAI,eAAe,WAAW;AACjE,cAAI,QAAQ,EAAG,gBAAe,IAAI;AAClC;AAAA,QACF;AAAA,QACA,KAAK,QAAQ;AACX,gBAAM,eAAe;AACrB,gBAAM,QAAQ,gBAAgB;AAC9B,cAAI,SAAS,EAAG,gBAAe,KAAK;AACpC;AAAA,QACF;AAAA,QACA,KAAK,OAAO;AACV,gBAAM,eAAe;AACrB,gBAAM,OAAO,eAAe;AAC5B,cAAI,QAAQ,EAAG,gBAAe,IAAI;AAClC;AAAA,QACF;AAAA,QACA,KAAK;AAAA,QACL,KAAK,KAAK;AACR,cAAI,MAAM,iBAAkB;AAC5B,cAAI,MAAM,QAAQ,OAAO,kBAAkB,MAAM,MAAM,EAAG;AAC1D,cAAI,MAAM,QAAQ,IAAK,OAAM,eAAe;AAC5C,cAAI,eAAe,KAAK,cAAc,MAAM,QAAQ;AAClD,kBAAM,OAAO,MAAM,WAAW,EAAE;AAChC,gBAAI,kBAAkB,IAAI,EAAG,MAAK,WAAW;AAAA,UAC/C;AACA;AAAA,QACF;AAAA,QACA,KAAK,UAAU;AACb,gBAAM,eAAe;AACrB,kBAAQ;AACR,sBAAY,SAAS,MAAM;AAC3B;AAAA,QACF;AAAA,QACA,KAAK,OAAO;AACV,kBAAQ;AACR;AAAA,QACF;AAAA,QACA;AACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,cAAc;AACzB;;;ANsNU,SA8LM,UA9LN,OAAAC,MA8LM,QAAAC,aA9LN;AAtSV,IAAM,wBAAwB;AAC9B,IAAM,qBAAqB;AAC3B,IAAM,aAAa;AACnB,IAAM,aAAa,aAAa;AAChC,IAAM,oBAAoB;AAC1B,IAAM,eAAe;AAErB,IAAM,eAAe,CAAC,SAAkC;AACtD,MAAI,SAAS,QAAQ,SAAS,UAAa,OAAO,SAAS;AACzD,WAAO;AACT,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,SAAU,QAAO,OAAO,IAAI;AAC5E,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO,KAAK,IAAI,YAAY,EAAE,KAAK,GAAG;AAC/D,MAAI,eAAe,IAAI,EAAG,QAAO,aAAa,KAAK,MAAM,QAAQ;AACjE,SAAO;AACT;AAEA,IAAM,cAAc,CAClB,OACA,UAC2B;AAC3B,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,MAAI,CAAC,WAAY,QAAO,CAAC,GAAG,KAAK;AAEjC,QAAM,SAAiC,CAAC;AACxC,MAAI,oBAA4C,CAAC;AAEjD,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,UAAU;AAC1B,YAAM,QAAQ,aAAa,KAAK,KAAK,EAAE,YAAY;AACnD,UAAI,MAAM,SAAS,UAAU,GAAG;AAC9B,eAAO,KAAK,GAAG,mBAAmB,IAAI;AACtC,4BAAoB,CAAC;AAAA,MACvB;AACA;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,WAAW;AAC3B,0BAAoB,CAAC,IAAI;AACzB;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,WAAW;AAC3B,UAAI,OAAO,SAAS,EAAG,mBAAkB,KAAK,IAAI;AAClD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,WAAW,CACf,SACuC,KAAK,SAAS;AAEvD,IAAM,kBAAkB;AAAA,EACtB,CACE;AAAA,IACE;AAAA,IACA,OAAO;AAAA,IACP,QAAQ,CAAC;AAAA,IACT,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,QACG;AACH,UAAM,EAAE,OAAO,SAAS,IAAIC,kBAAiB;AAAA,MAC3C;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,WAAW;AACjB,UAAM,SAASC,OAAM;AACrB,UAAM,CAAC,gBAAgB,iBAAiB,IAAIC,UAAS,KAAK;AAC1D,UAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,EAAE;AACjD,UAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,CAAC;AAClD,UAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AACrC,UAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAAS,EAAE;AACvD,UAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAwB,IAAI;AAC1E,UAAM,eAAeC,QAA8B,IAAI;AACvD,UAAM,aAAaA,QAA2B,IAAI;AAClD,UAAM,WAAWA,QAA2B,IAAI;AAChD,UAAM,WAAWA,QAAoB,CAAC,CAAC;AAEvC,UAAM,SAAS,eAAe,SAAY,aAAa;AACvD,UAAM,aAAa,SAAS,OAAO,YAAY,IAAI;AACnD,UAAM,eAAe,SAAS,OAAO,cAAc,IAAI,GAAG,gBAAgB;AAC1E,UAAM,sBACJ,kBAAkB,SAAS,aAAa,QAAQ;AAElD,UAAM,aAAa,uBAAuB;AAAA,MACxC;AAAA,MACA;AAAA,MACA,QAAQ,UAAU,CAAC,CAAC,WAAW,CAAC;AAAA,MAChC;AAAA,IACF,CAAC;AAED,UAAM,oBACJ,YAAY,aAAa;AAE3B,UAAM,gBAAgB,CACpB,mBACwB;AACxB,YAAM,QAAQ,eAAe,WAAW,KAAK;AAC7C,YAAM,aAAkC;AAAA,QACtC,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,iBAAiB,SAAS,OAAO,WAAW;AAAA,QAC5C,aAAa;AAAA,QACb,aAAa,SAAS,OAAO,OAAO;AAAA;AAAA,QAEpC,aAAa,QAAQ,gBAAgB;AAAA,QACrC,WAAW;AAAA,QACX,eAAe;AAAA,MACjB;AAEA,UAAI,MAAO,YAAW,SAAS,CAAC;AAAA,UAC3B,YAAW,MAAM,CAAC;AAEvB,UAAI,eAAe,SAAS,QAAQ,GAAG;AACrC,mBAAW,OAAO;AAClB,mBAAW,aAAa,CAAC;AAAA,MAC3B,WAAW,eAAe,SAAS,KAAK,GAAG;AACzC,mBAAW,QAAQ;AAAA,MACrB,OAAO;AACL,mBAAW,OAAO;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAEA,UAAM,UAAUC;AAAA,MACd,CAAC,aAAsB;AACrB,YAAI,eAAe,OAAW,mBAAkB,QAAQ;AACxD,uBAAe,QAAQ;AACvB,YAAI,CAAC,SAAU,gBAAe,EAAE;AAAA,MAClC;AAAA,MACA,CAAC,YAAY,YAAY;AAAA,IAC3B;AAEA,UAAM,YAAYA,aAAY,MAAM;AAClC,cAAQ,KAAK;AAAA,IACf,GAAG,CAAC,OAAO,CAAC;AAEZ,UAAM,aAAaA,aAAY,MAAM;AACnC,cAAQ,CAAC,MAAM;AAAA,IACjB,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,UAAM,eAAeA,aAAY,CAAC,IAAY,SAAmB;AAC/D,YAAM,gBAAgB,SAAS,QAAQ;AAAA,QACrC,CAAC,SAAS,KAAK,OAAO;AAAA,MACxB;AACA,UAAI,iBAAiB,GAAG;AACtB,iBAAS,QAAQ,aAAa,IAAI,EAAE,IAAI,KAAK;AAC7C,wBAAgB,CAAC,YAAY,UAAU,CAAC;AACxC,eAAO;AAAA,MACT;AACA,eAAS,QAAQ,KAAK,EAAE,IAAI,KAAK,CAAC;AAClC,sBAAgB,CAAC,YAAY,UAAU,CAAC;AACxC,aAAO,SAAS,QAAQ,SAAS;AAAA,IACnC,GAAG,CAAC,CAAC;AAEL,UAAM,iBAAiBA,aAAY,CAAC,OAAe;AACjD,YAAM,QAAQ,SAAS,QAAQ,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AACjE,UAAI,SAAS,GAAG;AACd,iBAAS,QAAQ,OAAO,OAAO,CAAC;AAChC,wBAAgB,CAAC,YAAY,UAAU,CAAC;AAAA,MAC1C;AAAA,IACF,GAAG,CAAC,CAAC;AAEL,UAAM,eAAeA,aAAY,CAAC,OAAe;AAC/C,aAAO,SAAS,QAAQ,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAAA,IAC5D,GAAG,CAAC,CAAC;AAEL,UAAM,QAAQ,QAAQ,MAAM,CAAC,GAAG,SAAS,OAAO,GAAG,CAAC,YAAY,CAAC;AACjE,UAAM,WAAW,sBAAsB;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAED,IAAAC,WAAU,MAAM;AACd,UAAI,CAAC,QAAQ;AACX,iBAAS,UAAU,CAAC;AACpB,wBAAgB,CAAC,YAAY,UAAU,CAAC;AACxC,iBAAS,EAAE;AACX,0BAAkB,EAAE;AACpB,2BAAmB,IAAI;AAAA,MACzB;AAAA,IACF,GAAG,CAAC,MAAM,CAAC;AAEX,IAAAA,WAAU,MAAM;AACd,YAAM,QAAQ;AAAA,QACZ,MAAM,kBAAkB,KAAK;AAAA,QAC7B;AAAA,MACF;AACA,aAAO,MAAM,aAAa,KAAK;AAAA,IACjC,GAAG,CAAC,KAAK,CAAC;AAEV,IAAAA,WAAU,MAAM;AACd,UAAI,CAAC,UAAU,CAAC,QAAS;AAEzB,YAAM,cAAc,CAAC,UAAsB;AACzC,cAAM,SAAS,MAAM;AACrB,YAAI,CAAC,UAAU,aAAa,SAAS,SAAS,MAAM,EAAG;AACvD,kBAAU;AAAA,MACZ;AAEA,YAAM,WAAW,MAAM,UAAU;AAEjC,eAAS,iBAAiB,aAAa,WAAW;AAClD,aAAO,iBAAiB,UAAU,QAAQ;AAC1C,aAAO,MAAM;AACX,iBAAS,oBAAoB,aAAa,WAAW;AACrD,eAAO,oBAAoB,UAAU,QAAQ;AAAA,MAC/C;AAAA,IACF,GAAG,CAAC,QAAQ,SAAS,SAAS,CAAC;AAE/B,IAAAC,iBAAgB,MAAM;AACpB,UAAI,CAAC,UAAU,CAAC,SAAS,QAAS;AAClC,YAAM,YACJ,SAAS,QAAQ,cAA2B,oBAAoB;AAClE,YAAM,cAAc,SAAS,QAAQ;AAAA,QACnC;AAAA,MACF;AACA,OAAC,aAAa,cAAc,MAAM;AAAA,IACpC,GAAG,CAAC,MAAM,CAAC;AAEX,IAAAA,iBAAgB,MAAM;AACpB,UAAI,CAAC,UAAU,CAAC,SAAS,QAAS;AAClC,YAAM,gBAAgB,SAAS;AAC/B,UAAI,iBAAiB,SAAS,QAAQ,SAAS,aAAa,EAAG;AAC/D,eAAS,QAAQ,MAAM;AAAA,IACzB,GAAG,CAAC,QAAQ,YAAY,CAAC;AAEzB,IAAAD,WAAU,MAAM;AACd,UAAI,OAAQ;AACZ,iBAAW,SAAS,MAAM;AAAA,IAC5B,GAAG,CAAC,MAAM,CAAC;AAEX,UAAM,eAAwC;AAAA,MAC5C,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,mBAAmB,CAAC,MAA4B,UAAkB;AACtE,UAAI,CAAC,SAAS,IAAI,GAAG;AACnB,eACE,gBAAAP;AAAA,UAAC;AAAA;AAAA,YAEE,GAAG;AAAA,YACJ;AAAA,YACA;AAAA;AAAA,UAHK,qBAAqB,KAAK;AAAA,QAIjC;AAAA,MAEJ;AAEA,YAAM,iBACJ,KAAK,mBACJ,SAAS,aACN,aACA,SAAS,UACP,UACA;AAER,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEE,GAAG;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU,MAAM;AACd,iBAAK,WAAW;AAChB,uBAAW,IAAI;AACf,gBAAI,oBAAqB,WAAU;AAAA,UACrC;AAAA;AAAA,QATK,qBAAqB,KAAK;AAAA,MAUjC;AAAA,IAEJ;AAEA,UAAM,gBAAgB,aAClB,YAAY,OAAO,cAAc,IACjC,CAAC,GAAG,KAAK;AAEb,UAAM,gBAAgB,MAAM;AAC1B,UAAI,WAAW,aAAa,SAAS,WAAW;AAC9C,cAAM,aAAa,SAAS,OAAO,QAAQ,MAAM,QAAQ;AACzD,eACE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,YAAW;AAAA,YACX,gBAAe;AAAA,YACf,WAAW;AAAA,YAEX,0BAAAA,KAAC,WAAQ,MAAK,MAAK,OAAO,YAAY;AAAA;AAAA,QACxC;AAAA,MAEJ;AAEA,UAAI,SAAU,QAAO;AAErB,YAAM,UAAU,cAAc,IAAI,gBAAgB;AAClD,UAAI,YAAY;AACd,gBAAQ;AAAA,UACN,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC,eAAY;AAAA,cACZ,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,QAAQ;AAAA,gBACR,iBAAiB,SAAS,OAAO,WAAW;AAAA,cAC9C;AAAA,cAEA,0BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAO;AAAA,kBACP,eAAe;AAAA,kBACf,aAAY;AAAA,kBACZ,WAAS;AAAA,kBACT;AAAA,kBACA;AAAA;AAAA,cACF;AAAA;AAAA,YAjBI;AAAA,UAkBN;AAAA,QACF;AAAA,MACF;AAEA,UAAI,QAAQ,UAAU,aAAa,IAAI,GAAI,QAAO;AAClD,aAAO,SAAS,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,GAAG,GAAI,wBAAa;AAAA,IAC7D;AAEA,UAAM,iBAAiB,CAAC,SAA6B;AACnD,eAAS,UAAU;AACnB,UAAI,OAAO,QAAQ,WAAY,KAAI,IAAI;AAAA,eAC9B,IAAK,KAAI,UAAU;AAAA,IAC9B;AAEA,UAAM,mBAAmB,CAAC,SAA6B;AACrD,iBAAW,UAAU;AAAA,IACvB;AAEA,UAAM,0BAA0B,CAAC,SAAiC;AAChE,UAAI,CAAC,MAAM;AACT,yBAAiB,IAAI;AACrB;AAAA,MACF;AACA,YAAM,aAAa,KAAK;AACxB;AAAA,QACE,sBAAsB,cAAc,aAAc;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,cACJ,WAAW,eAAe,OAAO,IAC/B,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,SAAS,CAAC,UAAU;AAClB,cAAI,CAAC,MAAM,iBAAkB,YAAW;AAAA,QAC1C;AAAA,QACA,OAAO,EAAE,SAAS,cAAc;AAAA,QAE/B,uBAAa,SAAoC;AAAA,UAChD,iBAAiB;AAAA,UACjB,iBAAiB,SAAS,SAAS;AAAA,QACrC,CAAC;AAAA;AAAA,IACH,IACE,UACF,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,UAAU;AAAA,QACV,iBAAc;AAAA,QACd,iBAAe,SAAS,SAAS;AAAA,QACjC,SAAS;AAAA,QAER;AAAA;AAAA,IACH,IACE;AAEN,UAAM,gBAAgB,WAClB;AAAA,MACE,UAAU;AAAA,MACV,MAAM,SAAS;AAAA,MACf,KAAK,SAAS;AAAA,IAChB,IACA,UACE;AAAA,MACE,UAAU;AAAA,MACV,MAAM,YAAY,QAAQ;AAAA,MAC1B,KAAK,YAAY,OAAO;AAAA,IAC1B,IACA;AAEN,WACE,gBAAAA,KAAC,mBAAmB,UAAnB,EAA4B,OAAO,cAClC,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,OAAO;AAAA,UACL,UAAU,WAAW,WAAW,aAAa;AAAA,UAC7C,SAAS,UAAU,iBAAiB;AAAA,QACtC;AAAA,QAEC;AAAA;AAAA,UACA,UACC,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,eAAa,cAAc,UAAU;AAAA,cACrC,kBAAgB;AAAA,cAChB,iBAAiB,SAAS,OAAO,WAAW;AAAA,cAC5C,aAAa,SAAS,OAAO,OAAO;AAAA,cACpC,aAAa;AAAA,cACb;AAAA,cACA,iBAAiB,WAAW;AAAA,cAC5B;AAAA,cACA,UAAU,WAAW;AAAA,cACrB,UAAU;AAAA,cACV,WAAW,SAAS;AAAA,cACpB,cAAc,MAAM,eAAe,EAAE;AAAA,cACrC,OAAO;AAAA,gBACL,GAAG;AAAA,gBACH,GAAG;AAAA,gBACH,QAAQ;AAAA,gBACR,WAAW;AAAA,gBACX,GAAI,YACA;AAAA,kBACE,UAAU;AAAA,gBACZ,IACA;AAAA,kBACE;AAAA,kBACA,WAAW;AAAA,gBACb;AAAA,gBACJ,SAAS;AAAA,cACX;AAAA,cAEC,sBACC,gBAAAC,MAAA,YACE;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,eAAY;AAAA,oBACZ,eAAY;AAAA,oBACZ,OAAO,cAAc,iBAAiB;AAAA;AAAA,gBACxC;AAAA,gBACA,gBAAAA,KAAC,SAAI,OAAO,EAAE,WAAW,WAAW,QAAQ,aAAa,GACtD,wBAAc,GACjB;AAAA,iBACF,IAEA,cAAc;AAAA;AAAA,UAElB;AAAA;AAAA;AAAA,IAEJ,GACF;AAAA,EAEJ;AACF;AAEA,gBAAgB,cAAc;AAEvB,IAAM,cAAc,OAAO,OAAO,iBAAiB;AAAA,EACxD,MAAM;AAAA,EACN,SAAS;AACX,CAAC;","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-context-menu",
3
- "version": "0.181.0",
3
+ "version": "0.182.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.181.0",
17
- "@xsolla/xui-core": "0.181.0",
18
- "@xsolla/xui-divider": "0.181.0",
19
- "@xsolla/xui-icons": "0.181.0",
20
- "@xsolla/xui-icons-base": "0.181.0",
21
- "@xsolla/xui-primitives-core": "0.181.0",
22
- "@xsolla/xui-radio": "0.181.0",
23
- "@xsolla/xui-spinner": "0.181.0",
24
- "@xsolla/xui-typography": "0.181.0"
16
+ "@xsolla/xui-checkbox": "0.182.0",
17
+ "@xsolla/xui-core": "0.182.0",
18
+ "@xsolla/xui-divider": "0.182.0",
19
+ "@xsolla/xui-icons": "0.182.0",
20
+ "@xsolla/xui-icons-base": "0.182.0",
21
+ "@xsolla/xui-primitives-core": "0.182.0",
22
+ "@xsolla/xui-radio": "0.182.0",
23
+ "@xsolla/xui-spinner": "0.182.0",
24
+ "@xsolla/xui-typography": "0.182.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": ">=16.8.0",
package/web/index.d.mts CHANGED
@@ -25,7 +25,7 @@ declare const useKeyboardNavigation: ({ isOpen, cells, activeIndex, setActiveInd
25
25
  };
26
26
 
27
27
  type ContextMenuSize = "sm" | "md" | "lg" | "xl";
28
- type ContextMenuPlacement = "bottom-start" | "top-start" | "bottom-end" | "top-end";
28
+ type ContextMenuPlacement = "bottom-start" | "top-start" | "bottom-end" | "top-end" | "bottom-center" | "top-center";
29
29
  type ContextMenuPresetType = "list" | "loading" | "phone" | "checkbox" | "status" | "brandLogo" | "radio" | "avatar";
30
30
  interface ContextMenuPosition {
31
31
  x: number;
@@ -87,6 +87,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
87
87
  emptyMessage?: string;
88
88
  empty?: ReactNode;
89
89
  trigger?: ReactNode;
90
+ /**
91
+ * Menu placement relative to the trigger element. The `*-center` variants
92
+ * horizontally center the panel on the trigger; every variant auto-flips on
93
+ * the vertical axis (and `start`/`end` flip horizontally) when the menu
94
+ * would clip the viewport. Only applies to trigger-anchored menus (ignored
95
+ * when `position` is set). Defaults to `"bottom-start"`.
96
+ */
90
97
  placement?: ContextMenuPlacement;
91
98
  position?: ContextMenuPosition;
92
99
  isOpen?: boolean;
@@ -94,6 +101,12 @@ interface ContextMenuProps extends ThemeOverrideProps {
94
101
  closeOnSelect?: boolean;
95
102
  width?: number | string;
96
103
  maxHeight?: number;
104
+ /**
105
+ * Render a directional arrow on the panel edge pointing toward the trigger,
106
+ * mirroring the Tooltip arrow. Only applies to trigger-anchored menus.
107
+ * Defaults to `false`.
108
+ */
109
+ withArrow?: boolean;
97
110
  onSelect?: (item: ContextMenuOptionItemProps) => void;
98
111
  "aria-label"?: string;
99
112
  testID?: string;
package/web/index.d.ts CHANGED
@@ -25,7 +25,7 @@ declare const useKeyboardNavigation: ({ isOpen, cells, activeIndex, setActiveInd
25
25
  };
26
26
 
27
27
  type ContextMenuSize = "sm" | "md" | "lg" | "xl";
28
- type ContextMenuPlacement = "bottom-start" | "top-start" | "bottom-end" | "top-end";
28
+ type ContextMenuPlacement = "bottom-start" | "top-start" | "bottom-end" | "top-end" | "bottom-center" | "top-center";
29
29
  type ContextMenuPresetType = "list" | "loading" | "phone" | "checkbox" | "status" | "brandLogo" | "radio" | "avatar";
30
30
  interface ContextMenuPosition {
31
31
  x: number;
@@ -87,6 +87,13 @@ interface ContextMenuProps extends ThemeOverrideProps {
87
87
  emptyMessage?: string;
88
88
  empty?: ReactNode;
89
89
  trigger?: ReactNode;
90
+ /**
91
+ * Menu placement relative to the trigger element. The `*-center` variants
92
+ * horizontally center the panel on the trigger; every variant auto-flips on
93
+ * the vertical axis (and `start`/`end` flip horizontally) when the menu
94
+ * would clip the viewport. Only applies to trigger-anchored menus (ignored
95
+ * when `position` is set). Defaults to `"bottom-start"`.
96
+ */
90
97
  placement?: ContextMenuPlacement;
91
98
  position?: ContextMenuPosition;
92
99
  isOpen?: boolean;
@@ -94,6 +101,12 @@ interface ContextMenuProps extends ThemeOverrideProps {
94
101
  closeOnSelect?: boolean;
95
102
  width?: number | string;
96
103
  maxHeight?: number;
104
+ /**
105
+ * Render a directional arrow on the panel edge pointing toward the trigger,
106
+ * mirroring the Tooltip arrow. Only applies to trigger-anchored menus.
107
+ * Defaults to `false`.
108
+ */
109
+ withArrow?: boolean;
97
110
  onSelect?: (item: ContextMenuOptionItemProps) => void;
98
111
  "aria-label"?: string;
99
112
  testID?: string;