Skip to content

Commit f3cd73c

Browse files
feat(filtering, autocomplete functionality , along with selecting an object): autocomplete works
We added filtering, user can select an option, and it reflects that in the input
1 parent 593aa80 commit f3cd73c

File tree

2 files changed

+156
-9
lines changed

2 files changed

+156
-9
lines changed

packages/kit-headless/src/components/Autocomplete/autocomplete.stories.tsx

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Meta, StoryObj } from 'storybook-framework-qwik';
22
import { userEvent, within } from '@storybook/testing-library';
33
import { expect } from '@storybook/jest';
4-
import { Test } from './autocomplete';
54

65
/*
76
@@ -10,6 +9,88 @@ import { Test } from './autocomplete';
109
1110
*/
1211

12+
const fruits = [
13+
'Apple',
14+
'Apricot',
15+
'Avocado 🥑',
16+
'Banana',
17+
'Bilberry',
18+
'Blackberry',
19+
'Blackcurrant',
20+
'Blueberry',
21+
'Boysenberry',
22+
'Currant',
23+
'Cherry',
24+
'Coconut',
25+
'Cranberry',
26+
'Cucumber',
27+
'Custard apple',
28+
'Damson',
29+
'Date',
30+
'Dragonfruit',
31+
'Durian',
32+
'Elderberry',
33+
'Feijoa',
34+
'Fig',
35+
'Gooseberry',
36+
'Grape',
37+
'Raisin',
38+
'Grapefruit',
39+
'Guava',
40+
'Honeyberry',
41+
'Huckleberry',
42+
'Jabuticaba',
43+
'Jackfruit',
44+
'Jambul',
45+
'Juniper berry',
46+
'Kiwifruit',
47+
'Kumquat',
48+
'Lemon',
49+
'Lime',
50+
'Loquat',
51+
'Longan',
52+
'Lychee',
53+
'Mango',
54+
'Mangosteen',
55+
'Marionberry',
56+
'Melon',
57+
'Cantaloupe',
58+
'Honeydew',
59+
'Watermelon',
60+
'Miracle fruit',
61+
'Mulberry',
62+
'Nectarine',
63+
'Nance',
64+
'Olive',
65+
'Orange',
66+
'Clementine',
67+
'Mandarine',
68+
'Tangerine',
69+
'Papaya',
70+
'Passionfruit',
71+
'Peach',
72+
'Pear',
73+
'Persimmon',
74+
'Plantain',
75+
'Plum',
76+
'Pineapple',
77+
'Pomegranate',
78+
'Pomelo',
79+
'Quince',
80+
'Raspberry',
81+
'Salmonberry',
82+
'Rambutan',
83+
'Redcurrant',
84+
'Salak',
85+
'Satsuma',
86+
'Soursop',
87+
'Star fruit',
88+
'Strawberry',
89+
'Tamarillo',
90+
'Tamarind',
91+
'Yuzu',
92+
];
93+
1394
import {
1495
AutocompleteRoot,
1596
AutocompleteLabel,
@@ -34,7 +115,7 @@ const RegularAutocomplete = () => (
34115
<AutocompleteRoot>
35116
<AutocompleteTrigger>
36117
<AutocompleteInput />
37-
<AutocompleteButton class="test" onClick$={() => console.log('hi')}>
118+
<AutocompleteButton>
38119
<svg
39120
xmlns="http://www.w3.org/2000/svg"
40121
viewBox="0 0 24 24"
@@ -50,9 +131,11 @@ const RegularAutocomplete = () => (
50131
</AutocompleteButton>
51132
</AutocompleteTrigger>
52133
<AutocompleteListbox>
53-
<AutocompleteOption>Option 1</AutocompleteOption>
54-
<AutocompleteOption>Option 2</AutocompleteOption>
55-
<AutocompleteOption>Option 3</AutocompleteOption>
134+
{fruits.map((fruit, index) => (
135+
<AutocompleteOption optionValue={fruit} key={index}>
136+
{fruit}
137+
</AutocompleteOption>
138+
))}
56139
</AutocompleteListbox>
57140
</AutocompleteRoot>
58141
</>

packages/kit-headless/src/components/Autocomplete/autocomplete.tsx

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import {
55
useContextProvider,
66
createContextId,
77
useSignal,
8-
Signal,
8+
type Signal,
99
QwikIntrinsicElements,
1010
useStore,
1111
useVisibleTask$,
12+
useTask$,
1213
$,
1314
useStylesScoped$,
1415
} from '@builder.io/qwik';
16+
import { routeAction$ } from '@builder.io/qwik-city';
1517

1618
import { computePosition, flip } from '@floating-ui/dom';
1719

@@ -103,6 +105,18 @@ import { computePosition, flip } from '@floating-ui/dom';
103105
Compute position & our triggerRef is what determines what is anchored with floating UI.
104106
https://floating-ui.com/docs/computePosition
105107
108+
109+
Autocomplete implementation:
110+
- grab reference to input box and listbox
111+
- search function that has an array of results, returns results
112+
- searchHandler function
113+
- sets input signal as whatever is in the text box
114+
- sets results to empty array
115+
- if input is not empty set results equal to the search function with our input signal value as param
116+
- showSuggestions function with results and our input signal value as params
117+
-
118+
119+
106120
*/
107121

108122
// Taken similar props from select + input Value
@@ -230,8 +244,45 @@ export type InputProps = QwikIntrinsicElements['input'];
230244

231245
// Add required context here
232246
export const AutocompleteInput = component$((props: InputProps) => {
247+
const ref = useSignal<HTMLElement>();
248+
const contextService = useContext(AutocompleteContextId);
233249
// required prop here
234-
return <input id="autocomplete-test" role="combobox" {...props} />;
250+
251+
useVisibleTask$(({ track }) => {
252+
track(() => contextService.inputValue.value);
253+
254+
if (
255+
contextService.inputValue.value.length > 0 &&
256+
document.activeElement === ref.value
257+
) {
258+
contextService.isExpanded.value = true;
259+
}
260+
261+
// Probably better to refactor Signal type later
262+
contextService.options.map((option: Signal) => {
263+
if (
264+
!option.value
265+
?.getAttribute('optionValue')
266+
?.match(contextService.inputValue.value)
267+
) {
268+
option.value.style.display = 'none';
269+
} else {
270+
option.value.style.display = '';
271+
}
272+
});
273+
274+
console.log(contextService.inputValue.value);
275+
});
276+
277+
return (
278+
<input
279+
ref={ref}
280+
id="autocomplete-test"
281+
role="combobox"
282+
bind:value={contextService.inputValue}
283+
{...props}
284+
/>
285+
);
235286
});
236287

237288
export type ButtonProps = QwikIntrinsicElements['button'];
@@ -281,6 +332,7 @@ export const AutocompleteListbox = component$((props: ListboxProps) => {
281332
const ref = useSignal<HTMLElement>();
282333
const contextService = useContext(AutocompleteContextId);
283334
contextService.listBoxRef = ref;
335+
284336
return (
285337
<ul
286338
ref={ref}
@@ -297,11 +349,23 @@ export const AutocompleteListbox = component$((props: ListboxProps) => {
297349
);
298350
});
299351

300-
export type OptionProps = QwikIntrinsicElements['li'];
352+
export type OptionProps = { optionValue: string } & QwikIntrinsicElements['li'];
301353

302354
export const AutocompleteOption = component$((props: OptionProps) => {
355+
const ref = useSignal<HTMLElement>();
356+
const contextService = useContext(AutocompleteContextId);
357+
contextService.options = [...contextService.options, ref];
358+
303359
return (
304-
<li role="option" {...props}>
360+
<li
361+
ref={ref}
362+
role="option"
363+
onClick$={() => {
364+
contextService.inputValue.value = props.optionValue;
365+
contextService.isExpanded.value = false;
366+
}}
367+
{...props}
368+
>
305369
<Slot />
306370
</li>
307371
);

0 commit comments

Comments
 (0)