import { forwardRef, useEffect, useImperativeHandle, useRef } from "react"; import { Search, X } from "lucide-react"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; function isTypingTarget(el: EventTarget | null) { if (!(el instanceof HTMLElement)) return false; return el.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName); } interface Props { value: string; onChange: (value: string) => void; placeholder?: string; className?: string; /** Focus on "/" from anywhere on the page (unless the user is typing). */ shortcut?: boolean; /** Runs before the shortcut focuses, e.g. to reveal a collapsed filter panel. */ onShortcut?: () => void; } /** * Search box with a "/" shortcut hint. The hint swaps to a clear button once * there is a query; Escape clears, and a second Escape leaves the field. */ export const SearchInput = forwardRef(function SearchInput( { value, onChange, placeholder = "Search…", className, shortcut = true, onShortcut }, ref ) { const inputRef = useRef(null); useImperativeHandle(ref, () => inputRef.current as HTMLInputElement); useEffect(() => { if (!shortcut) return; const onKey = (e: KeyboardEvent) => { if (e.key !== "/" || e.metaKey || e.ctrlKey || e.altKey || isTypingTarget(e.target)) return; e.preventDefault(); onShortcut?.(); inputRef.current?.focus(); inputRef.current?.select(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [shortcut, onShortcut]); return (
onChange(e.target.value)} onKeyDown={(e) => { if (e.key !== "Escape") return; if (value) onChange(""); else inputRef.current?.blur(); }} /> {value ? ( ) : ( shortcut && ( / ) )}
); });