ui/multisearch: make controlled for now

This commit is contained in:
Johannes Kirschbauer
2025-08-28 22:36:21 +02:00
parent 278af5f0f4
commit fc5b0e4113

View File

@@ -2,7 +2,15 @@ import Icon from "../Icon/Icon";
import { Button } from "../Button/Button"; import { Button } from "../Button/Button";
import styles from "./Search.module.css"; import styles from "./Search.module.css";
import { Combobox } from "@kobalte/core/combobox"; import { Combobox } from "@kobalte/core/combobox";
import { createMemo, createSignal, For, JSX, Match, Switch } from "solid-js"; import {
createEffect,
createMemo,
createSignal,
For,
JSX,
Match,
Switch,
} from "solid-js";
import { createVirtualizer, VirtualizerOptions } from "@tanstack/solid-virtual"; import { createVirtualizer, VirtualizerOptions } from "@tanstack/solid-virtual";
import { CollectionNode } from "@kobalte/core/*"; import { CollectionNode } from "@kobalte/core/*";
import cx from "classnames"; import cx from "classnames";
@@ -11,13 +19,16 @@ import { Loader } from "../Loader/Loader";
export interface Option { export interface Option {
value: string; value: string;
label: string; label: string;
disabled?: boolean;
} }
export interface ItemRenderOptions { export interface ItemRenderOptions {
selected: boolean; selected: boolean;
disabled: boolean;
} }
export interface SearchMultipleProps<T> { export interface SearchMultipleProps<T> {
values: T[]; // controlled values
onChange: (values: T[]) => void; onChange: (values: T[]) => void;
options: T[]; options: T[];
renderItem: (item: T, opts: ItemRenderOptions) => JSX.Element; renderItem: (item: T, opts: ItemRenderOptions) => JSX.Element;
@@ -29,12 +40,13 @@ export interface SearchMultipleProps<T> {
headerChildren?: JSX.Element; headerChildren?: JSX.Element;
loading?: boolean; loading?: boolean;
loadingComponent?: JSX.Element; loadingComponent?: JSX.Element;
divider?: boolean;
} }
export function SearchMultiple<T extends Option>( export function SearchMultiple<T extends Option>(
props: SearchMultipleProps<T>, props: SearchMultipleProps<T>,
) { ) {
// Controlled input value, to allow resetting the input itself // Controlled input value, to allow resetting the input itself
const [values, setValues] = createSignal<T[]>(props.initialValues || []); // const [values, setValues] = createSignal<T[]>(props.initialValues || []);
const [inputValue, setInputValue] = createSignal<string>(""); const [inputValue, setInputValue] = createSignal<string>("");
let inputEl: HTMLInputElement; let inputEl: HTMLInputElement;
@@ -60,21 +72,23 @@ export function SearchMultiple<T extends Option>(
return item?.rawValue?.value || `item-${index}`; return item?.rawValue?.value || `item-${index}`;
}, },
estimateSize: () => 42, estimateSize: () => 42,
gap: 6, gap: 0,
overscan: 5, overscan: 5,
...props.virtualizerOptions, ...props.virtualizerOptions,
}); });
return newVirtualizer; return newVirtualizer;
}); });
createEffect(() => {
console.log("multi values:", props.values);
});
return ( return (
<Combobox<T> <Combobox<T>
multiple multiple
value={values()} value={props.values}
onChange={(values) => { onChange={(values) => {
setValues(() => values); // setValues(() => values);
// setInputValue(value ? value.label : ""); console.log("onChange", values);
props.onChange(values); props.onChange(values);
}} }}
class={styles.searchContainer} class={styles.searchContainer}
@@ -83,6 +97,7 @@ export function SearchMultiple<T extends Option>(
optionValue="value" optionValue="value"
optionTextValue="label" optionTextValue="label"
optionLabel="label" optionLabel="label"
optionDisabled={"disabled"}
sameWidth={true} sameWidth={true}
open={true} open={true}
gutter={7} gutter={7}
@@ -183,11 +198,16 @@ export function SearchMultiple<T extends Option>(
return null; return null;
} }
const isSelected = () => const isSelected = () =>
values().some((v) => v.value === item.rawValue.value); props.values.some(
(v) => v.value === item.rawValue.value,
);
return ( return (
<Combobox.Item <Combobox.Item
item={item} item={item}
class={styles.searchItem} class={cx(
styles.searchItem,
props.divider && styles.hasDivider,
)}
style={{ style={{
position: "absolute", position: "absolute",
top: 0, top: 0,
@@ -199,6 +219,7 @@ export function SearchMultiple<T extends Option>(
> >
{props.renderItem(item.rawValue, { {props.renderItem(item.rawValue, {
selected: isSelected(), selected: isSelected(),
disabled: item.disabled,
})} })}
</Combobox.Item> </Combobox.Item>
); );