/ src / components / ui / search-input.tsx
search-input.tsx
 1  'use client'
 2  
 3  import { forwardRef, type InputHTMLAttributes } from 'react'
 4  import { cn } from '@/lib/utils'
 5  
 6  const SIZE_CLASSES = {
 7    sm: 'px-4 py-2.5 rounded-[12px] text-[13px] border-white/[0.04]',
 8    md: 'px-4 py-3.5 rounded-[14px] text-[15px] border-white/[0.08]',
 9  } as const
10  
11  interface SearchInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
12    size?: 'sm' | 'md'
13    onClear?: () => void
14  }
15  
16  export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
17    function SearchInput({ size = 'sm', onClear, value, className, ...props }, ref) {
18      const hasValue = typeof value === 'string' ? value.length > 0 : !!value
19  
20      return (
21        <div className={cn('relative', className)}>
22          <input
23            ref={ref}
24            type="text"
25            value={value}
26            className={cn(
27              'w-full border bg-surface text-text outline-none transition-all duration-200 placeholder:text-text-3/70 focus-glow',
28              SIZE_CLASSES[size],
29            )}
30            style={{ fontFamily: 'inherit' }}
31            {...props}
32          />
33          {hasValue && onClear && (
34            <button
35              type="button"
36              onClick={onClear}
37              className="absolute right-2.5 top-1/2 -translate-y-1/2 p-1 rounded-md text-text-3/50 hover:text-text-3 bg-transparent border-none cursor-pointer transition-colors"
38              aria-label="Clear search"
39            >
40              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
41                <path d="M18 6L6 18M6 6l12 12" />
42              </svg>
43            </button>
44          )}
45        </div>
46      )
47    },
48  )