{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "menu",
  "type": "registry:ui",
  "title": "Menu and correction popover",
  "description": "A frosted plate of 30 rows (frost-strong at .92, radius 18, padding 6, at least 200 wide) from a trigger or at the pointer: an engraved heading says what it acts on, pointer and keyboard share one highlight, keys at the right, destructive rows red, engraved separators; fades on settle. The correction popover is its right-click form. Built on Base UI Menu and Context Menu.",
  "dependencies": [
    "@base-ui/react@^1.8.0"
  ],
  "registryDependencies": [
    "https://metalui.dev/r/tokens.json"
  ],
  "files": [
    {
      "path": "packages/metalui/src/components/menu/menu.tsx",
      "type": "registry:ui",
      "target": "components/metalui/menu/menu.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { Menu as BaseMenu } from '@base-ui/react/menu';\nimport { ContextMenu as BaseContextMenu } from '@base-ui/react/context-menu';\nimport { Kbd } from '../kbd/kbd';\n\n/* ─────────────────────────────────────────────────────────\n * MENU and CORRECTION POPOVER (the brief, 04 §8, §18; the reference design's #pop) on Base UI Menu\n *   open      from a trigger (6 below it) or at the pointer (right-click): fades in on settle\n *   heading   what the menu acts on, engraved: \"NOTE · TASK BY RECOGNIZER 0.82\"\n *   rows      pointer and keyboard share one highlighted state; ↑ ↓ and type-ahead; ↩ chooses\n *   choose    the row runs and the menu closes (fades on release); focus returns to the trigger\n *   ⎋ / click outside  closes, nothing runs\n * ───────────────────────────────────────────────────────── */\n\n/* Styled with the theme's utilities (the menu recipe): a frosted plate that fades in on settle and out on\n * release; rows highlight under the pointer or the keys; destructive rows are red. */\nconst POSITIONER = 'mu-menu-positioner z-menu-z';\nconst PLATE = 'mu-menu min-w-menu-min-width p-menu-pad rounded-menu-radius outline-none recipe-menu backdrop-menu-blur menu-origin transition-opacity ease-settle duration-settle data-starting-style:opacity-0 data-ending-style:opacity-0 data-ending-style:ease-release data-ending-style:duration-release reduce-transparency:opaque-frost';\nconst HEADING = 'mu-menu-heading pt-menu-heading-pad-top px-menu-heading-pad-x pb-menu-heading-pad-bottom type-label engraved';\nconst ROW = 'mu-menu-row mu-icon-trigger flex items-center gap-menu-row-gap h-menu-row-height px-menu-row-pad rounded-menu-row-radius type-menu-row text-ink cursor-default outline-none select-none data-highlighted:recipe-menu-row-hover data-danger:text-red data-disabled:opacity-menu-row-disabled';\nconst GLYPH = 'mu-menu-glyph inline-grid flex-none text-ink2 in-data-danger:text-red [&>svg]:size-menu-row-glyph';\nconst LABEL = 'mu-menu-label flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap';\nconst KEY = 'mu-menu-key ml-menu-row-key-gap';\nconst SEP = 'mu-menu-sep h-menu-sep-thickness my-menu-sep-inset-y mx-menu-sep-inset-x recipe-menu-sep';\n\n/** The menu's part classes, for stills of it outside a popup (docs, previews). */\nexport const menuParts = { PLATE, HEADING, ROW, GLYPH, LABEL, KEY, SEP } as const;\n\nfunction offset() {\n  if (typeof window === 'undefined') return 6;\n  return parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--mu-menu-offset')) || 6;\n}\n\nfunction Plate({ heading, children }: { heading?: string; children: React.ReactNode }) {\n  return (\n    <BaseMenu.Popup className={PLATE}>\n      {heading ? (\n        <BaseMenu.Group>\n          <BaseMenu.GroupLabel className={HEADING}>{heading}</BaseMenu.GroupLabel>\n          {children}\n        </BaseMenu.Group>\n      ) : children}\n    </BaseMenu.Popup>\n  );\n}\n\nexport interface MenuProps {\n  /** The control that opens it. It must accept a ref and props (a Button, an icon button). */\n  trigger: React.ReactElement;\n  /** What the menu acts on, as an engraving above the rows. */\n  heading?: string;\n  side?: 'bottom' | 'top' | 'left' | 'right';\n  align?: 'start' | 'center' | 'end';\n  /** MenuItem and MenuSeparator. */\n  children: React.ReactNode;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n}\n\n/** A menu from a trigger: a frosted plate of rows 6 below it. */\nexport function Menu({ trigger, heading, side = 'bottom', align = 'start', children, open, onOpenChange }: MenuProps) {\n  return (\n    <BaseMenu.Root open={open} onOpenChange={onOpenChange ? (o) => onOpenChange(o) : undefined}>\n      <BaseMenu.Trigger render={trigger} />\n      <BaseMenu.Portal>\n        <BaseMenu.Positioner className={POSITIONER} side={side} align={align} sideOffset={offset()} collisionPadding={8}>\n          <Plate heading={heading}>{children}</Plate>\n        </BaseMenu.Positioner>\n      </BaseMenu.Portal>\n    </BaseMenu.Root>\n  );\n}\n\nexport interface ContextMenuProps {\n  /** The rows: MenuItem and MenuSeparator. */\n  menu: React.ReactNode;\n  /** What the menu acts on: for a correction, the cue's provenance. */\n  heading?: string;\n  /** The area that answers a right-click (or ⌃-click, or a long press). */\n  children: React.ReactElement;\n}\n\n/**\n * The correction popover: right-click a cue (or anything) for a menu at the pointer. Corrections win\n * and are remembered; the host shows a toast with Undo after one.\n */\nexport function ContextMenu({ menu, heading, children }: ContextMenuProps) {\n  return (\n    <BaseContextMenu.Root>\n      <BaseContextMenu.Trigger render={children} />\n      <BaseContextMenu.Portal>\n        <BaseContextMenu.Positioner className={POSITIONER} collisionPadding={8}>\n          <Plate heading={heading}>{menu}</Plate>\n        </BaseContextMenu.Positioner>\n      </BaseContextMenu.Portal>\n    </BaseContextMenu.Root>\n  );\n}\n\nexport interface MenuItemProps {\n  /** Runs when chosen (click, ↩, or a release after press-and-drag). */\n  onSelect?: () => void;\n  /** The 14 glyph at the left. */\n  icon?: React.ReactNode;\n  /** The key at the right: \"⌘Z\". */\n  shortcut?: string;\n  /** A destructive action: red. */\n  danger?: boolean;\n  disabled?: boolean;\n  children: React.ReactNode;\n}\n\n/** A 30 row. */\nexport function MenuItem({ onSelect, icon, shortcut, danger, disabled, children }: MenuItemProps) {\n  return (\n    <BaseMenu.Item className={ROW} onClick={onSelect} disabled={disabled} data-danger={danger ? '' : undefined}>\n      {icon && <span aria-hidden className={GLYPH}>{icon}</span>}\n      <span className={LABEL}>{children}</span>\n      {shortcut && <Kbd size=\"small\" className={KEY}>{shortcut}</Kbd>}\n    </BaseMenu.Item>\n  );\n}\n\n/** An engraved rule between groups of rows. */\nexport function MenuSeparator() {\n  return <BaseMenu.Separator className={SEP} />;\n}\n"
    }
  ],
  "docs": "Agent guide: https://metalui.dev/r/menu.md. SwiftUI: MetalMenuPanel, MetalMenuItem, View.metalMenu(isPresented:at:heading:items:) in the MetalUI Swift package."
}
