import { useState, useRef, useEffect, useCallback } from 'react'; interface Props { value: string; onChange: (value: string) => void; suggestions: string[]; placeholder?: string; className?: string; onKeyDown?: (e: React.KeyboardEvent) => void; } export default function AutocompleteInput({ value, onChange, suggestions, placeholder, className, onKeyDown }: Props) { const [open, setOpen] = useState(false); const [highlightIdx, setHighlightIdx] = useState(-1); const inputRef = useRef(null); const listRef = useRef(null); const filtered = value ? suggestions.filter(s => s.toLowerCase().includes(value.toLowerCase())) : suggestions; const handleSelect = useCallback((val: string) => { onChange(val); setOpen(false); setHighlightIdx(-1); }, [onChange]); const handleKeyDown = (e: React.KeyboardEvent) => { if (!open || filtered.length === 0) { // Tab with no dropdown: accept what's typed, let focus move naturally onKeyDown?.(e); return; } if (e.key === 'ArrowDown') { e.preventDefault(); setHighlightIdx(i => Math.min(i + 1, filtered.length - 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setHighlightIdx(i => Math.max(i - 1, 0)); } else if (e.key === 'Enter' && highlightIdx >= 0) { e.preventDefault(); handleSelect(filtered[highlightIdx]); } else if (e.key === 'Tab' && highlightIdx >= 0) { // Tab accepts highlighted suggestion handleSelect(filtered[highlightIdx]); // Don't prevent default — let focus move to next field } else if (e.key === 'Tab' && filtered.length > 0 && value) { // Tab with text typed: accept first match handleSelect(filtered[0]); } else if (e.key === 'Escape') { setOpen(false); setHighlightIdx(-1); } else { onKeyDown?.(e); } }; useEffect(() => { if (highlightIdx >= 0 && listRef.current) { const el = listRef.current.children[highlightIdx] as HTMLElement; el?.scrollIntoView({ block: 'nearest' }); } }, [highlightIdx]); return (
{ onChange(e.target.value); setOpen(true); setHighlightIdx(-1); }} onFocus={() => setOpen(true)} onBlur={() => { // Delay to allow click on dropdown items setTimeout(() => setOpen(false), 150); }} onKeyDown={handleKeyDown} placeholder={placeholder} className={className} autoComplete="off" /> {open && filtered.length > 0 && (
    {filtered.slice(0, 10).map((item, idx) => (
  • handleSelect(item)} onMouseEnter={() => setHighlightIdx(idx)} > {item}
  • ))}
)}
); }