koperasi/services/frontend/app/components/ui/combobox.tsx
2025-08-08 14:12:40 +07:00

92 lines
2.6 KiB
TypeScript

import { Check, ChevronsUpDown } from "lucide-react";
import * as React from "react";
import { Button } from "~/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "~/components/ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
import { cn } from "~/lib/clsx";
export interface ComboboxItem {
value: string;
label: string;
}
interface ComboboxProps {
items: ComboboxItem[];
placeholder?: string;
searchPlaceholder?: string;
buttonClassName?: string;
onValueChange?: (value: string) => void;
defaultValue?: string;
}
export function Combobox({
items,
placeholder = "Pilih salah satu...",
searchPlaceholder = "Cari opsi...",
buttonClassName = "w-[200px]",
onValueChange,
defaultValue = "",
}: ComboboxProps) {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState(defaultValue);
const handleSelect = (currentValue: string) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
if (onValueChange) {
onValueChange(currentValue === value ? "" : currentValue);
}
};
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className={cn(
"justify-between overflow-hidden font-normal text-gray-600",
buttonClassName,
)}
>
{value ? items.find((item) => item.value === value)?.label : placeholder}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className={cn("p-0", buttonClassName)}>
<Command className="w-full">
<CommandInput placeholder={searchPlaceholder} />
<CommandList>
<CommandEmpty>Tidak ada item yang ditemukan.</CommandEmpty>
<CommandGroup>
{items.map((item) => (
<CommandItem
key={item.value}
value={item.label}
onSelect={() => handleSelect(item.value)}
>
<Check
className={cn(
"mr-2 h-4 w-4",
value === item.value ? "opacity-100" : "opacity-0",
)}
/>
{item.label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}