{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-menu",
  "title": "dropdown-menu",
  "dependencies": [
    "@radix-ui/react-dropdown-menu",
    "class-variance-authority@^0.7"
  ],
  "registryDependencies": [
    "@dwellir/dwellir-theme",
    "@dwellir/utils",
    "@dwellir/input-modality",
    "@dwellir/portal-container",
    "@dwellir/rune-icons"
  ],
  "files": [
    {
      "path": "components/ui/dropdown-menu.tsx",
      "content": "'use client';\n\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { type ComponentProps, createContext, useContext } from 'react';\nimport { RuneCheck, RuneChevronRight, RuneCircle } from '@/components/brand/rune-icons';\nimport { useInputModality } from '@/lib/input-modality';\nimport { PortalContainer, usePortalContainer } from '@/lib/portal-container';\nimport { cn } from '@/lib/utils';\n\nconst contentVariants = cva(\n  'ui-popup-motion z-popover max-h-(--radix-dropdown-menu-content-available-height) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto border border-border bg-popover text-popover-foreground data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',\n  {\n    variants: {\n      size: {\n        default: 'min-w-48 rounded-2xl p-2 shadow-popover',\n        /* A compact menu, as in an app's header: the chosen item is tinted and checked on the right. */\n        sm: 'min-w-32 rounded-sm p-1 shadow-popover',\n      },\n    },\n    defaultVariants: { size: 'default' },\n  },\n);\n\ntype Size = NonNullable<VariantProps<typeof contentVariants>['size']>;\n\nconst SizeContext = createContext<Size>('default');\n\nconst itemVariants = cva(\n  \"relative flex cursor-pointer items-center gap-2 text-sm outline-hidden select-none focus:bg-secondary in-data-[input=keyboard]:focus:outline-solid in-data-[input=keyboard]:focus:outline-2 in-data-[input=keyboard]:focus:-outline-offset-2 in-data-[input=keyboard]:focus:outline-ring data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n  {\n    variants: {\n      /* inset lines the text up with items that lead with an icon or a mark. */\n      size: {\n        default: 'rounded-lg px-3 py-2 data-[inset]:pl-9',\n        sm: 'rounded-sm px-2.5 py-2 data-[inset]:pl-8.5',\n      },\n    },\n    defaultVariants: { size: 'default' },\n  },\n);\n\n/* Checkbox and radio items: room for the mark, left by default, right in a compact menu. */\nconst choiceItemVariants = cva('', {\n  variants: {\n    size: {\n      default: 'pl-9',\n      sm: 'pr-9 data-[state=checked]:bg-accent data-[state=checked]:text-accent-foreground data-[state=checked]:focus:bg-accent',\n    },\n  },\n  defaultVariants: { size: 'default' },\n});\n\nconst indicatorVariants = cva(\n  'pointer-events-none absolute flex size-4 items-center justify-center text-accent-ink',\n  {\n    variants: { size: { default: 'left-3', sm: 'right-2.5' } },\n    defaultVariants: { size: 'default' },\n  },\n);\n\nfunction DropdownMenu(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n  return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuPortal(props: ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n  return <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />;\n}\n\nfunction DropdownMenuTrigger(props: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n  useInputModality();\n  return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuContent({\n  className,\n  size,\n  container,\n  sideOffset = 6,\n  collisionPadding = 12,\n  children,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Content> &\n  VariantProps<typeof contentVariants> &\n  /* The element to render into; else the PortalContainer landmark, else the page body. */\n  Pick<ComponentProps<typeof DropdownMenuPrimitive.Portal>, 'container'>) {\n  return (\n    <DropdownMenuPrimitive.Portal container={usePortalContainer(container)}>\n      <DropdownMenuPrimitive.Content\n        data-slot=\"dropdown-menu-content\"\n        data-size={size ?? 'default'}\n        sideOffset={sideOffset}\n        collisionPadding={collisionPadding}\n        className={cn(contentVariants({ size }), className)}\n        {...props}\n      >\n        <SizeContext.Provider value={size ?? 'default'}>\n          {/* A modal menu hides the page: popups opened inside go to the body. */}\n          <PortalContainer id={null}>{children}</PortalContainer>\n        </SizeContext.Provider>\n      </DropdownMenuPrimitive.Content>\n    </DropdownMenuPrimitive.Portal>\n  );\n}\n\nfunction DropdownMenuGroup(props: ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n  return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuItem({\n  className,\n  inset,\n  variant = 'default',\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n  inset?: boolean;\n  variant?: 'default' | 'destructive';\n}) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.Item\n      data-slot=\"dropdown-menu-item\"\n      data-inset={inset}\n      data-variant={variant}\n      className={cn(\n        itemVariants({ size }),\n        'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive-10 data-[variant=destructive]:focus:text-destructive in-data-[input=keyboard]:data-[variant=destructive]:focus:outline-destructive data-[variant=destructive]:*:[svg]:text-destructive!',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuCheckboxItem({\n  className,\n  children,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.CheckboxItem\n      data-slot=\"dropdown-menu-checkbox-item\"\n      className={cn(itemVariants({ size }), choiceItemVariants({ size }), className)}\n      {...props}\n    >\n      <span className={indicatorVariants({ size })}>\n        <DropdownMenuPrimitive.ItemIndicator>\n          <RuneCheck className=\"size-4 text-accent-ink\" />\n        </DropdownMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </DropdownMenuPrimitive.CheckboxItem>\n  );\n}\n\nfunction DropdownMenuRadioGroup(props: ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n  return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n  className,\n  children,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.RadioItem\n      data-slot=\"dropdown-menu-radio-item\"\n      className={cn(itemVariants({ size }), choiceItemVariants({ size }), className)}\n      {...props}\n    >\n      <span className={indicatorVariants({ size })}>\n        <DropdownMenuPrimitive.ItemIndicator>\n          {size === 'sm' ? (\n            <RuneCheck className=\"size-4 text-accent-ink\" />\n          ) : (\n            <RuneCircle className=\"size-2 fill-current text-accent-ink\" />\n          )}\n        </DropdownMenuPrimitive.ItemIndicator>\n      </span>\n      {children}\n    </DropdownMenuPrimitive.RadioItem>\n  );\n}\n\nconst labelVariants = cva('', {\n  variants: {\n    size: {\n      default: 'px-3 pt-2 pb-1 text-xs font-medium text-muted-foreground data-[inset]:pl-9',\n      /* A compact menu's label is a plain note. */\n      sm: 'px-2.5 pt-2 pb-1 text-xs leading-snug text-muted-foreground data-[inset]:pl-8.5',\n    },\n  },\n  defaultVariants: { size: 'default' },\n});\n\nfunction DropdownMenuLabel({\n  className,\n  inset,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.Label\n      data-slot=\"dropdown-menu-label\"\n      data-inset={inset}\n      className={cn(labelVariants({ size }), className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSeparator({\n  className,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.Separator\n      data-slot=\"dropdown-menu-separator\"\n      className={cn(size === 'sm' ? '-mx-1 my-1' : '-mx-2 my-2', 'h-px bg-border', className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: ComponentProps<'span'>) {\n  return (\n    <span\n      data-slot=\"dropdown-menu-shortcut\"\n      className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSub(props: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n  return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\n/* An item that opens a submenu: it stays tinted while the submenu is open. */\nfunction DropdownMenuSubTrigger({\n  className,\n  inset,\n  children,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.SubTrigger\n      data-slot=\"dropdown-menu-sub-trigger\"\n      data-inset={inset}\n      className={cn(itemVariants({ size }), 'data-[state=open]:bg-secondary', className)}\n      {...props}\n    >\n      {children}\n      <RuneChevronRight aria-hidden=\"true\" className=\"ml-auto size-4\" />\n    </DropdownMenuPrimitive.SubTrigger>\n  );\n}\n\n/*\n * The submenu takes the size of the menu it opens from. Its narrower minimum,\n * upstream's 8rem, and the cap at the room beside its menu keep it on a phone.\n */\nfunction DropdownMenuSubContent({\n  className,\n  collisionPadding = 12,\n  ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n  const size = useContext(SizeContext);\n  return (\n    <DropdownMenuPrimitive.SubContent\n      data-slot=\"dropdown-menu-sub-content\"\n      data-size={size}\n      collisionPadding={collisionPadding}\n      className={cn(\n        contentVariants({ size }),\n        'min-w-32 max-w-(--radix-dropdown-menu-content-available-width)',\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"
    }
  ],
  "type": "registry:ui"
}