@@ -5,13 +5,15 @@ import {
5
5
useContextProvider ,
6
6
createContextId ,
7
7
useSignal ,
8
- Signal ,
8
+ type Signal ,
9
9
QwikIntrinsicElements ,
10
10
useStore ,
11
11
useVisibleTask$ ,
12
+ useTask$ ,
12
13
$ ,
13
14
useStylesScoped$ ,
14
15
} from '@builder.io/qwik' ;
16
+ import { routeAction$ } from '@builder.io/qwik-city' ;
15
17
16
18
import { computePosition , flip } from '@floating-ui/dom' ;
17
19
@@ -103,6 +105,18 @@ import { computePosition, flip } from '@floating-ui/dom';
103
105
Compute position & our triggerRef is what determines what is anchored with floating UI.
104
106
https://floating-ui.com/docs/computePosition
105
107
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
+
106
120
*/
107
121
108
122
// Taken similar props from select + input Value
@@ -230,8 +244,45 @@ export type InputProps = QwikIntrinsicElements['input'];
230
244
231
245
// Add required context here
232
246
export const AutocompleteInput = component$ ( ( props : InputProps ) => {
247
+ const ref = useSignal < HTMLElement > ( ) ;
248
+ const contextService = useContext ( AutocompleteContextId ) ;
233
249
// 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
+ ) ;
235
286
} ) ;
236
287
237
288
export type ButtonProps = QwikIntrinsicElements [ 'button' ] ;
@@ -281,6 +332,7 @@ export const AutocompleteListbox = component$((props: ListboxProps) => {
281
332
const ref = useSignal < HTMLElement > ( ) ;
282
333
const contextService = useContext ( AutocompleteContextId ) ;
283
334
contextService . listBoxRef = ref ;
335
+
284
336
return (
285
337
< ul
286
338
ref = { ref }
@@ -297,11 +349,23 @@ export const AutocompleteListbox = component$((props: ListboxProps) => {
297
349
) ;
298
350
} ) ;
299
351
300
- export type OptionProps = QwikIntrinsicElements [ 'li' ] ;
352
+ export type OptionProps = { optionValue : string } & QwikIntrinsicElements [ 'li' ] ;
301
353
302
354
export const AutocompleteOption = component$ ( ( props : OptionProps ) => {
355
+ const ref = useSignal < HTMLElement > ( ) ;
356
+ const contextService = useContext ( AutocompleteContextId ) ;
357
+ contextService . options = [ ...contextService . options , ref ] ;
358
+
303
359
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
+ >
305
369
< Slot />
306
370
</ li >
307
371
) ;
0 commit comments