"use client"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Field, FieldContent, FieldError, FieldLabel, } from "@/components/ui/field"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; import clsx from "clsx"; import { Check, ChevronsUpDown } from "lucide-react"; import * as React from "react"; import { Controller } from "react-hook-form"; export type MultiOption = { label: string; value: string }; type Props = { name: string; label?: string; options: MultiOption[]; placeholder?: string; disabled?: boolean; className?: string; renderCreate?: React.ReactNode; summaryFormatter?: ( selected: string[], all: MultiOption[], ) => React.ReactNode; listMaxHeight?: number; showChips?: boolean; }; export default function MultiSelectField({ name, label, options, placeholder = "Select options", disabled = false, className, renderCreate, summaryFormatter, listMaxHeight = 260, showChips = true, }: Props) { const [open, setOpen] = React.useState(false); return ( { const value: string[] = Array.isArray(field.value) ? field.value : []; const toggle = (v: string) => { const set = new Set(value); if (set.has(v)) { set.delete(v); } else { set.add(v); } field.onChange(Array.from(set)); }; const clearAll = () => field.onChange([]); const selectAll = () => field.onChange(options.map((o) => o.value)); const allSelected = options.length > 0 && value.length === options.length; const defaultSummary = () => { if (!value.length) return {placeholder}; const labels = value .map((v) => options.find((o) => o.value === v)?.label || v) .filter(Boolean); if (!showChips) { return ( {labels.length > 2 ? `${labels.length} selected` : labels.join(", ")} ); } return (
{labels.slice(0, 3).map((lab, i) => { const val = value[i]; return ( { e.stopPropagation(); field.onChange(value.filter((v) => v !== val)); }} > {lab} ); })} {labels.length > 3 && ( +{labels.length - 3} )}
); }; return ( {label && {label}} {/* Use width override here since you can't change the Popover wrapper */} {renderCreate ? (
{renderCreate}
) : null} {/* MUST live inside */}
No option found. {options.map((opt) => { const checked = value.includes(opt.value); return ( toggle(opt.value)} > {opt.label} {checked && } ); })}
{fieldState.invalid && }
); }} /> ); }