"use client"; import { useState, useRef, useId, useEffect } from "react"; import type { Choice } from "../forms/Selection.tsx"; export function MultiSelect({ label, value, onValueChange, options, max = Infinity, className = "", }: { label: string; value: readonly string[]; onValueChange: (value: string[]) => void; options: readonly Choice[]; max?: number; className?: string; }) { const [query, setQuery] = useState(""), ref = useRef(null), id = useId(); useEffect(() => { const close = (e: PointerEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) ref.current.open = false; }; document.addEventListener("pointerdown", close); return () => document.removeEventListener("pointerdown", close); }, []); return (
{ if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); if (ref.current) { ref.current.open = false; ref.current.querySelector("summary")?.focus(); } } }} > {label} {value.length} selected
setQuery(e.target.value)} placeholder="Filter options" />
{label} {options .filter((o) => o.label.toLowerCase().includes(query.toLowerCase())) .map((o) => ( ))}
{!options.some((o) => o.label.toLowerCase().includes(query.toLowerCase()), ) &&

No matching options.

} {Number.isFinite(max) && (

Choose up to {max}.

)}
); }