'use client'; import { useState, useRef, useEffect } from 'react'; import { Tag } from '@/lib/types'; import { useTagsAutocomplete } from '@/hooks/useTags'; import { Badge } from './Badge'; interface TagInputProps { tags: string[]; onChange: (tags: string[]) => void; placeholder?: string; maxTags?: number; className?: string; compactSuggestions?: boolean; // Pour adapter selon l'espace } export function TagInput({ tags, onChange, placeholder = "Ajouter des tags...", maxTags = 10, className = "", compactSuggestions = false }: TagInputProps) { const [inputValue, setInputValue] = useState(''); const [showSuggestions, setShowSuggestions] = useState(false); const [selectedIndex, setSelectedIndex] = useState(-1); const inputRef = useRef(null); const suggestionsRef = useRef(null); const { suggestions, loading, searchTags, clearSuggestions, loadPopularTags } = useTagsAutocomplete(); // Rechercher des suggestions quand l'input change useEffect(() => { if (inputValue.trim()) { searchTags(inputValue); setShowSuggestions(true); setSelectedIndex(-1); } else { clearSuggestions(); setShowSuggestions(false); } }, [inputValue, searchTags, clearSuggestions]); const addTag = (tagName: string) => { const trimmedTag = tagName.trim(); if (trimmedTag && !tags.includes(trimmedTag) && tags.length < maxTags) { onChange([...tags, trimmedTag]); } setInputValue(''); setShowSuggestions(false); setSelectedIndex(-1); }; const removeTag = (tagToRemove: string) => { onChange(tags.filter(tag => tag !== tagToRemove)); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); if (selectedIndex >= 0 && suggestions[selectedIndex]) { addTag(suggestions[selectedIndex].name); } else if (inputValue.trim()) { addTag(inputValue); } } else if (e.key === 'Escape') { setShowSuggestions(false); setSelectedIndex(-1); } else if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex(prev => prev < suggestions.length - 1 ? prev + 1 : prev ); } else if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex(prev => prev > 0 ? prev - 1 : -1); } else if (e.key === 'Backspace' && !inputValue && tags.length > 0) { // Supprimer le dernier tag si l'input est vide removeTag(tags[tags.length - 1]); } }; const handleSuggestionClick = (tag: Tag) => { addTag(tag.name); }; const handleBlur = (e: React.FocusEvent) => { // Délai pour permettre le clic sur une suggestion setTimeout(() => { if (!suggestionsRef.current?.contains(e.relatedTarget as Node)) { setShowSuggestions(false); setSelectedIndex(-1); } }, 150); }; const handleFocus = () => { if (inputValue.trim()) { // Si il y a du texte, afficher les suggestions existantes setShowSuggestions(true); } else { // Si l'input est vide, charger les tags populaires loadPopularTags(20); setShowSuggestions(true); } setSelectedIndex(-1); }; return (
{/* Container des tags et input */}
{/* Tags existants */} {tags.map((tag, index) => ( {tag} ))} {/* Input pour nouveau tag */} {tags.length < maxTags && ( setInputValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleBlur} onFocus={handleFocus} placeholder={tags.length === 0 ? placeholder : ""} className="flex-1 min-w-[120px] bg-transparent border-none outline-none text-[var(--foreground)] placeholder-[var(--muted-foreground)] text-sm" /> )}
{/* Suggestions dropdown */} {showSuggestions && (suggestions.length > 0 || loading) && (
{loading ? (
Recherche...
) : (
{suggestions.map((tag, index) => ( ))}
)}
)} {/* Indicateur de limite */} {tags.length >= maxTags && (
Limite de {maxTags} tags atteinte
)}
); }