{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-menu",
  "type": "registry:ui",
  "title": "Dropdown Menu",
  "description": "Dropdown menu with checkbox and radio items 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/dropdown-menu/dropdown-menu.tsx",
      "type": "registry:ui",
      "target": "components/ui/dropdown-menu/dropdown-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 { dropdownMenuStyleKeys, getDropdownMenuCheckState, getDropdownMenuPosition, getDropdownMenuState } from '../lib/core';\nimport type {\n\tDropdownMenuBaseProps,\n\tDropdownMenuCheckboxItemBaseProps,\n\tDropdownMenuContentBaseProps,\n\tDropdownMenuItemBaseProps,\n\tDropdownMenuLabelBaseProps,\n\tDropdownMenuPosition,\n\tDropdownMenuRadioGroupBaseProps,\n\tDropdownMenuRadioItemBaseProps,\n\tDropdownMenuSubBaseProps,\n\tDropdownMenuSubTriggerBaseProps,\n\tDropdownMenuTriggerBaseProps,\n} from '../lib/core';\nimport { PortalProvider, usePortalContainer, type PortalContainer } from '../portal';\nimport styles from './dropdown-menu.module.scss';\n\ninterface DropdownMenuContextValue {\n\topen: boolean;\n\tsetOpen: (open: boolean) => void;\n\ttriggerRef: React.RefObject<HTMLElement | null>;\n\tcontentId: string;\n\tcloseAll: () => void;\n}\n\nconst DropdownMenuContext = createContext<DropdownMenuContextValue | null>(null);\n\nfunction useDropdownMenuContext(): DropdownMenuContextValue {\n\tconst context = useContext(DropdownMenuContext);\n\tif (!context) {\n\t\tthrow new Error('DropdownMenu 子组件必须位于 <DropdownMenu> 内部。');\n\t}\n\treturn context;\n}\n\ninterface DropdownMenuContentContextValue {\n\titemsRef: React.RefObject<HTMLElement[]>;\n\tclose: () => void;\n}\n\nconst DropdownMenuContentContext = createContext<DropdownMenuContentContextValue | null>(null);\n\nfunction useDropdownMenuContentContext(): DropdownMenuContentContextValue {\n\tconst context = useContext(DropdownMenuContentContext);\n\tif (!context) {\n\t\tthrow new Error('DropdownMenu 菜单项必须位于 <DropdownMenuContent> 或 <DropdownMenuSubContent> 内部。');\n\t}\n\treturn context;\n}\n\ninterface DropdownMenuSubContextValue {\n\topen: boolean;\n\tsetOpen: (open: boolean) => void;\n\ttriggerRef: React.RefObject<HTMLElement | null>;\n}\n\nconst DropdownMenuSubContext = createContext<DropdownMenuSubContextValue | null>(null);\n\nfunction useDropdownMenuSubContext(): DropdownMenuSubContextValue {\n\tconst context = useContext(DropdownMenuSubContext);\n\tif (!context) {\n\t\tthrow new Error('DropdownMenu 子菜单组件必须位于 <DropdownMenuSub> 内部。');\n\t}\n\treturn context;\n}\n\ninterface DropdownMenuRadioGroupContextValue {\n\tvalue: string | undefined;\n\tsetValue: (value: string) => void;\n}\n\nconst DropdownMenuRadioGroupContext = createContext<DropdownMenuRadioGroupContextValue | null>(null);\n\nfunction useDropdownMenuRadioGroupContext(): DropdownMenuRadioGroupContextValue {\n\tconst context = useContext(DropdownMenuRadioGroupContext);\n\tif (!context) {\n\t\tthrow new Error('DropdownMenuRadioItem 必须位于 <DropdownMenuRadioGroup> 内部。');\n\t}\n\treturn context;\n}\n\nfunction DropdownMenuCheckIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[dropdownMenuStyleKeys.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 DropdownMenuRadioIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[dropdownMenuStyleKeys.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 DropdownMenuChevronIcon() {\n\treturn (\n\t\t<svg\n\t\t\tclassName={styles[dropdownMenuStyleKeys.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 DropdownMenuProps extends React.HTMLAttributes<HTMLDivElement>, DropdownMenuBaseProps {}\n\nconst DropdownMenu = React.forwardRef<HTMLDivElement, DropdownMenuProps>(({ 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\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<DropdownMenuContext.Provider value={{ open: isOpen, setOpen, triggerRef, contentId, closeAll }}>\n\t\t\t<div ref={ref} className={`${styles[dropdownMenuStyleKeys.root]} ${className}`} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</DropdownMenuContext.Provider>\n\t);\n});\nDropdownMenu.displayName = 'DropdownMenu';\n\nexport interface DropdownMenuPortalProps {\n\tcontainer?: PortalContainer;\n\tchildren?: React.ReactNode;\n}\n\nconst DropdownMenuPortal = ({ container, children }: DropdownMenuPortalProps) => {\n\treturn <PortalProvider container={container}>{children}</PortalProvider>;\n};\nDropdownMenuPortal.displayName = 'DropdownMenuPortal';\n\nexport interface DropdownMenuTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, DropdownMenuTriggerBaseProps {}\n\nconst DropdownMenuTrigger = React.forwardRef<HTMLButtonElement, DropdownMenuTriggerProps>(({ className = '', asChild = false, children, onClick, onKeyDown, ...props }, ref) => {\n\tconst context = useDropdownMenuContext();\n\n\tfunction setRef(element: HTMLElement | null) {\n\t\tcontext.triggerRef.current = element;\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element as HTMLButtonElement | null);\n\t\t} else if (ref) {\n\t\t\tref.current = element as HTMLButtonElement | null;\n\t\t}\n\t}\n\n\tfunction handleClick(event: React.MouseEvent<HTMLButtonElement>) {\n\t\tonClick?.(event);\n\t\tcontext.setOpen(!context.open);\n\t}\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n\t\tonKeyDown?.(event);\n\t\tif (event.defaultPrevented) {\n\t\t\treturn;\n\t\t}\n\t\tif (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n\t\t\tevent.preventDefault();\n\t\t\tcontext.setOpen(true);\n\t\t}\n\t}\n\n\tconst Comp = asChild ? Slot : 'button';\n\tconst state = getDropdownMenuState(context.open);\n\n\treturn (\n\t\t<Comp\n\t\t\tref={setRef}\n\t\t\ttype={asChild ? undefined : 'button'}\n\t\t\taria-haspopup=\"menu\"\n\t\t\taria-expanded={context.open}\n\t\t\taria-controls={context.contentId}\n\t\t\tdata-state={state}\n\t\t\tclassName={asChild ? undefined : `${styles[dropdownMenuStyleKeys.trigger]} ${className}`}\n\t\t\tonClick={handleClick}\n\t\t\tonKeyDown={handleKeyDown}\n\t\t\t{...props}>\n\t\t\t{children}\n\t\t</Comp>\n\t);\n});\nDropdownMenuTrigger.displayName = 'DropdownMenuTrigger';\n\nexport interface DropdownMenuContentProps extends React.HTMLAttributes<HTMLDivElement>, DropdownMenuContentBaseProps {\n\tcontainer?: PortalContainer;\n}\n\nconst DropdownMenuContent = React.forwardRef<HTMLDivElement, DropdownMenuContentProps>(\n\t({ className = '', side = 'bottom', align = 'center', sideOffset = 4, alignOffset = 0, container, children, ...props }, ref) => {\n\t\tconst { open, triggerRef, contentId, closeAll } = useDropdownMenuContext();\n\t\tconst portalContainer = usePortalContainer(container);\n\t\tconst [position, setPosition] = useState<DropdownMenuPosition | null>(null);\n\t\tconst contentRef = useRef<HTMLDivElement | null>(null);\n\t\tconst itemsRef = useRef<HTMLElement[]>([]);\n\n\t\tfunction setRef(element: HTMLDivElement | null) {\n\t\t\tcontentRef.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\tuseLayoutEffect(() => {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfunction updatePosition() {\n\t\t\t\tconst trigger = triggerRef.current;\n\t\t\t\tconst content = contentRef.current;\n\t\t\t\tif (!trigger || !content) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst triggerRect = trigger.getBoundingClientRect();\n\t\t\t\tconst contentSize = { width: content.offsetWidth, height: content.offsetHeight };\n\t\t\t\tconst viewport = { width: window.innerWidth, height: window.innerHeight };\n\t\t\t\tsetPosition(getDropdownMenuPosition({ triggerRect, contentSize, side, align, sideOffset, alignOffset, viewport }));\n\t\t\t}\n\n\t\t\tupdatePosition();\n\t\t\twindow.addEventListener('resize', updatePosition);\n\t\t\tdocument.addEventListener('scroll', updatePosition, true);\n\n\t\t\treturn () => {\n\t\t\t\twindow.removeEventListener('resize', updatePosition);\n\t\t\t\tdocument.removeEventListener('scroll', updatePosition, true);\n\t\t\t};\n\t\t}, [open, side, align, sideOffset, alignOffset, triggerRef]);\n\n\t\tuseEffect(() => {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst items = itemsRef.current;\n\t\t\tif (items.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\t\titems[0].setAttribute('data-highlighted', 'true');\n\t\t\titems[0].focus();\n\t\t}, [open]);\n\n\t\tuseEffect(() => {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfunction handlePointerDown(event: PointerEvent) {\n\t\t\t\tconst target = event.target as Node | null;\n\t\t\t\tif (!target) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst content = contentRef.current;\n\t\t\t\tconst trigger = triggerRef.current;\n\t\t\t\tif (content && content.contains(target)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (trigger && trigger.contains(target)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcloseAll();\n\t\t\t}\n\n\t\t\tdocument.addEventListener('pointerdown', handlePointerDown);\n\t\t\treturn () => document.removeEventListener('pointerdown', handlePointerDown);\n\t\t}, [open, triggerRef, closeAll]);\n\n\t\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n\t\t\tconst items = itemsRef.current.filter((item) => item.getAttribute('data-disabled') !== 'true');\n\t\t\tif (items.length === 0) {\n\t\t\t\tif (event.key === 'Escape') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tcloseAll();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst currentIndex = items.findIndex((item) => item.getAttribute('data-highlighted') === 'true');\n\n\t\t\tconst highlight = (next: number) => {\n\t\t\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\t\t\titems[next].setAttribute('data-highlighted', 'true');\n\t\t\t\titems[next].focus();\n\t\t\t};\n\n\t\t\tswitch (event.key) {\n\t\t\t\tcase 'ArrowDown':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(currentIndex < 0 ? 0 : (currentIndex + 1) % items.length);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ArrowUp':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(currentIndex < 0 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Home':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'End':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(items.length - 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Enter':\n\t\t\t\tcase ' ':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t(currentIndex >= 0 ? items[currentIndex] : items[0]).click();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Escape':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tcloseAll();\n\t\t\t\t\ttriggerRef.current?.focus();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst state = getDropdownMenuState(open);\n\t\tconst classes = [styles[dropdownMenuStyleKeys.content], className].filter(Boolean).join(' ');\n\n\t\tconst content = (\n\t\t\t<DropdownMenuContentContext.Provider value={{ itemsRef, close: closeAll }}>\n\t\t\t\t<div\n\t\t\t\t\tref={setRef}\n\t\t\t\t\tid={contentId}\n\t\t\t\t\trole=\"menu\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tdata-state={state}\n\t\t\t\t\tdata-side={side}\n\t\t\t\t\tdata-align={align}\n\t\t\t\t\tclassName={classes}\n\t\t\t\t\tstyle={position ? { top: `${position.top}px`, left: `${position.left}px` } : undefined}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t{...props}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</DropdownMenuContentContext.Provider>\n\t\t);\n\n\t\tif (!open || !portalContainer) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn createPortal(content, portalContainer);\n\t},\n);\nDropdownMenuContent.displayName = 'DropdownMenuContent';\n\nexport interface DropdownMenuGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownMenuGroup = React.forwardRef<HTMLDivElement, DropdownMenuGroupProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<div ref={ref} role=\"group\" className={`${styles[dropdownMenuStyleKeys.group]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nDropdownMenuGroup.displayName = 'DropdownMenuGroup';\n\nexport interface DropdownMenuLabelProps extends React.HTMLAttributes<HTMLDivElement>, DropdownMenuLabelBaseProps {}\n\nconst DropdownMenuLabel = React.forwardRef<HTMLDivElement, DropdownMenuLabelProps>(({ className = '', inset = false, children, ...props }, ref) => {\n\tconst classes = [styles[dropdownMenuStyleKeys.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});\nDropdownMenuLabel.displayName = 'DropdownMenuLabel';\n\nexport interface DropdownMenuSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownMenuSeparator = React.forwardRef<HTMLDivElement, DropdownMenuSeparatorProps>(({ className = '', ...props }, ref) => {\n\tconst classes = [styles[dropdownMenuStyleKeys.separator], className].filter(Boolean).join(' ');\n\treturn <div ref={ref} role=\"separator\" className={classes} {...props} />;\n});\nDropdownMenuSeparator.displayName = 'DropdownMenuSeparator';\n\nexport interface DropdownMenuShortcutProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst DropdownMenuShortcut = React.forwardRef<HTMLSpanElement, DropdownMenuShortcutProps>(({ className = '', children, ...props }, ref) => {\n\tconst classes = [styles[dropdownMenuStyleKeys.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});\nDropdownMenuShortcut.displayName = 'DropdownMenuShortcut';\n\nexport interface DropdownMenuItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'>, DropdownMenuItemBaseProps {}\n\nconst DropdownMenuItem = React.forwardRef<HTMLDivElement, DropdownMenuItemProps>(\n\t({ className = '', inset = false, variant = 'default', disabled = false, onSelect, children, ...props }, ref) => {\n\t\tconst { itemsRef, close } = useDropdownMenuContentContext();\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[dropdownMenuStyleKeys.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);\nDropdownMenuItem.displayName = 'DropdownMenuItem';\n\nexport interface DropdownMenuCheckboxItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'>, DropdownMenuCheckboxItemBaseProps {}\n\nconst DropdownMenuCheckboxItem = React.forwardRef<HTMLDivElement, DropdownMenuCheckboxItemProps>(\n\t({ className = '', checked, defaultChecked = false, onCheckedChange, disabled = false, onSelect, children, ...props }, ref) => {\n\t\tconst { itemsRef } = useDropdownMenuContentContext();\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(event: React.MouseEvent<HTMLDivElement>) {\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\tonSelect?.(event.nativeEvent);\n\t\t}\n\n\t\tconst classes = [styles[dropdownMenuStyleKeys.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={getDropdownMenuCheckState(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[dropdownMenuStyleKeys.indicator]}>{isChecked && <DropdownMenuCheckIcon />}</span>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t},\n);\nDropdownMenuCheckboxItem.displayName = 'DropdownMenuCheckboxItem';\n\nexport interface DropdownMenuRadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'>, DropdownMenuRadioGroupBaseProps {}\n\nconst DropdownMenuRadioGroup = React.forwardRef<HTMLDivElement, DropdownMenuRadioGroupProps>(({ 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[dropdownMenuStyleKeys.radioGroup], className].filter(Boolean).join(' ');\n\treturn (\n\t\t<DropdownMenuRadioGroupContext.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</DropdownMenuRadioGroupContext.Provider>\n\t);\n});\nDropdownMenuRadioGroup.displayName = 'DropdownMenuRadioGroup';\n\nexport interface DropdownMenuRadioItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'>, DropdownMenuRadioItemBaseProps {}\n\nconst DropdownMenuRadioItem = React.forwardRef<HTMLDivElement, DropdownMenuRadioItemProps>(({ className = '', value, disabled = false, onSelect, children, ...props }, ref) => {\n\tconst { itemsRef } = useDropdownMenuContentContext();\n\tconst { value: groupValue, setValue } = useDropdownMenuRadioGroupContext();\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(event: React.MouseEvent<HTMLDivElement>) {\n\t\tif (disabled) {\n\t\t\treturn;\n\t\t}\n\t\tsetValue(value);\n\t\tonSelect?.(event.nativeEvent);\n\t}\n\n\tconst classes = [styles[dropdownMenuStyleKeys.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={getDropdownMenuCheckState(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[dropdownMenuStyleKeys.indicator]}>{isChecked && <DropdownMenuRadioIcon />}</span>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nDropdownMenuRadioItem.displayName = 'DropdownMenuRadioItem';\n\nexport interface DropdownMenuSubProps extends DropdownMenuSubBaseProps {\n\tchildren?: React.ReactNode;\n}\n\nconst DropdownMenuSub = ({ open, defaultOpen = false, onOpenChange, children }: DropdownMenuSubProps) => {\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 <DropdownMenuSubContext.Provider value={{ open: isOpen, setOpen, triggerRef }}>{children}</DropdownMenuSubContext.Provider>;\n};\nDropdownMenuSub.displayName = 'DropdownMenuSub';\n\nexport interface DropdownMenuSubTriggerProps extends React.HTMLAttributes<HTMLDivElement>, DropdownMenuSubTriggerBaseProps {}\n\nconst DropdownMenuSubTrigger = React.forwardRef<HTMLDivElement, DropdownMenuSubTriggerProps>(({ className = '', inset = false, disabled = false, children, ...props }, ref) => {\n\tconst { itemsRef } = useDropdownMenuContentContext();\n\tconst { open, setOpen, triggerRef } = useDropdownMenuSubContext();\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 = getDropdownMenuState(open);\n\tconst classes = [styles[dropdownMenuStyleKeys.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<DropdownMenuChevronIcon />\n\t\t</div>\n\t);\n});\nDropdownMenuSubTrigger.displayName = 'DropdownMenuSubTrigger';\n\nexport interface DropdownMenuSubContentProps extends React.HTMLAttributes<HTMLDivElement>, DropdownMenuContentBaseProps {\n\tcontainer?: PortalContainer;\n}\n\nconst DropdownMenuSubContent = React.forwardRef<HTMLDivElement, DropdownMenuSubContentProps>(\n\t({ className = '', side = 'right', align = 'start', sideOffset = 0, alignOffset = 0, container, children, ...props }, ref) => {\n\t\tconst { open, setOpen, triggerRef } = useDropdownMenuSubContext();\n\t\tconst portalContainer = usePortalContainer(container);\n\t\tconst [position, setPosition] = useState<DropdownMenuPosition | null>(null);\n\t\tconst contentRef = useRef<HTMLDivElement | null>(null);\n\t\tconst itemsRef = useRef<HTMLElement[]>([]);\n\n\t\tfunction setRef(element: HTMLDivElement | null) {\n\t\t\tcontentRef.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\tuseLayoutEffect(() => {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfunction updatePosition() {\n\t\t\t\tconst trigger = triggerRef.current;\n\t\t\t\tconst content = contentRef.current;\n\t\t\t\tif (!trigger || !content) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst triggerRect = trigger.getBoundingClientRect();\n\t\t\t\tconst contentSize = { width: content.offsetWidth, height: content.offsetHeight };\n\t\t\t\tconst viewport = { width: window.innerWidth, height: window.innerHeight };\n\t\t\t\tsetPosition(getDropdownMenuPosition({ triggerRect, contentSize, side, align, sideOffset, alignOffset, viewport }));\n\t\t\t}\n\n\t\t\tupdatePosition();\n\t\t\twindow.addEventListener('resize', updatePosition);\n\t\t\tdocument.addEventListener('scroll', updatePosition, true);\n\n\t\t\treturn () => {\n\t\t\t\twindow.removeEventListener('resize', updatePosition);\n\t\t\t\tdocument.removeEventListener('scroll', updatePosition, true);\n\t\t\t};\n\t\t}, [open, side, align, sideOffset, alignOffset, triggerRef]);\n\n\t\tuseEffect(() => {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfunction handlePointerDown(event: PointerEvent) {\n\t\t\t\tconst target = event.target as Node | null;\n\t\t\t\tif (!target) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst content = contentRef.current;\n\t\t\t\tconst trigger = triggerRef.current;\n\t\t\t\tif (content && content.contains(target)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (trigger && trigger.contains(target)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetOpen(false);\n\t\t\t}\n\n\t\t\tdocument.addEventListener('pointerdown', handlePointerDown);\n\t\t\treturn () => document.removeEventListener('pointerdown', handlePointerDown);\n\t\t}, [open, triggerRef, setOpen]);\n\n\t\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n\t\t\tconst items = itemsRef.current.filter((item) => item.getAttribute('data-disabled') !== 'true');\n\n\t\t\tif (event.key === 'Escape' || event.key === 'ArrowLeft') {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tsetOpen(false);\n\t\t\t\ttriggerRef.current?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (items.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst currentIndex = items.findIndex((item) => item.getAttribute('data-highlighted') === 'true');\n\t\t\tconst highlight = (next: number) => {\n\t\t\t\titems.forEach((item) => item.removeAttribute('data-highlighted'));\n\t\t\t\titems[next].setAttribute('data-highlighted', 'true');\n\t\t\t\titems[next].focus();\n\t\t\t};\n\n\t\t\tswitch (event.key) {\n\t\t\t\tcase 'ArrowDown':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(currentIndex < 0 ? 0 : (currentIndex + 1) % items.length);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ArrowUp':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\thighlight(currentIndex < 0 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Enter':\n\t\t\t\tcase ' ':\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t(currentIndex >= 0 ? items[currentIndex] : items[0]).click();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst state = getDropdownMenuState(open);\n\t\tconst classes = [styles[dropdownMenuStyleKeys.subContent], className].filter(Boolean).join(' ');\n\n\t\tconst content = (\n\t\t\t<DropdownMenuContentContext.Provider value={{ itemsRef, close: () => setOpen(false) }}>\n\t\t\t\t<div\n\t\t\t\t\tref={setRef}\n\t\t\t\t\trole=\"menu\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tdata-state={state}\n\t\t\t\t\tdata-side={side}\n\t\t\t\t\tdata-align={align}\n\t\t\t\t\tclassName={classes}\n\t\t\t\t\tstyle={position ? { top: `${position.top}px`, left: `${position.left}px` } : undefined}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t{...props}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</DropdownMenuContentContext.Provider>\n\t\t);\n\n\t\tif (!open || !portalContainer) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn createPortal(content, portalContainer);\n\t},\n);\nDropdownMenuSubContent.displayName = 'DropdownMenuSubContent';\n\nexport {\n\tDropdownMenu,\n\tDropdownMenuPortal,\n\tDropdownMenuTrigger,\n\tDropdownMenuContent,\n\tDropdownMenuGroup,\n\tDropdownMenuLabel,\n\tDropdownMenuItem,\n\tDropdownMenuCheckboxItem,\n\tDropdownMenuRadioGroup,\n\tDropdownMenuRadioItem,\n\tDropdownMenuSeparator,\n\tDropdownMenuShortcut,\n\tDropdownMenuSub,\n\tDropdownMenuSubTrigger,\n\tDropdownMenuSubContent,\n};\nexport default DropdownMenu;\n"
    },
    {
      "path": "packages/styles/scss/components/dropdown-menu.module.scss",
      "type": "registry:file",
      "target": "components/ui/dropdown-menu/dropdown-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\talign-items: center;\n\tborder: none;\n\tbackground: transparent;\n\tpadding: 0;\n\tcolor: inherit;\n\tfont: inherit;\n\tcursor: pointer;\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\n\t\t&[data-side='top'] {\n\t\t\ttransform: translateY(0.25rem);\n\t\t}\n\n\t\t&[data-side='right'] {\n\t\t\ttransform: translateX(-0.25rem);\n\t\t}\n\n\t\t&[data-side='bottom'] {\n\t\t\ttransform: translateY(-0.25rem);\n\t\t}\n\n\t\t&[data-side='left'] {\n\t\t\ttransform: translateX(0.25rem);\n\t\t}\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.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// Optional theme hooks; every fallback is the original Tile value.\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\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\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/dropdown-menu/index.ts",
      "type": "registry:ui",
      "target": "components/ui/dropdown-menu/index.ts",
      "content": "export {\n\tDropdownMenu,\n\tDropdownMenuPortal,\n\tDropdownMenuTrigger,\n\tDropdownMenuContent,\n\tDropdownMenuGroup,\n\tDropdownMenuLabel,\n\tDropdownMenuItem,\n\tDropdownMenuCheckboxItem,\n\tDropdownMenuRadioGroup,\n\tDropdownMenuRadioItem,\n\tDropdownMenuSeparator,\n\tDropdownMenuShortcut,\n\tDropdownMenuSub,\n\tDropdownMenuSubTrigger,\n\tDropdownMenuSubContent,\n\ttype DropdownMenuProps,\n\ttype DropdownMenuPortalProps,\n\ttype DropdownMenuTriggerProps,\n\ttype DropdownMenuContentProps,\n\ttype DropdownMenuGroupProps,\n\ttype DropdownMenuLabelProps,\n\ttype DropdownMenuItemProps,\n\ttype DropdownMenuCheckboxItemProps,\n\ttype DropdownMenuRadioGroupProps,\n\ttype DropdownMenuRadioItemProps,\n\ttype DropdownMenuSeparatorProps,\n\ttype DropdownMenuShortcutProps,\n\ttype DropdownMenuSubProps,\n\ttype DropdownMenuSubTriggerProps,\n\ttype DropdownMenuSubContentProps,\n} from './dropdown-menu';\n"
    }
  ]
}
