'use client' import { useState } from 'react' import { Combobox as HeadlessCombobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Label, } from '@headlessui/react' import { ChevronDownIcon, UserIcon } from '@heroicons/react/20/solid' export type ComboboxVariant = 'simple' | 'status' | 'image' | 'secondary' export type ComboboxItem = { id: string | number | null name: string online?: boolean imageUrl?: string secondaryText?: string username?: string } type ComboboxProps = { label?: string items: ComboboxItem[] value: ComboboxItem | null onChange: (item: ComboboxItem | null) => void variant?: ComboboxVariant placeholder?: string allowCustomValue?: boolean createOptionLabel?: (value: string) => string emptyText?: string disabled?: boolean required?: boolean className?: string inputClassName?: string } function classNames(...classes: Array) { return classes.filter(Boolean).join(' ') } function getSecondaryText(item: ComboboxItem) { return item.secondaryText ?? item.username } export default function Combobox({ label, items, value, onChange, variant = 'simple', placeholder, allowCustomValue = false, createOptionLabel, emptyText = 'Keine Ergebnisse gefunden.', disabled = false, required = false, className, inputClassName, }: ComboboxProps) { const [query, setQuery] = useState('') const normalizedQuery = query.trim().toLowerCase() const filteredItems = normalizedQuery === '' ? items : items.filter((item) => { const secondaryText = getSecondaryText(item) return ( item.name.toLowerCase().includes(normalizedQuery) || secondaryText?.toLowerCase().includes(normalizedQuery) ) }) function renderOptionContent(item: ComboboxItem, isCustomValue = false) { if (variant === 'status') { return (
) } if (variant === 'image') { return (
{item.imageUrl ? ( ) : (
)} {item.name}
) } if (variant === 'secondary') { const secondaryText = getSecondaryText(item) return (
{item.name} {secondaryText && ( {secondaryText} )}
) } return {item.name} } return ( { setQuery('') onChange(item) }} disabled={disabled} className={className} > {label && ( )}
setQuery(event.target.value)} onBlur={() => setQuery('')} displayValue={(item: ComboboxItem | null) => item?.name ?? ''} /> {allowCustomValue && query.trim().length > 0 && ( {renderOptionContent( { id: null, name: createOptionLabel ? createOptionLabel(query.trim()) : query.trim(), }, true, )} )} {filteredItems.map((item) => ( {renderOptionContent(item)} ))} {filteredItems.length === 0 && !allowCustomValue && (
{emptyText}
)}
) }