import React, { useState, useRef, useEffect, useCallback } from 'react' import { ChevronDown, X } from 'lucide-react' import { cn } from '@/lib/utils' import Input from './Input' interface UserPromptInputWithHistoryProps { value: string onChange: (value: string) => void placeholder?: string className?: string id?: string history: string[] onSelectFromHistory: (prompt: string) => void onDeleteFromHistory?: (index: number) => void } export default function UserPromptInputWithHistory({ value, onChange, placeholder, className, id, history, onSelectFromHistory, onDeleteFromHistory }: UserPromptInputWithHistoryProps) { const [isOpen, setIsOpen] = useState(false) const [selectedIndex, setSelectedIndex] = useState(-1) const [isHovered, setIsHovered] = useState(false) const dropdownRef = useRef(null) const inputRef = useRef(null) // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false) setSelectedIndex(-1) } } document.addEventListener('mousedown', handleClickOutside) return () => { document.removeEventListener('mousedown', handleClickOutside) } }, []) // Handle keyboard navigation const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (!isOpen) { if (e.key === 'ArrowDown' && history.length > 0) { e.preventDefault() setIsOpen(true) setSelectedIndex(0) } return } switch (e.key) { case 'ArrowDown': e.preventDefault() setSelectedIndex(prev => prev < history.length - 1 ? prev + 1 : prev ) break case 'ArrowUp': e.preventDefault() setSelectedIndex(prev => prev > 0 ? prev - 1 : -1) if (selectedIndex === 0) { setSelectedIndex(-1) } break case 'Enter': if (selectedIndex >= 0 && selectedIndex < history.length) { e.preventDefault() const selectedPrompt = history[selectedIndex] onSelectFromHistory(selectedPrompt) setIsOpen(false) setSelectedIndex(-1) } break case 'Escape': e.preventDefault() setIsOpen(false) setSelectedIndex(-1) break } }, [isOpen, selectedIndex, history, onSelectFromHistory]) const handleInputClick = () => { if (history.length > 0) { setIsOpen(!isOpen) setSelectedIndex(-1) } } const handleDropdownItemClick = (prompt: string) => { onSelectFromHistory(prompt) setIsOpen(false) setSelectedIndex(-1) inputRef.current?.focus() } const handleInputChange = (e: React.ChangeEvent) => { onChange(e.target.value) } const handleMouseEnter = () => { setIsHovered(true) } const handleMouseLeave = () => { setIsHovered(false) } // Handle delete history item with boundary cases const handleDeleteHistoryItem = useCallback((index: number, e: React.MouseEvent) => { e.stopPropagation() // Prevent triggering item selection onDeleteFromHistory?.(index) // Handle boundary cases if (history.length === 1) { // Deleting the last item, close dropdown setIsOpen(false) setSelectedIndex(-1) } else if (selectedIndex === index) { // Deleting currently selected item, adjust selection setSelectedIndex(prev => prev > 0 ? prev - 1 : -1) } else if (selectedIndex > index) { // Deleting item before selected item, adjust index setSelectedIndex(prev => prev - 1) } }, [onDeleteFromHistory, history.length, selectedIndex]) return (
0 ? 'pr-5' : 'pr-2', 'w-full', className)} /> {isHovered && history.length > 0 && ( )}
{/* Dropdown */} {isOpen && history.length > 0 && (
{history.map((prompt, index) => (
{onDeleteFromHistory && ( )}
))}
)}
) }