{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-menu",
  "title": "Menu",
  "description": "The Material menu: standard and vibrant items, leading icons, trailing text, submenus, and destructive actions.",
  "dependencies": [
    "@base-ui/react@^1.7.0",
    "class-variance-authority@^0.7.1",
    "lucide-react@^1.33.0"
  ],
  "registryDependencies": [
    "https://guillermo-rebolledo.github.io/materialcn/r/materialcn-theme.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/theme-context.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/utils.json"
  ],
  "files": [
    {
      "path": "src/components/ui/dropdown-menu.tsx",
      "content": "import * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport { CheckIcon, ChevronRightIcon } from \"lucide-react\"\n\nimport { ThemeContext } from \"@/components/theme-context\"\nimport { cn } from \"@/lib/utils\"\nimport {\n  dropdownMenuContentVariants,\n  dropdownMenuItemVariants,\n  dropdownMenuSelectableItemVariants,\n  dropdownMenuSubTriggerVariants,\n  type DropdownMenuPresentation,\n} from \"./dropdown-menu-variants\"\n\nconst DropdownMenuPresentationContext =\n  React.createContext<DropdownMenuPresentation>(\"standard\")\n\nfunction DropdownMenu(props: MenuPrimitive.Root.Props) {\n  return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({ className, ...props }: MenuPrimitive.Portal.Props) {\n  const theme = React.use(ThemeContext)\n\n  return (\n    <MenuPrimitive.Portal\n      data-slot=\"dropdown-menu-portal\"\n      className={cn(theme?.resolvedTheme, className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * Click-triggered by default. `openOnHover` switches it to the navigation-menu\n * shape, where requiring a click at every level is tedious.\n *\n * Hover alone would leave keyboard users with a menu they cannot reach the same\n * way, so when `openOnHover` is set, moving focus to the trigger opens it too.\n * That is done by clicking the trigger rather than by driving the open state\n * from outside: the click goes through the primitive's own path, so it behaves\n * identically to a real one and works whether the menu is controlled or not.\n *\n * The pointer travelling diagonally from the trigger toward the menu is the\n * other classic failure — it leaves the trigger before it reaches the popup, so\n * a naive implementation closes half way. The primitive covers that with a\n * safe-area polygon; `closeDelay` is the belt to its braces.\n */\nfunction DropdownMenuTrigger({\n  closeDelay,\n  onFocus,\n  openOnHover,\n  ...props\n}: MenuPrimitive.Trigger.Props) {\n  return (\n    <MenuPrimitive.Trigger\n      data-slot=\"dropdown-menu-trigger\"\n      openOnHover={openOnHover}\n      closeDelay={openOnHover ? (closeDelay ?? 150) : closeDelay}\n      onFocus={(event) => {\n        onFocus?.(event)\n        if (!openOnHover || event.defaultPrevented) return\n\n        const trigger = event.currentTarget\n        // Only keyboard focus. A click also focuses, and opening from that\n        // would immediately fight the click's own toggle.\n        if (!trigger.matches(\":focus-visible\")) return\n        // The primitive's trigger toggles, so opening an already-open menu\n        // would close it — which is what happens when focus returns from the\n        // popup.\n        if (trigger.getAttribute(\"data-popup-open\") !== null) return\n\n        trigger.click()\n      }}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuContent({\n  align = \"start\",\n  alignOffset = 0,\n  side = \"bottom\",\n  sideOffset = 4,\n  variant = \"standard\",\n  className,\n  children,\n  ...props\n}: MenuPrimitive.Popup.Props &\n  Pick<\n    MenuPrimitive.Positioner.Props,\n    \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n  > & {\n    variant?: DropdownMenuPresentation\n  }) {\n  return (\n    <DropdownMenuPortal>\n      <MenuPrimitive.Positioner\n        className=\"isolate z-(--m3-z-menu) outline-none\"\n        align={align}\n        alignOffset={alignOffset}\n        side={side}\n        sideOffset={sideOffset}\n      >\n        <MenuPrimitive.Popup\n          data-slot=\"dropdown-menu-content\"\n          data-presentation={variant}\n          className={cn(\n            dropdownMenuContentVariants({ presentation: variant }),\n            className,\n          )}\n          {...props}\n        >\n          <DropdownMenuPresentationContext value={variant}>\n            {children}\n          </DropdownMenuPresentationContext>\n        </MenuPrimitive.Popup>\n      </MenuPrimitive.Positioner>\n    </DropdownMenuPortal>\n  )\n}\n\nfunction DropdownMenuGroup({ className, ...props }: MenuPrimitive.Group.Props) {\n  return (\n    <MenuPrimitive.Group\n      data-slot=\"dropdown-menu-group\"\n      className={cn(\"flex flex-col rounded-m3-sm py-0.5\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuLabel({\n  className,\n  inset,\n  ...props\n}: MenuPrimitive.GroupLabel.Props & { inset?: boolean }) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <MenuPrimitive.GroupLabel\n      data-slot=\"dropdown-menu-label\"\n      data-inset={inset}\n      className={cn(\n        \"flex h-8 items-center px-4 text-m3-label-lg data-inset:pl-10\",\n        presentation === \"standard\"\n          ? \"text-m3-on-surface-variant\"\n          : \"text-m3-on-tertiary-container\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  ...props\n}: MenuPrimitive.Item.Props & {\n  inset?: boolean\n  variant?: \"default\" | \"destructive\"\n}) {\n  return (\n    <MenuPrimitive.Item\n      data-slot=\"dropdown-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      className={cn(dropdownMenuItemVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuSub(props: MenuPrimitive.SubmenuRoot.Props) {\n  return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean }) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <MenuPrimitive.SubmenuTrigger\n      data-slot=\"dropdown-menu-sub-trigger\"\n      data-inset={inset}\n      className={cn(\n        dropdownMenuSubTriggerVariants({ presentation }),\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <ChevronRightIcon aria-hidden=\"true\" className=\"ml-auto\" />\n    </MenuPrimitive.SubmenuTrigger>\n  )\n}\n\nfunction DropdownMenuSubContent({\n  align = \"start\",\n  alignOffset = -3,\n  side = \"right\",\n  sideOffset = 0,\n  className,\n  ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <DropdownMenuContent\n      data-slot=\"dropdown-menu-sub-content\"\n      variant={presentation}\n      className={className}\n      align={align}\n      alignOffset={alignOffset}\n      side={side}\n      sideOffset={sideOffset}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuCheckboxItem({\n  className,\n  children,\n  checked,\n  inset,\n  ...props\n}: MenuPrimitive.CheckboxItem.Props & { inset?: boolean }) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <MenuPrimitive.CheckboxItem\n      data-slot=\"dropdown-menu-checkbox-item\"\n      data-inset={inset}\n      className={cn(\n        dropdownMenuSelectableItemVariants({ presentation }),\n        className,\n      )}\n      checked={checked}\n      {...props}\n    >\n      <span\n        className=\"pointer-events-none absolute right-4 flex size-5 items-center justify-center\"\n        data-slot=\"dropdown-menu-checkbox-item-indicator\"\n      >\n        <MenuPrimitive.CheckboxItemIndicator>\n          <CheckIcon aria-hidden=\"true\" />\n        </MenuPrimitive.CheckboxItemIndicator>\n      </span>\n      {children}\n    </MenuPrimitive.CheckboxItem>\n  )\n}\n\nfunction DropdownMenuRadioGroup(props: MenuPrimitive.RadioGroup.Props) {\n  return (\n    <MenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n  )\n}\n\nfunction DropdownMenuRadioItem({\n  className,\n  children,\n  inset,\n  ...props\n}: MenuPrimitive.RadioItem.Props & { inset?: boolean }) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <MenuPrimitive.RadioItem\n      data-slot=\"dropdown-menu-radio-item\"\n      data-inset={inset}\n      className={cn(\n        dropdownMenuSelectableItemVariants({ presentation }),\n        className,\n      )}\n      {...props}\n    >\n      <span\n        className=\"pointer-events-none absolute right-4 flex size-5 items-center justify-center\"\n        data-slot=\"dropdown-menu-radio-item-indicator\"\n      >\n        <MenuPrimitive.RadioItemIndicator>\n          <CheckIcon aria-hidden=\"true\" />\n        </MenuPrimitive.RadioItemIndicator>\n      </span>\n      {children}\n    </MenuPrimitive.RadioItem>\n  )\n}\n\nfunction DropdownMenuSeparator({\n  className,\n  ...props\n}: MenuPrimitive.Separator.Props) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <MenuPrimitive.Separator\n      data-slot=\"dropdown-menu-separator\"\n      className={cn(\n        \"mx-3 my-0.5 h-px shrink-0\",\n        presentation === \"standard\"\n          ? \"bg-m3-outline-variant\"\n          : \"bg-m3-on-tertiary-container/20\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction DropdownMenuShortcut({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  const presentation = React.use(DropdownMenuPresentationContext)\n\n  return (\n    <span\n      data-slot=\"dropdown-menu-shortcut\"\n      className={cn(\n        \"ml-auto text-m3-label-sm tracking-normal\",\n        presentation === \"standard\"\n          ? \"text-m3-on-surface-variant\"\n          : \"text-m3-on-tertiary-container\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuPortal,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuTrigger,\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "src/components/ui/dropdown-menu-variants.ts",
      "content": "import { cva } from \"class-variance-authority\"\n\n/** Material 3 action-menu surfaces from the current design kit. */\nexport const dropdownMenuContentVariants = cva(\n  [\n    \"z-(--m3-z-menu) max-h-(--available-height) w-(--anchor-width) min-w-52\",\n    // Kit: a 16dp-radius container at elevation 3 holding 8dp-radius group\n    // cards 2dp apart.\n    \"flex flex-col gap-0.5 overflow-x-hidden overflow-y-auto rounded-m3-lg\",\n    \"text-m3-label-lg shadow-m3-3 outline-none\",\n    \"duration-(--m3-spring-effects-fast-duration) ease-(--m3-spring-effects-fast)\",\n    \"data-open:animate-in data-open:fade-in-0\",\n    \"data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0\",\n  ],\n  {\n    variants: {\n      presentation: {\n        standard: \"bg-m3-surface-container-low text-m3-on-surface\",\n        vibrant: \"bg-m3-tertiary-container text-m3-on-tertiary-container\",\n      },\n    },\n    defaultVariants: { presentation: \"standard\" },\n  },\n)\n\nconst menuItemBase = [\n  \"relative isolate flex h-12 cursor-default items-center gap-2 px-4\",\n  \"outline-none select-none\",\n  \"before:pointer-events-none before:absolute before:inset-x-1 before:inset-y-0.5 before:-z-20 before:rounded-m3-xs before:opacity-0\",\n  \"after:pointer-events-none after:absolute after:inset-x-1 after:inset-y-0.5 after:-z-10 after:rounded-m3-xs after:bg-current after:opacity-0\",\n  \"after:transition-opacity after:duration-(--m3-spring-effects-fast-duration) after:ease-(--m3-spring-effects-fast)\",\n  \"hover:not-data-disabled:after:opacity-8 focus-visible:not-data-disabled:after:opacity-10 active:not-data-disabled:after:opacity-10\",\n  // Kit focus indicator: a 2dp Secondary stroke 4dp outside the state layer.\n  \"focus-visible:before:opacity-100 focus-visible:before:-inset-x-0 focus-visible:before:-inset-y-0 focus-visible:before:rounded-[6px] focus-visible:before:ring-2 focus-visible:before:ring-m3-secondary focus-visible:data-checked:before:rounded-[14px]\",\n  \"data-disabled:pointer-events-none data-disabled:opacity-38\",\n  \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5\",\n  \"data-inset:pl-10\",\n]\n\nexport const dropdownMenuItemVariants = cva(menuItemBase, {\n  variants: {\n    variant: {\n      default: \"\",\n      destructive: \"text-m3-error\",\n    },\n  },\n  defaultVariants: { variant: \"default\" },\n})\n\nexport const dropdownMenuSelectableItemVariants = cva(\n  [\n    ...menuItemBase,\n    \"pr-11 data-checked:before:rounded-m3-md data-checked:before:opacity-100 data-checked:after:rounded-m3-md\",\n  ],\n  {\n    variants: {\n      presentation: {\n        standard:\n          \"data-checked:before:bg-m3-tertiary-container data-checked:text-m3-on-tertiary-container\",\n        vibrant:\n          \"data-checked:before:bg-m3-tertiary data-checked:text-m3-on-tertiary\",\n      },\n    },\n    defaultVariants: { presentation: \"standard\" },\n  },\n)\n\nexport const dropdownMenuSubTriggerVariants = cva(\n  [\n    ...menuItemBase,\n    \"data-popup-open:before:rounded-m3-md data-popup-open:before:opacity-100 data-popup-open:after:rounded-m3-md\",\n  ],\n  {\n    variants: {\n      presentation: {\n        standard:\n          \"data-popup-open:before:bg-m3-tertiary-container data-popup-open:text-m3-on-tertiary-container\",\n        vibrant:\n          \"data-popup-open:before:bg-m3-tertiary data-popup-open:text-m3-on-tertiary\",\n      },\n    },\n    defaultVariants: { presentation: \"standard\" },\n  },\n)\n\nexport type DropdownMenuPresentation = \"standard\" | \"vibrant\"\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "overlays"
  ],
  "type": "registry:ui"
}