{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "title": "Context Menu",
  "description": "Pointer context menu on Base UI with menu settle and row stagger.",
  "dependencies": [
    "@base-ui/react",
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "@atroui/utils",
    "@atroui/motion"
  ],
  "files": [
    {
      "path": "registry/default/ui/context-menu.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ContextMenu as ContextMenuPrimitive } from \"@base-ui/react/context-menu\"\nimport { Check, ChevronRight } from \"lucide-react\"\nimport {\n  AnimatePresence,\n  LayoutGroup,\n  motion,\n  useReducedMotion,\n} from \"motion/react\"\n\nimport {\n  layoutTween,\n  menuItemVariants,\n  menuPopupMotion,\n} from \"@/lib/motion\"\nimport { cn } from \"@/lib/utils\"\n\n/** Layered pop elevation — ring-as-border + cast stack + top light. */\nconst overlayElevation =\n  \"ds-elev-pop\"\n\ntype ContextMenuOpenContextValue = {\n  open: boolean\n}\n\nconst ContextMenuOpenContext =\n  React.createContext<ContextMenuOpenContextValue | null>(null)\n\ntype ContextMenuHighlightContextValue = {\n  layoutId: string\n  activeId: string | null\n  setActiveId: (id: string | null) => void\n  reduce: boolean | null\n}\n\nconst ContextMenuHighlightContext =\n  React.createContext<ContextMenuHighlightContextValue | null>(null)\n\nfunction useContextMenuOpen() {\n  const ctx = React.useContext(ContextMenuOpenContext)\n  if (!ctx) {\n    throw new Error(\n      \"ContextMenu parts must be used within <ContextMenu> or <ContextMenuSub>\"\n    )\n  }\n  return ctx.open\n}\n\nfunction ContextMenu({\n  open: openProp,\n  defaultOpen = false,\n  onOpenChange,\n  ...props\n}: ContextMenuPrimitive.Root.Props) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n  const isControlled = openProp !== undefined\n  const open = isControlled ? openProp : uncontrolledOpen\n\n  const handleOpenChange = React.useCallback<\n    NonNullable<ContextMenuPrimitive.Root.Props[\"onOpenChange\"]>\n  >(\n    (next, eventDetails) => {\n      if (!isControlled) setUncontrolledOpen(next)\n      onOpenChange?.(next, eventDetails)\n    },\n    [isControlled, onOpenChange]\n  )\n\n  return (\n    <ContextMenuOpenContext.Provider value={{ open }}>\n      <ContextMenuPrimitive.Root\n        data-slot=\"context-menu\"\n        open={open}\n        onOpenChange={handleOpenChange}\n        {...props}\n      />\n    </ContextMenuOpenContext.Provider>\n  )\n}\n\nfunction ContextMenuTrigger({\n  className,\n  ...props\n}: ContextMenuPrimitive.Trigger.Props) {\n  return (\n    <ContextMenuPrimitive.Trigger\n      data-slot=\"context-menu-trigger\"\n      className={cn(className)}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) {\n  return (\n    <ContextMenuPrimitive.Portal data-slot=\"context-menu-portal\" {...props} />\n  )\n}\n\nfunction ContextMenuContent({\n  align = \"start\",\n  alignOffset = 0,\n  side = \"bottom\",\n  sideOffset = 4,\n  className,\n  render,\n  onMouseLeave,\n  ...props\n}: ContextMenuPrimitive.Popup.Props &\n  Pick<\n    ContextMenuPrimitive.Positioner.Props,\n    \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n  >) {\n  const open = useContextMenuOpen()\n  const reduce = useReducedMotion()\n  const groupId = React.useId()\n  const [activeId, setActiveId] = React.useState<string | null>(null)\n\n  const highlight = React.useMemo<ContextMenuHighlightContextValue>(\n    () => ({\n      layoutId: `${groupId}-ink`,\n      activeId,\n      setActiveId,\n      reduce: reduce ?? false,\n    }),\n    [activeId, groupId, reduce]\n  )\n\n  return (\n    <AnimatePresence>\n      {open ? (\n        <ContextMenuPrimitive.Portal keepMounted key=\"context-menu-portal\">\n          <ContextMenuPrimitive.Positioner\n            className=\"isolate z-50 outline-none\"\n            align={align}\n            alignOffset={alignOffset}\n            side={side}\n            sideOffset={sideOffset}\n          >\n            <LayoutGroup id={groupId}>\n              <ContextMenuHighlightContext.Provider value={highlight}>\n                <ContextMenuPrimitive.Popup\n                  data-slot=\"context-menu-content\"\n                  className={cn(\n                    \"z-50 max-h-(--available-height) min-w-40 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-[var(--radius)] bg-popover p-0.5 text-popover-foreground outline-none\",\n                    \"data-closed:overflow-hidden\",\n                    overlayElevation,\n                    className\n                  )}\n                  render={render ?? <motion.div {...menuPopupMotion(reduce)} />}\n                  onMouseLeave={(event) => {\n                    setActiveId(null)\n                    onMouseLeave?.(event)\n                  }}\n                  {...props}\n                />\n              </ContextMenuHighlightContext.Provider>\n            </LayoutGroup>\n          </ContextMenuPrimitive.Positioner>\n        </ContextMenuPrimitive.Portal>\n      ) : null}\n    </AnimatePresence>\n  )\n}\n\nfunction ContextMenuHighlight({\n  itemId,\n  tone = \"default\",\n}: {\n  itemId: string\n  tone?: \"default\" | \"destructive\"\n}) {\n  const highlight = React.useContext(ContextMenuHighlightContext)\n  if (!highlight || highlight.reduce || highlight.activeId !== itemId) {\n    return null\n  }\n  return (\n    <motion.span\n      layoutId={highlight.layoutId}\n      className={cn(\n        \"absolute inset-0 z-0 rounded-[calc(var(--radius)-2px)]\",\n        tone === \"destructive\" ? \"bg-destructive/10\" : \"bg-muted/80\"\n      )}\n      transition={layoutTween}\n      aria-hidden\n    />\n  )\n}\n\nconst itemBase =\n  \"relative flex cursor-default items-center gap-2 rounded-[calc(var(--radius)-2px)] px-2 py-0.5 text-[0.8125rem] leading-snug outline-none select-none\"\n\nfunction useContextMenuItemMotion(itemId: string) {\n  const highlight = React.useContext(ContextMenuHighlightContext)\n  const reduce = highlight?.reduce ?? false\n\n  const arm = React.useCallback(() => {\n    highlight?.setActiveId(itemId)\n  }, [highlight, itemId])\n\n  return {\n    reduce,\n    arm,\n    rowMotion: reduce ? undefined : menuItemVariants,\n  }\n}\n\nfunction ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) {\n  return <ContextMenuPrimitive.Group data-slot=\"context-menu-group\" {...props} />\n}\n\nfunction ContextMenuLabel({\n  className,\n  inset,\n  ...props\n}: ContextMenuPrimitive.GroupLabel.Props & {\n  inset?: boolean\n}) {\n  return (\n    <ContextMenuPrimitive.GroupLabel\n      data-slot=\"context-menu-label\"\n      data-inset={inset}\n      className={cn(\n        \"px-2 py-1 text-[0.6875rem] font-medium tracking-wide text-muted-foreground data-[inset]:pl-7\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  onMouseEnter,\n  onFocus,\n  children,\n  ...props\n}: ContextMenuPrimitive.Item.Props & {\n  inset?: boolean\n  variant?: \"default\" | \"destructive\"\n}) {\n  const itemId = React.useId()\n  const { reduce, arm, rowMotion } = useContextMenuItemMotion(itemId)\n\n  return (\n    <ContextMenuPrimitive.Item\n      data-slot=\"context-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      className={cn(\n        itemBase,\n        reduce\n          ? \"data-highlighted:bg-muted data-highlighted:text-foreground data-[variant=destructive]:data-highlighted:bg-destructive/10\"\n          : \"data-highlighted:text-foreground\",\n        \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n        \"data-[variant=destructive]:text-destructive\",\n        \"data-[inset]:pl-7\",\n        \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5\",\n        className\n      )}\n      render={rowMotion ? <motion.div variants={rowMotion} /> : undefined}\n      onMouseEnter={(event) => {\n        arm()\n        onMouseEnter?.(event)\n      }}\n      onFocus={(event) => {\n        arm()\n        onFocus?.(event)\n      }}\n      {...props}\n    >\n      <ContextMenuHighlight itemId={itemId} tone={variant} />\n      <span className=\"relative z-[1] flex min-w-0 flex-1 items-center gap-2\">\n        {children}\n      </span>\n    </ContextMenuPrimitive.Item>\n  )\n}\n\nfunction ContextMenuSub({\n  open: openProp,\n  defaultOpen = false,\n  onOpenChange,\n  ...props\n}: ContextMenuPrimitive.SubmenuRoot.Props) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n  const isControlled = openProp !== undefined\n  const open = isControlled ? openProp : uncontrolledOpen\n\n  const handleOpenChange = React.useCallback<\n    NonNullable<ContextMenuPrimitive.SubmenuRoot.Props[\"onOpenChange\"]>\n  >(\n    (next, eventDetails) => {\n      if (!isControlled) setUncontrolledOpen(next)\n      onOpenChange?.(next, eventDetails)\n    },\n    [isControlled, onOpenChange]\n  )\n\n  return (\n    <ContextMenuOpenContext.Provider value={{ open }}>\n      <ContextMenuPrimitive.SubmenuRoot\n        data-slot=\"context-menu-sub\"\n        open={open}\n        onOpenChange={handleOpenChange}\n        {...props}\n      />\n    </ContextMenuOpenContext.Provider>\n  )\n}\n\nfunction ContextMenuSubTrigger({\n  className,\n  inset,\n  children,\n  onMouseEnter,\n  onFocus,\n  ...props\n}: ContextMenuPrimitive.SubmenuTrigger.Props & {\n  inset?: boolean\n}) {\n  const itemId = React.useId()\n  const { reduce, arm, rowMotion } = useContextMenuItemMotion(itemId)\n\n  return (\n    <ContextMenuPrimitive.SubmenuTrigger\n      data-slot=\"context-menu-sub-trigger\"\n      data-inset={inset}\n      className={cn(\n        itemBase,\n        reduce\n          ? \"data-highlighted:bg-muted data-highlighted:text-foreground data-popup-open:bg-muted data-popup-open:text-foreground\"\n          : \"data-highlighted:text-foreground data-popup-open:text-foreground\",\n        \"data-[inset]:pl-7\",\n        \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5\",\n        className\n      )}\n      render={rowMotion ? <motion.div variants={rowMotion} /> : undefined}\n      onMouseEnter={(event) => {\n        arm()\n        onMouseEnter?.(event)\n      }}\n      onFocus={(event) => {\n        arm()\n        onFocus?.(event)\n      }}\n      {...props}\n    >\n      <ContextMenuHighlight itemId={itemId} />\n      <span className=\"relative z-[1] flex min-w-0 flex-1 items-center gap-2\">\n        {children}\n        <ChevronRight className=\"ml-auto size-3.5 text-muted-foreground\" />\n      </span>\n    </ContextMenuPrimitive.SubmenuTrigger>\n  )\n}\n\nfunction ContextMenuSubContent({\n  align = \"start\",\n  alignOffset = -3,\n  side = \"right\",\n  sideOffset = 0,\n  className,\n  ...props\n}: React.ComponentProps<typeof ContextMenuContent>) {\n  return (\n    <ContextMenuContent\n      data-slot=\"context-menu-sub-content\"\n      className={cn(\"min-w-36\", className)}\n      align={align}\n      alignOffset={alignOffset}\n      side={side}\n      sideOffset={sideOffset}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuCheckboxItem({\n  className,\n  children,\n  checked,\n  inset,\n  onMouseEnter,\n  onFocus,\n  ...props\n}: ContextMenuPrimitive.CheckboxItem.Props & {\n  inset?: boolean\n}) {\n  const itemId = React.useId()\n  const { reduce, arm, rowMotion } = useContextMenuItemMotion(itemId)\n\n  return (\n    <ContextMenuPrimitive.CheckboxItem\n      data-slot=\"context-menu-checkbox-item\"\n      data-inset={inset}\n      className={cn(\n        itemBase,\n        \"pr-2 pl-7\",\n        reduce\n          ? \"data-highlighted:bg-muted data-highlighted:text-foreground\"\n          : \"data-highlighted:text-foreground\",\n        \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n        \"data-[inset]:pl-7\",\n        className\n      )}\n      render={rowMotion ? <motion.div variants={rowMotion} /> : undefined}\n      checked={checked}\n      onMouseEnter={(event) => {\n        arm()\n        onMouseEnter?.(event)\n      }}\n      onFocus={(event) => {\n        arm()\n        onFocus?.(event)\n      }}\n      {...props}\n    >\n      <ContextMenuHighlight itemId={itemId} />\n      <span className=\"pointer-events-none absolute left-2 z-[1] flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.CheckboxItemIndicator>\n          <Check className=\"size-3\" />\n        </ContextMenuPrimitive.CheckboxItemIndicator>\n      </span>\n      <span className=\"relative z-[1] flex min-w-0 flex-1 items-center gap-2\">\n        {children}\n      </span>\n    </ContextMenuPrimitive.CheckboxItem>\n  )\n}\n\nfunction ContextMenuRadioGroup({\n  ...props\n}: ContextMenuPrimitive.RadioGroup.Props) {\n  return (\n    <ContextMenuPrimitive.RadioGroup\n      data-slot=\"context-menu-radio-group\"\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuRadioItem({\n  className,\n  children,\n  inset,\n  onMouseEnter,\n  onFocus,\n  ...props\n}: ContextMenuPrimitive.RadioItem.Props & {\n  inset?: boolean\n}) {\n  const itemId = React.useId()\n  const { reduce, arm, rowMotion } = useContextMenuItemMotion(itemId)\n\n  return (\n    <ContextMenuPrimitive.RadioItem\n      data-slot=\"context-menu-radio-item\"\n      data-inset={inset}\n      className={cn(\n        itemBase,\n        \"pr-2 pl-7\",\n        reduce\n          ? \"data-highlighted:bg-muted data-highlighted:text-foreground\"\n          : \"data-highlighted:text-foreground\",\n        \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n        className\n      )}\n      render={rowMotion ? <motion.div variants={rowMotion} /> : undefined}\n      onMouseEnter={(event) => {\n        arm()\n        onMouseEnter?.(event)\n      }}\n      onFocus={(event) => {\n        arm()\n        onFocus?.(event)\n      }}\n      {...props}\n    >\n      <ContextMenuHighlight itemId={itemId} />\n      <span className=\"pointer-events-none absolute left-2 z-[1] flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.RadioItemIndicator>\n          <Check className=\"size-3\" />\n        </ContextMenuPrimitive.RadioItemIndicator>\n      </span>\n      <span className=\"relative z-[1] flex min-w-0 flex-1 items-center gap-2\">\n        {children}\n      </span>\n    </ContextMenuPrimitive.RadioItem>\n  )\n}\n\nfunction ContextMenuSeparator({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      role=\"separator\"\n      aria-orientation=\"horizontal\"\n      data-slot=\"context-menu-separator\"\n      className={cn(\"-mx-1 my-1 h-px bg-border-subtle\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuShortcut({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"context-menu-shortcut\"\n      className={cn(\n        \"ml-auto font-mono text-[0.6875rem] tracking-wide text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  ContextMenu,\n  ContextMenuCheckboxItem,\n  ContextMenuContent,\n  ContextMenuGroup,\n  ContextMenuItem,\n  ContextMenuLabel,\n  ContextMenuPortal,\n  ContextMenuRadioGroup,\n  ContextMenuRadioItem,\n  ContextMenuSeparator,\n  ContextMenuShortcut,\n  ContextMenuSub,\n  ContextMenuSubContent,\n  ContextMenuSubTrigger,\n  ContextMenuTrigger,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/context-menu.tsx"
    }
  ],
  "type": "registry:ui"
}