import { useEffect, useId, useRef, useState } from 'react'; export type ToolbarSelectOption = { value: string; label: string; }; type Props = { value: string; options: ToolbarSelectOption[]; ariaLabel: string; onChange(value: string): void; }; export function ToolbarSelect({ value, options, ariaLabel, onChange }: Props) { const [open, setOpen] = useState(false); const rootRef = useRef(null); const listId = useId(); const selected = options.find((option) => option.value === value) || options[0]; useEffect(() => { if (!open) return; function onPointer(event: MouseEvent) { if (!rootRef.current?.contains(event.target as Node)) setOpen(false); } function onKey(event: KeyboardEvent) { if (event.key === 'Escape') { event.preventDefault(); setOpen(false); return; } if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return; event.preventDefault(); const idx = options.findIndex((option) => option.value === value); const nextIndex = event.key === 'ArrowDown' ? Math.min(options.length - 1, Math.max(0, idx + 1)) : Math.max(0, idx < 0 ? 0 : idx - 1); const next = options[nextIndex]; if (next) onChange(next.value); } document.addEventListener('mousedown', onPointer); document.addEventListener('keydown', onKey); return () => { document.removeEventListener('mousedown', onPointer); document.removeEventListener('keydown', onKey); }; }, [open, options, value, onChange]); return (
{open ? ( ) : null}
); }