Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { Check, ChevronsUpDown } 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"; | |
| export interface ComboboxOption { | |
| label: string; | |
| value: string; | |
| } | |
| interface ComboboxProps { | |
| options: ComboboxOption[]; | |
| value?: string; | |
| onValueChange?: (value: string) => void; | |
| placeholder?: string; | |
| emptyMessage?: string; | |
| className?: string; | |
| disabled?: boolean; | |
| searchPlaceholder?: string; | |
| } | |
| export function Combobox({ | |
| options, | |
| value, | |
| onValueChange, | |
| placeholder = "Select option...", | |
| emptyMessage = "No options found.", | |
| className, | |
| disabled = false, | |
| searchPlaceholder = "Search..." | |
| }: ComboboxProps) { | |
| const [open, setOpen] = React.useState(false); | |
| const selectedOption = options.find(option => option.value === value); | |
| return ( | |
| <div className="relative w-full"> | |
| <Popover open={open} onOpenChange={setOpen}> | |
| <PopoverTrigger asChild> | |
| <Button | |
| variant="outline" | |
| role="combobox" | |
| aria-expanded={open} | |
| className={cn("w-full justify-between", className)} | |
| disabled={disabled} | |
| > | |
| {selectedOption ? selectedOption.label : placeholder} | |
| <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> | |
| </Button> | |
| </PopoverTrigger> | |
| <PopoverContent className="w-full p-0" align="start"> | |
| <Command> | |
| <CommandInput placeholder={searchPlaceholder} /> | |
| <CommandEmpty>{emptyMessage}</CommandEmpty> | |
| <CommandGroup className="max-h-64 overflow-auto"> | |
| {options.map((option) => ( | |
| <CommandItem | |
| key={option.value} | |
| value={option.value} | |
| onSelect={() => { | |
| onValueChange?.(option.value); | |
| setOpen(false); | |
| }} | |
| > | |
| <Check | |
| className={cn( | |
| "mr-2 h-4 w-4", | |
| value === option.value ? "opacity-100" : "opacity-0" | |
| )} | |
| /> | |
| {option.label} | |
| </CommandItem> | |
| ))} | |
| </CommandGroup> | |
| </Command> | |
| </PopoverContent> | |
| </Popover> | |
| </div> | |
| ); | |
| } |