{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "title": "Context Menu",
  "author": "@fma-ui/ui",
  "description": "A menu that opens on right-click (or long-press on touch) instead of a regular trigger click. Supports nested submenus, separators, and keyboard shortcut display.",
  "dependencies": [
    "class-variance-authority@^0.7.1",
    "cn@^0.4.0",
    "lucide-react@^1.52.0",
    "react-aria-components@^1.21.1"
  ],
  "files": [
    {
      "path": "src/core/context-menu/context-menu.tsx",
      "content": "import { cva } from \"class-variance-authority\";\nimport { cn } from \"cn\";\nimport { CheckIcon, ChevronRightIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport {\n  composeRenderProps,\n  Header as HeaderPrimitive,\n  MenuItem as MenuItemPrimitive,\n  type MenuItemProps as MenuItemPrimitiveProps,\n  Menu as MenuPrimitive,\n  MenuSection as MenuSectionPrimitive,\n  type MenuSectionProps as MenuSectionPrimitiveProps,\n  MenuTrigger as MenuTriggerPrimitive,\n  Popover as PopoverPrimitive,\n  Separator as SeparatorPrimitive,\n  SubmenuTrigger as SubmenuTriggerPrimitive,\n} from \"react-aria-components\";\n\nfunction ContextMenu({\n  \"data-slot\": dataSlot = \"context-menu-content\",\n  placement = \"bottom start\",\n  offset = 4,\n  crossOffset = 0,\n  className,\n  children,\n  ...props\n}: Omit<React.ComponentProps<typeof MenuPrimitive<object>>, \"children\" | \"className\"> &\n  Pick<React.ComponentProps<typeof PopoverPrimitive>, \"placement\" | \"offset\" | \"crossOffset\"> & {\n    \"data-slot\"?: string;\n    className?: string;\n    children?: React.ReactNode;\n  }) {\n  return (\n    <PopoverPrimitive\n      data-slot={dataSlot}\n      placement={placement}\n      offset={offset}\n      crossOffset={crossOffset}\n      className={cn(\n        \"z-50 w-(--trigger-width) min-w-36 origin-(--trigger-anchor-point) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-entering:animate-in data-entering:fade-in-0 data-entering:zoom-in-95 data-exiting:animate-out data-exiting:overflow-hidden data-exiting:fade-out-0 data-exiting:zoom-out-95 data-[placement=bottom]:slide-in-from-top-2 data-[placement=left]:slide-in-from-right-2 data-[placement=right]:slide-in-from-left-2 data-[placement=top]:slide-in-from-bottom-2\",\n        className,\n      )}\n    >\n      <MenuPrimitive\n        className=\"max-h-[inherit] overflow-x-hidden overflow-y-auto outline-hidden\"\n        {...props}\n      >\n        {children}\n      </MenuPrimitive>\n    </PopoverPrimitive>\n  );\n}\n\nfunction ContextMenuTrigger({\n  ...props\n}: Omit<React.ComponentProps<typeof MenuTriggerPrimitive>, \"trigger\">) {\n  return <MenuTriggerPrimitive data-slot=\"context-menu\" trigger=\"contextMenu\" {...props} />;\n}\n\nfunction ContextMenuGroup({\n  ...props\n}: Omit<MenuSectionPrimitiveProps<object>, \"children\"> & {\n  children?: React.ReactNode;\n}) {\n  return <MenuSectionPrimitive data-slot=\"context-menu-group\" {...props} />;\n}\n\nfunction ContextMenuLabel({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<typeof HeaderPrimitive> & {\n  inset?: boolean;\n}) {\n  return (\n    <HeaderPrimitive\n      data-slot=\"context-menu-label\"\n      data-inset={inset}\n      className={cn(\n        \"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nconst contextMenuItemVariants = cva(\n  \"group/context-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  {\n    variants: {\n      selectionMode: {\n        none: \"gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive\",\n        single:\n          \"gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm focus:bg-accent focus:text-accent-foreground data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4\",\n        multiple:\n          \"gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm focus:bg-accent focus:text-accent-foreground data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4\",\n      },\n    },\n  },\n);\n\nfunction ContextMenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  children,\n  ...props\n}: MenuItemPrimitiveProps<object> & {\n  inset?: boolean;\n  variant?: \"default\" | \"destructive\";\n}) {\n  return (\n    <MenuItemPrimitive\n      data-slot=\"context-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      textValue={typeof children === \"string\" ? children : props.textValue}\n      className={composeRenderProps(className, (className, { selectionMode }) =>\n        cn(contextMenuItemVariants({ selectionMode }), className),\n      )}\n      {...props}\n    >\n      {composeRenderProps(children, (children, { isSelected, selectionMode }) => (\n        <>\n          {selectionMode !== \"none\" ? (\n            <span\n              className=\"pointer-events-none absolute right-2\"\n              data-slot={\n                selectionMode === \"single\"\n                  ? \"context-menu-radio-item-indicator\"\n                  : \"context-menu-checkbox-item-indicator\"\n              }\n            >\n              {isSelected ? <CheckIcon /> : null}\n            </span>\n          ) : null}\n          {children}\n        </>\n      ))}\n    </MenuItemPrimitive>\n  );\n}\n\nfunction ContextMenuSub({ ...props }: React.ComponentProps<typeof SubmenuTriggerPrimitive>) {\n  return <SubmenuTriggerPrimitive data-slot=\"context-menu-sub\" {...props} />;\n}\n\nfunction ContextMenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: MenuItemPrimitiveProps<object> & {\n  inset?: boolean;\n}) {\n  return (\n    <MenuItemPrimitive\n      data-slot=\"context-menu-sub-trigger\"\n      data-inset={inset}\n      textValue={typeof children === \"string\" ? children : props.textValue}\n      className={cn(\n        \"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      {...props}\n    >\n      {composeRenderProps(children, (children) => (\n        <>\n          {children}\n          <ChevronRightIcon className=\"ml-auto\" />\n        </>\n      ))}\n    </MenuItemPrimitive>\n  );\n}\n\nfunction ContextMenuSubContent({\n  placement = \"end top\",\n  crossOffset = -3,\n  offset = 0,\n  className,\n  ...props\n}: React.ComponentProps<typeof ContextMenu>) {\n  return (\n    <ContextMenu\n      data-slot=\"context-menu-sub-content\"\n      className={cn(\n        \"w-auto min-w-32 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg duration-100\",\n        className,\n      )}\n      placement={placement}\n      crossOffset={crossOffset}\n      offset={offset}\n      {...props}\n    />\n  );\n}\n\nfunction ContextMenuSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SeparatorPrimitive>) {\n  return (\n    <SeparatorPrimitive\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({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"context-menu-shortcut\"\n      className={cn(\n        \"ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  ContextMenu,\n  ContextMenuGroup,\n  ContextMenuItem,\n  ContextMenuLabel,\n  ContextMenuSeparator,\n  ContextMenuShortcut,\n  ContextMenuSub,\n  ContextMenuSubContent,\n  ContextMenuSubTrigger,\n  ContextMenuTrigger,\n};\n",
      "type": "registry:component",
      "target": "components/fma-ui/context-menu.tsx"
    }
  ],
  "meta": {
    "status": "stable",
    "source": "customized",
    "origin": "shadcn/ui, style: aria-nova (base: react-aria-components). The trigger region must call usePress() — wrap a plain element in react-aria-components' Pressable if it doesn't already.",
    "tags": [
      "react-aria",
      "menu",
      "context-menu",
      "nova"
    ]
  },
  "categories": [
    "overlay"
  ],
  "type": "registry:ui"
}