{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "search-bar",
  "title": "Search Bar",
  "description": "Controlled search input with submit-on-Enter, a clear button, and an optional image-search trigger.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "input"
  ],
  "files": [
    {
      "path": "registry/default/components/search-bar.tsx",
      "content": "import * as React from \"react\";\nimport { ImageIcon, Search, X } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\n\nexport interface SearchBarProps extends Omit<React.ComponentProps<\"form\">, \"onSubmit\"> {\n  value: string;\n  onValueChange: (value: string) => void;\n  onSubmit?: (value: string) => void;\n  placeholder?: string;\n  /**\n   * Enable image search. When set, a button lets the shopper pick an image file;\n   * the chosen `File` is emitted here for you to read/encode and pass to\n   * `client.products.searchByImage`.\n   */\n  onImageSelected?: (file: File) => void;\n  loading?: boolean;\n}\n\nexport function SearchBar({\n  value,\n  onValueChange,\n  onSubmit,\n  placeholder = \"Search products\",\n  onImageSelected,\n  loading = false,\n  className,\n  ...props\n}: SearchBarProps) {\n  const fileInput = React.useRef<HTMLInputElement>(null);\n\n  const handleSubmit = (event: React.FormEvent) => {\n    event.preventDefault();\n    onSubmit?.(value);\n  };\n\n  const handleFile = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (file) {\n      onImageSelected?.(file);\n    }\n    event.target.value = \"\";\n  };\n\n  return (\n    <form\n      role=\"search\"\n      data-slot=\"search-bar\"\n      onSubmit={handleSubmit}\n      className={cn(\"relative flex items-center gap-2\", className)}\n      {...props}\n    >\n      <div className=\"relative flex-1\">\n        <Search\n          aria-hidden\n          className=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n        />\n        <Input\n          type=\"search\"\n          value={value}\n          onChange={(event) => onValueChange(event.target.value)}\n          placeholder={placeholder}\n          aria-busy={loading}\n          className=\"h-10 pr-9 pl-9 [&::-webkit-search-cancel-button]:appearance-none\"\n        />\n        {value ? (\n          <button\n            type=\"button\"\n            onClick={() => onValueChange(\"\")}\n            aria-label=\"Clear search\"\n            className=\"absolute top-1/2 right-2 flex size-6 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n          >\n            <X className=\"size-4\" />\n          </button>\n        ) : null}\n      </div>\n\n      {onImageSelected ? (\n        <>\n          <input\n            ref={fileInput}\n            type=\"file\"\n            accept=\"image/*\"\n            onChange={handleFile}\n            className=\"hidden\"\n          />\n          <Button\n            type=\"button\"\n            variant=\"outline\"\n            size=\"icon\"\n            className=\"size-10 shrink-0\"\n            aria-label=\"Search by image\"\n            onClick={() => fileInput.current?.click()}\n          >\n            <ImageIcon className=\"size-4\" />\n          </Button>\n        </>\n      ) : null}\n    </form>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}