'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Check, ChevronDown, Loader2, Search } from 'lucide-react'; export type FormSelectOption = { value: string; label: string; hint?: string; imageUrl?: string; }; type FormSelectProps = { label: string; placeholder: string; value: string; options: FormSelectOption[]; disabled?: boolean; loading?: boolean; searchable?: boolean; onChange: (value: string) => void; }; export function FormSelect({ label, placeholder, value, options, disabled = false, loading = false, searchable = false, onChange, }: FormSelectProps) { const [open, setOpen] = useState(false); const [query, setQuery] = useState(''); const rootRef = useRef(null); const searchRef = useRef(null); const selected = options.find((option) => option.value === value); const isDisabled = disabled || loading; const filtered = useMemo(() => { const q = query.trim().toLowerCase(); if (!q) return options; return options.filter((option) => `${option.label} ${option.hint || ''}`.toLowerCase().includes(q) ); }, [options, query]); useEffect(() => { const onDocClick = (event: MouseEvent) => { if (!rootRef.current?.contains(event.target as Node)) { setOpen(false); } }; const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') setOpen(false); }; document.addEventListener('mousedown', onDocClick); document.addEventListener('keydown', onKey); return () => { document.removeEventListener('mousedown', onDocClick); document.removeEventListener('keydown', onKey); }; }, []); useEffect(() => { if (!open) { setQuery(''); return; } const id = window.setTimeout(() => searchRef.current?.focus(), 0); return () => window.clearTimeout(id); }, [open]); const showSearch = searchable && options.length > 6; return (
{label} {open && (
{showSearch && (
setQuery(event.target.value)} placeholder={`Search ${label.toLowerCase()}...`} className="w-full h-9 pl-8 pr-3 rounded-lg bg-gray-50 border border-gray-200 text-[12px] text-[#1a1a1a] outline-none focus:border-primary focus:ring-2 focus:ring-primary/15" />
)}
    {filtered.length === 0 ? (
  • No matches found
  • ) : ( filtered.map((option) => { const isSelected = option.value === value; return (
  • ); }) )}
)}
); }