File size: 3,015 Bytes
e6f1924
 
58a84ad
e6f1924
 
 
 
 
 
 
 
 
 
 
 
 
58a84ad
 
 
e6f1924
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58a84ad
e6f1924
 
 
 
 
 
 
58a84ad
e6f1924
 
 
58a84ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6f1924
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58a84ad
e6f1924
58a84ad
 
e6f1924
58a84ad
 
 
e6f1924
 
 
 
 
 
 
 
 
 
58a84ad
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"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]);
    }
    // Don't close the popover - keep it open for multiple selections
  };

  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>
  );
}