Skip to content

Commit 43cb309

Browse files
committed
chore(combobox): optimize filtering
1 parent 956e2f2 commit 43cb309

File tree

2 files changed

+17
-11
lines changed
  • apps/website/src/routes/docs/headless/(components)/combobox
  • packages/kit-headless/src/components/combobox

2 files changed

+17
-11
lines changed

apps/website/src/routes/docs/headless/(components)/combobox/examples.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ export const StringCombobox = component$(() => {
131131
return (
132132
<PreviewCodeExample>
133133
<div class="flex flex-col gap-4" q:slot="actualComponent">
134+
<div>
135+
This uses a custom filter to only filter from the beginning of the options.
136+
</div>
134137
<Combobox
135138
options={fruitsSig.value}
136139
defaultLabel="Currant"

packages/kit-headless/src/components/combobox/combobox.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ import {
88
useId,
99
useSignal,
1010
useTask$,
11+
useComputed$,
1112
} from '@builder.io/qwik';
13+
import { JSX } from '@builder.io/qwik/jsx-runtime';
14+
import ComboboxContextId from './combobox-context-id';
15+
import { ComboboxContext } from './combobox-context.type';
16+
import { getOptionLabel } from './utils';
1217

1318
import { type Option } from './combobox-context.type';
1419

20+
type QrlType<T> = T extends QRL<infer U> ? U : never;
21+
1522
export type ComboboxProps<
1623
O extends Option = Option,
1724
Complex extends { option: O; key: number } = { option: O; key: number },
@@ -43,11 +50,6 @@ export type OptionInfo = {
4350
index: number;
4451
};
4552

46-
import ComboboxContextId from './combobox-context-id';
47-
import { ComboboxContext } from './combobox-context.type';
48-
import { JSX } from '@builder.io/qwik/jsx-runtime';
49-
import { getOptionLabel } from './utils';
50-
5153
export const Combobox = component$(
5254
<
5355
O extends Option = Option,
@@ -69,22 +71,23 @@ export const Combobox = component$(
6971
...rest
7072
} = props;
7173

74+
const complexSig = useComputed$(() =>
75+
options.map((option, key) => ({ option, key } as Complex)),
76+
);
7277
const optionsSig = useSignal<Complex[]>([]);
7378
const inputValueSig = useSignal<string>(defaultLabel);
7479
useTask$(async ({ track }) => {
75-
// TODO track in separate signal to prevent copying on every key
76-
const opts = track(() =>
77-
options.map((option, key) => ({ option, key } as Complex)),
78-
);
80+
const opts = track(() => complexSig.value);
7981
const inputValue = track(() => inputValueSig.value);
80-
81-
let filterFunction = await track(() => filter$)?.resolve();
82+
let filterFunction: QrlType<ComboboxProps<O, Complex>['filter$']> | undefined =
83+
await track(() => filter$)?.resolve();
8284

8385
if (!filterFunction) {
8486
const labelKey = track(() => optionLabelKey);
8587

8688
filterFunction = (value: string, options: Complex[]) => {
8789
if (!options) return [];
90+
if (!value) return options;
8891
return options.filter(({ option }) => {
8992
if (typeof option === 'string')
9093
return option.toLowerCase().includes(value.toLowerCase());

0 commit comments

Comments
 (0)