{
  "name": "menu",
  "type": "registry:ui",
  "title": "Menu",
  "description": "Menu presents grouped actions, choices, links, and submenus from a trigger button.",
  "registryDependencies": [
    "@siteplane/base"
  ],
  "dependencies": [
    "@base-ui/react@1.5.0",
    "lucide-react@1.18.0"
  ],
  "files": [
    {
      "path": "src/components/ui/icons.tsx",
      "type": "registry:ui",
      "content": "import type React from \"react\";\n\n// Siteplane-UI-Haken-Glyphe (bewusst andere Geometrie als lucide `Check`).\n// Einzige Quelle fuer den statischen Selected-Marker in Select, Combobox, Menu,\n// ContextMenu und Drawer. (Die Checkbox nutzt eine eigene, ueber\n// `siteplane-checkbox-check` animierte Variante und bleibt davon unberuehrt.)\nexport function CheckIcon(props: React.ComponentProps<\"svg\">): React.ReactElement {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      fill=\"none\"\n      height=\"24\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"2\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      {...props}\n    >\n      <path d=\"M5.252 12.7 10.2 18.63 18.748 5.37\" />\n    </svg>\n  );\n}\n"
    },
    {
      "path": "src/components/ui/menu-shared.tsx",
      "type": "registry:ui",
      "content": "import type React from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { CheckIcon } from \"@/components/ui/icons\";\nimport { surfaceClassNames } from \"@/components/ui/surface\";\nimport { shortcutClassName } from \"@/components/ui/typography\";\n\n// Eine Quelle fuer das gesamte Menu-Styling. `Menu` (@base-ui/react/menu) und\n// `ContextMenu` (@base-ui/react/context-menu) wrappen unterschiedliche Primitive,\n// teilen aber exakt dieselbe Optik. Frueher waren beide Dateien byte-fuer-byte\n// Zwillinge; jetzt importieren sie diese Konstanten, damit eine Styling-Aenderung\n// garantiert beide Familien erreicht.\n//\n// WICHTIG: alle Klassen sind literale Strings — Tailwind v4 scannt den Quelltext,\n// dynamisch zusammengebaute Klassen wuerden nicht generiert. Die slot-gebundenen\n// Switch-Thumb-Selektoren existieren deshalb je einmal pro Familie.\n\nexport const menuPopupClassName = cn(\n  surfaceClassNames.floatingOverlay,\n  \"flex not-[class*='min-w-']:min-w-32 origin-(--transform-origin) rounded-lg outline-none before:rounded-[inherit] focus:outline-none\",\n);\n\nexport type MenuPopupWidth = \"auto\" | \"trigger\" | \"content\" | \"at-least-trigger\";\n\nexport const menuPopupWidthClassNames: Record<MenuPopupWidth, string> = {\n  auto: \"\",\n  content: \"w-max max-w-(--available-width)\",\n  trigger: \"min-w-0 w-(--anchor-width)\",\n  \"at-least-trigger\":\n    \"min-w-(--anchor-width) w-max max-w-(--available-width)\",\n};\n\n// Menuezeilen folgen derselben globalen controlSize-Achse wie ihr Trigger,\n// behalten als wiederholte Listenelemente aber eine kompaktere eigene\n// Geometrie. `default` bleibt die bestehende Dashboard-Dichte; lg entspricht\n// der jeweiligen Button-Hoehe, xl bleibt bewusst unter dem 56px-CTA-Format.\nconst menuRowSizeClassName =\n  \"in-[[data-control-size=sm]]:min-h-7 in-[[data-control-size=sm]]:py-0.5 in-[[data-control-size=sm]]:text-sm in-[[data-control-size=lg]]:min-h-10 in-[[data-control-size=lg]]:text-base in-[[data-control-size=xl]]:min-h-12 in-[[data-control-size=xl]]:text-base sm:in-[[data-control-size=sm]]:min-h-6 sm:in-[[data-control-size=sm]]:text-sm sm:in-[[data-control-size=lg]]:min-h-9 sm:in-[[data-control-size=lg]]:text-base sm:in-[[data-control-size=xl]]:min-h-11 sm:in-[[data-control-size=xl]]:text-base\";\n\nconst menuRowIconSizeClassName =\n  \"in-[[data-control-size=sm]]:[&_svg:not([class*='size-'])]:size-4 in-[[data-control-size=lg]]:[&_svg:not([class*='size-'])]:size-4.5 in-[[data-control-size=xl]]:[&_svg:not([class*='size-'])]:size-5 sm:in-[[data-control-size=sm]]:[&_svg:not([class*='size-'])]:size-3.5 sm:in-[[data-control-size=lg]]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-control-size=xl]]:[&_svg:not([class*='size-'])]:size-5\";\n\n// Item + LinkItem teilen sich exakt dieselbe Klasse.\nexport const menuItemClassName = cn(\n  \"flex min-h-8 cursor-pointer select-none items-center gap-2 whitespace-nowrap rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not([class*='opacity-'])]:opacity-80 [&>svg:not([class*='size-'])]:size-4.5 sm:[&>svg:not([class*='size-'])]:size-4 [&>svg]:pointer-events-none [&>svg]:-mx-0.5 [&>svg]:shrink-0\",\n  menuRowSizeClassName,\n  menuRowIconSizeClassName,\n);\n\nexport const menuCheckboxItemClassName = cn(\n  \"grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-pointer items-center gap-2 whitespace-nowrap rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  menuRowSizeClassName,\n  menuRowIconSizeClassName,\n);\n\nexport const menuCheckboxItemSwitchGridClassName = \"grid-cols-[1fr_auto] gap-4 pe-1.5\";\nexport const menuCheckboxItemDefaultGridClassName = \"grid-cols-[.75rem_1fr] pe-4\";\n\nexport const menuSwitchTrackClassName =\n  \"inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-(--motion-duration-base) [--thumb-size:--spacing(5)] in-[[data-size=sm]]:[--thumb-size:--spacing(4)] in-[[data-size=lg]]:[--thumb-size:--spacing(6)] in-[[data-size=xl]]:[--thumb-size:--spacing(7)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 motion-reduce:transition-none sm:[--thumb-size:--spacing(4)] sm:in-[[data-size=sm]]:[--thumb-size:--spacing(3.5)] sm:in-[[data-size=lg]]:[--thumb-size:--spacing(5)] sm:in-[[data-size=xl]]:[--thumb-size:--spacing(6)]\";\n\n// Slot-gebunden -> je ein literaler String pro Familie (Tailwind-Scan).\nexport const menuSwitchThumbClassName =\n  \"pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_var(--motion-duration-base),border-radius_var(--motion-duration-base),scale_var(--motion-duration-micro)_var(--motion-duration-micro),transform-origin_var(--motion-duration-base)] motion-reduce:transition-none\";\n\nexport const contextMenuSwitchThumbClassName =\n  \"pointer-events-none block aspect-square h-full in-[[data-slot=context-menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=context-menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=context-menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=context-menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_var(--motion-duration-base),border-radius_var(--motion-duration-base),scale_var(--motion-duration-micro)_var(--motion-duration-micro),transform-origin_var(--motion-duration-base)] motion-reduce:transition-none\";\n\nexport const menuRadioItemClassName = cn(\n  \"grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-pointer grid-cols-[.75rem_1fr] items-center gap-2 whitespace-nowrap rounded-sm py-1 ps-2 pe-4 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n  menuRowSizeClassName,\n  menuRowIconSizeClassName,\n);\n\nexport const menuGroupLabelClassName =\n  \"px-2 py-1.5 font-medium text-muted-foreground text-xs data-inset:ps-9 in-[[data-control-size=sm]]:py-1 in-[[data-control-size=lg]]:py-2 in-[[data-control-size=lg]]:text-sm in-[[data-control-size=xl]]:py-2.5 in-[[data-control-size=xl]]:text-sm sm:data-inset:ps-8\";\n\nexport const menuSeparatorClassName =\n  \"mx-2 my-1 h-px bg-border in-[[data-control-size=lg]]:my-1.5 in-[[data-control-size=xl]]:my-2\";\n\nexport const menuShortcutClassName = shortcutClassName;\n\nexport const menuSubTriggerClassName = cn(\n  \"flex min-h-8 cursor-pointer items-center gap-2 whitespace-nowrap rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not(:last-child)]:-mx-0.5 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none\",\n  menuRowSizeClassName,\n  menuRowIconSizeClassName,\n);\n\n// Statischer Haken im Default-Checkbox-/Radio-Item (eine Glyphe, kein Inline-SVG).\nexport function MenuItemCheck(): React.ReactElement {\n  return <CheckIcon />;\n}\n"
    },
    {
      "path": "src/components/ui/typography.ts",
      "type": "registry:ui",
      "content": "export const codeInlineClassName =\n  \"rounded-(--code-inline-radius) border border-border bg-muted px-1.5 py-0.5 font-mono [font-size:var(--code-inline-font-size)] text-foreground\";\n\nexport const codeBlockBaseClassName =\n  \"relative w-full overflow-x-auto rounded-lg border border-border bg-muted/50 font-mono text-foreground leading-relaxed\";\n\nexport const codeBlockSizeClassNames = {\n  default: \"px-3.5 py-3 text-xs\",\n  sm: \"px-3 py-2 [font-size:var(--code-block-sm-font-size)]\",\n} as const;\n\nexport const kbdClassName =\n  \"pointer-events-none inline-flex h-5 min-w-5 shrink-0 select-none items-center justify-center gap-1 whitespace-nowrap rounded-(--kbd-radius) bg-muted px-1 font-medium font-sans text-muted-foreground text-xs [&_svg:not([class*='size-'])]:size-3\";\n\nexport const shortcutClassName =\n  \"ms-auto font-medium font-sans text-muted-foreground/72 text-xs tracking-normal\";\n"
    },
    {
      "path": "src/components/ui/menu.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\";\nimport { ChevronRightIcon } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  SiteplaneUIPortalScope,\n  useResolvedControlSize,\n  type SiteplaneControlSize,\n} from \"@/components/ui/siteplane-provider\";\nimport {\n  MenuItemCheck,\n  menuCheckboxItemClassName,\n  menuCheckboxItemDefaultGridClassName,\n  menuCheckboxItemSwitchGridClassName,\n  menuGroupLabelClassName,\n  menuItemClassName,\n  menuPopupClassName,\n  menuPopupWidthClassNames,\n  menuRadioItemClassName,\n  menuSeparatorClassName,\n  menuShortcutClassName,\n  menuSubTriggerClassName,\n  type MenuPopupWidth,\n  menuSwitchThumbClassName,\n  menuSwitchTrackClassName,\n} from \"@/components/ui/menu-shared\";\n\nexport const MenuCreateHandle: typeof MenuPrimitive.createHandle =\n  MenuPrimitive.createHandle;\n\nexport const Menu: typeof MenuPrimitive.Root = MenuPrimitive.Root;\n\nexport const MenuPortal: typeof MenuPrimitive.Portal = MenuPrimitive.Portal;\n\nexport function MenuTrigger({\n  className,\n  children,\n  ...props\n}: MenuPrimitive.Trigger.Props): React.ReactElement {\n  return (\n    <MenuPrimitive.Trigger\n      className={className}\n      data-slot=\"menu-trigger\"\n      {...props}\n    >\n      {children}\n    </MenuPrimitive.Trigger>\n  );\n}\n\nexport function MenuPopup({\n  children,\n  className,\n  sideOffset = 4,\n  align = \"center\",\n  alignOffset,\n  side = \"bottom\",\n  anchor,\n  portalProps,\n  width = \"auto\",\n  ...props\n}: MenuPrimitive.Popup.Props & {\n  align?: MenuPrimitive.Positioner.Props[\"align\"];\n  sideOffset?: MenuPrimitive.Positioner.Props[\"sideOffset\"];\n  alignOffset?: MenuPrimitive.Positioner.Props[\"alignOffset\"];\n  side?: MenuPrimitive.Positioner.Props[\"side\"];\n  anchor?: MenuPrimitive.Positioner.Props[\"anchor\"];\n  portalProps?: MenuPrimitive.Portal.Props;\n  width?: MenuPopupWidth;\n}): React.ReactElement {\n  return (\n    <MenuPortal {...portalProps}>\n      <SiteplaneUIPortalScope>\n        <MenuPrimitive.Positioner\n          align={align}\n          alignOffset={alignOffset}\n          anchor={anchor}\n          className=\"z-50\"\n          data-slot=\"menu-positioner\"\n          side={side}\n          sideOffset={sideOffset}\n        >\n          <MenuPrimitive.Popup\n            className={cn(\n              menuPopupClassName,\n              menuPopupWidthClassNames[width],\n              className,\n            )}\n            data-slot=\"menu-popup\"\n            {...props}\n          >\n            <div className=\"max-h-(--available-height) w-full overflow-y-auto p-1\">\n              {children}\n            </div>\n          </MenuPrimitive.Popup>\n        </MenuPrimitive.Positioner>\n      </SiteplaneUIPortalScope>\n    </MenuPortal>\n  );\n}\n\nexport function MenuGroup(\n  props: MenuPrimitive.Group.Props,\n): React.ReactElement {\n  return <MenuPrimitive.Group data-slot=\"menu-group\" {...props} />;\n}\n\nexport function MenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  ...props\n}: MenuPrimitive.Item.Props & {\n  inset?: boolean;\n  variant?: \"default\" | \"destructive\";\n}): React.ReactElement {\n  return (\n    <MenuPrimitive.Item\n      className={cn(menuItemClassName, className)}\n      data-inset={inset}\n      data-slot=\"menu-item\"\n      data-variant={variant}\n      {...props}\n    />\n  );\n}\n\nexport function MenuLinkItem({\n  className,\n  inset,\n  variant = \"default\",\n  closeOnClick = true,\n  ...props\n}: MenuPrimitive.LinkItem.Props & {\n  inset?: boolean;\n  variant?: \"default\" | \"destructive\";\n}): React.ReactElement {\n  return (\n    <MenuPrimitive.LinkItem\n      className={cn(menuItemClassName, className)}\n      closeOnClick={closeOnClick}\n      data-inset={inset}\n      data-slot=\"menu-link-item\"\n      data-variant={variant}\n      {...props}\n    />\n  );\n}\n\nexport function MenuCheckboxItem({\n  className,\n  children,\n  checked,\n  size,\n  variant = \"default\",\n  ...props\n}: MenuPrimitive.CheckboxItem.Props & {\n  size?: SiteplaneControlSize;\n  variant?: \"default\" | \"switch\";\n}): React.ReactElement {\n  const resolvedSize = useResolvedControlSize(size);\n\n  return (\n    <MenuPrimitive.CheckboxItem\n      checked={checked}\n      className={cn(\n        menuCheckboxItemClassName,\n        variant === \"switch\"\n          ? menuCheckboxItemSwitchGridClassName\n          : menuCheckboxItemDefaultGridClassName,\n        className,\n      )}\n      data-size={resolvedSize}\n      data-slot=\"menu-checkbox-item\"\n      {...props}\n    >\n      {variant === \"switch\" ? (\n        <>\n          <span className=\"col-start-1\">{children}</span>\n          <MenuPrimitive.CheckboxItemIndicator\n            className={menuSwitchTrackClassName}\n            keepMounted\n          >\n            <span className={menuSwitchThumbClassName} />\n          </MenuPrimitive.CheckboxItemIndicator>\n        </>\n      ) : (\n        <>\n          <MenuPrimitive.CheckboxItemIndicator className=\"col-start-1 -ms-0.5\">\n            <MenuItemCheck />\n          </MenuPrimitive.CheckboxItemIndicator>\n          <span className=\"col-start-2\">{children}</span>\n        </>\n      )}\n    </MenuPrimitive.CheckboxItem>\n  );\n}\n\nexport function MenuRadioGroup(\n  props: MenuPrimitive.RadioGroup.Props,\n): React.ReactElement {\n  return <MenuPrimitive.RadioGroup data-slot=\"menu-radio-group\" {...props} />;\n}\n\nexport function MenuRadioItem({\n  className,\n  children,\n  ...props\n}: MenuPrimitive.RadioItem.Props): React.ReactElement {\n  return (\n    <MenuPrimitive.RadioItem\n      className={cn(menuRadioItemClassName, className)}\n      data-slot=\"menu-radio-item\"\n      {...props}\n    >\n      <MenuPrimitive.RadioItemIndicator className=\"col-start-1 -ms-0.5\">\n        <MenuItemCheck />\n      </MenuPrimitive.RadioItemIndicator>\n      <span className=\"col-start-2\">{children}</span>\n    </MenuPrimitive.RadioItem>\n  );\n}\n\nexport function MenuGroupLabel({\n  className,\n  inset,\n  ...props\n}: MenuPrimitive.GroupLabel.Props & {\n  inset?: boolean;\n}): React.ReactElement {\n  return (\n    <MenuPrimitive.GroupLabel\n      className={cn(menuGroupLabelClassName, className)}\n      data-inset={inset}\n      data-slot=\"menu-label\"\n      {...props}\n    />\n  );\n}\n\nexport function MenuSeparator({\n  className,\n  ...props\n}: MenuPrimitive.Separator.Props): React.ReactElement {\n  return (\n    <MenuPrimitive.Separator\n      className={cn(menuSeparatorClassName, className)}\n      data-slot=\"menu-separator\"\n      {...props}\n    />\n  );\n}\n\nexport function MenuShortcut({\n  className,\n  ...props\n}: React.ComponentProps<\"kbd\">): React.ReactElement {\n  return (\n    <kbd\n      className={cn(menuShortcutClassName, className)}\n      data-slot=\"menu-shortcut\"\n      {...props}\n    />\n  );\n}\n\nexport function MenuSub(\n  props: MenuPrimitive.SubmenuRoot.Props,\n): React.ReactElement {\n  return <MenuPrimitive.SubmenuRoot data-slot=\"menu-sub\" {...props} />;\n}\n\nexport function MenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: MenuPrimitive.SubmenuTrigger.Props & {\n  inset?: boolean;\n}): React.ReactElement {\n  return (\n    <MenuPrimitive.SubmenuTrigger\n      className={cn(menuSubTriggerClassName, className)}\n      data-inset={inset}\n      data-slot=\"menu-sub-trigger\"\n      {...props}\n    >\n      {children}\n      <ChevronRightIcon className=\"ms-auto -me-0.5 opacity-80\" />\n    </MenuPrimitive.SubmenuTrigger>\n  );\n}\n\nexport function MenuSubPopup({\n  className,\n  sideOffset = 0,\n  alignOffset,\n  align = \"start\",\n  ...props\n}: MenuPrimitive.Popup.Props & {\n  align?: MenuPrimitive.Positioner.Props[\"align\"];\n  sideOffset?: MenuPrimitive.Positioner.Props[\"sideOffset\"];\n  alignOffset?: MenuPrimitive.Positioner.Props[\"alignOffset\"];\n  width?: MenuPopupWidth;\n}): React.ReactElement {\n  const defaultAlignOffset = align !== \"center\" ? -5 : undefined;\n\n  return (\n    <MenuPopup\n      align={align}\n      alignOffset={alignOffset ?? defaultAlignOffset}\n      className={className}\n      data-slot=\"menu-sub-content\"\n      side=\"inline-end\"\n      sideOffset={sideOffset}\n      {...props}\n    />\n  );\n}\n\nexport {\n  MenuPrimitive,\n  MenuCreateHandle as DropdownMenuCreateHandle,\n  Menu as DropdownMenu,\n  MenuPortal as DropdownMenuPortal,\n  MenuTrigger as DropdownMenuTrigger,\n  MenuPopup as DropdownMenuContent,\n  MenuGroup as DropdownMenuGroup,\n  MenuItem as DropdownMenuItem,\n  MenuCheckboxItem as DropdownMenuCheckboxItem,\n  MenuRadioGroup as DropdownMenuRadioGroup,\n  MenuRadioItem as DropdownMenuRadioItem,\n  MenuGroupLabel as DropdownMenuLabel,\n  MenuSeparator as DropdownMenuSeparator,\n  MenuShortcut as DropdownMenuShortcut,\n  MenuSub as DropdownMenuSub,\n  MenuSubTrigger as DropdownMenuSubTrigger,\n  MenuSubPopup as DropdownMenuSubContent,\n};\n"
    }
  ],
  "categories": [
    "overlays"
  ],
  "docs": "# Menu\n\n> Siteplane UI release `0.1.1`.\n\n## Public Purpose\n\nMenu presents grouped actions, choices, links, and submenus from a trigger. Use\nform controls such as Select, Checkbox, or Switch when the value belongs to a\nform field.\n\n## Import\n\n`import { Menu, MenuCheckboxItem, MenuCreateHandle, MenuGroup, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger } from \"@/components/ui/menu\";`\n\n## Public API\n\n- `MenuPopup side` accepts top, right, bottom, left, inline-start, and\n  inline-end and defaults to bottom.\n- `align` accepts start, center, or end and defaults to center.\n  `sideOffset` defaults to 4; `alignOffset` adjusts the cross-axis position.\n- `anchor` attaches the popup to another element or virtual anchor.\n- `width` accepts `\"auto\"`, `\"trigger\"`, `\"content\"`, or\n  `\"at-least-trigger\"`.\n- Use `inset` on items, group labels, and submenu triggers to align rows\n  without leading icons.\n- `MenuCheckboxItem size` accepts `\"sm\"`, `\"default\"`, `\"lg\"`, and\n  `\"xl\"`.\n- All item, selection, label, separator, and submenu rows inherit the\n  provider `controlSize`; repeated rows use the compact menu geometry from the\n  global size contract rather than the 56px XL CTA height.\n- `MenuLinkItem closeOnClick` defaults to `true`; use `false` only when the\n  menu should remain open after navigation.\n- `MenuCreateHandle` supports detached triggers and imperative opening.\n- Use `disabled` for unavailable items and the native icon slot treatment for\n  leading icons.\n\n## Public Motion\n\n- Popup and submenu placement, scale, fade, and reduced-motion behavior are\n  native.\n- Active items, selection items, and submenu triggers use a pointer cursor.\n- Do not wrap the popup in a second animation.\n\n## Public Accessibility\n\n- Give every trigger visible text or an accessible label.\n- Give a popup without visible context an accessible menu label.\n- Preserve Arrow key navigation, focus, Escape, outside click, and focus\n  restoration.\n- Keep disabled items unavailable and visibly distinct.\n- Checkbox and radio items retain their selection indicators; shortcuts are\n  supporting text only.\n\n## Public Agent Guidance\n\n- Use Menu for actions and menu choices, not ordinary form fields.\n- Do not render raw items outside Menu and MenuPopup.\n- Use placement, anchor, width, inset, size, link, disabled, and handle APIs\n  instead of local menu implementations.\n- Preserve native item, submenu, selection, cursor, focus, and motion behavior.\n\n## Public Links\n\n- [Documentation and preview](https://ui.siteplane.io/docs/components/overlays/menu)\n\n- [Registry source](https://ui.siteplane.io/r/menu.json)\n",
  "meta": {
    "siteplane:agentContractVersion": 1,
    "siteplane:docs": "https://ui.siteplane.io/docs/components/overlays/menu",
    "siteplane:releaseVersion": "0.1.1",
    "siteplane:sourceOwned": true
  },
  "devDependencies": []
}
