import { useState, useMemo, useRef, useEffect } from "react"; import Fuse from "fuse.js"; interface ProductIndex { id: string; name: string; category: string; } interface Props { products: ProductIndex[]; basePath: string; } export default function SearchBar({ products, basePath }: Props) { const [query, setQuery] = useState(""); const [isOpen, setIsOpen] = useState(false); const wrapRef = useRef(null); const fuse = useMemo( () => new Fuse(products, { keys: ["name", "category"], threshold: 0.3, includeScore: true, }), [products], ); const results = query.length >= 2 ? fuse.search(query).slice(0, 8) : []; useEffect(() => { const handler = (e: MouseEvent) => { if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) { setIsOpen(false); } }; document.addEventListener("click", handler); return () => document.removeEventListener("click", handler); }, []); return (
{ setQuery(e.target.value); setIsOpen(true); }} onFocus={() => setIsOpen(true)} placeholder="Search for a product..." style={{ width: "100%", padding: "14px 16px 14px 44px", background: "var(--surface)", border: "1.5px solid var(--border)", borderRadius: "var(--radius)", fontSize: "1rem", color: "var(--text)", outline: "none", }} />
{isOpen && results.length > 0 && (
{results.map((r) => ( { (e.currentTarget as HTMLElement).style.background = "var(--surface2)"; }} onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.background = "transparent"; }} > {r.item.name} {r.item.category} ))}
)} {isOpen && query.length >= 2 && results.length === 0 && (
No products found
)}
); }