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,
|
InputGroupInput,
|
||||||
} from "@/components/ui/input-group"
|
} 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) {
|
function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
|
||||||
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
|
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user