import { useEffect, useMemo, useRef, useState } from 'react'; import { IconHash } from '@tabler/icons-react'; function CommunityAutocompleteInput({ value, onChange, communities = [], placeholder = '', className = 'form-control', onSelectMeta, maxSuggestions = 8, useShortValue = false, // если true, передавать только короткую часть community (120 вместо 65000:120) }) { const containerRef = useRef(null); const inputRef = useRef(null); const [open, setOpen] = useState(false); const [activeIndex, setActiveIndex] = useState(-1); const suggestions = useMemo(() => { const q = String(value || '').toLowerCase(); if (!q) return communities.slice(0, maxSuggestions); const filtered = communities.filter((c) => { const v = (c.value || '').toLowerCase(); const n = (c.name || '').toLowerCase(); const d = (c.description || '').toLowerCase(); const t = Array.isArray(c.tags) ? c.tags.join(' ').toLowerCase() : ''; return v.includes(q) || n.includes(q) || d.includes(q) || t.includes(q); }); return filtered.slice(0, maxSuggestions); }, [value, communities, maxSuggestions]); useEffect(() => { const handleOutside = (e) => { if (!containerRef.current) return; if (!containerRef.current.contains(e.target)) setOpen(false); }; document.addEventListener('click', handleOutside); return () => document.removeEventListener('click', handleOutside); }, []); const selectItem = (item) => { // Если useShortValue=true, извлекаем только часть после двоеточия (если есть) let valueToSet = item.value; if (useShortValue && typeof item.value === 'string' && item.value.includes(':')) { valueToSet = item.value.split(':')[1] || item.value; } onChange(valueToSet); if (onSelectMeta) onSelectMeta(item); setOpen(false); setActiveIndex(-1); if (inputRef.current) inputRef.current.focus(); }; const handleKeyDown = (e) => { if (!open && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) { setOpen(true); return; } if (!open) return; if (e.key === 'ArrowDown') { e.preventDefault(); setActiveIndex((prev) => Math.min(prev + 1, suggestions.length - 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setActiveIndex((prev) => Math.max(prev - 1, 0)); } else if (e.key === 'Enter') { if (activeIndex >= 0 && activeIndex < suggestions.length) { e.preventDefault(); selectItem(suggestions[activeIndex]); } } else if (e.key === 'Escape') { setOpen(false); setActiveIndex(-1); } }; return (
{ onChange(e.target.value); setOpen(true); }} onFocus={() => setOpen(true)} onKeyDown={handleKeyDown} autoComplete="off" /> {open && suggestions.length > 0 && (
{suggestions.map((s, idx) => { const label = s.name ? `${s.value} - ${s.name}` : `${s.value}`; const description = s.description || ''; const tags = Array.isArray(s.tags) ? s.tags : []; return ( ); })}
)}
); } export default CommunityAutocompleteInput;