This commit is contained in:
2026-02-16 19:34:35 +00:00
commit 9ab0940ca4
784 changed files with 41710 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
import type { SelectOption } from 'types';
import * as React from 'react';
import { useNavigate } from 'react-router';
import { cn } from 'helpers/cn';
import { Check, ChevronsUpDown } from 'lucide-react';
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 { Separator } from '@/components/ui/separator';
type ComboboxProps<T> = {
options: SelectOption[];
value: string | number;
onChange: (value: T) => void;
placeholder?: string;
className?: string;
};
export const Combobox = <T extends string | number>({
options,
value,
onChange,
placeholder = 'Select...',
className,
}: ComboboxProps<T>) => {
const navigate = useNavigate();
const [open, setOpen] = React.useState(false);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className={cn('w-[200px] justify-between', className)}
>
<span className="block truncate">
{value ? options?.find((option) => option.value === value)?.label : placeholder}
</span>
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className={cn('w-[200px] justify-between', className)}>
<Command>
<CommandInput placeholder={placeholder} />
<CommandEmpty></CommandEmpty>
<CommandGroup className="max-h-96 overflow-auto">
{options?.map((option) => (
<div key={option.value}>
<CommandItem
value={option?.label || '' + option.value}
onSelect={(currentValue) => {
if (option.href) {
return navigate(option.href);
}
const newValue = options.find(
(option) => option.label?.toLowerCase() === currentValue.toLowerCase(),
)?.value;
if (value && value !== newValue) {
const setValue = typeof value === 'number' ? Number(newValue) : '' + newValue;
onChange(setValue as T);
}
setOpen(false);
}}
>
<Check className={cn('mr-2 h-4 w-4', value === option.value ? 'opacity-100' : 'opacity-0')} />
{option.label}
</CommandItem>
{option.href && <Separator className="my-2" />}
</div>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
);
};