| "use client"; |
|
|
| import { Badge } from "@/components/ui/badge"; |
| import { |
| Command, |
| CommandEmpty, |
| CommandGroup, |
| CommandInput, |
| CommandItem, |
| CommandList, |
| } from "@/components/ui/command"; |
| import { |
| Popover, |
| PopoverContent, |
| PopoverTrigger, |
| } from "@/components/ui/popover"; |
| import { cn } from "@/lib/utils"; |
| import { Check, ChevronsUpDown } from "lucide-react"; |
| import * as React from "react"; |
|
|
| export function MultiSelect({ |
| options, |
| value, |
| onChange, |
| placeholder = 'Select...', |
| }: { |
| options: { label: string; value: string }[]; |
| value: string[]; |
| onChange: (values: string[]) => void; |
| placeholder?: string; |
| }) { |
| const [open, setOpen] = React.useState(false); |
|
|
| const toggleValue = (val: string) => { |
| if (value.includes(val)) { |
| onChange(value.filter((v) => v !== val)); |
| } else { |
| onChange([...value, val]); |
| } |
| |
| }; |
|
|
| return ( |
| <Popover open={open} onOpenChange={setOpen}> |
| <PopoverTrigger asChild> |
| <div |
| className={cn( |
| "border w-full min-h-[40px] px-3 py-2 rounded-md flex items-center justify-between cursor-pointer gap-2", |
| value.length === 0 && "text-muted-foreground" |
| )} |
| > |
| <div className="flex flex-wrap gap-1 flex-1"> |
| {value.length === 0 ? ( |
| <span>{placeholder}</span> |
| ) : ( |
| value.map((val) => ( |
| <Badge |
| key={val} |
| variant="secondary" |
| className="text-xs px-2 py-0.5 gap-1" |
| > |
| {val} |
| </Badge> |
| )) |
| )} |
| </div> |
| <ChevronsUpDown className="h-4 w-4 opacity-50 shrink-0" /> |
| </div> |
| </PopoverTrigger> |
| |
| <PopoverContent className="p-0 w-[250px]"> |
| <Command> |
| <CommandInput placeholder="Search..." /> |
| <CommandList> |
| <CommandEmpty>No results found.</CommandEmpty> |
| |
| <CommandGroup> |
| {options.map((option) => { |
| const selected = value.includes(option.value); |
| |
| return ( |
| <CommandItem |
| key={option.value} |
| onSelect={() => toggleValue(option.value)} |
| className="flex items-center gap-2 cursor-pointer" |
| > |
| <div |
| className={cn( |
| "h-4 w-4 border rounded-sm flex items-center justify-center", |
| selected ? "bg-primary border-primary" : "border-input" |
| )} |
| > |
| {selected && <Check className="h-3 w-3 text-primary-foreground" />} |
| </div> |
| {option.label} |
| </CommandItem> |
| ); |
| })} |
| </CommandGroup> |
| </CommandList> |
| </Command> |
| </PopoverContent> |
| </Popover> |
| ); |
| } |