{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "title": "Context Menu",
  "description": "Right-click menu on radix-ui with items, checkbox and radio items, submenus, labels, separators and shortcuts. Item variant default or danger. Icons work with lucide svg and remixicon i. Exports the full ContextMenu part set.",
  "dependencies": [
    "radix-ui@^1.6.1",
    "lucide-react@^1.23.0",
    "tw-animate-css@^1.4.0"
  ],
  "registryDependencies": [
    "@ai2/tokens",
    "@ai2/primitives"
  ],
  "files": [
    {
      "path": "registry/ai2/ui/context-menu.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { Check, ChevronRight, Circle } from \"lucide-react\"\nimport { ContextMenu as ContextMenuPrimitive } from \"@/registry/ai2/ui/primitives\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction ContextMenu(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.Root>\n) {\n  return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />\n}\n\nfunction ContextMenuTrigger(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>\n) {\n  return (\n    <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />\n  )\n}\n\nfunction ContextMenuGroup(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.Group>\n) {\n  return <ContextMenuPrimitive.Group data-slot=\"context-menu-group\" {...props} />\n}\n\nfunction ContextMenuPortal(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.Portal>\n) {\n  return (\n    <ContextMenuPrimitive.Portal data-slot=\"context-menu-portal\" {...props} />\n  )\n}\n\nfunction ContextMenuSub(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.Sub>\n) {\n  return <ContextMenuPrimitive.Sub data-slot=\"context-menu-sub\" {...props} />\n}\n\nfunction ContextMenuRadioGroup(\n  props: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>\n) {\n  return (\n    <ContextMenuPrimitive.RadioGroup\n      data-slot=\"context-menu-radio-group\"\n      {...props}\n    />\n  )\n}\n\nconst menuItemBase =\n  \"relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-none transition-colors duration-(--motion-fast) focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_i]:pointer-events-none [&_i]:shrink-0 [&_i]:text-base [&_i]:leading-none [&_i:not([class*='text-'])]:text-muted-foreground\"\n\nfunction ContextMenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {\n  inset?: boolean\n}) {\n  return (\n    <ContextMenuPrimitive.SubTrigger\n      data-slot=\"context-menu-sub-trigger\"\n      data-inset={inset}\n      className={cn(\n        menuItemBase,\n        \"data-[inset]:ps-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <ChevronRight className=\"ms-auto\" />\n    </ContextMenuPrimitive.SubTrigger>\n  )\n}\n\nfunction ContextMenuSubContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {\n  return (\n    <ContextMenuPrimitive.SubContent\n      data-slot=\"context-menu-sub-content\"\n      className={cn(\n        /* Same rationale as Content: because Radix has horizontal shift\n           disabled, the clamp is not a fixed vw but the available width the\n           popper computes. */\n        \"z-50 max-w-(--radix-context-menu-content-available-width) min-w-32 origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 motion-reduce:animate-none\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {\n  return (\n    <ContextMenuPrimitive.Portal>\n      <ContextMenuPrimitive.Content\n        data-slot=\"context-menu-content\"\n        /* At 320px the menu overflowed the viewport (measured: left 162 +\n           width 192 = right edge 354, 34px outside).\n           ROOT CAUSE (verified against the floating-ui source): inside\n           shift(), `crossAxis = getSideAxis(placement)` and `mainAxis` is its\n           opposite. When side is \"right\", mainAxis becomes VERTICAL; Radix\n           Popper configures shift with `{mainAxis: true, crossAxis: false}`,\n           so HORIZONTAL shifting is off from the start. collisionPadding\n           computes the overflow correctly but cannot move the box\n           horizontally; `sticky` changes the limiter, not the axis (both were\n           measured, neither changed the result). flip sees 34px of overflow on\n           both sides when the cursor is dead centre, so it stays on \"right\" in\n           the tie.\n           Since Radix does not expose crossAxis shift, one lever remains:\n           WIDTH. `--radix-context-menu-content-available-width` is what the\n           size middleware computes for the final position (142px in that\n           measurement) and it has already subtracted collisionPadding. A fixed\n           `calc(100vw-2rem)` could not catch this because the menu (192) stayed\n           under that clamp (288). */\n        collisionPadding={16}\n        className={cn(\n          \"z-50 max-h-(--radix-context-menu-content-available-height) max-w-(--radix-context-menu-content-available-width) min-w-32 origin-(--radix-context-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 motion-reduce:animate-none\",\n          className\n        )}\n        {...props}\n      />\n    </ContextMenuPrimitive.Portal>\n  )\n}\n\nfunction ContextMenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\n  inset?: boolean\n  variant?: \"default\" | \"danger\"\n}) {\n  return (\n    <ContextMenuPrimitive.Item\n      data-slot=\"context-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      className={cn(\n        menuItemBase,\n        \"data-[inset]:ps-8 data-[variant=danger]:text-danger data-[variant=danger]:focus:bg-danger-soft data-[variant=danger]:focus:text-danger-soft-foreground data-[variant=danger]:*:[svg]:text-danger data-[variant=danger]:*:[i]:text-danger\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuCheckboxItem({\n  className,\n  children,\n  checked,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {\n  return (\n    <ContextMenuPrimitive.CheckboxItem\n      data-slot=\"context-menu-checkbox-item\"\n      className={cn(menuItemBase, \"py-1.5 ps-8 pe-2\", className)}\n      checked={checked}\n      {...props}\n    >\n      <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.ItemIndicator>\n          <Check className=\"size-4\" />\n        </ContextMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </ContextMenuPrimitive.CheckboxItem>\n  )\n}\n\nfunction ContextMenuRadioItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {\n  return (\n    <ContextMenuPrimitive.RadioItem\n      data-slot=\"context-menu-radio-item\"\n      className={cn(menuItemBase, \"py-1.5 ps-8 pe-2\", className)}\n      {...props}\n    >\n      <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n        <ContextMenuPrimitive.ItemIndicator>\n          <Circle className=\"size-2 fill-current\" />\n        </ContextMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </ContextMenuPrimitive.RadioItem>\n  )\n}\n\nfunction ContextMenuLabel({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {\n  inset?: boolean\n}) {\n  return (\n    <ContextMenuPrimitive.Label\n      data-slot=\"context-menu-label\"\n      data-inset={inset}\n      className={cn(\n        \"px-2 py-1.5 text-xs font-medium text-muted-foreground data-[inset]:ps-8\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ContextMenuSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {\n  return (\n    <ContextMenuPrimitive.Separator\n      data-slot=\"context-menu-separator\"\n      className={cn(\"-mx-1 my-1 h-px bg-border\", 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        \"ms-auto text-xs tracking-widest text-muted-foreground\",\n        className\n      )}\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"
    }
  ],
  "docs": "Wrap the target in ContextMenuTrigger; the menu opens on right-click. Use variant=danger on destructive items. Mirrors DropdownMenu but for contextual actions.",
  "categories": [
    "overlay"
  ],
  "type": "registry:ui"
}