{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-menu",
  "title": "Dropdown-menu",
  "description": "A dropdown-menu component.",
  "dependencies": [
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "registryDependencies": [
    "@cubby-ui/scroll-area",
    "@cubby-ui/switch",
    "@cubby-ui/elevated",
    "@cubby-ui/popup-search"
  ],
  "files": [
    {
      "path": "registry/default/dropdown-menu/dropdown-menu.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Menu as BaseMenu } from \"@base-ui/react/menu\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport {\n  Cancel01Icon,\n  CheckIcon,\n  ChevronRightIcon,\n  Search01Icon,\n} from \"@hugeicons/core-free-icons\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  solidSurface,\n  type SurfaceLevel,\n} from \"@/registry/default/lib/elevated\";\nimport {\n  POPUP_ITEM,\n  POPUP_SEARCH_CLEAR,\n  POPUP_SEARCH_FIELD,\n  POPUP_SEARCH_ICON,\n  POPUP_SEARCH_INPUT,\n  POPUP_SEARCH_MENU_FIELD,\n} from \"@/registry/default/lib/popup-search\";\nimport { ScrollArea } from \"@/registry/default/scroll-area/scroll-area\";\nimport {\n  SwitchVisual,\n  type SwitchVisualProps,\n} from \"@/registry/default/switch/switch\";\n\n// Shared shell for checkbox and radio items. Padding matches the plain menu\n// item so labels line up across every item type; the indicator lives in a\n// reserved right-hand column so toggling never shifts the label.\nconst toggleItemClasses = [\n  POPUP_ITEM,\n  \"group/switch data-highlighted:bg-surface-hover data-highlighted:text-accent-foreground grid cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-60 data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n];\n\n// The check draws itself in. `pathLength` restates the path as 1 unit\n// long, so the dash values are fractions of the stroke and survive a HugeIcons\n// reshape. Deriving the icon array is the only way to reach the path.\nconst checkIcon = CheckIcon.map(([tag, attrs]) => [\n  tag,\n  { ...attrs, pathLength: 1 },\n]) as typeof CheckIcon;\n\nconst checkmarkClasses =\n  \"[&_path]:ease-out-expo [&_path]:transition-[stroke-dashoffset] [&_path]:duration-150 [&_path]:[stroke-dasharray:1] in-data-checked:[&_path]:[stroke-dashoffset:0] in-data-unchecked:[&_path]:[stroke-dashoffset:1] motion-reduce:[&_path]:transition-none\" +\n  // Fully undrawn, the dash leaves a zero-length piece whose round cap shows\n  // as a dot on high-density screens. Fading the unchecked mark out hides it.\n  \" transition-opacity duration-150 ease-out in-data-unchecked:opacity-0 motion-reduce:transition-none\";\n\nfunction DropdownMenu<Payload = unknown>({\n  ...props\n}: BaseMenu.Root.Props<Payload>) {\n  return <BaseMenu.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuPortal({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Portal>) {\n  return <BaseMenu.Portal data-slot=\"dropdown-menu-portal\" {...props} />;\n}\n\nfunction DropdownMenuTrigger({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Trigger>) {\n  return <BaseMenu.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuPositioner({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Positioner>) {\n  return (\n    <BaseMenu.Positioner data-slot=\"dropdown-menu-positioner\" {...props} />\n  );\n}\n\nfunction DropdownMenuPopup({\n  className,\n  level = 3,\n  shadowLevel = 3,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Popup> & {\n  /** Surface elevation (1-8) for the popup bg. Bump inside a Dialog or other elevated container. Defaults to 3. */\n  level?: SurfaceLevel;\n  /** Shadow weight (1-8). Defaults to 3 so the menu looks the same at any nesting depth. */\n  shadowLevel?: SurfaceLevel;\n}) {\n  return (\n    <BaseMenu.Popup\n      data-slot=\"dropdown-menu-popup\"\n      data-level={level}\n      className={cn(\n        \"text-popover-foreground relative max-h-(--available-height) max-w-(--available-width) min-w-[12rem] overflow-hidden rounded-xl outline-none\",\n        solidSurface(level, shadowLevel),\n        \"origin-(--transform-origin) transition-[scale,opacity] duration-100 ease-(--ease-out-expo)\",\n        \"data-starting-style:scale-95 data-starting-style:opacity-0\",\n        \"data-ending-style:scale-95 data-ending-style:opacity-0\",\n        // Own compositor layer while mounted. The scale-in puts each row at a\n        // different sub-pixel offset, which reads as a ripple; promoted, the\n        // rows raster once.\n        \"will-change-transform\",\n        \"motion-reduce:transition-none motion-reduce:will-change-auto\",\n        // Only 'trigger-change'. Base UI waits on this transition to unmount, so\n        // suppressing 'dismiss' kills the exit, and 'click' is inferred from\n        // `event.detail === 0`, which every right-click matches.\n        \"data-[instant=trigger-change]:transition-none\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/**\n * Crossfades content when a detached trigger swaps what the menu shows. Its\n * presence also switches Base UI's positioner from `transform` to `top`/`left`\n * so the popup can grow from the right edge. Leave it out of menus that never\n * swap content.\n */\nfunction DropdownMenuViewport({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Viewport>) {\n  return (\n    <BaseMenu.Viewport\n      data-slot=\"dropdown-menu-viewport\"\n      className={cn(\n        // `h-full` and the cap both matter. At rest --popup-height is `auto`, so\n        // only the cap bounds the viewport and engages overflow-y. Mid-swap it is\n        // a transitioning px value that `h-full` tracks; without it the viewport\n        // snaps to the new content's height and clips the outgoing rows.\n        // No `max-w`: `w-full` inherits the popup's capped width.\n        \"relative h-full max-h-(--available-height) w-full overflow-clip p-1 [--viewport-padding:0.25rem]\",\n        // A column down to Base UI's content wrapper, so a filterable list shrinks\n        // to fit a short screen. Off during swaps: the animating height would\n        // collapse the new content's separators.\n        \"flex flex-col *:data-current:flex *:data-current:flex-col not-data-transitioning:*:data-current:min-h-0\",\n        \"not-data-transitioning:overflow-y-auto\",\n        // Content width only during a swap, so content doesn't re-flow as the popup\n        // morphs. Base UI pins --popup-width to the natural width during the\n        // entrance, which a popup width or dropped padding would contradict.\n        \"data-transitioning:**:data-current:w-[calc(var(--popup-width)-2*var(--viewport-padding))]\",\n        \"**:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-padding))]\",\n        // Non-directional crossfade, matching Popover: both halves recede to 0.96\n        // in place and the popup's size morph carries the movement.\n        \"**:data-current:scale-100 **:data-current:opacity-100\",\n        \"**:data-previous:scale-100 **:data-previous:opacity-100\",\n        \"**:data-current:transition-[scale,opacity] **:data-current:duration-150 **:data-current:ease-[cubic-bezier(0.22,1,0.36,1)]\",\n        \"**:data-previous:transition-[scale,opacity] **:data-previous:duration-150 **:data-previous:ease-[cubic-bezier(0.22,1,0.36,1)]\",\n        \"**:data-current:data-starting-style:scale-[0.96] **:data-current:data-starting-style:opacity-0\",\n        \"**:data-previous:data-ending-style:scale-[0.96] **:data-previous:data-ending-style:opacity-0\",\n        // Same guard as the popup's. Targets the content: the viewport has no\n        // transitions and transition-property doesn't inherit.\n        \"[[data-instant=trigger-change]_&_[data-current]]:transition-none [[data-instant=trigger-change]_&_[data-previous]]:transition-none\",\n        \"motion-reduce:**:data-current:transition-none motion-reduce:**:data-previous:transition-none\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuContent({\n  className,\n  positionerClassName,\n  viewportClassName,\n  children,\n  sideOffset = 4,\n  align = \"center\",\n  side = \"bottom\",\n  ...props\n}: React.ComponentProps<typeof DropdownMenuPopup> & {\n  /** Classes for the positioner (the element Base UI moves into place), merged last. */\n  positionerClassName?: string;\n  /** Classes for the padded box around the items, e.g. `p-0` for a filterable menu. */\n  viewportClassName?: string;\n  align?: BaseMenu.Positioner.Props[\"align\"];\n  sideOffset?: BaseMenu.Positioner.Props[\"sideOffset\"];\n  side?: BaseMenu.Positioner.Props[\"side\"];\n}) {\n  return (\n    <DropdownMenuPortal>\n      <DropdownMenuPositioner\n        className={cn(\n          \"z-50 h-(--positioner-height) max-h-(--available-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom,transform] duration-150 ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none motion-reduce:transition-none\",\n          positionerClassName,\n        )}\n        sideOffset={sideOffset}\n        align={align}\n        side={side}\n      >\n        <DropdownMenuPopup\n          data-slot=\"dropdown-menu-content\"\n          className={cn(\n            // Base UI derives --popup-width by measuring at `width:auto`, so two\n            // menus that both sit on this floor morph position and height but not\n            // width. That is the accepted trade: menus narrower than 12rem read\n            // as cramped, and width is the least visible of the three.\n            \"h-(--popup-height,auto) w-(--popup-width,auto)\",\n            \"transition-[width,height,scale,opacity] duration-[150ms,150ms,100ms,100ms] ease-[cubic-bezier(0.22,1,0.36,1),cubic-bezier(0.22,1,0.36,1),var(--ease-out-expo),var(--ease-out-expo)]\",\n            className,\n          )}\n          {...props}\n        >\n          <DropdownMenuViewport className={viewportClassName}>\n            {children}\n          </DropdownMenuViewport>\n        </DropdownMenuPopup>\n      </DropdownMenuPositioner>\n    </DropdownMenuPortal>\n  );\n}\n\nfunction DropdownMenuGroup({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Group>) {\n  return <BaseMenu.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuItem({\n  className,\n  inset,\n  variant = \"default\",\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Item> & {\n  inset?: boolean;\n  variant?: \"default\" | \"destructive\";\n}) {\n  return (\n    <BaseMenu.Item\n      data-slot=\"dropdown-menu-item\"\n      data-inset={inset || undefined}\n      data-variant={variant}\n      className={cn(\n        POPUP_ITEM,\n        \"data-highlighted:bg-surface-hover data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive-foreground data-[variant=destructive]:*:[svg]:text-destructive! data-highlighted:data-[variant=destructive]:*:[svg]:text-destructive-foreground! [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-60 data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuShortcut({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"dropdown-menu-shortcut\"\n      className={cn(\n        \"text-muted-foreground ml-auto text-xs tracking-widest\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Separator>) {\n  return (\n    <BaseMenu.Separator\n      data-slot=\"dropdown-menu-separator\"\n      // Inset to the item label, not the popup edge: mx-2.5 clears the\n      // viewport's p-1 plus the item's px-2.5, so the rule starts where the\n      // text does instead of running into the popup's rounded corners.\n      className={cn(\n        \"bg-border mx-2.5 my-1 h-px\",\n        // While filtering, Base UI hides emptied groups. Drop a rule that\n        // would follow one, or that has nothing left to separate below it.\n        \"[&:not(:has(~:not([hidden]):not([role=separator])))]:hidden [[hidden]+&]:hidden\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuLabel({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  inset?: boolean;\n}) {\n  return (\n    <div\n      data-slot=\"dropdown-menu-label\"\n      data-inset={inset || undefined}\n      className={cn(\n        \"px-2.5 py-1.5 text-xs font-medium data-inset:pl-8\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuGroupLabel({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.GroupLabel> & {\n  inset?: boolean;\n}) {\n  return (\n    <BaseMenu.GroupLabel\n      data-slot=\"dropdown-menu-group-label\"\n      data-inset={inset || undefined}\n      className={cn(\n        \"px-2.5 py-1.5 text-xs font-medium data-inset:pl-8\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuCheckboxItem({\n  className,\n  children,\n  checked,\n  inset,\n  indicator = \"check\",\n  switchColor = \"primary\",\n  switchShape = \"circle\",\n  switchSize = \"xs\",\n  switchMotion = \"default\",\n  ...props\n}: React.ComponentProps<typeof BaseMenu.CheckboxItem> & {\n  inset?: boolean;\n  /** Which indicator sits in the right-hand column. `\"switch\"` is visual only — the item keeps the `menuitemcheckbox` role. */\n  indicator?: \"check\" | \"switch\";\n  /** Checked track colour, when `indicator=\"switch\"`. */\n  switchColor?: SwitchVisualProps[\"color\"];\n  /** Thumb silhouette, when `indicator=\"switch\"`. */\n  switchShape?: SwitchVisualProps[\"shape\"];\n  /** Thumb size, when `indicator=\"switch\"`. Defaults to `xs`, which matches the row's text. */\n  switchSize?: SwitchVisualProps[\"size\"];\n  /** How the thumb travels, when `indicator=\"switch\"`. */\n  switchMotion?: SwitchVisualProps[\"motion\"];\n}) {\n  return (\n    <BaseMenu.CheckboxItem\n      data-slot=\"dropdown-menu-checkbox-item\"\n      data-inset={inset || undefined}\n      data-indicator={indicator}\n      className={cn(\n        toggleItemClasses,\n        indicator === \"switch\"\n          ? \"grid-cols-[1fr_auto] gap-3\"\n          : \"grid-cols-[1fr_1rem] gap-2\",\n        className,\n      )}\n      checked={checked}\n      {...props}\n    >\n      <span className=\"col-start-1 flex min-w-0 items-center gap-2\">\n        {children}\n      </span>\n      {indicator === \"switch\" ? (\n        // Visual only: the row carries the role and the click target, so a real\n        // Switch here would nest a focusable control inside a menuitemcheckbox.\n        // Base UI's indicator supplies the aria-hidden.\n        <SwitchVisual\n          color={switchColor}\n          shape={switchShape}\n          size={switchSize}\n          motion={switchMotion}\n          className=\"col-start-2\"\n          render={<BaseMenu.CheckboxItemIndicator keepMounted />}\n        />\n      ) : (\n        <BaseMenu.CheckboxItemIndicator\n          keepMounted\n          className=\"col-start-2 flex items-center justify-center\"\n        >\n          <HugeiconsIcon\n            icon={checkIcon}\n            strokeWidth={2.5}\n            className={cn(\"size-4\", checkmarkClasses)}\n          />\n        </BaseMenu.CheckboxItemIndicator>\n      )}\n    </BaseMenu.CheckboxItem>\n  );\n}\n\nfunction DropdownMenuRadioGroup({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.RadioGroup>) {\n  return (\n    <BaseMenu.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n  );\n}\n\nfunction DropdownMenuRadioItem({\n  className,\n  children,\n  inset,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.RadioItem> & {\n  inset?: boolean;\n}) {\n  return (\n    <BaseMenu.RadioItem\n      data-slot=\"dropdown-menu-radio-item\"\n      data-inset={inset || undefined}\n      className={cn(toggleItemClasses, \"grid-cols-[1fr_1rem] gap-2\", className)}\n      {...props}\n    >\n      <span className=\"col-start-1 flex min-w-0 items-center gap-2\">\n        {children}\n      </span>\n      <BaseMenu.RadioItemIndicator\n        keepMounted\n        className=\"col-start-2 flex items-center justify-center\"\n      >\n        <HugeiconsIcon\n          icon={checkIcon}\n          strokeWidth={2.5}\n          className={cn(\"size-4\", checkmarkClasses)}\n        />\n      </BaseMenu.RadioItemIndicator>\n    </BaseMenu.RadioItem>\n  );\n}\n\nfunction DropdownMenuLinkItem({\n  className,\n  inset,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.LinkItem> & {\n  inset?: boolean;\n}) {\n  return (\n    <BaseMenu.LinkItem\n      data-slot=\"dropdown-menu-link-item\"\n      data-inset={inset || undefined}\n      className={cn(\n        POPUP_ITEM,\n        \"data-highlighted:bg-surface-hover data-highlighted:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 no-underline outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-60 data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DropdownMenuSub({\n  ...props\n}: React.ComponentProps<typeof BaseMenu.SubmenuRoot>) {\n  return <BaseMenu.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n  className,\n  inset,\n  children,\n  delay = 0,\n  closeDelay = 0,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.SubmenuTrigger> & {\n  inset?: boolean;\n}) {\n  return (\n    <BaseMenu.SubmenuTrigger\n      data-slot=\"dropdown-menu-sub-trigger\"\n      data-inset={inset || undefined}\n      delay={delay}\n      closeDelay={closeDelay}\n      className={cn(\n        POPUP_ITEM,\n        \"data-highlighted:bg-surface-hover data-highlighted:text-accent-foreground data-popup-open:bg-surface-hover data-popup-open:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-60 data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <HugeiconsIcon\n        icon={ChevronRightIcon}\n        className=\"ml-auto size-4\"\n        strokeWidth={2}\n      />\n    </BaseMenu.SubmenuTrigger>\n  );\n}\n\nfunction DropdownMenuSubContent({\n  className,\n  positionerClassName,\n  viewportClassName,\n  children,\n  // 8px, not 0: the positioner anchors to the sub-trigger, which sits 4px\n  // inside the parent popup because of its p-1. A 0 offset therefore overlaps\n  // the parent's edge by 4px; 8 leaves a 4px gap, matching Menubar.\n  sideOffset = 8,\n  align = \"start\",\n  alignOffset,\n  level = 5,\n  shadowLevel = 3,\n  ...props\n}: React.ComponentProps<typeof BaseMenu.Popup> & {\n  /** Classes for the positioner (the element Base UI moves into place), merged last. */\n  positionerClassName?: string;\n  align?: BaseMenu.Positioner.Props[\"align\"];\n  alignOffset?: BaseMenu.Positioner.Props[\"alignOffset\"];\n  sideOffset?: BaseMenu.Positioner.Props[\"sideOffset\"];\n  /** Surface elevation level for the submenu bg (1-8). Defaults to 5 — one tier above the parent menu's default of 3. Bump higher when nesting inside a Dialog. */\n  level?: SurfaceLevel;\n  /** Shadow weight (1-8). Pinned to 3 by default so the submenu reads the same dropdown weight as its parent. */\n  shadowLevel?: SurfaceLevel;\n  /** Classes for the padded box around the items, e.g. `p-0` for a filterable menu. */\n  viewportClassName?: string;\n}) {\n  // Default alignOffset to -5 when align is not \"center\" to line up first item with trigger\n  const defaultAlignOffset = align !== \"center\" ? -4 : undefined;\n\n  return (\n    <DropdownMenuPortal>\n      {/* Base UI re-places a submenu a frame after its parent moves; the\n          parent's glide hides the lag. */}\n      <DropdownMenuPositioner\n        className={cn(\n          \"z-50 max-h-(--available-height) max-w-(--available-width) transition-[top,left,right,bottom,transform] duration-150 ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none motion-reduce:transition-none\",\n          positionerClassName,\n        )}\n        sideOffset={sideOffset}\n        align={align}\n        alignOffset={alignOffset ?? defaultAlignOffset}\n      >\n        <DropdownMenuPopup\n          data-slot=\"dropdown-menu-content\"\n          level={level}\n          shadowLevel={shadowLevel}\n          className={className}\n          {...props}\n        >\n          {/* The popup above is capped at --available-height and clips, so the\n            scroll container has to live here or a tall submenu silently\n            truncates. The main popups get this from Menu.Viewport; a\n            submenu has none, so it is spelled out. */}\n          <div\n            className={cn(\n              \"flex max-h-(--available-height) flex-col overflow-x-hidden overflow-y-auto p-1\",\n              viewportClassName,\n            )}\n          >\n            {children}\n          </div>\n        </DropdownMenuPopup>\n      </DropdownMenuPositioner>\n    </DropdownMenuPortal>\n  );\n}\n\n// Filtering (Base UI preview API). Wrap `DropdownMenu` or `DropdownMenuSub` in\n// the provider, then put a `DropdownMenuInput` above a `DropdownMenuList`.\nfunction DropdownMenuFilter({\n  autoHighlight = true,\n  ...props\n}: BaseMenu.FilterProvider.Props) {\n  // Highlight the top match while typing, so Enter runs it.\n  return <BaseMenu.FilterProvider autoHighlight={autoHighlight} {...props} />;\n}\n\nfunction DropdownMenuInput({\n  className,\n  inputClassName,\n  showClear = true,\n  clearLabel,\n  \"aria-label\": ariaLabel = \"Search\",\n  ...props\n}: BaseMenu.Input.Props & {\n  /** Class applied to the inner `<input>`. `className` styles the field. */\n  inputClassName?: string;\n  /** Show a clear button while the query has text. */\n  showClear?: boolean;\n  /** Accessible name of the clear button. Defaults to \"Clear search\". */\n  clearLabel?: string;\n}) {\n  return (\n    <div\n      data-slot=\"dropdown-menu-input-group\"\n      // Outside the list's scroll, as in Base UI's filter demo. An item's height\n      // (32px); the list's own padding forms the gap below it.\n      className={cn(POPUP_SEARCH_FIELD, POPUP_SEARCH_MENU_FIELD, className)}\n    >\n      <HugeiconsIcon\n        icon={Search01Icon}\n        strokeWidth={2}\n        className={POPUP_SEARCH_ICON}\n      />\n      <BaseMenu.Input\n        data-slot=\"dropdown-menu-input\"\n        className={cn(POPUP_SEARCH_INPUT, inputClassName)}\n        // The placeholder isn't a name; pass a specific label when you can.\n        aria-label={ariaLabel}\n        {...props}\n      />\n      {showClear && <DropdownMenuClear aria-label={clearLabel} />}\n    </div>\n  );\n}\n\nfunction DropdownMenuClear({\n  className,\n  children,\n  \"aria-label\": ariaLabel = \"Clear search\",\n  ...props\n}: BaseMenu.Clear.Props) {\n  return (\n    <BaseMenu.Clear\n      data-slot=\"dropdown-menu-clear\"\n      aria-label={ariaLabel}\n      className={cn(POPUP_SEARCH_CLEAR, className)}\n      {...props}\n    >\n      {children ?? (\n        <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-4\" />\n      )}\n    </BaseMenu.Clear>\n  );\n}\n\nfunction DropdownMenuList({\n  className,\n  ...props\n}: Omit<BaseMenu.List.Props, \"className\"> & {\n  /** Styles the scroll area around the list, e.g. to change its height cap. */\n  className?: string;\n}) {\n  return (\n    // Scrolls on its own so the field stays put. Padding sits inside the scroll so\n    // rows reach the popup's edges. Capped at 20rem; shrinks as a flex item to\n    // fit a short screen, as Combobox's and Select's lists do.\n    <ScrollArea fadeEdges=\"y\" className={cn(\"max-h-80\", className)}>\n      <BaseMenu.List\n        data-slot=\"dropdown-menu-list\"\n        className=\"p-1\"\n        {...props}\n      />\n    </ScrollArea>\n  );\n}\n\nfunction DropdownMenuEmpty({ className, ...props }: BaseMenu.Empty.Props) {\n  return (\n    <BaseMenu.Empty\n      data-slot=\"dropdown-menu-empty\"\n      // Lines up with the item labels. The list's 8px padding still renders below,\n      // so it sits 10px from the field and the bottom.\n      className={cn(\n        \"text-muted-foreground shrink-0 px-3.5 pt-2.5 pb-0.5 text-sm\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nconst useDropdownMenuFilter = BaseMenu.useFilter;\n\nconst createDropdownMenuHandle = BaseMenu.createHandle;\n\nexport {\n  DropdownMenu,\n  DropdownMenuPortal,\n  DropdownMenuTrigger,\n  DropdownMenuPositioner,\n  DropdownMenuPopup,\n  DropdownMenuViewport,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuLabel,\n  DropdownMenuGroupLabel,\n  DropdownMenuItem,\n  DropdownMenuLinkItem,\n  DropdownMenuCheckboxItem,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuSub,\n  DropdownMenuSubTrigger,\n  DropdownMenuSubContent,\n  DropdownMenuFilter,\n  DropdownMenuInput,\n  DropdownMenuClear,\n  DropdownMenuList,\n  DropdownMenuEmpty,\n  useDropdownMenuFilter,\n  createDropdownMenuHandle,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/dropdown-menu.tsx"
    }
  ],
  "type": "registry:ui"
}