import React, { useState, useRef, useEffect, memo } from "react"; import { useGenerator } from "../../context/GeneratorContext"; const SearchIcon = ({ className = "w-5 h-5" }) => ( ); function SearchBar({ value, onChange, placeholder = "Search images...", onSubmit, showSubmitButton = true, submitLabel = "Search", disabled = false, providerId, isSearching = false, }) { const [inputValue, setInputValue] = useState(value); const [showHistory, setShowHistory] = useState(false); const [selectedHistoryIndex, setSelectedHistoryIndex] = useState(-1); const inputRef = useRef(null); const historyListRef = useRef(null); const generator = useGenerator(); const history = providerId ? generator.getSearchHistory(providerId) : []; const addToHistory = providerId ? generator.addSearchToHistory : () => {}; const clearHistory = providerId ? generator.clearSearchHistory : () => {}; // Sync input value when external value changes useEffect(() => { setInputValue(value); }, [value]); // Reset selected index when history visibility changes useEffect(() => { if (!showHistory) { setSelectedHistoryIndex(-1); } }, [showHistory]); useEffect(() => { const handleKeyDown = (e) => { if ((e.ctrlKey || e.metaKey) && e.key === "k") { e.preventDefault(); inputRef.current?.focus(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, []); const handleSubmit = (e) => { e.preventDefault(); const q = (inputValue || "").trim(); if (q) addToHistory(providerId, q); setShowHistory(false); onChange(q); // Only update search query on submit onSubmit?.(); }; const handleHistorySelect = (item) => { setInputValue(item); onChange(item); // Trigger search when selecting from history setShowHistory(false); inputRef.current?.focus(); }; const handleClear = () => { setInputValue(""); onChange(""); // Trigger search with empty query }; const hasText = (inputValue || "").trim().length > 0; return (
setInputValue(e.target.value)} onFocus={() => history.length > 0 && setShowHistory(true)} onBlur={() => setTimeout(() => setShowHistory(false), 200)} onKeyDown={(e) => { if (e.key === "Escape") { setShowHistory(false); if (inputValue) { setInputValue(""); onChange(""); } e.currentTarget.blur(); return; } if (!showHistory || history.length === 0) return; if (e.key === "ArrowDown") { e.preventDefault(); setSelectedHistoryIndex((prev) => prev < history.length - 1 ? prev + 1 : prev ); } else if (e.key === "ArrowUp") { e.preventDefault(); setSelectedHistoryIndex((prev) => (prev > 0 ? prev - 1 : -1)); } else if (e.key === "Enter" && selectedHistoryIndex >= 0) { e.preventDefault(); handleHistorySelect(history[selectedHistoryIndex]); } }} placeholder={placeholder} disabled={disabled} className="search-input-field" aria-label={placeholder} aria-describedby={showHistory ? "search-history-list" : undefined} aria-activedescendant={ showHistory && selectedHistoryIndex >= 0 ? `history-item-${selectedHistoryIndex}` : undefined } aria-expanded={showHistory} aria-controls="search-history-list" />
{hasText && !isSearching && ( )} {showSubmitButton && ( )}
{showHistory && history.length > 0 && (
Recent searches
{history.map((item, i) => ( ))}
)}
); } export default memo(SearchBar);