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 )