{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "combobox",
  "title": "Combobox",
  "description": "A text input with a filterable list, for choosing from more options than a select can comfortably show.",
  "dependencies": [
    "@base-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://www.prfct.dev/r/utils.json",
    "https://www.prfct.dev/r/button.json",
    "https://www.prfct.dev/r/input-group.json",
    "https://www.prfct.dev/r/locale.json"
  ],
  "files": [
    {
      "path": "components/ui/combobox.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Combobox as ComboboxPrimitive } from \"@base-ui/react\"\nimport { cn } from \"@/lib/utils\"\nimport { CheckIcon, ChevronsUpDownIcon, XIcon } from \"lucide-react\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n} from \"@/components/ui/input-group\"\nimport { useLocale } from \"@/components/ui/locale\"\n\n/**\n * The element the list lines up with. By default Base UI anchors to the bare\n * `<input>`; prfct anchors to the whole input group so the list matches the\n * field's visible edges, including its buttons.\n */\nconst ComboboxAnchorContext =\n  React.createContext<React.RefObject<HTMLDivElement | null> | null>(null)\n\n/** True inside the popup: an input there must not anchor its own popup. */\nconst ComboboxPopupContext = React.createContext(false)\n\nfunction Combobox<\n  Value,\n  Multiple extends boolean | undefined = false,\n  Item = Value,\n>(props: ComboboxPrimitive.Root.Props<Value, Multiple, Item>) {\n  const anchorRef = React.useRef<HTMLDivElement | null>(null)\n  return (\n    <ComboboxAnchorContext.Provider value={anchorRef}>\n      <ComboboxPrimitive.Root {...props} />\n    </ComboboxAnchorContext.Provider>\n  )\n}\n\nfunction ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {\n  return <ComboboxPrimitive.Value data-slot=\"combobox-value\" {...props} />\n}\n\nfunction ComboboxTrigger({\n  className,\n  children,\n  ...props\n}: ComboboxPrimitive.Trigger.Props) {\n  return (\n    <ComboboxPrimitive.Trigger\n      data-slot=\"combobox-trigger\"\n      className={cn(\"[&_svg:not([class*='size-'])]:size-4\", className)}\n      {...props}\n    >\n      {children}\n      <ChevronsUpDownIcon className=\"pointer-events-none size-3.5! text-muted-foreground\" />\n    </ComboboxPrimitive.Trigger>\n  )\n}\n\nfunction ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {\n  const { messages } = useLocale()\n  return (\n    <ComboboxPrimitive.Clear\n      data-slot=\"combobox-clear\"\n      render={<InputGroupButton variant=\"ghost\" size=\"icon-xs\" />}\n      className={cn(\"text-muted-foreground hover:text-foreground\", className)}\n      {...props}\n    >\n      <XIcon className=\"pointer-events-none\" />\n      <span className=\"sr-only\">{messages.clear}</span>\n    </ComboboxPrimitive.Clear>\n  )\n}\n\nfunction 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  const anchorRef = React.useContext(ComboboxAnchorContext)\n  const insidePopup = React.useContext(ComboboxPopupContext)\n  const { messages } = useLocale()\n\n  return (\n    <InputGroup\n      ref={insidePopup ? undefined : anchorRef}\n      className={cn(\"w-auto\", className)}\n    >\n      <ComboboxPrimitive.Input\n        render={<InputGroupInput disabled={disabled} />}\n        {...props}\n      />\n      <InputGroupAddon align=\"inline-end\">\n        {showTrigger && (\n          <InputGroupButton\n            size=\"icon-xs\"\n            variant=\"ghost\"\n            aria-label={messages.toggleOptions}\n            render={<ComboboxTrigger />}\n            data-slot=\"input-group-button\"\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}\n\nfunction ComboboxContent({\n  className,\n  side = \"bottom\",\n  sideOffset = 6,\n  align = \"start\",\n  alignOffset = 0,\n  anchor,\n  children,\n  ...props\n}: ComboboxPrimitive.Popup.Props &\n  Pick<\n    ComboboxPrimitive.Positioner.Props,\n    \"side\" | \"align\" | \"sideOffset\" | \"alignOffset\" | \"anchor\"\n  >) {\n  const fieldAnchor = React.useContext(ComboboxAnchorContext)\n\n  return (\n    <ComboboxPrimitive.Portal>\n      <ComboboxPrimitive.Positioner\n        side={side}\n        sideOffset={sideOffset}\n        align={align}\n        alignOffset={alignOffset}\n        anchor={anchor ?? fieldAnchor ?? undefined}\n        className=\"isolate z-popover\"\n      >\n        <ComboboxPrimitive.Popup\n          data-slot=\"combobox-content\"\n          data-chips={!!anchor}\n          className={cn(\n            \"group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[max(var(--anchor-width),12rem)] popup-motion overflow-hidden rounded-xl bg-popover text-popover-foreground shadow-floating ring-1 ring-edge\",\n            \"data-[chips=true]:min-w-(--anchor-width)\",\n            \"*:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:w-auto *:data-[slot=input-group]:bg-surface *:data-[slot=input-group]:shadow-none\",\n            className\n          )}\n          {...props}\n        >\n          <ComboboxPopupContext.Provider value={true}>\n            {children}\n          </ComboboxPopupContext.Provider>\n        </ComboboxPrimitive.Popup>\n      </ComboboxPrimitive.Positioner>\n    </ComboboxPrimitive.Portal>\n  )\n}\n\nfunction ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {\n  return (\n    <ComboboxPrimitive.List\n      data-slot=\"combobox-list\"\n      className={cn(\n        \"max-h-[min(18rem,calc(var(--available-height)-2.25rem))] scroll-py-1 scrollbar-thin overflow-y-auto overscroll-contain p-1 data-empty:p-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxItem({\n  className,\n  children,\n  ...props\n}: ComboboxPrimitive.Item.Props) {\n  return (\n    <ComboboxPrimitive.Item\n      data-slot=\"combobox-item\"\n      className={cn(\n        \"relative flex min-h-8 w-full cursor-default items-center gap-2 rounded-lg py-1.5 pr-8 pl-2 text-sm text-foreground outline-hidden select-none\",\n        \"data-highlighted:bg-accent data-highlighted:text-accent-foreground\",\n        \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n        \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n        className\n      )}\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 text-foreground!\" />\n      </ComboboxPrimitive.ItemIndicator>\n    </ComboboxPrimitive.Item>\n  )\n}\n\nfunction ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {\n  return (\n    <ComboboxPrimitive.Group\n      data-slot=\"combobox-group\"\n      className={cn(className)}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxLabel({\n  className,\n  ...props\n}: ComboboxPrimitive.GroupLabel.Props) {\n  return (\n    <ComboboxPrimitive.GroupLabel\n      data-slot=\"combobox-label\"\n      className={cn(\n        \"px-2 pt-2 pb-1 text-xs font-medium text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {\n  return (\n    <ComboboxPrimitive.Collection data-slot=\"combobox-collection\" {...props} />\n  )\n}\n\nfunction ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {\n  return (\n    <ComboboxPrimitive.Empty\n      data-slot=\"combobox-empty\"\n      className={cn(\n        \"hidden w-full justify-center py-6 text-center text-sm text-muted-foreground group-data-empty/combobox-content:flex\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxSeparator({\n  className,\n  ...props\n}: ComboboxPrimitive.Separator.Props) {\n  return (\n    <ComboboxPrimitive.Separator\n      data-slot=\"combobox-separator\"\n      className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxChips({\n  className,\n  ...props\n}: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &\n  ComboboxPrimitive.Chips.Props) {\n  return (\n    <ComboboxPrimitive.Chips\n      data-slot=\"combobox-chips\"\n      className={cn(\n        \"flex min-h-9 flex-wrap items-center gap-1 rounded-lg border border-input bg-field px-3 py-1 text-sm shadow-xs\",\n        \"transition-[border-color,box-shadow] duration-fast ease-standard hover:border-gray-10\",\n        \"focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/20\",\n        \"has-aria-invalid:border-danger-9 has-aria-invalid:focus-within:ring-danger-9/20\",\n        \"has-data-[slot=combobox-chip]:px-1\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxChip({\n  className,\n  children,\n  showRemove = true,\n  removeLabel,\n  ...props\n}: ComboboxPrimitive.Chip.Props & {\n  showRemove?: boolean\n  /** Accessible name of the remove button. Defaults to \"Remove {children}\". */\n  removeLabel?: string\n}) {\n  const { messages } = useLocale()\n  return (\n    <ComboboxPrimitive.Chip\n      data-slot=\"combobox-chip\"\n      className={cn(\n        \"flex h-6 w-fit items-center justify-center gap-1 rounded-md bg-secondary px-2 text-xs font-medium whitespace-nowrap text-secondary-foreground\",\n        \"has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0.5\",\n        \"data-highlighted:bg-gray-5\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      {showRemove && (\n        <ComboboxPrimitive.ChipRemove\n          aria-label={\n            removeLabel ??\n            (typeof children === \"string\"\n              ? messages.removeItem.replace(\"{item}\", children)\n              : messages.remove)\n          }\n          render={<Button variant=\"ghost\" size=\"icon-xs\" />}\n          className=\"size-5 rounded-sm text-muted-foreground hover:bg-gray-5 hover:text-foreground [&_svg]:size-3!\"\n          data-slot=\"combobox-chip-remove\"\n        >\n          <XIcon className=\"pointer-events-none\" />\n        </ComboboxPrimitive.ChipRemove>\n      )}\n    </ComboboxPrimitive.Chip>\n  )\n}\n\nfunction ComboboxChipsInput({\n  className,\n  ...props\n}: ComboboxPrimitive.Input.Props) {\n  return (\n    <ComboboxPrimitive.Input\n      data-slot=\"combobox-chip-input\"\n      className={cn(\n        \"h-7 min-w-16 flex-1 bg-transparent px-1 outline-none placeholder:text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction useComboboxAnchor() {\n  return React.useRef<HTMLDivElement | null>(null)\n}\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"
    }
  ],
  "type": "registry:ui"
}