{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "type": "registry:ui",
  "title": "Context Menu",
  "description": "Right-click context menu for Tile UI.",
  "dependencies": [
    "@radix-ui/react-slot",
    "react-dom"
  ],
  "devDependencies": [
    "sass"
  ],
  "registryDependencies": [
    "@tile-ui/core",
    "@tile-ui/portal",
    "@tile-ui/styles"
  ],
  "files": [
    {
      "path": "packages/react/src/components/context-menu/context-menu.tsx",
      "type": "registry:ui",
      "target": "components/ui/context-menu/context-menu.tsx",
      "content": "import React, { createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Slot } from '@radix-ui/react-slot';\nimport { contextMenuStyleKeys, getContextMenuCheckState, getContextMenuPosition, getContextMenuState } from '../lib/core';\nimport type {\n\tContextMenuBaseProps,\n\tContextMenuCheckboxItemBaseProps,\n\tContextMenuItemBaseProps,\n\tContextMenuLabelBaseProps,\n\tContextMenuPosition,\n\tContextMenuRadioGroupBaseProps,\n\tContextMenuRadioItemBaseProps,\n\tContextMenuSubBaseProps,\n\tContextMenuSubTriggerBaseProps,\n\tContextMenuTriggerBaseProps,\n} from '../lib/core';\nimport { PortalProvider, usePortalContainer, type PortalContainer } from '../portal';\nimport styles from './context-menu.module.scss';\n\ninterface ContextMenuContextValue {\n\topen: boolean;\n\tsetOpen: (open: boolean) => void;\n\ttriggerRef: React.RefObject<HTMLElement | null>;\n\tcontentId: string;\n\tposition: ContextMenuPosition | null;\n\tsetPosition: (position: ContextMenuPosition) => void;\n\tcloseAll: () => void;\n}\n\nconst ContextMenuContext = createContext<ContextMenuContextValue | null>(null);\n\nfunction useContextMenuContext(): ContextMenuContextValue {\n\tconst context = useContext(ContextMenuContext);\n\tif (!context) {\n\t\tthrow new Error('ContextMenu 子组件必须位于 <ContextMenu> 内部。');\n\t}\n\treturn context;\n}\n\ninterface ContextMenuContentContextValue {\n\titemsRef: React.RefObject<HTMLElement[]>;\n\tclose: () => void;\n}\n\nconst ContextMenuContentContext = createContext<ContextMenuContentContextValue | null>(null);\n\nfunction useContextMenuContentContext(): ContextMenuContentContextValue {\n\tconst context = useContext(ContextMenuContentContext);\n\tif (!context) {\n\t\tthrow new Error('ContextMenu 菜单项必须位于 <ContextMenuContent> 或 <ContextMenuSubContent> 内部。');\n\t}\n\treturn context;\n}\n\ninterface ContextMenuSubContextValue {\n\topen: boolean;\n\tsetOpen: (open: boolean) => void;\n\ttriggerRef: React.RefObject<HTMLElement | null>;\n}\n\nconst ContextMenuSubContext = createContext<ContextMenuSubContextValue | null>(null);\n\nfunction useContextMenuSubContext(): ContextMenuSubContextValue {\n\tconst context = useContext(ContextMenuSubContext);\n\tif (!context) {\n\t\tthrow new Error('ContextMenu 子菜单组件必须位于 <ContextMenuSub> 内部。');\n\t}\n\treturn context;\n}\n\ninterface ContextMenuRadioGroupContextValue {\n\tvalue: string | undefined;\n\tsetValue: (value: string) => void;\n}\n\nconst ContextMenuRadioGroupContext = createContext<ContextMenuRadioGroupContextValue | null>(null);\n\nfunction useContextMenuRadioGroupContext(): ContextMenuRadioGroupContextValue {\n\tconst context = useContext(ContextMenuRadioGroupContext);\n\tif (!context) {\n\t\tthrow new Error('ContextMenuRadioItem 必须位于 <ContextMenuRadioGroup> 内部。');\n\t}\n\treturn context;\n}\n\nfunction ContextMenuCheckIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[contextMenuStyleKeys.checkIcon]}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\">\n\t\t\t<path d=\"M20 6 9 17l-5-5\" />\n\t\t</svg>\n\t);\n}\n\nfunction ContextMenuRadioIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[contextMenuStyleKeys.radioIcon]}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"currentColor\"\n\t\t\taria-hidden=\"true\">\n\t\t\t<circle cx=\"12\" cy=\"12\" r=\"6\" />\n\t\t</svg>\n\t);\n}\n\nfunction ContextMenuChevronIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[contextMenuStyleKeys.chevron]}\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\">\n\t\t\t<path d=\"m9 18 6-6-6-6\" />\n\t\t</svg>\n\t);\n}\n\nexport interface ContextMenuProps extends React.HTMLAttributes<HTMLDivElement>, ContextMenuBaseProps {}\n\nconst ContextMenu = React.forwardRef<HTMLDivElement, ContextMenuProps>(({ className = '', open, defaultOpen = false, onOpenChange, children, ...props }, ref) => {\n\tconst [internalOpen, setInternalOpen] = useState(defaultOpen);\n\tconst isOpen = open !== undefined ? open : internalOpen;\n\tconst triggerRef = useRef<HTMLElement | null>(null);\n\tconst contentId = useId();\n\tconst [position, setPosition] = useState<ContextMenuPosition | null>(null);\n\n\tconst setOpen = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (open === undefined) {\n\t\t\t\tsetInternalOpen(next);\n\t\t\t}\n\t\t\tonOpenChange?.(next);\n\t\t},\n\t\t[open, onOpenChange],\n\t);\n\n\tconst closeAll = useCallback(() => {\n\t\tsetOpen(false);\n\t}, [setOpen]);\n\n\treturn (\n\t\t<ContextMenuContext.Provider value={{ open: isOpen, setOpen, triggerRef, contentId, position, setPosition, closeAll }}>\n\t\t\t<div ref={ref} className={`${styles[contextMenuStyleKeys.root]} ${className}`} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ContextMenuContext.Provider>\n\t);\n});\nContextMenu.displayName = 'ContextMenu';\n\nexport interface ContextMenuPortalProps {\n\tcontainer?: PortalContainer;\n\tchildren?: React.ReactNode;\n}\n\nconst ContextMenuPortal = ({ container, children }: ContextMenuPortalProps) => {\n\treturn <PortalProvider container={container}>{children}</PortalProvider>;\n};\nContextMenuPortal.displayName = 'ContextMenuPortal';\n\nexport interface ContextMenuTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, ContextMenuTriggerBaseProps {}\n\nconst ContextMenuTrigger = React.forwardRef<HTMLButtonElement, ContextMenuTriggerProps>(\n\t({ className = '', asChild = false, children, onContextMenu, onKeyDown, ...props }, ref) => {\n\t\tconst context = useContextMenuContext();\n\n\t\tfunction setRef(element: HTMLElement | null) {\n\t\t\tcontext.triggerRef.current = element;\n\t\t\tif (typeof ref === 'function') {\n\t\t\t\tref(element as HTMLButtonElement | null);\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = element as HTMLButtonElement | null;\n\t\t\t}\n\t\t}\n\n\t\tfunction handleContextMenu(event: React.MouseEvent<HTMLButtonElement>) {\n\t\t\tonContextMenu?.(event);\n\t\t\tif (event.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tevent.preventDefault();\n\t\t\tcontext.setPosition({ top: event.clientY, left: event.clientX });\n\t\t\tcontext.setOpen(true);\n\t\t}\n\n\t\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n\t\t\tonKeyDown?.(event);\n\t\t\tif (event.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.key === 'ContextMenu' || (event.key === 'F10' && event.shiftKey)) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst rect = event.currentTarget.getBoundingClientRect();\n\t\t\t\tcontext.setPosition({ top: rect.bottom, left: rect.left });\n\t\t\t\tcontext.setOpen(true);\n\t\t\t}\n\t\t}\n\n\t\tconst Comp = asChild ? Slot : 'button';\n\t\tconst state = getContextMenuState(context.open);\n\n\t\treturn (\n\t\t\t<Comp\n\t\t\t\tref={setRef}\n\t\t\t\ttype={asChild ? undefined : 'button'}\n\t\t\t\tdata-state={state}\n\t\t\t\taria-haspopup=\"menu\"\n\t\t\t\taria-expanded={context.open}\n\t\t\t\taria-controls={context.contentId}\n\t\t\t\tclassName={asChild ? undefined : `${styles[contextMenuStyleKeys.trigger]} ${className}`}\n\t\t\t\tonContextMenu={handleContextMenu}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t{...props}>\n\t\t\t\t{children}\n\t\t\t</Comp>\n\t\t);\n\t},\n);\nContextMenuTrigger.displayName = 'ContextMenuTrigger';\n\nexport interface ContextMenuContentProps extends React.HTMLAttributes<HTMLDivElement> {\n\tcontainer?: PortalContainer;\n}\n\nconst ContextMenuContent = React.forwardRef<HTMLDivElement, ContextMenuContentProps>(({ className = '', container, children, ...props }, ref) => {\n\tconst { open, position, setPosition, triggerRef, closeAll, contentId } = useContextMenuContext();\n\tconst portalContainer = usePortalContainer(container);\n\tconst contentRef = useRef<HTMLDivElement | null>(null);\n\tconst itemsRef = useRef<HTMLElement[]>([]);\n\tconst latestPositionRef = useRef(position);\n\tlatestPositionRef.current = position;\n\n\tfunction setRef(element: HTMLDivElement | null) {\n\t\tcontentRef.current = element;\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element);\n\t\t} else if (ref) {\n\t\t\tref.current = element;\n\t\t}\n\t}\n\n\tuseLayoutEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\n\t\tfunction updatePosition() {\n\t\t\tconst content = contentRef.current;\n\t\t\tif (!content) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst contentSize = { width: content.offsetWidth, height: content.offsetHeight };\n\t\t\tconst viewport = { width: window.innerWidth, height: window.innerHeight };\n\t\t\tconst base = latestPositionRef.current ?? { top: 0, left: 0 };\n\t\t\tsetPosition(getContextMenuPosition({ x: base.left, y: base.top, contentSize, viewport }));\n\t\t}\n\n\t\tupdatePosition();\n\t\twindow.addEventListener('resize', updatePosition);\n\t\tdocument.addEventListener('scroll', updatePosition, true);\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener('resize', updatePosition);\n\t\t\tdocument.removeEventListener('scroll', updatePosition, true);\n\t\t};\n\t}, [open, setPosition]);\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\t\tconst items = itemsRef.current;\n\t\tif (items.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\titems[0].setAttribute('data-highlighted', 'true');\n\t\titems[0].focus();\n\t}, [open]);\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\n\t\tfunction handlePointerDown(event: PointerEvent) {\n\t\t\tconst target = event.target as Node | null;\n\t\t\tif (!target) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst content = contentRef.current;\n\t\t\tif (content && content.contains(target)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcloseAll();\n\t\t}\n\n\t\tfunction handleKeyDown(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tcloseAll();\n\t\t\t\ttriggerRef.current?.focus();\n\t\t\t}\n\t\t}\n\n\t\tdocument.addEventListener('pointerdown', handlePointerDown);\n\t\tdocument.addEventListener('keydown', handleKeyDown);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('pointerdown', handlePointerDown);\n\t\t\tdocument.removeEventListener('keydown', handleKeyDown);\n\t\t};\n\t}, [open, closeAll, triggerRef]);\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n\t\tconst items = itemsRef.current.filter((item) => item.getAttribute('data-disabled') !== 'true');\n\t\tif (items.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentIndex = items.findIndex((item) => item.getAttribute('data-highlighted') === 'true');\n\n\t\tconst highlight = (next: number) => {\n\t\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\t\titems[next].setAttribute('data-highlighted', 'true');\n\t\t\titems[next].focus();\n\t\t};\n\n\t\tswitch (event.key) {\n\t\t\tcase 'ArrowDown':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(currentIndex < 0 ? 0 : (currentIndex + 1) % items.length);\n\t\t\t\tbreak;\n\t\t\tcase 'ArrowUp':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(currentIndex < 0 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length);\n\t\t\t\tbreak;\n\t\t\tcase 'Home':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(0);\n\t\t\t\tbreak;\n\t\t\tcase 'End':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(items.length - 1);\n\t\t\t\tbreak;\n\t\t\tcase 'Enter':\n\t\t\tcase ' ':\n\t\t\t\tevent.preventDefault();\n\t\t\t\t(currentIndex >= 0 ? items[currentIndex] : items[0]).click();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst state = getContextMenuState(open);\n\tconst classes = [styles[contextMenuStyleKeys.content], className].filter(Boolean).join(' ');\n\n\tconst content = (\n\t\t<ContextMenuContentContext.Provider value={{ itemsRef, close: closeAll }}>\n\t\t\t<div\n\t\t\t\tref={setRef}\n\t\t\t\tid={contentId}\n\t\t\t\trole=\"menu\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\tdata-state={state}\n\t\t\t\tclassName={classes}\n\t\t\t\tstyle={position ? { top: `${position.top}px`, left: `${position.left}px` } : undefined}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t{...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ContextMenuContentContext.Provider>\n\t);\n\n\tif (!open || !portalContainer) {\n\t\treturn null;\n\t}\n\n\treturn createPortal(content, portalContainer);\n});\nContextMenuContent.displayName = 'ContextMenuContent';\n\nexport interface ContextMenuGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst ContextMenuGroup = React.forwardRef<HTMLDivElement, ContextMenuGroupProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<div ref={ref} role=\"group\" className={`${styles[contextMenuStyleKeys.group]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nContextMenuGroup.displayName = 'ContextMenuGroup';\n\nexport interface ContextMenuLabelProps extends React.HTMLAttributes<HTMLDivElement>, ContextMenuLabelBaseProps {}\n\nconst ContextMenuLabel = React.forwardRef<HTMLDivElement, ContextMenuLabelProps>(({ className = '', inset = false, children, ...props }, ref) => {\n\tconst classes = [styles[contextMenuStyleKeys.label], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<div ref={ref} data-inset={inset} className={classes} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nContextMenuLabel.displayName = 'ContextMenuLabel';\n\nexport interface ContextMenuSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst ContextMenuSeparator = React.forwardRef<HTMLDivElement, ContextMenuSeparatorProps>(({ className = '', ...props }, ref) => {\n\tconst classes = [styles[contextMenuStyleKeys.separator], className].filter(Boolean).join(' ');\n\treturn <div ref={ref} role=\"separator\" className={classes} {...props} />;\n});\nContextMenuSeparator.displayName = 'ContextMenuSeparator';\n\nexport interface ContextMenuShortcutProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst ContextMenuShortcut = React.forwardRef<HTMLSpanElement, ContextMenuShortcutProps>(({ className = '', children, ...props }, ref) => {\n\tconst classes = [styles[contextMenuStyleKeys.shortcut], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<span ref={ref} className={classes} {...props}>\n\t\t\t{children}\n\t\t</span>\n\t);\n});\nContextMenuShortcut.displayName = 'ContextMenuShortcut';\n\nexport interface ContextMenuItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'>, ContextMenuItemBaseProps {}\n\nconst ContextMenuItem = React.forwardRef<HTMLDivElement, ContextMenuItemProps>(\n\t({ className = '', inset = false, variant = 'default', disabled = false, onSelect, children, ...props }, ref) => {\n\t\tconst { itemsRef, close } = useContextMenuContentContext();\n\t\tconst itemRef = useRef<HTMLDivElement | null>(null);\n\n\t\tuseEffect(() => {\n\t\t\tconst element = itemRef.current;\n\t\t\tif (!element) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\titemsRef.current.push(element);\n\t\t\treturn () => {\n\t\t\t\titemsRef.current = itemsRef.current.filter((item) => item !== element);\n\t\t\t};\n\t\t}, [itemsRef]);\n\n\t\tfunction setRef(element: HTMLDivElement | null) {\n\t\t\titemRef.current = element;\n\t\t\tif (typeof ref === 'function') {\n\t\t\t\tref(element);\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = element;\n\t\t\t}\n\t\t}\n\n\t\tfunction handleClick(event: React.MouseEvent<HTMLDivElement>) {\n\t\t\tif (disabled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tonSelect?.(event.nativeEvent);\n\t\t\tclose();\n\t\t}\n\n\t\tconst classes = [styles[contextMenuStyleKeys.item], className].filter(Boolean).join(' ');\n\t\treturn (\n\t\t\t<div ref={setRef} role=\"menuitem\" tabIndex={-1} data-inset={inset} data-variant={variant} data-disabled={disabled} className={classes} onClick={handleClick} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nContextMenuItem.displayName = 'ContextMenuItem';\n\nexport interface ContextMenuCheckboxItemProps extends React.HTMLAttributes<HTMLDivElement>, ContextMenuCheckboxItemBaseProps {}\n\nconst ContextMenuCheckboxItem = React.forwardRef<HTMLDivElement, ContextMenuCheckboxItemProps>(\n\t({ className = '', checked, defaultChecked = false, onCheckedChange, disabled = false, children, ...props }, ref) => {\n\t\tconst { itemsRef } = useContextMenuContentContext();\n\t\tconst itemRef = useRef<HTMLDivElement | null>(null);\n\t\tconst [internalChecked, setInternalChecked] = useState(defaultChecked);\n\t\tconst isChecked = checked !== undefined ? checked : internalChecked;\n\n\t\tuseEffect(() => {\n\t\t\tconst element = itemRef.current;\n\t\t\tif (!element) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\titemsRef.current.push(element);\n\t\t\treturn () => {\n\t\t\t\titemsRef.current = itemsRef.current.filter((item) => item !== element);\n\t\t\t};\n\t\t}, [itemsRef]);\n\n\t\tfunction setRef(element: HTMLDivElement | null) {\n\t\t\titemRef.current = element;\n\t\t\tif (typeof ref === 'function') {\n\t\t\t\tref(element);\n\t\t\t} else if (ref) {\n\t\t\t\tref.current = element;\n\t\t\t}\n\t\t}\n\n\t\tfunction handleClick() {\n\t\t\tif (disabled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst next = !isChecked;\n\t\t\tif (checked === undefined) {\n\t\t\t\tsetInternalChecked(next);\n\t\t\t}\n\t\t\tonCheckedChange?.(next);\n\t\t}\n\n\t\tconst classes = [styles[contextMenuStyleKeys.checkboxItem], className].filter(Boolean).join(' ');\n\t\treturn (\n\t\t\t<div\n\t\t\t\tref={setRef}\n\t\t\t\trole=\"menuitemcheckbox\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\taria-checked={isChecked}\n\t\t\t\tdata-checked={getContextMenuCheckState(isChecked)}\n\t\t\t\tdata-disabled={disabled}\n\t\t\t\tclassName={classes}\n\t\t\t\tonClick={handleClick}\n\t\t\t\t{...props}>\n\t\t\t\t<span className={styles[contextMenuStyleKeys.indicator]}>{isChecked && <ContextMenuCheckIcon />}</span>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nContextMenuCheckboxItem.displayName = 'ContextMenuCheckboxItem';\n\nexport interface ContextMenuRadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'>, ContextMenuRadioGroupBaseProps {}\n\nconst ContextMenuRadioGroup = React.forwardRef<HTMLDivElement, ContextMenuRadioGroupProps>(({ className = '', value, defaultValue, onValueChange, children, ...props }, ref) => {\n\tconst [internalValue, setInternalValue] = useState(defaultValue);\n\tconst resolvedValue = value !== undefined ? value : internalValue;\n\n\tconst setValue = useCallback(\n\t\t(next: string) => {\n\t\t\tif (value === undefined) {\n\t\t\t\tsetInternalValue(next);\n\t\t\t}\n\t\t\tonValueChange?.(next);\n\t\t},\n\t\t[value, onValueChange],\n\t);\n\n\tconst classes = [styles[contextMenuStyleKeys.radioGroup], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<ContextMenuRadioGroupContext.Provider value={{ value: resolvedValue, setValue }}>\n\t\t\t<div ref={ref} role=\"group\" className={classes} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ContextMenuRadioGroupContext.Provider>\n\t);\n});\nContextMenuRadioGroup.displayName = 'ContextMenuRadioGroup';\n\nexport interface ContextMenuRadioItemProps extends React.HTMLAttributes<HTMLDivElement>, ContextMenuRadioItemBaseProps {}\n\nconst ContextMenuRadioItem = React.forwardRef<HTMLDivElement, ContextMenuRadioItemProps>(({ className = '', value, disabled = false, children, ...props }, ref) => {\n\tconst { itemsRef } = useContextMenuContentContext();\n\tconst { value: groupValue, setValue } = useContextMenuRadioGroupContext();\n\tconst itemRef = useRef<HTMLDivElement | null>(null);\n\tconst isChecked = groupValue === value;\n\n\tuseEffect(() => {\n\t\tconst element = itemRef.current;\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\t\titemsRef.current.push(element);\n\t\treturn () => {\n\t\t\titemsRef.current = itemsRef.current.filter((item) => item !== element);\n\t\t};\n\t}, [itemsRef]);\n\n\tfunction setRef(element: HTMLDivElement | null) {\n\t\titemRef.current = element;\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element);\n\t\t} else if (ref) {\n\t\t\tref.current = element;\n\t\t}\n\t}\n\n\tfunction handleClick() {\n\t\tif (disabled) {\n\t\t\treturn;\n\t\t}\n\t\tsetValue(value);\n\t}\n\n\tconst classes = [styles[contextMenuStyleKeys.radioItem], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<div\n\t\t\tref={setRef}\n\t\t\trole=\"menuitemradio\"\n\t\t\ttabIndex={-1}\n\t\t\taria-checked={isChecked}\n\t\t\tdata-checked={getContextMenuCheckState(isChecked)}\n\t\t\tdata-disabled={disabled}\n\t\t\tclassName={classes}\n\t\t\tonClick={handleClick}\n\t\t\t{...props}>\n\t\t\t<span className={styles[contextMenuStyleKeys.indicator]}>{isChecked && <ContextMenuRadioIcon />}</span>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nContextMenuRadioItem.displayName = 'ContextMenuRadioItem';\n\nexport interface ContextMenuSubProps extends ContextMenuSubBaseProps {\n\tchildren?: React.ReactNode;\n}\n\nconst ContextMenuSub = ({ open, defaultOpen = false, onOpenChange, children }: ContextMenuSubProps) => {\n\tconst [internalOpen, setInternalOpen] = useState(defaultOpen);\n\tconst isOpen = open !== undefined ? open : internalOpen;\n\tconst triggerRef = useRef<HTMLElement | null>(null);\n\n\tconst setOpen = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (open === undefined) {\n\t\t\t\tsetInternalOpen(next);\n\t\t\t}\n\t\t\tonOpenChange?.(next);\n\t\t},\n\t\t[open, onOpenChange],\n\t);\n\n\treturn <ContextMenuSubContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>{children}</ContextMenuSubContext.Provider>;\n};\nContextMenuSub.displayName = 'ContextMenuSub';\n\nexport interface ContextMenuSubTriggerProps extends React.HTMLAttributes<HTMLDivElement>, ContextMenuSubTriggerBaseProps {}\n\nconst ContextMenuSubTrigger = React.forwardRef<HTMLDivElement, ContextMenuSubTriggerProps>(({ className = '', inset = false, disabled = false, children, ...props }, ref) => {\n\tconst { itemsRef } = useContextMenuContentContext();\n\tconst { open, setOpen, triggerRef } = useContextMenuSubContext();\n\tconst itemRef = useRef<HTMLDivElement | null>(null);\n\n\tuseEffect(() => {\n\t\tconst element = itemRef.current;\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\t\titemsRef.current.push(element);\n\t\treturn () => {\n\t\t\titemsRef.current = itemsRef.current.filter((item) => item !== element);\n\t\t};\n\t}, [itemsRef]);\n\n\tfunction setRef(element: HTMLDivElement | null) {\n\t\titemRef.current = element;\n\t\ttriggerRef.current = element;\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element);\n\t\t} else if (ref) {\n\t\t\tref.current = element;\n\t\t}\n\t}\n\n\tfunction handleMouseEnter() {\n\t\tif (disabled) {\n\t\t\treturn;\n\t\t}\n\t\tsetOpen(true);\n\t}\n\n\tfunction handleClick() {\n\t\tif (disabled) {\n\t\t\treturn;\n\t\t}\n\t\tsetOpen(!open);\n\t}\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n\t\tif (disabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (event.key === 'ArrowRight' || event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tsetOpen(true);\n\t\t}\n\t}\n\n\tconst state = getContextMenuState(open);\n\tconst classes = [styles[contextMenuStyleKeys.subTrigger], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<div\n\t\t\tref={setRef}\n\t\t\trole=\"menuitem\"\n\t\t\ttabIndex={-1}\n\t\t\taria-haspopup=\"menu\"\n\t\t\taria-expanded={open}\n\t\t\tdata-state={state}\n\t\t\tdata-inset={inset}\n\t\t\tdata-disabled={disabled}\n\t\t\tclassName={classes}\n\t\t\tonMouseEnter={handleMouseEnter}\n\t\t\tonClick={handleClick}\n\t\t\tonKeyDown={handleKeyDown}\n\t\t\t{...props}>\n\t\t\t{children}\n\t\t\t<ContextMenuChevronIcon />\n\t\t</div>\n\t);\n});\nContextMenuSubTrigger.displayName = 'ContextMenuSubTrigger';\n\nexport interface ContextMenuSubContentProps extends React.HTMLAttributes<HTMLDivElement> {\n\tcontainer?: PortalContainer;\n}\n\nconst ContextMenuSubContent = React.forwardRef<HTMLDivElement, ContextMenuSubContentProps>(({ className = '', container, children, ...props }, ref) => {\n\tconst { open, setOpen, triggerRef } = useContextMenuSubContext();\n\tconst portalContainer = usePortalContainer(container);\n\tconst [position, setPosition] = useState<ContextMenuPosition | null>(null);\n\tconst contentRef = useRef<HTMLDivElement | null>(null);\n\tconst itemsRef = useRef<HTMLElement[]>([]);\n\n\tfunction setRef(element: HTMLDivElement | null) {\n\t\tcontentRef.current = element;\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element);\n\t\t} else if (ref) {\n\t\t\tref.current = element;\n\t\t}\n\t}\n\n\tuseLayoutEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\n\t\tfunction updatePosition() {\n\t\t\tconst trigger = triggerRef.current;\n\t\t\tconst content = contentRef.current;\n\t\t\tif (!trigger || !content) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst triggerRect = trigger.getBoundingClientRect();\n\t\t\tconst contentSize = { width: content.offsetWidth, height: content.offsetHeight };\n\t\t\tconst viewport = { width: window.innerWidth, height: window.innerHeight };\n\t\t\tsetPosition(getContextMenuPosition({ x: triggerRect.right, y: triggerRect.top, contentSize, viewport }));\n\t\t}\n\n\t\tupdatePosition();\n\t\twindow.addEventListener('resize', updatePosition);\n\t\tdocument.addEventListener('scroll', updatePosition, true);\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener('resize', updatePosition);\n\t\t\tdocument.removeEventListener('scroll', updatePosition, true);\n\t\t};\n\t}, [open, triggerRef]);\n\n\tuseEffect(() => {\n\t\tif (!open) {\n\t\t\treturn;\n\t\t}\n\n\t\tfunction handlePointerDown(event: PointerEvent) {\n\t\t\tconst target = event.target as Node | null;\n\t\t\tif (!target) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst content = contentRef.current;\n\t\t\tconst trigger = triggerRef.current;\n\t\t\tif (content && content.contains(target)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (trigger && trigger.contains(target)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetOpen(false);\n\t\t}\n\n\t\tdocument.addEventListener('pointerdown', handlePointerDown);\n\t\treturn () => document.removeEventListener('pointerdown', handlePointerDown);\n\t}, [open, triggerRef, setOpen]);\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n\t\tconst items = itemsRef.current.filter((item) => item.getAttribute('data-disabled') !== 'true');\n\n\t\tif (event.key === 'Escape' || event.key === 'ArrowLeft') {\n\t\t\tevent.preventDefault();\n\t\t\tsetOpen(false);\n\t\t\ttriggerRef.current?.focus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (items.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentIndex = items.findIndex((item) => item.getAttribute('data-highlighted') === 'true');\n\t\tconst highlight = (next: number) => {\n\t\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\t\titems[next].setAttribute('data-highlighted', 'true');\n\t\t\titems[next].focus();\n\t\t};\n\n\t\tswitch (event.key) {\n\t\t\tcase 'ArrowDown':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(currentIndex < 0 ? 0 : (currentIndex + 1) % items.length);\n\t\t\t\tbreak;\n\t\t\tcase 'ArrowUp':\n\t\t\t\tevent.preventDefault();\n\t\t\t\thighlight(currentIndex < 0 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length);\n\t\t\t\tbreak;\n\t\t\tcase 'Enter':\n\t\t\tcase ' ':\n\t\t\t\tevent.preventDefault();\n\t\t\t\t(currentIndex >= 0 ? items[currentIndex] : items[0]).click();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst state = getContextMenuState(open);\n\tconst classes = [styles[contextMenuStyleKeys.subContent], className].filter(Boolean).join(' ');\n\n\tconst content = (\n\t\t<ContextMenuContentContext.Provider value={{ itemsRef, close: () => setOpen(false) }}>\n\t\t\t<div\n\t\t\t\tref={setRef}\n\t\t\t\trole=\"menu\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\tdata-state={state}\n\t\t\t\tclassName={classes}\n\t\t\t\tstyle={position ? { top: `${position.top}px`, left: `${position.left}px` } : undefined}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t{...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ContextMenuContentContext.Provider>\n\t);\n\n\tif (!open || !portalContainer) {\n\t\treturn null;\n\t}\n\n\treturn createPortal(content, portalContainer);\n});\nContextMenuSubContent.displayName = 'ContextMenuSubContent';\n\nexport {\n\tContextMenu,\n\tContextMenuPortal,\n\tContextMenuTrigger,\n\tContextMenuContent,\n\tContextMenuGroup,\n\tContextMenuLabel,\n\tContextMenuItem,\n\tContextMenuCheckboxItem,\n\tContextMenuRadioGroup,\n\tContextMenuRadioItem,\n\tContextMenuSeparator,\n\tContextMenuShortcut,\n\tContextMenuSub,\n\tContextMenuSubTrigger,\n\tContextMenuSubContent,\n};\nexport default ContextMenu;\n"
    },
    {
      "path": "packages/styles/scss/components/context-menu.module.scss",
      "type": "registry:file",
      "target": "components/ui/context-menu/context-menu.module.scss",
      "content": "@use '../../../styles/variables/colors' as *;\n\n// 根容器\n.root {\n\tdisplay: inline-flex;\n}\n\n// 触发器（默认无样式，接收右键事件）\n.trigger {\n\tdisplay: inline-flex;\n}\n\n// 弹出内容面板\n.content {\n\tposition: fixed;\n\tz-index: $z-dropdown;\n\tmin-width: 8rem;\n\tmax-width: calc(100vw - 1rem);\n\tmax-height: calc(100vh - 1rem);\n\toverflow-x: hidden;\n\toverflow-y: auto;\n\tborder-radius: $radius-md;\n\tborder: 1px solid $border;\n\tbackground-color: $popover;\n\tcolor: $popover-foreground;\n\tpadding: $spacing-1;\n\tbox-shadow: $shadow-md;\n\toutline: none;\n\ttransition:\n\t\topacity $transition-fast,\n\t\tvisibility $transition-fast,\n\t\ttransform $transition-fast;\n\n\t&[data-state='closed'] {\n\t\topacity: 0;\n\t\tvisibility: hidden;\n\t\tpointer-events: none;\n\t\ttransform: scale(0.95);\n\t}\n\n\t&[data-state='open'] {\n\t\topacity: 1;\n\t\tvisibility: visible;\n\t\tpointer-events: auto;\n\t\ttransform: scale(1);\n\t}\n}\n\n// 子菜单弹出面板\n.subContent {\n\tposition: fixed;\n\tz-index: $z-dropdown;\n\tmin-width: 8rem;\n\toverflow: hidden;\n\tborder-radius: $radius-md;\n\tborder: 1px solid $border;\n\tbackground-color: $popover;\n\tcolor: $popover-foreground;\n\tpadding: $spacing-1;\n\tbox-shadow: $shadow-lg;\n\toutline: none;\n\ttransition:\n\t\topacity $transition-fast,\n\t\tvisibility $transition-fast,\n\t\ttransform $transition-fast;\n\n\t&[data-state='closed'] {\n\t\topacity: 0;\n\t\tvisibility: hidden;\n\t\tpointer-events: none;\n\t\ttransform: translateX(-0.25rem);\n\t}\n\n\t&[data-state='open'] {\n\t\topacity: 1;\n\t\tvisibility: visible;\n\t\tpointer-events: auto;\n\t\ttransform: translate(0, 0);\n\t}\n}\n\n// 分组容器（占位，无视觉样式）\n.group {\n\tdisplay: block;\n}\n\n// 菜单项\n.item {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: $spacing-2;\n\tborder-radius: $radius-sm;\n\tpadding: $spacing-1_5 $spacing-2;\n\tfont-size: $text-sm;\n\tline-height: $leading-normal;\n\tcolor: $popover-foreground;\n\toutline: none;\n\tcursor: default;\n\tuser-select: none;\n\n\t&[data-highlighted='true'] {\n\t\tbackground-color: $accent;\n\t\tcolor: $accent-foreground;\n\t}\n\n\t&[data-inset='true'] {\n\t\tpadding-left: $spacing-8;\n\t}\n\n\t&[data-variant='destructive'] {\n\t\tcolor: $destructive;\n\n\t\t&[data-highlighted='true'] {\n\t\t\tbackground-color: color-mix(in srgb, $destructive 10%, transparent);\n\t\t\tcolor: $destructive;\n\t\t}\n\t}\n\n\t&[data-disabled='true'] {\n\t\tpointer-events: none;\n\t\topacity: 0.5;\n\t}\n\n\t& > svg {\n\t\tpointer-events: none;\n\t\tflex-shrink: 0;\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tcolor: $muted-foreground;\n\t}\n\n\t&[data-variant='destructive'] > svg {\n\t\tcolor: $destructive;\n\t}\n}\n\n// 复选框菜单项\n.checkboxItem {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: $spacing-2;\n\tborder-radius: $radius-sm;\n\tpadding: $spacing-1_5 $spacing-2 $spacing-1_5 $spacing-8;\n\tfont-size: $text-sm;\n\tline-height: $leading-normal;\n\tcolor: $popover-foreground;\n\toutline: none;\n\tcursor: default;\n\tuser-select: none;\n\n\t&[data-highlighted='true'] {\n\t\tbackground-color: $accent;\n\t\tcolor: $accent-foreground;\n\t}\n\n\t&[data-disabled='true'] {\n\t\tpointer-events: none;\n\t\topacity: 0.5;\n\t}\n\n\t& > svg {\n\t\tpointer-events: none;\n\t\tflex-shrink: 0;\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tcolor: $muted-foreground;\n\t}\n}\n\n// 单选组容器\n.radioGroup {\n\tdisplay: block;\n}\n\n// 单选菜单项\n.radioItem {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: $spacing-2;\n\tborder-radius: $radius-sm;\n\tpadding: $spacing-1_5 $spacing-2 $spacing-1_5 $spacing-8;\n\tfont-size: $text-sm;\n\tline-height: $leading-normal;\n\tcolor: $popover-foreground;\n\toutline: none;\n\tcursor: default;\n\tuser-select: none;\n\n\t&[data-highlighted='true'] {\n\t\tbackground-color: $accent;\n\t\tcolor: $accent-foreground;\n\t}\n\n\t&[data-disabled='true'] {\n\t\tpointer-events: none;\n\t\topacity: 0.5;\n\t}\n\n\t& > svg {\n\t\tpointer-events: none;\n\t\tflex-shrink: 0;\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tcolor: $muted-foreground;\n\t}\n}\n\n// 勾选/单选指示器（绝对定位在左侧）\n.indicator {\n\tposition: absolute;\n\tleft: $spacing-2;\n\tdisplay: inline-flex;\n\twidth: 0.875rem;\n\theight: 0.875rem;\n\talign-items: center;\n\tjustify-content: center;\n\tcolor: currentcolor;\n\n\t.checkIcon {\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t}\n\n\t.radioIcon {\n\t\twidth: 0.5rem;\n\t\theight: 0.5rem;\n\t\tfill: currentColor;\n\t}\n}\n\n// 标签\n.label {\n\tpadding: $spacing-1_5 $spacing-2;\n\tfont-size: $text-sm;\n\tfont-weight: $font-medium;\n\tcolor: $foreground;\n\n\t&[data-inset='true'] {\n\t\tpadding-left: $spacing-8;\n\t}\n}\n\n// 分隔线\n.separator {\n\tmargin: $spacing-1 (-$spacing-1);\n\theight: 1px;\n\tbackground-color: $border;\n}\n\n// 快捷键文本\n.shortcut {\n\tmargin-left: auto;\n\tfont-size: $text-xs;\n\tletter-spacing: 0.1em;\n\tcolor: $muted-foreground;\n}\n\n// 子菜单触发器\n.subTrigger {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: $spacing-2;\n\tborder-radius: $radius-sm;\n\tpadding: $spacing-1_5 $spacing-2;\n\tfont-size: $text-sm;\n\tline-height: $leading-normal;\n\tcolor: $popover-foreground;\n\toutline: none;\n\tcursor: default;\n\tuser-select: none;\n\n\t&[data-highlighted='true'],\n\t&[data-state='open'] {\n\t\tbackground-color: $accent;\n\t\tcolor: $accent-foreground;\n\t}\n\n\t&[data-inset='true'] {\n\t\tpadding-left: $spacing-8;\n\t}\n\n\t&[data-disabled='true'] {\n\t\tpointer-events: none;\n\t\topacity: 0.5;\n\t}\n\n\t& > svg {\n\t\tpointer-events: none;\n\t\tflex-shrink: 0;\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tcolor: $muted-foreground;\n\t}\n}\n\n// 子菜单箭头\n.chevron {\n\tmargin-left: auto;\n\twidth: 1rem;\n\theight: 1rem;\n\n\t[dir='rtl'] & {\n\t\ttransform: rotate(180deg);\n\t}\n}\n\n// Context menus share the generic dropdown surface and row styling interfaces.\n.content,\n.subContent {\n\tmin-width: var(--tile-menu-min-width, 8rem);\n\tborder-radius: var(--tile-menu-panel-radius, $radius-md);\n\tborder-color: var(--tile-menu-border, $border);\n\tbackground-color: var(--tile-menu-background, $popover);\n\tcolor: var(--tile-menu-foreground, $popover-foreground);\n\tpadding: var(--tile-menu-padding, $spacing-1);\n}\n.content {\n\tbox-shadow: var(--tile-menu-shadow, $shadow-md);\n}\n.subContent {\n\tbox-shadow: var(--tile-menu-shadow, $shadow-lg);\n}\n.item,\n.checkboxItem,\n.radioItem,\n.subTrigger {\n\tborder-radius: var(--tile-menu-item-radius, $radius-sm);\n\tfont-size: var(--tile-menu-font-size, $text-sm);\n\tline-height: var(--tile-menu-line-height, $leading-normal);\n\tcolor: var(--tile-menu-foreground, $popover-foreground);\n\t&[data-highlighted='true'] {\n\t\tbackground-color: var(--tile-menu-highlight-background, $accent);\n\t\tcolor: var(--tile-menu-highlight-foreground, $accent-foreground);\n\t}\n\t& > svg {\n\t\tcolor: var(--tile-menu-subtle, $muted-foreground);\n\t}\n\t&:focus-visible {\n\t\tbox-shadow: var(--tile-menu-focus-shadow, none);\n\t}\n}\n.item,\n.subTrigger {\n\tpadding: var(--tile-menu-item-padding, $spacing-1_5 $spacing-2);\n}\n.checkboxItem,\n.radioItem {\n\tpadding: var(--tile-menu-check-padding, $spacing-1_5 $spacing-2 $spacing-1_5 $spacing-8);\n}\n.subTrigger[data-state='open'] {\n\tbackground-color: var(--tile-menu-highlight-background, $accent);\n\tcolor: var(--tile-menu-highlight-foreground, $accent-foreground);\n}\n.item[data-variant='destructive'] {\n\tcolor: var(--tile-menu-destructive-foreground, $destructive);\n\t& > svg {\n\t\tcolor: var(--tile-menu-destructive-foreground, $destructive);\n\t}\n\t&[data-highlighted='true'] {\n\t\tbackground-color: var(--tile-menu-destructive-background, color-mix(in srgb, $destructive 10%, transparent));\n\t\tcolor: var(--tile-menu-destructive-foreground, $destructive);\n\t}\n}\n.label {\n\tpadding: var(--tile-menu-label-padding, $spacing-1_5 $spacing-2);\n\tfont-size: var(--tile-menu-label-font-size, $text-sm);\n\tfont-weight: var(--tile-menu-label-font-weight, $font-medium);\n\tcolor: var(--tile-menu-label-foreground, $foreground);\n}\n.item[data-inset='true'],\n.subTrigger[data-inset='true'],\n.label[data-inset='true'] {\n\tpadding-left: $spacing-8;\n}\n.separator {\n\tbackground-color: var(--tile-menu-separator, $border);\n}\n.shortcut {\n\tcolor: var(--tile-menu-subtle, $muted-foreground);\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.content,\n\t.subContent {\n\t\ttransition: none;\n\t}\n}\n"
    },
    {
      "path": "packages/react/src/components/context-menu/index.ts",
      "type": "registry:ui",
      "target": "components/ui/context-menu/index.ts",
      "content": "export {\n\tContextMenu,\n\tContextMenuPortal,\n\tContextMenuTrigger,\n\tContextMenuContent,\n\tContextMenuGroup,\n\tContextMenuLabel,\n\tContextMenuItem,\n\tContextMenuCheckboxItem,\n\tContextMenuRadioGroup,\n\tContextMenuRadioItem,\n\tContextMenuSeparator,\n\tContextMenuShortcut,\n\tContextMenuSub,\n\tContextMenuSubTrigger,\n\tContextMenuSubContent,\n\ttype ContextMenuProps,\n\ttype ContextMenuPortalProps,\n\ttype ContextMenuTriggerProps,\n\ttype ContextMenuContentProps,\n\ttype ContextMenuGroupProps,\n\ttype ContextMenuLabelProps,\n\ttype ContextMenuItemProps,\n\ttype ContextMenuCheckboxItemProps,\n\ttype ContextMenuRadioGroupProps,\n\ttype ContextMenuRadioItemProps,\n\ttype ContextMenuSeparatorProps,\n\ttype ContextMenuShortcutProps,\n\ttype ContextMenuSubProps,\n\ttype ContextMenuSubTriggerProps,\n\ttype ContextMenuSubContentProps,\n} from './context-menu';\n"
    }
  ]
}
