// Dropdown unificado con la estética de la web. // Uso: // const Select = ({ value, onChange, options = [], mono = false, placeholder = '—', disabled = false, style, className = '' }) => { const [open, setOpen] = useState(false); const [highlight, setHighlight] = useState(0); const wrapRef = useRef(null); const listRef = useRef(null); const btnRef = useRef(null); const [menuPos, setMenuPos] = useState({ top: 0, left: 0, width: 0, placement: 'bottom' }); const current = options.find(o => String(o.value) === String(value)); const label = current ? current.label : placeholder; useEffect(() => { if (!open) return; const close = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target) && listRef.current && !listRef.current.contains(e.target)) setOpen(false); }; const esc = (e) => { if (e.key === 'Escape') setOpen(false); }; document.addEventListener('mousedown', close); document.addEventListener('keydown', esc); return () => { document.removeEventListener('mousedown', close); document.removeEventListener('keydown', esc); }; }, [open]); useEffect(() => { if (!open || !btnRef.current) return; const r = btnRef.current.getBoundingClientRect(); const maxH = 280; const below = window.innerHeight - r.bottom; const above = r.top; const placement = below < maxH + 20 && above > below ? 'top' : 'bottom'; setMenuPos({ top: placement === 'bottom' ? r.bottom + 6 : r.top - 6, left: r.left, width: r.width, placement }); // scroll current into view setTimeout(() => { if (listRef.current) { const active = listRef.current.querySelector('.select-option.active'); if (active) active.scrollIntoView({ block: 'nearest' }); } }, 0); }, [open]); useEffect(() => { if (open) { const idx = options.findIndex(o => String(o.value) === String(value)); setHighlight(idx >= 0 ? idx : 0); } }, [open]); const onKey = (e) => { if (disabled) return; if (!open && (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); setOpen(true); return; } if (!open) return; if (e.key === 'ArrowDown') { e.preventDefault(); setHighlight(h => Math.min(h + 1, options.length - 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setHighlight(h => Math.max(h - 1, 0)); } else if (e.key === 'Enter') { e.preventDefault(); const o = options[highlight]; if (o) { onChange(o.value); setOpen(false); } } else if (e.key === 'Home') { setHighlight(0); } else if (e.key === 'End') { setHighlight(options.length - 1); } }; return