feat: enhance Combobox component with multi-select filtering and grouped item handling
This commit is contained in:
parent
8f9eb5f77a
commit
aa47ec494e
@ -13,7 +13,58 @@ import {
|
||||
InputGroupInput,
|
||||
} from "@/components/ui/input-group"
|
||||
|
||||
const Combobox = ComboboxPrimitive.Root
|
||||
function isGroupedItems(
|
||||
items: readonly unknown[]
|
||||
): items is ReadonlyArray<{ items: readonly unknown[] }> {
|
||||
return (
|
||||
items.length > 0 &&
|
||||
typeof items[0] === "object" &&
|
||||
items[0] !== null &&
|
||||
"items" in items[0]
|
||||
)
|
||||
}
|
||||
|
||||
function Combobox<Value, Multiple extends boolean | undefined = false>({
|
||||
items,
|
||||
multiple,
|
||||
value,
|
||||
isItemEqualToValue,
|
||||
...props
|
||||
}: ComboboxPrimitive.Root.Props<Value, Multiple>) {
|
||||
// In multi-select mode, once an option is chosen it's represented as a
|
||||
// chip, so it's removed from the dropdown list instead of staying there
|
||||
// with a checkmark.
|
||||
const filteredItems = React.useMemo(() => {
|
||||
if (!multiple || !items) return items
|
||||
|
||||
const selected = value as unknown as Value[] | null | undefined
|
||||
if (!Array.isArray(selected) || selected.length === 0) return items
|
||||
|
||||
const isEqual =
|
||||
isItemEqualToValue ?? ((a: Value, b: Value) => Object.is(a, b))
|
||||
const isNotSelected = (item: Value) =>
|
||||
!selected.some((selectedValue) => isEqual(item, selectedValue))
|
||||
|
||||
if (isGroupedItems(items)) {
|
||||
return items.map((group) => ({
|
||||
...group,
|
||||
items: group.items.filter((item) => isNotSelected(item as Value)),
|
||||
}))
|
||||
}
|
||||
|
||||
return (items as readonly Value[]).filter(isNotSelected)
|
||||
}, [items, multiple, value, isItemEqualToValue])
|
||||
|
||||
return (
|
||||
<ComboboxPrimitive.Root
|
||||
items={filteredItems}
|
||||
multiple={multiple}
|
||||
value={value}
|
||||
isItemEqualToValue={isItemEqualToValue}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
|
||||
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user