{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "search-bar",
  "type": "registry:block",
  "title": "Search Bar",
  "description": "A reusable search component with autocomplete functionality and keyboard navigation.",
  "files": [
    {
      "path": "src/components/deso/search-bar.tsx",
      "content": "'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { Input } from '@/components/ui/input';\nimport { Button } from '@/components/ui/button';\nimport { Search, X, Loader2 } from 'lucide-react';\nimport { cn } from '@/lib/utils/deso';\n\nexport interface SearchBarAutocompleteItem {\n  id: string;\n  label: string;\n  value: string;\n  data?: any;\n}\n\nexport interface SearchBarProps {\n  placeholder?: string;\n  value?: string;\n  onChange?: (value: string) => void;\n  onSearch?: (value: string) => void;\n  onClear?: () => void;\n  onFocus?: () => void;\n  className?: string;\n  showSearchButton?: boolean;\n  showClearButton?: boolean;\n  size?: 'sm' | 'md' | 'lg';\n  \n  // Autocomplete props\n  showAutocomplete?: boolean;\n  autocompleteItems?: SearchBarAutocompleteItem[];\n  onSelectItem?: (item: SearchBarAutocompleteItem) => void;\n  isLoading?: boolean;\n  emptyMessage?: string;\n  minCharsForAutocomplete?: number;\n  renderItem?: (item: SearchBarAutocompleteItem) => React.ReactNode;\n}\n\nexport function SearchBar({\n  placeholder = 'Search...',\n  value: controlledValue,\n  onChange,\n  onSearch,\n  onClear,\n  onFocus,\n  className,\n  showSearchButton = false,\n  showClearButton = true,\n  size = 'md',\n  \n  // Autocomplete props\n  showAutocomplete = false,\n  autocompleteItems = [],\n  onSelectItem,\n  isLoading = false,\n  emptyMessage = 'No results found',\n  minCharsForAutocomplete = 1,\n  renderItem,\n}: SearchBarProps) {\n  const [internalValue, setInternalValue] = useState('');\n  const [showDropdown, setShowDropdown] = useState(false);\n  const [focusedIndex, setFocusedIndex] = useState(-1);\n  const containerRef = useRef<HTMLDivElement>(null);\n  const inputRef = useRef<HTMLInputElement>(null);\n  \n  const value = controlledValue !== undefined ? controlledValue : internalValue;\n  const shouldShowDropdown = showAutocomplete && showDropdown && value.length >= minCharsForAutocomplete;\n\n  // Close dropdown when clicking outside\n  useEffect(() => {\n    const handleClickOutside = (event: MouseEvent) => {\n      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n        setShowDropdown(false);\n        setFocusedIndex(-1);\n      }\n    };\n\n    document.addEventListener('mousedown', handleClickOutside);\n    return () => document.removeEventListener('mousedown', handleClickOutside);\n  }, []);\n\n  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const newValue = e.target.value;\n    if (controlledValue === undefined) {\n      setInternalValue(newValue);\n    }\n    onChange?.(newValue);\n    \n    if (showAutocomplete) {\n      setShowDropdown(true);\n      setFocusedIndex(-1);\n    }\n  };\n\n  const handleFocus = () => {\n    onFocus?.();\n    if (showAutocomplete && value.length >= minCharsForAutocomplete) {\n      setShowDropdown(true);\n    }\n  };\n\n  const handleSearch = () => {\n    onSearch?.(value);\n    setShowDropdown(false);\n  };\n\n  const handleClear = () => {\n    if (controlledValue === undefined) {\n      setInternalValue('');\n    }\n    onChange?.('');\n    onClear?.();\n    setShowDropdown(false);\n    setFocusedIndex(-1);\n  };\n\n  const handleSelectItem = (item: SearchBarAutocompleteItem) => {\n    if (controlledValue === undefined) {\n      setInternalValue(item.value);\n    }\n    onChange?.(item.value);\n    onSelectItem?.(item);\n    setShowDropdown(false);\n    setFocusedIndex(-1);\n    inputRef.current?.blur();\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (!shouldShowDropdown) {\n      if (e.key === 'Enter') {\n        handleSearch();\n      }\n      return;\n    }\n\n    switch (e.key) {\n      case 'Enter':\n        e.preventDefault();\n        if (focusedIndex >= 0 && autocompleteItems[focusedIndex]) {\n          handleSelectItem(autocompleteItems[focusedIndex]);\n        } else {\n          handleSearch();\n        }\n        break;\n      case 'ArrowDown':\n        e.preventDefault();\n        setFocusedIndex(prev => \n          prev < autocompleteItems.length - 1 ? prev + 1 : prev\n        );\n        break;\n      case 'ArrowUp':\n        e.preventDefault();\n        setFocusedIndex(prev => prev > 0 ? prev - 1 : -1);\n        break;\n      case 'Escape':\n        setShowDropdown(false);\n        setFocusedIndex(-1);\n        inputRef.current?.blur();\n        break;\n    }\n  };\n\n  const sizeClasses = {\n    sm: 'h-8',\n    md: 'h-10',\n    lg: 'h-12',\n  };\n\n  const getDropdownContent = () => {\n    if (isLoading) {\n      return (\n        <div className=\"flex items-center justify-center p-4\">\n          <Loader2 className=\"h-4 w-4 animate-spin mr-2\" />\n          <span className=\"text-sm text-muted-foreground\">Loading...</span>\n        </div>\n      );\n    }\n\n    if (autocompleteItems.length === 0) {\n      return (\n        <div className=\"p-4 text-sm text-muted-foreground text-center\">\n          {emptyMessage}\n        </div>\n      );\n    }\n\n    return (\n      <div className=\"py-1\">\n        {autocompleteItems.map((item, index) => (\n          <div\n            key={item.id}\n            className={cn(\n              'px-3 py-2 cursor-pointer text-sm transition-colors',\n              'hover:bg-muted focus:bg-muted',\n              focusedIndex === index && 'bg-muted'\n            )}\n            onClick={() => handleSelectItem(item)}\n            onMouseEnter={() => setFocusedIndex(index)}\n          >\n            {renderItem ? renderItem(item) : item.label}\n          </div>\n        ))}\n      </div>\n    );\n  };\n\n  return (\n    <div ref={containerRef} className={cn('relative flex items-center', className)}>\n      <div className=\"relative flex-1\">\n        <Search className=\"absolute right-4 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n        <Input\n          ref={inputRef}\n          type=\"text\"\n          placeholder={placeholder}\n          value={value}\n          onChange={handleInputChange}\n          onFocus={handleFocus}\n          onKeyDown={handleKeyDown}\n          className={cn(\n            'rounded-full',\n            showClearButton && value && 'pr-10',\n            sizeClasses[size]\n          )}\n        />\n        {showClearButton && value && (\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            onClick={handleClear}\n            className=\"absolute right-[8px] top-1/2 transform -translate-y-1/2 h-6 w-6 hover:bg-muted/50\"\n          >\n            <X className=\"h-3 w-3\" />\n          </Button>\n        )}\n        \n        {/* Autocomplete Dropdown */}\n        {shouldShowDropdown && (\n          <div className=\"absolute top-full left-0 right-0 mt-1 bg-background border border-border rounded-xl z-50 max-h-60 overflow-y-auto\">\n            {getDropdownContent()}\n          </div>\n        )}\n      </div>\n      {showSearchButton && (\n        <Button\n          onClick={handleSearch}\n          className={cn('ml-2', sizeClasses[size])}\n        >\n          Search\n        </Button>\n      )}\n    </div>\n  );\n} ",
      "type": "registry:component",
      "target": "src/components/deso-ui/search-bar.tsx"
    }
  ]
}