{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "title": "Context menu",
  "author": "andongmin94",
  "description": "A contextual action menu opened with a secondary pointer action.",
  "dependencies": [
    "@base-ui/react@^1.6.0"
  ],
  "files": [
    {
      "path": "src/components/ui/context-menu.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { ContextMenu as ContextMenuPrimitive } from \"@base-ui/react/context-menu\";\nimport { DirectionProvider } from \"@base-ui/react/direction-provider\";\n\nimport { cn } from \"@/lib/utils\";\nimport { ChevronRightIcon, CheckIcon, CircleIcon } from \"lucide-react\";\n\ntype MenuLifecycleHandler<EventType extends Event = Event> = {\n  bivarianceHack(event: EventType): void;\n}[\"bivarianceHack\"];\n\ntype MenuOutsideEvent = CustomEvent<{ originalEvent: Event }>;\n\nfunction setMenuOutsideEventTarget(event: Event, originalEvent: Event) {\n  for (const property of [\"target\", \"currentTarget\"] as const) {\n    Object.defineProperty(event, property, {\n      configurable: true,\n      value: originalEvent.target,\n    });\n  }\n}\n\ntype MenuContentLifecycleProps = {\n  onCloseAutoFocus?: MenuLifecycleHandler;\n  onEscapeKeyDown?: MenuLifecycleHandler<KeyboardEvent>;\n  onFocusOutside?: MenuLifecycleHandler<MenuOutsideEvent>;\n  onInteractOutside?: MenuLifecycleHandler<MenuOutsideEvent>;\n  onOpenAutoFocus?: MenuLifecycleHandler;\n  onPointerDownOutside?: MenuLifecycleHandler<MenuOutsideEvent>;\n};\n\ntype CheckedState = boolean | \"indeterminate\";\ntype CollisionBoundary =\n  | ContextMenuPrimitive.Positioner.Props[\"collisionBoundary\"]\n  | null\n  | Array<Element | null>;\ntype CSSPropertiesWithVariables = React.CSSProperties & {\n  [name: `--${string}`]: string | number | undefined;\n};\ntype MenuPositioningProps = Pick<\n  ContextMenuPrimitive.Positioner.Props,\n  | \"align\"\n  | \"alignOffset\"\n  | \"arrowPadding\"\n  | \"collisionAvoidance\"\n  | \"collisionPadding\"\n  | \"disableAnchorTracking\"\n  | \"positionMethod\"\n  | \"side\"\n  | \"sideOffset\"\n> & {\n  avoidCollisions?: boolean;\n  collisionBoundary?: CollisionBoundary;\n  hideWhenDetached?: boolean;\n  sticky?: \"partial\" | \"always\";\n  updatePositionStrategy?: \"optimized\" | \"always\";\n};\n\nconst contextMenuCssVariables: CSSPropertiesWithVariables = {\n  \"--radix-context-menu-content-available-height\": \"var(--available-height)\",\n  \"--radix-context-menu-content-available-width\": \"var(--available-width)\",\n  \"--radix-context-menu-content-transform-origin\": \"var(--transform-origin)\",\n  \"--radix-context-menu-trigger-height\": \"var(--anchor-height)\",\n  \"--radix-context-menu-trigger-width\": \"var(--anchor-width)\",\n};\n\nfunction mergePopupStyle(\n  style: ContextMenuPrimitive.Popup.Props[\"style\"],\n): ContextMenuPrimitive.Popup.Props[\"style\"] {\n  if (typeof style === \"function\") {\n    return (state) => ({ ...contextMenuCssVariables, ...style(state) });\n  }\n\n  return { ...contextMenuCssVariables, ...style };\n}\n\nfunction normalizeCollisionBoundary(\n  collisionBoundary: CollisionBoundary | undefined,\n): ContextMenuPrimitive.Positioner.Props[\"collisionBoundary\"] {\n  if (Array.isArray(collisionBoundary)) {\n    const boundaries: Element[] = [];\n    for (const boundary of collisionBoundary) {\n      if (boundary) boundaries.push(boundary);\n    }\n    return boundaries;\n  }\n\n  return collisionBoundary ?? undefined;\n}\n\nfunction preserveRadixEventCancellation<\n  Props extends { [key: string]: unknown; children?: React.ReactNode },\n>(child: React.ReactElement<Props>): React.ReactElement<Props> {\n  const eventProps: Record<string, unknown> = {};\n\n  for (const [name, handler] of Object.entries(child.props)) {\n    if (/^on[A-Z]/.test(name) && typeof handler === \"function\") {\n      eventProps[name] = (...args: unknown[]) => {\n        (handler as (...handlerArgs: unknown[]) => void)(...args);\n        const event = args[0] as\n          | { defaultPrevented?: boolean; preventBaseUIHandler?: () => void }\n          | undefined;\n        if (event?.defaultPrevented) event.preventBaseUIHandler?.();\n      };\n    }\n  }\n\n  return React.cloneElement(child, eventProps as Partial<Props>);\n}\n\nfunction getAsChildElement(children: React.ReactNode, componentName: string) {\n  const child = React.Children.toArray(children).find(React.isValidElement);\n\n  if (!child) {\n    throw new Error(`${componentName} with asChild requires a valid React element child.`);\n  }\n\n  return preserveRadixEventCancellation(\n    child as React.ReactElement<{\n      [key: string]: unknown;\n      children?: React.ReactNode;\n      className?: string;\n    }>,\n  );\n}\n\ntype MenuLifecycleHandlers = Pick<\n  MenuContentLifecycleProps,\n  \"onEscapeKeyDown\" | \"onFocusOutside\" | \"onInteractOutside\" | \"onPointerDownOutside\"\n>;\n\ntype ContextMenuAdapterContextValue = {\n  lifecycleHandlersRef: React.MutableRefObject<MenuLifecycleHandlers>;\n  open: boolean;\n  setLoopFocus: React.Dispatch<React.SetStateAction<boolean>>;\n  setTriggerDisabled: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nconst ContextMenuAdapterContext = React.createContext<ContextMenuAdapterContextValue | null>(null);\n\ntype ContextMenuRadioGroupContextValue = {\n  setValue: (value: string) => void;\n  value: string | undefined;\n};\n\nconst ContextMenuRadioGroupContext = React.createContext<ContextMenuRadioGroupContextValue | null>(\n  null,\n);\n\ntype ContextMenuRootProps = Omit<ContextMenuPrimitive.Root.Props, \"onOpenChange\"> & {\n  dir?: \"ltr\" | \"rtl\";\n  modal?: boolean;\n  onOpenChange?: (open: boolean) => void;\n};\n\ntype ContextMenuSubProps = Omit<ContextMenuPrimitive.SubmenuRoot.Props, \"onOpenChange\"> & {\n  onOpenChange?: (open: boolean) => void;\n};\n\nfunction useContextMenuAdapter(\n  openProp: boolean | undefined,\n  defaultOpen: boolean | undefined,\n  onOpenChange: ((open: boolean) => void) | undefined,\n) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false);\n  const [loopFocus, setLoopFocus] = React.useState(false);\n  const [triggerDisabled, setTriggerDisabled] = React.useState(false);\n  const open = openProp ?? uncontrolledOpen;\n  const lifecycleHandlersRef = React.useRef<MenuLifecycleHandlers>({});\n\n  const handleOpenChange = React.useCallback(\n    (nextOpen: boolean, eventDetails: ContextMenuPrimitive.Root.ChangeEventDetails) => {\n      const event = eventDetails.event;\n\n      if (!nextOpen) {\n        const handlers = lifecycleHandlersRef.current;\n        let closeEvent: Event | undefined;\n\n        if (eventDetails.reason === \"escape-key\") {\n          handlers.onEscapeKeyDown?.(eventDetails.event);\n          closeEvent = eventDetails.event;\n        } else if (eventDetails.reason === \"outside-press\") {\n          const outsideEvent = new CustomEvent<{ originalEvent: Event }>(\"pointerDownOutside\", {\n            cancelable: true,\n            detail: { originalEvent: event },\n          });\n          setMenuOutsideEventTarget(outsideEvent, event);\n          handlers.onPointerDownOutside?.(outsideEvent);\n          handlers.onInteractOutside?.(outsideEvent);\n          closeEvent = outsideEvent;\n        } else if (eventDetails.reason === \"focus-out\") {\n          const outsideEvent = new CustomEvent<{ originalEvent: Event }>(\"focusOutside\", {\n            cancelable: true,\n            detail: { originalEvent: event },\n          });\n          setMenuOutsideEventTarget(outsideEvent, event);\n          handlers.onFocusOutside?.(outsideEvent);\n          handlers.onInteractOutside?.(outsideEvent);\n          closeEvent = outsideEvent;\n        }\n\n        if (closeEvent?.defaultPrevented) {\n          eventDetails.cancel();\n          return;\n        }\n      }\n\n      if (openProp === undefined) {\n        setUncontrolledOpen(nextOpen);\n      }\n      onOpenChange?.(nextOpen);\n    },\n    [onOpenChange, openProp],\n  );\n\n  const context = React.useMemo<ContextMenuAdapterContextValue>(\n    () => ({ lifecycleHandlersRef, open, setLoopFocus, setTriggerDisabled }),\n    [open],\n  );\n\n  return { context, handleOpenChange, loopFocus, triggerDisabled };\n}\n\nfunction useMenuOpenAutoFocus(onOpenAutoFocus: MenuLifecycleHandler | undefined) {\n  const adapter = React.useContext(ContextMenuAdapterContext);\n  const previouslyOpenRef = React.useRef(false);\n  const [blockInitialFocus, setBlockInitialFocus] = React.useState(false);\n\n  React.useLayoutEffect(() => {\n    const open = adapter?.open ?? false;\n    let firstFrame = 0;\n    let secondFrame = 0;\n\n    if (open && !previouslyOpenRef.current && onOpenAutoFocus) {\n      const event = new Event(\"openAutoFocus\", { cancelable: true });\n      onOpenAutoFocus(event);\n\n      if (event.defaultPrevented) {\n        setBlockInitialFocus(true);\n        if (typeof window.requestAnimationFrame === \"function\") {\n          firstFrame = window.requestAnimationFrame(() => {\n            secondFrame = window.requestAnimationFrame(() => setBlockInitialFocus(false));\n          });\n        } else {\n          setBlockInitialFocus(false);\n        }\n      }\n    } else if (!open) {\n      setBlockInitialFocus(false);\n    }\n\n    previouslyOpenRef.current = open;\n    return () => {\n      if (typeof window.cancelAnimationFrame === \"function\") {\n        if (firstFrame) window.cancelAnimationFrame(firstFrame);\n        if (secondFrame) window.cancelAnimationFrame(secondFrame);\n      }\n    };\n  }, [adapter, onOpenAutoFocus]);\n\n  return blockInitialFocus;\n}\n\ntype MenuItemOnClick = ContextMenuPrimitive.Item.Props[\"onClick\"];\ntype MenuItemClickEvent = Parameters<NonNullable<MenuItemOnClick>>[0];\n\nfunction handleMenuItemSelect(\n  event: MenuItemClickEvent,\n  onClick: MenuItemOnClick,\n  onSelect: MenuLifecycleHandler | undefined,\n) {\n  onClick?.(event);\n\n  const selectEvent = new CustomEvent(\"menu.itemSelect\", {\n    bubbles: true,\n    cancelable: true,\n  });\n  const item = event.currentTarget;\n  const handleSelect = (customEvent: Event) => onSelect?.(customEvent);\n  item.addEventListener(selectEvent.type, handleSelect, { once: true });\n  item.dispatchEvent(selectEvent);\n\n  if (selectEvent.defaultPrevented) {\n    event.preventBaseUIHandler();\n  }\n\n  return selectEvent;\n}\n\nfunction ContextMenu({\n  children,\n  defaultOpen,\n  dir,\n  disabled,\n  loopFocus,\n  modal = true,\n  onOpenChange,\n  open,\n  ...props\n}: ContextMenuRootProps) {\n  const adapter = useContextMenuAdapter(open, defaultOpen, onOpenChange);\n\n  // Base UI context menus are modal by design; consume the Radix prop without forwarding it.\n  void modal;\n\n  const root = (\n    <ContextMenuPrimitive.Root\n      data-slot=\"context-menu\"\n      defaultOpen={defaultOpen}\n      disabled={disabled ?? adapter.triggerDisabled}\n      loopFocus={loopFocus ?? adapter.loopFocus}\n      onOpenChange={adapter.handleOpenChange}\n      open={open}\n      {...props}\n    >\n      {children}\n    </ContextMenuPrimitive.Root>\n  );\n\n  return (\n    <ContextMenuAdapterContext.Provider value={adapter.context}>\n      {dir ? <DirectionProvider direction={dir}>{root}</DirectionProvider> : root}\n    </ContextMenuAdapterContext.Provider>\n  );\n}\n\nfunction ContextMenuPortal({\n  forceMount,\n  keepMounted,\n  ...props\n}: ContextMenuPrimitive.Portal.Props & { forceMount?: boolean }) {\n  return (\n    <ContextMenuPrimitive.Portal\n      data-slot=\"context-menu-portal\"\n      keepMounted={forceMount ?? keepMounted}\n      {...props}\n    />\n  );\n}\n\nfunction ContextMenuTrigger({\n  asChild = false,\n  children,\n  className,\n  disabled = false,\n  onContextMenu,\n  onKeyDown,\n  onTouchStart,\n  render,\n  ...props\n}: ContextMenuPrimitive.Trigger.Props & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n  disabled?: boolean;\n}) {\n  const adapter = React.useContext(ContextMenuAdapterContext);\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuTrigger\") : render;\n  const setTriggerDisabled = adapter?.setTriggerDisabled;\n\n  React.useLayoutEffect(() => {\n    setTriggerDisabled?.(disabled);\n    return () => setTriggerDisabled?.(false);\n  }, [disabled, setTriggerDisabled]);\n\n  return (\n    <ContextMenuPrimitive.Trigger\n      data-slot=\"context-menu-trigger\"\n      data-disabled={disabled ? \"\" : undefined}\n      data-state={adapter ? (adapter.open ? \"open\" : \"closed\") : undefined}\n      aria-disabled={disabled || undefined}\n      className={cn(\"select-none\", className)}\n      onContextMenu={(event) => {\n        onContextMenu?.(event);\n        if (disabled) event.preventBaseUIHandler();\n      }}\n      onKeyDown={(event) => {\n        onKeyDown?.(event);\n        if (\n          disabled ||\n          event.defaultPrevented ||\n          (event.key !== \"ContextMenu\" && !(event.key === \"F10\" && event.shiftKey))\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const rect = event.currentTarget.getBoundingClientRect();\n        event.currentTarget.dispatchEvent(\n          new MouseEvent(\"contextmenu\", {\n            bubbles: true,\n            cancelable: true,\n            clientX: rect.left + rect.width / 2,\n            clientY: rect.top + rect.height / 2,\n          }),\n        );\n      }}\n      onTouchStart={(event) => {\n        onTouchStart?.(event);\n        if (disabled) event.preventBaseUIHandler();\n      }}\n      render={renderElement}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </ContextMenuPrimitive.Trigger>\n  );\n}\n\nfunction ContextMenuContent({\n  className,\n  align = \"start\",\n  alignOffset = 4,\n  arrowPadding = 0,\n  asChild = false,\n  avoidCollisions = true,\n  children,\n  collisionAvoidance,\n  collisionBoundary,\n  collisionPadding = 0,\n  disableAnchorTracking,\n  side = \"right\",\n  sideOffset = 0,\n  finalFocus,\n  forceMount,\n  hideWhenDetached = false,\n  inert,\n  loop = false,\n  onCloseAutoFocus,\n  onEscapeKeyDown,\n  onFocusOutside,\n  onInteractOutside,\n  onOpenAutoFocus,\n  onPointerDownOutside,\n  positionMethod,\n  render,\n  sticky,\n  style,\n  updatePositionStrategy,\n  ...props\n}: ContextMenuPrimitive.Popup.Props &\n  MenuPositioningProps &\n  MenuContentLifecycleProps & { asChild?: boolean; forceMount?: boolean; loop?: boolean }) {\n  const adapter = React.useContext(ContextMenuAdapterContext);\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuContent\") : render;\n\n  if (adapter) {\n    adapter.lifecycleHandlersRef.current = {\n      onEscapeKeyDown,\n      onFocusOutside,\n      onInteractOutside,\n      onPointerDownOutside,\n    };\n  }\n\n  const blockInitialFocus = useMenuOpenAutoFocus(onOpenAutoFocus);\n\n  React.useLayoutEffect(() => {\n    adapter?.setLoopFocus(loop);\n  }, [adapter, loop]);\n\n  const adaptedFinalFocus: ContextMenuPrimitive.Popup.Props[\"finalFocus\"] = onCloseAutoFocus\n    ? (closeType) => {\n        const event = new Event(\"closeAutoFocus\", { cancelable: true });\n        onCloseAutoFocus(event);\n\n        if (event.defaultPrevented) {\n          return false;\n        }\n        if (typeof finalFocus === \"function\") {\n          return finalFocus(closeType);\n        }\n        if (typeof finalFocus === \"object\" && finalFocus !== null) {\n          return finalFocus.current;\n        }\n        return typeof finalFocus === \"boolean\" ? finalFocus : true;\n      }\n    : finalFocus;\n\n  return (\n    <ContextMenuPrimitive.Portal keepMounted={forceMount}>\n      <ContextMenuPrimitive.Positioner\n        align={align}\n        alignOffset={alignOffset}\n        arrowPadding={arrowPadding}\n        collisionAvoidance={\n          avoidCollisions\n            ? collisionAvoidance\n            : { align: \"none\", fallbackAxisSide: \"none\", side: \"none\" }\n        }\n        collisionBoundary={normalizeCollisionBoundary(collisionBoundary)}\n        collisionPadding={collisionPadding}\n        disableAnchorTracking={updatePositionStrategy === \"always\" ? false : disableAnchorTracking}\n        positionMethod={positionMethod}\n        side={side}\n        sideOffset={sideOffset}\n        sticky={sticky === undefined ? undefined : sticky === \"always\"}\n        className={cn(\n          \"isolate z-50 outline-none\",\n          hideWhenDetached && \"data-anchor-hidden:pointer-events-none data-anchor-hidden:invisible\",\n        )}\n      >\n        <ContextMenuPrimitive.Popup\n          data-slot=\"context-menu-content\"\n          data-state={adapter ? (adapter.open ? \"open\" : \"closed\") : undefined}\n          finalFocus={adaptedFinalFocus}\n          inert={inert || blockInitialFocus}\n          render={renderElement}\n          style={mergePopupStyle(style)}\n          className={cn(\n            \"z-50 min-w-[8rem] origin-(--transform-origin) overflow-hidden rounded-base border-2 border-border bg-main p-1 font-base text-main-foreground duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n            className,\n          )}\n          {...props}\n        >\n          {asChild ? undefined : children}\n        </ContextMenuPrimitive.Popup>\n      </ContextMenuPrimitive.Positioner>\n    </ContextMenuPrimitive.Portal>\n  );\n}\n\nfunction ContextMenuGroup({\n  asChild = false,\n  children,\n  render,\n  ...props\n}: ContextMenuPrimitive.Group.Props & { asChild?: boolean }) {\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuGroup\") : render;\n\n  return (\n    <ContextMenuPrimitive.Group data-slot=\"context-menu-group\" render={renderElement} {...props}>\n      {asChild ? undefined : children}\n    </ContextMenuPrimitive.Group>\n  );\n}\n\nfunction ContextMenuLabel({\n  asChild = false,\n  children,\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  asChild?: boolean;\n  inset?: boolean;\n}) {\n  if (asChild) {\n    const child = getAsChildElement(children, \"ContextMenuLabel\");\n    return React.cloneElement(child, {\n      ...props,\n      \"data-inset\": inset,\n      \"data-slot\": \"context-menu-label\",\n      className: cn(\n        \"border-2 border-transparent px-2 py-1.5 text-sm font-base text-main-foreground data-inset:pl-8\",\n        child.props.className,\n        className,\n      ),\n      role: \"presentation\",\n    });\n  }\n\n  return (\n    <div\n      data-slot=\"context-menu-label\"\n      data-inset={inset}\n      role=\"presentation\"\n      className={cn(\n        \"border-2 border-transparent px-2 py-1.5 text-sm font-base text-main-foreground data-inset:pl-8\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nfunction ContextMenuItem({\n  asChild = false,\n  children,\n  className,\n  inset,\n  label,\n  onClick,\n  onSelect,\n  render,\n  textValue,\n  variant = \"default\",\n  ...props\n}: ContextMenuPrimitive.Item.Props & {\n  asChild?: boolean;\n  inset?: boolean;\n  onSelect?: MenuLifecycleHandler;\n  textValue?: string;\n  variant?: \"default\" | \"destructive\";\n}) {\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuItem\") : render;\n\n  return (\n    <ContextMenuPrimitive.Item\n      data-slot=\"context-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      label={label ?? textValue}\n      render={renderElement}\n      className={cn(\n        \"group/context-menu-item relative flex cursor-default items-center gap-2 rounded-base border-2 border-transparent bg-main px-2 py-1.5 text-sm font-base outline-hidden transition-colors select-none focus:border-border data-inset:pl-8 data-[variant=destructive]:text-destructive data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n        className,\n      )}\n      onClick={(event) => handleMenuItemSelect(event, onClick, onSelect)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </ContextMenuPrimitive.Item>\n  );\n}\n\nfunction ContextMenuSub({\n  children,\n  defaultOpen,\n  loopFocus,\n  onOpenChange,\n  open,\n  ...props\n}: ContextMenuSubProps) {\n  const adapter = useContextMenuAdapter(open, defaultOpen, onOpenChange);\n\n  return (\n    <ContextMenuAdapterContext.Provider value={adapter.context}>\n      <ContextMenuPrimitive.SubmenuRoot\n        data-slot=\"context-menu-sub\"\n        defaultOpen={defaultOpen}\n        loopFocus={loopFocus ?? adapter.loopFocus}\n        onOpenChange={adapter.handleOpenChange}\n        open={open}\n        {...props}\n      >\n        {children}\n      </ContextMenuPrimitive.SubmenuRoot>\n    </ContextMenuAdapterContext.Provider>\n  );\n}\n\nfunction ContextMenuSubTrigger({\n  asChild = false,\n  className,\n  inset,\n  children,\n  label,\n  render,\n  textValue,\n  ...props\n}: ContextMenuPrimitive.SubmenuTrigger.Props & {\n  asChild?: boolean;\n  inset?: boolean;\n  textValue?: string;\n}) {\n  const adapter = React.useContext(ContextMenuAdapterContext);\n  const child = asChild ? getAsChildElement(children, \"ContextMenuSubTrigger\") : null;\n  const triggerChildren = (\n    <>\n      {child ? child.props.children : children}\n      <ChevronRightIcon className=\"ml-auto\" />\n    </>\n  );\n  const renderElement = child ? React.cloneElement(child, undefined, triggerChildren) : render;\n\n  return (\n    <ContextMenuPrimitive.SubmenuTrigger\n      data-slot=\"context-menu-sub-trigger\"\n      data-inset={inset}\n      data-state={adapter ? (adapter.open ? \"open\" : \"closed\") : undefined}\n      label={label ?? textValue}\n      render={renderElement}\n      className={cn(\n        \"flex cursor-default items-center gap-2 rounded-base border-2 border-transparent bg-main px-2 py-1.5 text-sm font-base outline-hidden select-none focus:border-border data-inset:pl-8 data-open:border-border data-popup-open:border-border [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n        className,\n      )}\n      {...props}\n    >\n      {child ? undefined : triggerChildren}\n    </ContextMenuPrimitive.SubmenuTrigger>\n  );\n}\n\nfunction ContextMenuSubContent({ ...props }: React.ComponentProps<typeof ContextMenuContent>) {\n  return (\n    <ContextMenuContent\n      data-slot=\"context-menu-sub-content\"\n      className=\"shadow-none\"\n      side=\"right\"\n      {...props}\n    />\n  );\n}\n\ntype ContextMenuCheckboxItemProps = Omit<\n  ContextMenuPrimitive.CheckboxItem.Props,\n  \"checked\" | \"defaultChecked\" | \"onCheckedChange\"\n> & {\n  asChild?: boolean;\n  checked?: CheckedState;\n  defaultChecked?: CheckedState;\n  inset?: boolean;\n  onCheckedChange?: (checked: boolean) => void;\n  onSelect?: MenuLifecycleHandler;\n  textValue?: string;\n};\n\nfunction ContextMenuCheckboxItem({\n  asChild = false,\n  className,\n  children,\n  checked,\n  defaultChecked = false,\n  closeOnClick = true,\n  inset,\n  label,\n  onCheckedChange,\n  onClick,\n  onSelect,\n  render,\n  textValue,\n  ...props\n}: ContextMenuCheckboxItemProps) {\n  const controlled = checked !== undefined;\n  const [uncontrolledChecked, setUncontrolledChecked] = React.useState(defaultChecked);\n  const currentChecked = checked ?? uncontrolledChecked;\n  const child = asChild ? getAsChildElement(children, \"ContextMenuCheckboxItem\") : null;\n  const state =\n    currentChecked === \"indeterminate\" ? \"indeterminate\" : currentChecked ? \"checked\" : \"unchecked\";\n  const itemChildren = (\n    <>\n      <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.CheckboxItemIndicator\n          data-state={state}\n          keepMounted={currentChecked === \"indeterminate\"}\n        >\n          <CheckIcon />\n        </ContextMenuPrimitive.CheckboxItemIndicator>\n      </span>\n      {child ? child.props.children : children}\n    </>\n  );\n  const renderElement = child ? React.cloneElement(child, undefined, itemChildren) : render;\n\n  return (\n    <ContextMenuPrimitive.CheckboxItem\n      data-slot=\"context-menu-checkbox-item\"\n      data-inset={inset}\n      data-state={state}\n      aria-checked={currentChecked === \"indeterminate\" ? \"mixed\" : currentChecked}\n      label={label ?? textValue}\n      render={renderElement}\n      className={cn(\n        \"relative flex cursor-default items-center gap-2 rounded-base border-2 border-transparent py-1.5 pr-2 pl-8 text-sm font-base text-main-foreground outline-hidden transition-colors select-none focus:border-border data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      checked={currentChecked === true}\n      closeOnClick={closeOnClick}\n      onClick={(event) => {\n        handleMenuItemSelect(event, onClick, onSelect);\n        const nextChecked = currentChecked === \"indeterminate\" ? true : !currentChecked;\n        if (!controlled) setUncontrolledChecked(nextChecked);\n        onCheckedChange?.(nextChecked);\n      }}\n      {...props}\n    >\n      {child ? undefined : itemChildren}\n    </ContextMenuPrimitive.CheckboxItem>\n  );\n}\n\ntype ContextMenuRadioGroupProps = Omit<\n  ContextMenuPrimitive.RadioGroup.Props,\n  \"defaultValue\" | \"onValueChange\" | \"value\"\n> & {\n  defaultValue?: string;\n  onValueChange?: (value: string) => void;\n  value?: string;\n};\n\nfunction ContextMenuRadioGroup({\n  asChild = false,\n  children,\n  defaultValue,\n  onValueChange,\n  render,\n  value: valueProp,\n  ...props\n}: ContextMenuRadioGroupProps & { asChild?: boolean }) {\n  const controlled = valueProp !== undefined;\n  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);\n  const value = valueProp ?? uncontrolledValue;\n  const context = React.useMemo<ContextMenuRadioGroupContextValue>(\n    () => ({\n      setValue(nextValue) {\n        if (!controlled) setUncontrolledValue(nextValue);\n        onValueChange?.(nextValue);\n      },\n      value,\n    }),\n    [controlled, onValueChange, value],\n  );\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuRadioGroup\") : render;\n\n  return (\n    <ContextMenuRadioGroupContext.Provider value={context}>\n      <ContextMenuPrimitive.RadioGroup\n        data-slot=\"context-menu-radio-group\"\n        render={renderElement}\n        value={value ?? null}\n        {...props}\n      >\n        {asChild ? undefined : children}\n      </ContextMenuPrimitive.RadioGroup>\n    </ContextMenuRadioGroupContext.Provider>\n  );\n}\n\nfunction ContextMenuRadioItem({\n  asChild = false,\n  className,\n  children,\n  closeOnClick = true,\n  inset,\n  label,\n  onClick,\n  onSelect,\n  render,\n  textValue,\n  ...props\n}: Omit<ContextMenuPrimitive.RadioItem.Props, \"value\"> & {\n  asChild?: boolean;\n  inset?: boolean;\n  onSelect?: MenuLifecycleHandler;\n  textValue?: string;\n  value: string;\n}) {\n  const radioGroup = React.useContext(ContextMenuRadioGroupContext);\n  if (!radioGroup) {\n    throw new Error(\"ContextMenuRadioItem must be used within ContextMenuRadioGroup\");\n  }\n  const child = asChild ? getAsChildElement(children, \"ContextMenuRadioItem\") : null;\n  const state = radioGroup.value === props.value ? \"checked\" : \"unchecked\";\n  const itemChildren = (\n    <>\n      <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.RadioItemIndicator data-state={state}>\n          <CircleIcon className=\"size-2 fill-current\" />\n        </ContextMenuPrimitive.RadioItemIndicator>\n      </span>\n      {child ? child.props.children : children}\n    </>\n  );\n  const renderElement = child ? React.cloneElement(child, undefined, itemChildren) : render;\n\n  return (\n    <ContextMenuPrimitive.RadioItem\n      data-slot=\"context-menu-radio-item\"\n      data-inset={inset}\n      data-state={state}\n      label={label ?? textValue}\n      render={renderElement}\n      className={cn(\n        \"relative flex cursor-default items-center gap-2 rounded-base border-2 border-transparent py-1.5 pr-2 pl-8 text-sm font-base text-main-foreground outline-hidden transition-colors select-none focus:border-border data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      closeOnClick={closeOnClick}\n      onClick={(event) => {\n        handleMenuItemSelect(event, onClick, onSelect);\n        radioGroup.setValue(props.value);\n      }}\n      {...props}\n    >\n      {child ? undefined : itemChildren}\n    </ContextMenuPrimitive.RadioItem>\n  );\n}\n\nfunction ContextMenuSeparator({\n  asChild = false,\n  children,\n  className,\n  render,\n  ...props\n}: ContextMenuPrimitive.Separator.Props & { asChild?: boolean }) {\n  const renderElement = asChild ? getAsChildElement(children, \"ContextMenuSeparator\") : render;\n\n  return (\n    <ContextMenuPrimitive.Separator\n      data-slot=\"context-menu-separator\"\n      render={renderElement}\n      className={cn(\"-mx-1 my-1 h-0.5 bg-border\", className)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </ContextMenuPrimitive.Separator>\n  );\n}\n\nfunction ContextMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"context-menu-shortcut\"\n      className={cn(\"ml-auto text-xs font-base tracking-widest\", className)}\n      {...props}\n    />\n  );\n}\n\nexport {\n  ContextMenu,\n  ContextMenuTrigger,\n  ContextMenuContent,\n  ContextMenuItem,\n  ContextMenuCheckboxItem,\n  ContextMenuRadioItem,\n  ContextMenuLabel,\n  ContextMenuSeparator,\n  ContextMenuShortcut,\n  ContextMenuGroup,\n  ContextMenuPortal,\n  ContextMenuSub,\n  ContextMenuSubContent,\n  ContextMenuSubTrigger,\n  ContextMenuRadioGroup,\n};\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "overlay",
    "menu"
  ],
  "type": "registry:ui"
}