{
  "$schema": "https://blode.co/ui/schema/registry-item.json",
  "name": "combobox",
  "title": "Combobox",
  "author": "Matthew Blode",
  "description": "An autocomplete input that combines a text field with a filterable dropdown list.",
  "dependencies": ["@base-ui/react", "blode-icons-react"],
  "registryDependencies": ["button", "input-group"],
  "files": [
    {
      "path": "ui/combobox.tsx",
      "content": "\"use client\";\n\nimport { Combobox as ComboboxPrimitive } from \"@base-ui/react\";\nimport { CheckIcon, ChevronDownIcon, CrossSmallIcon, XIcon } from \"blode-icons-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n} from \"@/components/ui/input-group\";\n\nconst Combobox = ComboboxPrimitive.Root;\n\nconst ComboboxValue = ({ ...props }: ComboboxPrimitive.Value.Props) => (\n  <ComboboxPrimitive.Value data-slot=\"combobox-value\" {...props} />\n);\n\nconst ComboboxTrigger = ({\n  className,\n  children,\n  render,\n  ...props\n}: ComboboxPrimitive.Trigger.Props) => (\n  <ComboboxPrimitive.Trigger\n    className={cn(\"[&_svg:not([class*='size-'])]:size-4\", className)}\n    data-slot=\"combobox-trigger\"\n    render={\n      render ?? <InputGroupButton data-slot=\"input-group-button\" size=\"icon-xs\" variant=\"ghost\" />\n    }\n    {...props}\n  >\n    {children}\n    <ChevronDownIcon className=\"pointer-events-none size-4 text-muted-foreground\" />\n  </ComboboxPrimitive.Trigger>\n);\n\nconst ComboboxClear = ({ className, ...props }: ComboboxPrimitive.Clear.Props) => (\n  <ComboboxPrimitive.Clear\n    className={cn(className)}\n    data-slot=\"combobox-clear\"\n    render={<InputGroupButton size=\"icon-xs\" variant=\"ghost\" />}\n    {...props}\n  >\n    <XIcon className=\"pointer-events-none\" />\n  </ComboboxPrimitive.Clear>\n);\n\nconst ComboboxInput = ({\n  className,\n  children,\n  disabled = false,\n  showTrigger = true,\n  showClear = false,\n  ...props\n}: ComboboxPrimitive.Input.Props & {\n  showTrigger?: boolean;\n  showClear?: boolean;\n}) => (\n  <InputGroup\n    className={cn(\"h-[var(--field-height)] w-auto rounded-[var(--field-radius)]\", className)}\n  >\n    <ComboboxPrimitive.Input render={<InputGroupInput disabled={disabled} />} {...props} />\n    <InputGroupAddon align=\"inline-end\">\n      {showTrigger && (\n        <ComboboxTrigger\n          className=\"group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent\"\n          disabled={disabled}\n        />\n      )}\n      {showClear && <ComboboxClear disabled={disabled} />}\n    </InputGroupAddon>\n    {children}\n  </InputGroup>\n);\n\nconst ComboboxContent = ({\n  className,\n  side = \"bottom\",\n  sideOffset = 6,\n  align = \"start\",\n  alignOffset = 0,\n  anchor,\n  ...props\n}: ComboboxPrimitive.Popup.Props &\n  Pick<\n    ComboboxPrimitive.Positioner.Props,\n    \"side\" | \"align\" | \"sideOffset\" | \"alignOffset\" | \"anchor\"\n  >) => (\n  <ComboboxPrimitive.Portal>\n    <ComboboxPrimitive.Positioner\n      align={align}\n      alignOffset={alignOffset}\n      anchor={anchor}\n      className=\"isolate z-50\"\n      side={side}\n      sideOffset={sideOffset}\n    >\n      <ComboboxPrimitive.Popup\n        className={cn(\n          \"data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 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-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 cn-menu-target group/combobox-content relative max-h-(--available-height) w-(--anchor-width) min-w-[calc(var(--anchor-width)+--spacing(7))] max-w-(--available-width) origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) data-closed:animate-out data-open:animate-in *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none\",\n          className,\n        )}\n        data-chips={!!anchor}\n        data-slot=\"combobox-content\"\n        {...props}\n      />\n    </ComboboxPrimitive.Positioner>\n  </ComboboxPrimitive.Portal>\n);\n\nconst ComboboxList = ({ className, ...props }: ComboboxPrimitive.List.Props) => (\n  <ComboboxPrimitive.List\n    className={cn(\n      \"no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0\",\n      className,\n    )}\n    data-slot=\"combobox-list\"\n    {...props}\n  />\n);\n\nconst ComboboxItem = ({ className, children, ...props }: ComboboxPrimitive.Item.Props) => (\n  <ComboboxPrimitive.Item\n    className={cn(\n      \"relative flex w-full cursor-default select-none items-center gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-50 not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n      className,\n    )}\n    data-slot=\"combobox-item\"\n    {...props}\n  >\n    {children}\n    <ComboboxPrimitive.ItemIndicator\n      render={\n        <span className=\"pointer-events-none absolute right-2 flex size-4 items-center justify-center\" />\n      }\n    >\n      <CheckIcon className=\"pointer-events-none\" />\n    </ComboboxPrimitive.ItemIndicator>\n  </ComboboxPrimitive.Item>\n);\n\nconst ComboboxGroup = ({ className, ...props }: ComboboxPrimitive.Group.Props) => (\n  <ComboboxPrimitive.Group className={cn(className)} data-slot=\"combobox-group\" {...props} />\n);\n\nconst ComboboxLabel = ({ className, ...props }: ComboboxPrimitive.GroupLabel.Props) => (\n  <ComboboxPrimitive.GroupLabel\n    className={cn(\"px-2 py-1.5 text-muted-foreground text-xs\", className)}\n    data-slot=\"combobox-label\"\n    {...props}\n  />\n);\n\nconst ComboboxCollection = ({ ...props }: ComboboxPrimitive.Collection.Props) => (\n  <ComboboxPrimitive.Collection data-slot=\"combobox-collection\" {...props} />\n);\n\nconst ComboboxEmpty = ({ className, ...props }: ComboboxPrimitive.Empty.Props) => (\n  <ComboboxPrimitive.Empty\n    className={cn(\n      \"hidden w-full justify-center py-2 text-center text-muted-foreground text-sm group-data-empty/combobox-content:flex\",\n      className,\n    )}\n    data-slot=\"combobox-empty\"\n    {...props}\n  />\n);\n\nconst ComboboxSeparator = ({ className, ...props }: ComboboxPrimitive.Separator.Props) => (\n  <ComboboxPrimitive.Separator\n    className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n    data-slot=\"combobox-separator\"\n    {...props}\n  />\n);\n\nconst ComboboxChips = ({ className, ...props }: ComboboxPrimitive.Chips.Props) => (\n  <ComboboxPrimitive.Chips\n    className={cn(\n      \"flex min-h-8 flex-wrap items-center gap-1 rounded-lg border border-input bg-transparent bg-clip-padding px-2.5 py-1 text-sm transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 has-aria-invalid:border-destructive has-data-[slot=combobox-chip]:px-1 has-aria-invalid:ring-3 has-aria-invalid:ring-destructive/20 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40\",\n      className,\n    )}\n    data-slot=\"combobox-chips\"\n    {...props}\n  />\n);\n\nconst ComboboxChip = ({\n  className,\n  children,\n  showRemove = true,\n  ...props\n}: ComboboxPrimitive.Chip.Props & {\n  showRemove?: boolean;\n}) => (\n  <ComboboxPrimitive.Chip\n    className={cn(\n      \"flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 whitespace-nowrap rounded-sm bg-muted px-1.5 font-medium text-foreground text-xs has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-data-[slot=combobox-chip-remove]:pr-0 has-disabled:opacity-50\",\n      className,\n    )}\n    data-slot=\"combobox-chip\"\n    {...props}\n  >\n    {children}\n    {showRemove && (\n      <ComboboxPrimitive.ChipRemove\n        className=\"-ml-1 opacity-50 hover:opacity-100\"\n        data-slot=\"combobox-chip-remove\"\n        render={<Button size=\"icon-xs\" variant=\"ghost\" />}\n      >\n        <CrossSmallIcon className=\"pointer-events-none\" />\n      </ComboboxPrimitive.ChipRemove>\n    )}\n  </ComboboxPrimitive.Chip>\n);\n\nconst ComboboxChipsInput = ({ className, ...props }: ComboboxPrimitive.Input.Props) => (\n  <ComboboxPrimitive.Input\n    className={cn(\"min-w-16 flex-1 outline-none\", className)}\n    data-slot=\"combobox-chip-input\"\n    {...props}\n  />\n);\n\nconst useComboboxAnchor = () => React.useRef<HTMLDivElement | null>(null);\n\nexport {\n  Combobox,\n  ComboboxInput,\n  ComboboxContent,\n  ComboboxList,\n  ComboboxItem,\n  ComboboxGroup,\n  ComboboxLabel,\n  ComboboxCollection,\n  ComboboxEmpty,\n  ComboboxSeparator,\n  ComboboxChips,\n  ComboboxChip,\n  ComboboxChipsInput,\n  ComboboxTrigger,\n  ComboboxValue,\n  useComboboxAnchor,\n};\n",
      "type": "registry:ui",
      "target": ""
    }
  ],
  "type": "registry:ui"
}
