{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "context-menu", "type": "registry:ui", "title": "Context Menu", "files": [ { "path": "ui/context-menu.tsrx", "type": "registry:ui", "target": "components/ui/context-menu.tsrx", "content": "// Base UI base context-menu — runs on @octanejs/base-ui's `ContextMenu`. Class strings from the\n// maintainer-supplied radix source; every difference below was checked against rendered DOM.\n//\n// This is dropdown-menu's sibling and inherits its findings, WITH ONE IMPROVEMENT: `ContextMenu`\n// ships a real `Separator` part, which `Menu` does not, so the separator is the primitive here\n// rather than a plain host element. It emits `role=\"separator\"`, `aria-orientation` and\n// `data-orientation`.\n//\n// CARRIED OVER FROM dropdown-menu, all re-verified against this primitive:\n// - Two CSS variables are renamed. Radix publishes per-component names; Base UI's Positioner\n// publishes generic ones, and a utility naming a variable nothing sets does nothing, silently:\n// --radix-context-menu-content-available-height -> --available-height\n// --radix-context-menu-content-transform-origin -> --transform-origin\n// - The submenu trigger marks itself open with `data-popup-open`, not the `data-open` the popup\n// carries, so radix's `data-open:bg-accent` would leave an open submenu's parent row unstyled.\n// - `Label` stays a plain `
`: `ContextMenu.GroupLabel` requires a `ContextMenu.Group`\n// ancestor and throws without one, while shadcn's label is used standalone.\n// - Radix's `focus:` item utilities carry over unchanged, because Base UI moves real DOM focus\n// onto the highlighted item as well as publishing `data-highlighted`.\n//\n// POSITIONING PROPS GO TO THE POSITIONER, NOT THE POPUP. Radix has one `Content` element that takes\n// them all; Base UI splits positioning into its own layer, so anything swept onto `Popup` by a rest\n// spread is inert — `side=\"top\"` would silently leave the menu on its default side and also land on\n// the DOM as an invalid attribute. They are destructured and forwarded explicitly.\nimport { type OctaneNode } from 'octane';\nimport { ContextMenu as ContextMenuPrimitive } from '@octanejs/base-ui/context-menu';\nimport { CheckIcon, ChevronRightIcon } from '@octanejs/lucide';\n\nimport { cn } from '@/lib/utils';\n\ntype Props = { className?: string; children?: OctaneNode } & Record;\n\nexport interface BaseUiPositioningProps {\n\t/** Forwarded to the Positioner; see the note at the top of this file. */\n\tside?: 'top' | 'right' | 'bottom' | 'left';\n\tsideOffset?: number;\n\talign?: 'start' | 'center' | 'end';\n\talignOffset?: number;\n\tanchor?: unknown;\n\tpositionMethod?: 'absolute' | 'fixed';\n\tcollisionBoundary?: unknown;\n\tcollisionPadding?: unknown;\n\tcollisionAvoidance?: unknown;\n\tarrowPadding?: number;\n\tsticky?: boolean;\n\tdisableAnchorTracking?: boolean;\n}\n\nexport function ContextMenu(props: Record) @{\n\t\n}\n\nexport function ContextMenuTrigger({ className, ...props }: Props) @{\n\t\n}\n\nexport function ContextMenuGroup(props: Record) @{\n\t\n}\n\nexport function ContextMenuPortal(props: Record) @{\n\t\n}\n\nexport function ContextMenuSub(props: Record) @{\n\t\n}\n\nexport function ContextMenuRadioGroup(props: Record) @{\n\t\n}\n\nexport function ContextMenuContent({\n\tclassName,\n\tside,\n\tsideOffset,\n\talign,\n\talignOffset,\n\tanchor,\n\tpositionMethod,\n\tcollisionBoundary,\n\tcollisionPadding,\n\tcollisionAvoidance,\n\tarrowPadding,\n\tsticky,\n\tdisableAnchorTracking,\n\t...props\n}: Props & BaseUiPositioningProps) @{\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n}\n\nexport function ContextMenuItem({ className, inset, variant = 'default', ...props }: Props & {\n\tinset?: boolean;\n\tvariant?: 'default' | 'destructive';\n}) @{\n\t\n}\n\nexport function ContextMenuSubTrigger(props: Props & { inset?: boolean }) @{\n\tconst { className, children: _children, inset, ...rest } = props;\n\n\t\n\t\t{props.children}\n\t\t\n\t\n}\n\nexport function ContextMenuSubContent({\n\tclassName,\n\tside,\n\tsideOffset,\n\talign,\n\talignOffset,\n\tanchor,\n\tpositionMethod,\n\tcollisionBoundary,\n\tcollisionPadding,\n\tcollisionAvoidance,\n\tarrowPadding,\n\tsticky,\n\tdisableAnchorTracking,\n\t...props\n}: Props & BaseUiPositioningProps) @{\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n}\n\nexport function ContextMenuCheckboxItem(props: Props & {\n\tchecked?: boolean;\n\tinset?: boolean;\n}) @{\n\tconst { className, children: _children, checked, inset, ...rest } = props;\n\n\t\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\t{props.children}\n\t\n}\n\nexport function ContextMenuRadioItem(props: Props & { inset?: boolean }) @{\n\tconst { className, children: _children, inset, ...rest } = props;\n\n\t\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\t{props.children}\n\t\n}\n\nexport function ContextMenuLabel({ className, inset, ...props }: Props & { inset?: boolean }) @{\n\t\n}\n\nexport function ContextMenuSeparator({ className, ...props }: Props) @{\n\t\n}\n\nexport function ContextMenuShortcut({ className, ...props }: Props) @{\n\t\n}\n" } ], "dependencies": [ "@octanejs/base-ui@0.1.33", "@octanejs/lucide@0.1.30" ], "registryDependencies": [ "@octane/utils" ] }