{{#if framework == "nextjs"}} "use client"; {{/if}} import * as React from "react"; {{#if framework == "nextjs"}} import { useRouter, useSearchParams } from "next/navigation"; {{else}} import { useNavigate, useSearchParams } from "react-router"; {{/if}} import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; import { formUrlQuery, removeKeysFromQuery } from "@/lib/utils/url-helpers"; type SearchBarProps = { placeholder?: string; className?: string; inputClassName?: string; paramKey?: string; defaultValue?: string; debounceMs?: number; replace?: boolean; minLength?: number; autoFocus?: boolean; showClear?: boolean; ariaLabel?: string; onDebouncedChange?: (value: string) => void; }; export default function SearchBar({ placeholder = "Search by title", className, inputClassName, paramKey = "search", defaultValue = "", debounceMs = 400, replace = true, minLength = 0, autoFocus = false, showClear = true, ariaLabel = "Search", onDebouncedChange, }: SearchBarProps) { {{#if framework == "nextjs"}} const router = useRouter(); const searchParams = useSearchParams(); {{else}} const navigate = useNavigate(); const [searchParams] = useSearchParams(); {{/if}} const [value, setValue] = React.useState(() => { return searchParams?.get(paramKey) ?? defaultValue; }); React.useEffect(() => { const urlVal = searchParams?.get(paramKey) ?? defaultValue; setValue((prev) => (prev !== urlVal ? urlVal : prev)); }, [searchParams, paramKey, defaultValue]); React.useEffect(() => { const t = setTimeout(() => { const trimmed = value.trim(); const meetsMin = trimmed.length >= minLength; const qs = searchParams?.toString() ?? ""; const newUrl = meetsMin && trimmed !== defaultValue ? formUrlQuery({ params: qs, key: paramKey, value: trimmed }) : removeKeysFromQuery({ params: qs, keysToRemove: [paramKey] }); {{#if framework == "nextjs"}} if (replace) router.replace(newUrl, { scroll: false }); else router.push(newUrl, { scroll: false }); {{else}} navigate(newUrl, { replace }); {{/if}} onDebouncedChange?.(trimmed); }, debounceMs); return () => clearTimeout(t); }, [ value, debounceMs, replace, {{#if framework == "nextjs"}} router, {{else}} navigate, {{/if}} searchParams, paramKey, defaultValue, minLength, onDebouncedChange, ]); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Escape" && value) setValue(""); }; return (
setValue(e.target.value)} onKeyDown={handleKeyDown} autoFocus={autoFocus} className={cn("pr-8", inputClassName, "bg-transparent")} />
{showClear && value ? ( ) : null}
); }