"use client"; import * as React from "react"; import { ChevronDown, Check } from "lucide-react"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; interface Option { value: string; label: string; count?: number; } interface MultiSelectProps { options: Option[]; value: string[]; onValueChange: (value: string[]) => void; placeholder?: string; className?: string; maxSelection?: number; searchPlaceholder?: string; showAllOption?: boolean; allOptionLabel?: string; } export function MultiSelect({ options, value, onValueChange, placeholder = "Select items...", className, maxSelection, searchPlaceholder = "Search options...", showAllOption = true, allOptionLabel = "All", }: MultiSelectProps) { const [open, setOpen] = React.useState(false); const [searchValue, setSearchValue] = React.useState(""); const isAllSelected = value.includes("*"); const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()), ); const handleSelect = (optionValue: string) => { if (optionValue === "*") { // Toggle "All" selection if (isAllSelected) { onValueChange([]); } else { onValueChange(["*"]); } } else { let newValue: string[]; if (value.includes(optionValue)) { // Remove the item newValue = value.filter((v) => v !== optionValue && v !== "*"); } else { // Add the item and remove "All" if present newValue = [...value.filter((v) => v !== "*"), optionValue]; // Check max selection limit if (maxSelection && newValue.length > maxSelection) { return; } } onValueChange(newValue); } }; const getDisplayText = () => { if (isAllSelected) { return allOptionLabel; } if (value.length === 0) { return placeholder; } // Extract the noun from placeholder (e.g., "Select data sources..." -> "data sources") const noun = placeholder .toLowerCase() .replace("select ", "") .replace("...", ""); return `${value.length} ${noun}`; }; return ( No items found. {showAllOption && ( handleSelect("*")} className="cursor-pointer" > {allOptionLabel} )} {filteredOptions.map((option) => ( handleSelect(option.value)} className="cursor-pointer" > {option.label} {option.count !== undefined && ( {option.count} )} ))} ); }