Spaces:
Running
Running
| import * as React from "react"; | |
| import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; | |
| import { Check, ChevronDown, X } from "lucide-react"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Button } from "@/components/ui/button"; | |
| interface AgentMultiSelectProps { | |
| options: string[]; | |
| value: string[]; | |
| onChange: (value: string[]) => void; | |
| placeholder?: string; | |
| } | |
| export const AgentMultiSelect: React.FC<AgentMultiSelectProps> = ({ | |
| options, | |
| value, | |
| onChange, | |
| placeholder = "Filter by agent", | |
| }) => { | |
| const toggle = (agent: string) => { | |
| if (value.includes(agent)) { | |
| onChange(value.filter((a) => a !== agent)); | |
| } else { | |
| onChange([...value, agent]); | |
| } | |
| }; | |
| return ( | |
| <DropdownMenu.Root> | |
| <DropdownMenu.Trigger asChild> | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| className="flex items-center gap-2 bg-background" | |
| > | |
| <span className="truncate max-w-[200px] text-sm"> | |
| {value.length === 0 ? placeholder : `${value.length} selected`} | |
| </span> | |
| <ChevronDown className="h-4 w-4" /> | |
| </Button> | |
| </DropdownMenu.Trigger> | |
| <DropdownMenu.Content | |
| className="bg-popover border rounded-md shadow-lg p-2 max-h-60 overflow-y-auto" | |
| align="start" | |
| > | |
| {options.map((opt) => { | |
| const checked = value.includes(opt); | |
| return ( | |
| <DropdownMenu.Item | |
| key={opt} | |
| onSelect={(e) => { | |
| e.preventDefault(); | |
| toggle(opt); | |
| }} | |
| className="flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer hover:bg-muted focus:outline-none" | |
| > | |
| <span | |
| className={`h-4 w-4 border rounded-sm flex items-center justify-center text-primary ${ | |
| checked ? "bg-primary text-white" : "bg-background" | |
| }`} | |
| > | |
| {checked && <Check className="h-3 w-3" />} | |
| </span> | |
| <span className="text-sm truncate">{opt}</span> | |
| </DropdownMenu.Item> | |
| ); | |
| })} | |
| </DropdownMenu.Content> | |
| {/* Selected chips */} | |
| {value.length > 0 && ( | |
| <div className="flex flex-wrap gap-1 mt-2"> | |
| {value.map((v) => ( | |
| <Badge | |
| key={v} | |
| variant="secondary" | |
| className="flex items-center gap-1" | |
| > | |
| {v} | |
| <X className="h-3 w-3 cursor-pointer" onClick={() => toggle(v)} /> | |
| </Badge> | |
| ))} | |
| </div> | |
| )} | |
| </DropdownMenu.Root> | |
| ); | |
| }; | |