{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "menu",
  "title": "Menu",
  "description": "A selector plate: items engraved into brushed metal, the highlighted one pressed in, a lamp for checked settings, engraved rules between groups and keycaps for shortcuts. Dropdown, submenu and context menu.",
  "dependencies": [
    "@base-ui/react",
    "cn"
  ],
  "registryDependencies": [
    "https://bevel-ui.vercel.app/r/bevel.json"
  ],
  "files": [
    {
      "path": "registry/bevel/ui/menu.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ContextMenu as ContextMenuPrimitive } from \"@base-ui/react/context-menu\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport { cn } from \"cn\"\n\n/** A trigger and the plate it opens. */\nfunction Menu(props: MenuPrimitive.Root.Props) {\n  return <MenuPrimitive.Root data-slot=\"menu\" {...props} />\n}\n\n/** Opens the plate. Renders a button; pass `render` to use your own. */\nfunction MenuTrigger(props: MenuPrimitive.Trigger.Props) {\n  return <MenuPrimitive.Trigger data-slot=\"menu-trigger\" {...props} />\n}\n\nconst plate = cn(\n  \"menu-plate flex max-h-(--available-height) min-w-(--menu-min-width) origin-(--transform-origin) flex-col overflow-y-auto overscroll-contain rounded-(--bevel-radius-md) p-1 text-sm outline-none\",\n  \"transition-[translate,opacity] duration-(--bevel-duration-small) ease-(--bevel-ease-out) motion-reduce:transition-none\",\n  \"data-starting-style:opacity-0 data-ending-style:opacity-0\",\n  \"data-[side=bottom]:data-starting-style:-translate-y-(--menu-lift) data-[side=top]:data-starting-style:translate-y-(--menu-lift)\",\n  \"data-[side=right]:data-starting-style:-translate-x-(--menu-lift) data-[side=left]:data-starting-style:translate-x-(--menu-lift)\",\n  \"forced-colors:border forced-colors:border-[CanvasText]\"\n)\n\ntype MenuContentProps = MenuPrimitive.Popup.Props &\n  Pick<MenuPrimitive.Positioner.Props, \"side\" | \"align\" | \"sideOffset\" | \"alignOffset\" | \"collisionPadding\">\n\n/** The plate: brushed metal, items engraved into it. Drops a short way from the trigger. */\nfunction MenuContent({\n  className,\n  side = \"bottom\",\n  align = \"start\",\n  sideOffset = 6,\n  alignOffset = 0,\n  collisionPadding = 8,\n  ...props\n}: MenuContentProps) {\n  return (\n    <MenuPrimitive.Portal>\n      <MenuPrimitive.Positioner\n        side={side}\n        align={align}\n        sideOffset={sideOffset}\n        alignOffset={alignOffset}\n        collisionPadding={collisionPadding}\n        className=\"z-50 outline-none\"\n      >\n        <MenuPrimitive.Popup data-slot=\"menu-content\" className={cn(plate, className)} {...props} />\n      </MenuPrimitive.Positioner>\n    </MenuPrimitive.Portal>\n  )\n}\n\n/* The highlighted item sits pressed into the plate. */\nconst item = cn(\n  \"relative flex min-h-8 cursor-default items-center gap-2 rounded-(--bevel-radius-sm) px-2 py-1.5 outline-none select-none\",\n  \"data-highlighted:bevel-pressed data-highlighted:[text-shadow:none]\",\n  \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n  \"data-[variant=destructive]:text-(--menu-danger)\",\n  \"forced-colors:data-highlighted:outline forced-colors:data-highlighted:outline-[Highlight]\",\n  \"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-(--menu-ink-muted) data-[variant=destructive]:[&_svg]:text-current\"\n)\n\ntype MenuItemProps = MenuPrimitive.Item.Props & {\n  /** \"destructive\" engraves the item in red, for delete and the like. */\n  variant?: \"default\" | \"destructive\"\n}\n\nfunction MenuItem({ className, variant = \"default\", ...props }: MenuItemProps) {\n  return <MenuPrimitive.Item data-slot=\"menu-item\" data-variant={variant} className={cn(item, className)} {...props} />\n}\n\n/** An item that navigates: a real link, so it opens in a new tab and shows its address. */\nfunction MenuLinkItem({ className, ...props }: MenuPrimitive.LinkItem.Props) {\n  return <MenuPrimitive.LinkItem data-slot=\"menu-link-item\" className={cn(item, className)} {...props} />\n}\n\n/** A small lamp: lit when its item is checked. The pill is a checkbox, the round one a radio. */\nfunction MenuLamp({ shape }: { shape: \"pill\" | \"round\" }) {\n  return (\n    <span\n      aria-hidden\n      data-slot=\"menu-lamp\"\n      className={cn(\n        \"bevel-led shrink-0 forced-color-adjust-none forced-colors:border forced-colors:border-[CanvasText] in-data-checked:forced-colors:bg-[Highlight]\",\n        shape === \"pill\" ? \"h-1.5 w-2.5 rounded-full\" : \"size-2 rounded-full\"\n      )}\n    />\n  )\n}\n\n/** A setting you turn on and off. A lamp on the left lights when it's on. */\nfunction MenuCheckboxItem({ className, children, ...props }: MenuPrimitive.CheckboxItem.Props) {\n  return (\n    <MenuPrimitive.CheckboxItem\n      data-slot=\"menu-checkbox-item\"\n      closeOnClick={false}\n      className={cn(item, \"pl-2.5\", className)}\n      {...props}\n    >\n      <MenuLamp shape=\"pill\" />\n      {children}\n    </MenuPrimitive.CheckboxItem>\n  )\n}\n\nfunction MenuRadioGroup(props: MenuPrimitive.RadioGroup.Props) {\n  return <MenuPrimitive.RadioGroup data-slot=\"menu-radio-group\" {...props} />\n}\n\n/** One of a set. The chosen one's lamp is lit. */\nfunction MenuRadioItem({ className, children, ...props }: MenuPrimitive.RadioItem.Props) {\n  return (\n    <MenuPrimitive.RadioItem\n      data-slot=\"menu-radio-item\"\n      closeOnClick={false}\n      className={cn(item, \"pl-2.5\", className)}\n      {...props}\n    >\n      <MenuLamp shape=\"round\" />\n      {children}\n    </MenuPrimitive.RadioItem>\n  )\n}\n\nfunction MenuGroup(props: MenuPrimitive.Group.Props) {\n  return <MenuPrimitive.Group data-slot=\"menu-group\" {...props} />\n}\n\n/** A small stamped heading over a group. */\nfunction MenuGroupLabel({ className, ...props }: MenuPrimitive.GroupLabel.Props) {\n  return (\n    <MenuPrimitive.GroupLabel\n      data-slot=\"menu-group-label\"\n      className={cn(\n        \"px-2 pt-2 pb-1 text-(length:--bevel-fine) font-semibold tracking-(--bevel-tracking-label) text-(--menu-ink-muted) uppercase\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/** An engraved rule between groups. */\nfunction MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {\n  return <MenuPrimitive.Separator data-slot=\"menu-separator\" className={cn(\"menu-rule -mx-1 my-1\", className)} {...props} />\n}\n\ntype MenuShortcutProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n  /** One keycap per key, e.g. [\"⌘\", \"C\"]. Also set aria-keyshortcuts on the item. */\n  keys: string[]\n}\n\n/** The item's keyboard shortcut, as small keycaps at the end of the row. Hidden from screen readers. */\nfunction MenuShortcut({ className, keys, ...props }: MenuShortcutProps) {\n  return (\n    <span\n      aria-hidden\n      data-slot=\"menu-shortcut\"\n      className={cn(\"ml-auto flex shrink-0 items-center gap-0.5 pl-4 [text-shadow:none]\", className)}\n      {...props}\n    >\n      {keys.map((key, i) => (\n        <kbd\n          key={i}\n          data-slot=\"menu-key\"\n          className=\"bevel-raised inline-flex h-(--menu-key-size) min-w-(--menu-key-size) -translate-y-px items-center justify-center rounded-(--bevel-radius-xs) px-1 font-sans text-(length:--bevel-fine) leading-none font-medium text-(--menu-key-foreground)\"\n        >\n          {key}\n        </kbd>\n      ))}\n    </span>\n  )\n}\n\n/** Holds a submenu: its trigger item and its own plate. */\nfunction MenuSub(props: MenuPrimitive.SubmenuRoot.Props) {\n  return <MenuPrimitive.SubmenuRoot data-slot=\"menu-sub\" {...props} />\n}\n\n/** The item that opens a submenu, with a chevron. Opens on hover, → or Enter. */\nfunction MenuSubTrigger({ className, children, ...props }: MenuPrimitive.SubmenuTrigger.Props) {\n  return (\n    <MenuPrimitive.SubmenuTrigger\n      data-slot=\"menu-sub-trigger\"\n      className={cn(item, \"data-popup-open:bevel-pressed data-popup-open:[text-shadow:none]\", className)}\n      {...props}\n    >\n      {children}\n      <svg aria-hidden viewBox=\"0 0 16 16\" className=\"ml-auto\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n        <path d=\"M6 4l4 4-4 4\" />\n      </svg>\n    </MenuPrimitive.SubmenuTrigger>\n  )\n}\n\n/** A submenu's plate. Opens beside its trigger. */\nfunction MenuSubContent({ side = \"right\", align = \"start\", sideOffset = 2, alignOffset = -4, ...props }: MenuContentProps) {\n  return <MenuContent side={side} align={align} sideOffset={sideOffset} alignOffset={alignOffset} {...props} />\n}\n\n/** Right-click (or long-press) an area to open a plate at the pointer. */\nfunction ContextMenu(props: ContextMenuPrimitive.Root.Props) {\n  return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />\n}\n\n/** The area that opens the context menu. Renders a div. */\nfunction ContextMenuTrigger(props: ContextMenuPrimitive.Trigger.Props) {\n  return <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />\n}\n\n/** The context menu's plate, at the pointer. Fill it with the same Menu items. */\nfunction ContextMenuContent({\n  className,\n  ...props\n}: MenuPrimitive.Popup.Props & Pick<ContextMenuPrimitive.Positioner.Props, \"side\" | \"align\" | \"sideOffset\" | \"alignOffset\">) {\n  const { side, align, sideOffset, alignOffset, ...popup } = props\n  return (\n    <ContextMenuPrimitive.Portal>\n      <ContextMenuPrimitive.Positioner\n        side={side}\n        align={align}\n        sideOffset={sideOffset}\n        alignOffset={alignOffset}\n        collisionPadding={8}\n        className=\"z-50 outline-none\"\n      >\n        <ContextMenuPrimitive.Popup data-slot=\"menu-content\" className={cn(plate, className)} {...popup} />\n      </ContextMenuPrimitive.Positioner>\n    </ContextMenuPrimitive.Portal>\n  )\n}\n\nexport {\n  Menu,\n  MenuTrigger,\n  MenuContent,\n  MenuItem,\n  MenuLinkItem,\n  MenuCheckboxItem,\n  MenuRadioGroup,\n  MenuRadioItem,\n  MenuGroup,\n  MenuGroupLabel,\n  MenuSeparator,\n  MenuShortcut,\n  MenuSub,\n  MenuSubTrigger,\n  MenuSubContent,\n  ContextMenu,\n  ContextMenuTrigger,\n  ContextMenuContent,\n}\nexport type { MenuContentProps, MenuItemProps, MenuShortcutProps }\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    ":root": {
      "--menu-plate": "oklch(0.91 0.004 250)",
      "--menu-plate-edge": "oklch(0.68 0.006 250)",
      "--menu-rim": "oklch(0 0 0 / 0.14)",
      "--menu-brush": "oklch(1 0 0 / 0.05)",
      "--menu-ink": "oklch(0.25 0.01 260)",
      "--menu-ink-muted": "oklch(0.45 0.01 260)",
      "--menu-engrave": "0 1px 0 oklch(1 0 0 / 0.55)",
      "--menu-rule-shade": "oklch(0 0 0 / 0.16)",
      "--menu-rule-light": "oklch(1 0 0 / 0.7)",
      "--menu-lamp-off": "oklch(0.6 0.02 150)",
      "--menu-lamp-on": "oklch(0.74 0.19 145)",
      "--menu-key": "oklch(0.98 0.003 90)",
      "--menu-key-edge": "oklch(0.74 0.006 250)",
      "--menu-key-foreground": "oklch(0.32 0.01 260)",
      "--menu-danger": "oklch(0.5 0.19 27)",
      "--menu-depth": "inset 0 1px 0 var(--bevel-highlight-strong), inset 0 0 0 1px var(--menu-rim), 0 1px 1px var(--bevel-cast), 0 10px 22px -8px var(--bevel-cast)",
      "--menu-min-width": "12rem",
      "--menu-key-size": "1.125rem",
      "--menu-lift": "0.25rem"
    },
    ".dark": {
      "--menu-plate": "oklch(0.32 0.006 260)",
      "--menu-plate-edge": "oklch(0.2 0.006 260)",
      "--menu-rim": "oklch(0 0 0 / 0.4)",
      "--menu-ink": "oklch(0.94 0.004 90)",
      "--menu-ink-muted": "oklch(0.72 0.008 260)",
      "--menu-engrave": "0 -1px 0 oklch(0 0 0 / 0.5)",
      "--menu-rule-shade": "oklch(0 0 0 / 0.45)",
      "--menu-rule-light": "oklch(1 0 0 / 0.08)",
      "--menu-lamp-off": "oklch(0.38 0.02 150)",
      "--menu-key": "oklch(0.42 0.006 260)",
      "--menu-key-edge": "oklch(0.22 0.006 260)",
      "--menu-key-foreground": "oklch(0.92 0.004 90)",
      "--menu-danger": "oklch(0.72 0.17 27)"
    },
    "[data-slot=\"menu-content\"]": {
      "--bevel-material": "var(--menu-plate)",
      "--bevel-material-edge": "var(--menu-plate-edge)"
    },
    "[data-slot=\"menu-shortcut\"]": {
      "--bevel-material": "var(--menu-key)",
      "--bevel-material-edge": "var(--menu-key-edge)"
    },
    "[data-slot=\"menu-lamp\"]": {
      "--bevel-led": "var(--menu-lamp-off)"
    },
    "[data-checked] > [data-slot=\"menu-lamp\"]": {
      "--bevel-led": "var(--menu-lamp-on)"
    },
    "@utility menu-plate": {
      "background-color": "var(--menu-plate)",
      "background-image": "linear-gradient(to bottom, var(--bevel-highlight), transparent 40%, var(--bevel-shade) 140%), repeating-linear-gradient(90deg, var(--menu-brush) 0 1px, transparent 1px 3px)",
      "box-shadow": "var(--menu-depth)",
      "color": "var(--menu-ink)",
      "text-shadow": "var(--menu-engrave)"
    },
    "@utility menu-rule": {
      "border-top": "1px solid var(--menu-rule-shade)",
      "border-bottom": "1px solid var(--menu-rule-light)"
    }
  },
  "categories": [
    "essentials"
  ],
  "type": "registry:ui"
}