"use client"; import { useState, useRef, useEffect } from "react"; import { ChevronDown, Search } from "lucide-react"; import { cn } from "@/lib/utils"; interface SearchableSelectProps { label?: string; value: string; onChange: (value: string) => void; options: { value: string; label: string }[]; disabled?: boolean; className?: string; } export function SearchableSelect({ label, value, onChange, options, disabled, className, }: SearchableSelectProps) { const [open, setOpen] = useState(false); const [query, setQuery] = useState(""); const containerRef = useRef(null); const inputRef = useRef(null); const filtered = query ? options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())) : options; const selectedLabel = options.find((o) => o.value === value)?.label ?? value; useEffect(() => { if (open) { setQuery(""); setTimeout(() => inputRef.current?.focus(), 0); } }, [open]); useEffect(() => { function handleClickOutside(e: MouseEvent) { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setOpen(false); } } document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); function handleKeyDown(e: React.KeyboardEvent) { if (e.key === "Escape") setOpen(false); } return (
{label && ( )}
{open && (
setQuery(e.target.value)} onKeyDown={handleKeyDown} placeholder="Cari..." className="w-full text-xs outline-none placeholder:text-neutral-400" />
    {filtered.length === 0 ? (
  • Tidak ditemukan
  • ) : ( filtered.map((opt) => (
  • { onChange(opt.value); setOpen(false); }} className={cn( "px-3 py-1.5 text-xs cursor-pointer hover:bg-neutral-50", opt.value === value && "font-medium text-brand-green bg-brand-green/5" )} > {opt.label}
  • )) )}
)}
); }