{
  "$schema": "https://ethereal-ui.saefulrohman.dev/schema/registry-item.json",
  "name": "combobox",
  "title": "Combobox",
  "type": "registry:primitives",
  "description": "Searchable dropdown selector with instant filtering, checkmarks, and optional right-aligned metadata badges.",
  "dependencies": [
    "@radix-ui/react-popover",
    "lucide-react"
  ],
  "usage": "import * as React from \"react\"\nimport { Combobox } from \"@etherealui/react\"\n\nexport function ComboboxDemo() {\n  const [value, setValue] = React.useState(\"us-east\")\n  return (\n    <Combobox\n      className=\"w-64\"\n      value={value}\n      onValueChange={setValue}\n      options={[\n        { value: \"us-east\", label: \"US East (N. Virginia)\", badge: \"Primary\" },\n        { value: \"eu-central\", label: \"EU Central (Frankfurt)\", badge: \"EU\" },\n        { value: \"ap-south\", label: \"Asia Pacific (Singapore)\", badge: \"APAC\" },\n      ]}\n    />\n  )\n}",
  "files": [
    {
      "path": "packages/ui/src/primitives/select.tsx",
      "target": "components/ui/combobox.tsx",
      "type": "registry:primitives",
      "content": "import * as React from \"react\"\nimport * as SelectPrimitive from \"@radix-ui/react-select\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { Check, ChevronDown, Search, ChevronsUpDown } from \"lucide-react\"\nimport { cn } from \"../utils/cn\"\n\nconst Select = SelectPrimitive.Root\nconst SelectGroup = SelectPrimitive.Group\nconst SelectValue = SelectPrimitive.Value\n\nconst SelectTrigger = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Trigger>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n  <SelectPrimitive.Trigger\n    ref={ref}\n    className={cn(\n      \"flex h-9 w-full items-center justify-between gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2 text-xs text-zinc-900 placeholder:text-zinc-400 transition-colors hover:bg-zinc-50 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:opacity-50 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100 dark:hover:bg-zinc-800/60 [&>span]:line-clamp-1 cursor-pointer\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n    <SelectPrimitive.Icon asChild>\n      <ChevronDown className=\"h-3.5 w-3.5 text-zinc-400 shrink-0\" />\n    </SelectPrimitive.Icon>\n  </SelectPrimitive.Trigger>\n))\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\nconst SelectContent = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n  <SelectPrimitive.Portal>\n    <SelectPrimitive.Content\n      ref={ref}\n      className={cn(\n        \"relative z-50 max-h-72 min-w-[8rem] overflow-hidden rounded-xl border border-zinc-200 bg-white text-zinc-900 shadow-lg dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100\",\n        position === \"popper\" &&\n          \"data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1\",\n        className\n      )}\n      position={position}\n      {...props}\n    >\n      <SelectPrimitive.Viewport\n        className={cn(\n          \"p-1\",\n          position === \"popper\" &&\n            \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\"\n        )}\n      >\n        {children}\n      </SelectPrimitive.Viewport>\n    </SelectPrimitive.Content>\n  </SelectPrimitive.Portal>\n))\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\nconst SelectItem = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Item>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n  <SelectPrimitive.Item\n    ref={ref}\n    className={cn(\n      \"relative flex w-full cursor-pointer select-none items-center rounded-lg py-1.5 pl-8 pr-2.5 text-xs text-zinc-700 outline-none transition-colors focus:bg-zinc-100 focus:text-zinc-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:text-zinc-200 dark:focus:bg-zinc-800 dark:focus:text-white\",\n      className\n    )}\n    {...props}\n  >\n    <span className=\"absolute left-2.5 flex h-3.5 w-3.5 items-center justify-center\">\n      <SelectPrimitive.ItemIndicator>\n        <Check className=\"h-3.5 w-3.5 text-blue-600 dark:text-blue-400\" />\n      </SelectPrimitive.ItemIndicator>\n    </span>\n    <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n  </SelectPrimitive.Item>\n))\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\nexport interface ComboboxOption {\n  value: string\n  label: string\n  badge?: string\n}\n\nexport interface ComboboxProps {\n  options: ComboboxOption[]\n  value: string\n  onValueChange: (value: string) => void\n  placeholder?: string\n  searchPlaceholder?: string\n  className?: string\n}\n\nconst Combobox: React.FC<ComboboxProps> = ({\n  options,\n  value,\n  onValueChange,\n  placeholder = \"Select option...\",\n  searchPlaceholder = \"Search...\",\n  className,\n}) => {\n  const [open, setOpen] = React.useState(false)\n  const [query, setQuery] = React.useState(\"\")\n\n  const selected = options.find((o) => o.value === value)\n  const filtered = React.useMemo(() => {\n    if (!query.trim()) return options\n    return options.filter((o) =>\n      o.label.toLowerCase().includes(query.toLowerCase())\n    )\n  }, [options, query])\n\n  return (\n    <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n      <PopoverPrimitive.Trigger asChild>\n        <button\n          type=\"button\"\n          className={cn(\n            \"flex h-9 w-full items-center justify-between gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2 text-xs text-zinc-900 transition-colors hover:bg-zinc-50 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100 dark:hover:bg-zinc-800/60 cursor-pointer\",\n            className\n          )}\n        >\n          <span className={cn(\"truncate\", !selected && \"text-zinc-400\")}>\n            {selected ? selected.label : placeholder}\n          </span>\n          <ChevronsUpDown className=\"h-3.5 w-3.5 text-zinc-400 shrink-0\" />\n        </button>\n      </PopoverPrimitive.Trigger>\n      <PopoverPrimitive.Portal>\n        <PopoverPrimitive.Content\n          align=\"start\"\n          sideOffset={6}\n          className=\"z-50 w-64 rounded-xl border border-zinc-200 bg-white p-1.5 text-zinc-900 shadow-lg focus:outline-none dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-100\"\n        >\n          <div className=\"flex items-center gap-2 border-b border-zinc-200 px-2.5 py-1.5 dark:border-zinc-800\">\n            <Search className=\"h-3.5 w-3.5 text-zinc-400\" />\n            <input\n              type=\"text\"\n              value={query}\n              onChange={(e) => setQuery(e.target.value)}\n              placeholder={searchPlaceholder}\n              className=\"w-full bg-transparent text-xs text-zinc-900 placeholder:text-zinc-400 focus:outline-none dark:text-zinc-100\"\n            />\n          </div>\n          <div className=\"mt-1 max-h-52 overflow-y-auto space-y-0.5\">\n            {filtered.length === 0 ? (\n              <div className=\"py-4 text-center text-xs text-zinc-400\">\n                No matching items found.\n              </div>\n            ) : (\n              filtered.map((opt) => {\n                const isSelected = opt.value === value\n                return (\n                  <button\n                    key={opt.value}\n                    type=\"button\"\n                    onClick={() => {\n                      onValueChange(opt.value)\n                      setOpen(false)\n                      setQuery(\"\")\n                    }}\n                    className={cn(\n                      \"flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-xs transition-colors cursor-pointer\",\n                      isSelected\n                        ? \"bg-blue-50 text-blue-700 dark:bg-blue-500/15 dark:text-blue-300\"\n                        : \"text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800\"\n                    )}\n                  >\n                    <span className=\"flex items-center gap-2\">\n                      <Check\n                        className={cn(\n                          \"h-3.5 w-3.5\",\n                          isSelected ? \"opacity-100 text-blue-600 dark:text-blue-400\" : \"opacity-0\"\n                        )}\n                      />\n                      {opt.label}\n                    </span>\n                    {opt.badge && (\n                      <span className=\"rounded bg-zinc-100 px-1.5 py-0.5 font-mono text-[10px] text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400\">\n                        {opt.badge}\n                      </span>\n                    )}\n                  </button>\n                )\n              })\n            )}\n          </div>\n        </PopoverPrimitive.Content>\n      </PopoverPrimitive.Portal>\n    </PopoverPrimitive.Root>\n  )\n}\nCombobox.displayName = \"Combobox\"\n\nexport {\n  Select,\n  SelectGroup,\n  SelectValue,\n  SelectTrigger,\n  SelectContent,\n  SelectItem,\n  Combobox,\n}\n"
    }
  ]
}