import { useState, useRef, useEffect } from "react"; import { Input } from "./Input"; interface AutocompleteOption { value: string; label: string; data?: any; } interface AutocompleteInputProps { name?: string; label?: string; placeholder?: string; value: string; onChange: (value: string) => void; onSelect?: (option: AutocompleteOption) => void; options: AutocompleteOption[]; error?: string; required?: boolean; disabled?: boolean; loading?: boolean; } export function AutocompleteInput({ name, label, placeholder, value, onChange, onSelect, options, error, required, disabled, loading }: AutocompleteInputProps) { const [isOpen, setIsOpen] = useState(false); const [highlightedIndex, setHighlightedIndex] = useState(-1); const inputRef = useRef(null); const listRef = useRef(null); const containerRef = useRef(null); // Filter options based on input value const filteredOptions = options.filter(option => option.label.toLowerCase().includes(value.toLowerCase()) || option.value.toLowerCase().includes(value.toLowerCase()) ); // Handle input change const handleInputChange = (e: React.ChangeEvent) => { const newValue = e.target.value; onChange(newValue); setIsOpen(true); setHighlightedIndex(-1); }; // Handle option selection const handleOptionSelect = (option: AutocompleteOption) => { onChange(option.value); onSelect?.(option); setIsOpen(false); setHighlightedIndex(-1); }; // Handle keyboard navigation const handleKeyDown = (e: React.KeyboardEvent) => { if (!isOpen) { if (e.key === "ArrowDown" || e.key === "Enter") { setIsOpen(true); return; } return; } switch (e.key) { case "ArrowDown": e.preventDefault(); setHighlightedIndex(prev => prev < filteredOptions.length - 1 ? prev + 1 : 0 ); break; case "ArrowUp": e.preventDefault(); setHighlightedIndex(prev => prev > 0 ? prev - 1 : filteredOptions.length - 1 ); break; case "Enter": e.preventDefault(); if (highlightedIndex >= 0 && filteredOptions[highlightedIndex]) { handleOptionSelect(filteredOptions[highlightedIndex]); } break; case "Escape": setIsOpen(false); setHighlightedIndex(-1); break; } }; // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setIsOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); // Scroll highlighted option into view useEffect(() => { if (highlightedIndex >= 0 && listRef.current) { const highlightedElement = listRef.current.children[highlightedIndex] as HTMLElement; if (highlightedElement) { highlightedElement.scrollIntoView({ block: "nearest", behavior: "smooth" }); } } }, [highlightedIndex]); return (
setIsOpen(true)} error={error} required={required} disabled={disabled} endIcon={
{loading ? ( ) : isOpen ? ( ) : ( )}
} /> {/* Dropdown */} {isOpen && filteredOptions.length > 0 && (
    {filteredOptions.map((option, index) => (
  • { e.preventDefault(); e.stopPropagation(); handleOptionSelect(option); }} onMouseDown={(e) => { e.preventDefault(); // Prevent input from losing focus }} onMouseEnter={() => setHighlightedIndex(index)} >
    {option.value}
    {option.label !== option.value && (
    {option.label}
    )}
  • ))}
)} {/* No results */} {isOpen && filteredOptions.length === 0 && value.length > 0 && (
لا توجد نتائج مطابقة
)}
); }