import * as React from 'react'; import { Badge } from '@/components/ui/badge'; import { Command, CommandGroup, CommandInput, CommandItem, CommandList, } from '@/components/ui/command'; import { ChevronsUpDownIcon } from 'lucide-react'; import { useOnClickOutside } from 'usehooks-ts'; import { Button } from './button'; import { Checkbox } from './checkbox'; import { Popover, PopoverContent, PopoverTrigger } from './popover'; type IValue = any; type IItem = Record<'value' | 'label', IValue>; interface ComboboxAdvancedProps { value: IValue[]; onChange: React.Dispatch>; items: IItem[]; placeholder: string; className?: string; } export function ComboboxAdvanced({ items, value, onChange, placeholder, className, }: ComboboxAdvancedProps) { const [open, setOpen] = React.useState(false); const [inputValue, setInputValue] = React.useState(''); const ref = React.useRef(null); useOnClickOutside(ref, () => setOpen(false)); const selectables = items .filter((item) => !value.find((s) => s === item.value)) .filter( (item) => (typeof item.label === 'string' && item.label.toLowerCase().includes(inputValue.toLowerCase())) || (typeof item.value === 'string' && item.value.toLowerCase().includes(inputValue.toLowerCase())) ); const renderItem = (item: IItem) => { const checked = !!value.find((s) => s === item.value); return ( { e.preventDefault(); e.stopPropagation(); }} onSelect={() => { setInputValue(''); onChange((prev) => { if (prev.includes(item.value)) { return prev.filter((s) => s !== item.value); } return [...prev, item.value]; }); }} className={'cursor-pointer flex items-center gap-2'} > {item?.label ?? item?.value} ); }; const renderUnknownItem = (value: IValue) => { const item = items.find((item) => item.value === value); return item ? renderItem(item) : renderItem({ value, label: value }); }; return ( {inputValue !== '' && renderItem({ value: inputValue, label: `Pick '${inputValue}'`, })} {value.map(renderUnknownItem)} {selectables.map(renderItem)} ); }