1
- import { type JSXNode , Component } from '@builder.io/qwik' ;
1
+ import { Component , JSXChildren } from '@builder.io/qwik' ;
2
2
import { HComboboxRootImpl , HComboboxRootImplProps } from './combobox-root' ;
3
3
import { HComboboxItem as InternalComboboxItem } from './combobox-item' ;
4
4
import { HComboboxItemLabel as InternalComboboxItemLabel } from './combobox-item-label' ;
5
5
import { HComboboxEmpty as InternalComboboxEmpty } from './combobox-empty' ;
6
6
import { HComboboxErrorMessage } from './combobox-error-message' ;
7
+ import { findComponent , processChildren } from '../../utils/inline-component' ;
7
8
8
9
export type TItemsMap = Map <
9
10
number ,
@@ -13,8 +14,8 @@ export type TItemsMap = Map<
13
14
export type InternalComboboxProps = {
14
15
/** When a value is passed, we check if it's an actual item value, and get its index at pre-render time.
15
16
**/
16
- _valuePropIndex ?: number | null ;
17
- _value ?: string ;
17
+ initialIndex ?: number | null ;
18
+ initialValue ?: string ;
18
19
19
20
/** Checks if the consumer added the label in their JSX */
20
21
_label ?: boolean ;
@@ -35,7 +36,7 @@ export const HComboboxRoot: Component<InternalComboboxProps & HComboboxRootImplP
35
36
props : InternalComboboxProps & HComboboxRootImplProps ,
36
37
) => {
37
38
const {
38
- children : myChildren ,
39
+ children,
39
40
comboboxItemComponent : UserItem ,
40
41
comboboxItemLabelComponent : UserItemLabel ,
41
42
...rest
@@ -47,121 +48,87 @@ export const HComboboxRoot: Component<InternalComboboxProps & HComboboxRootImplP
47
48
48
49
// source of truth
49
50
const itemsMap = new Map ( ) ;
51
+
50
52
let currItemIndex = 0 ;
53
+ let initialIndex = null ;
54
+ let initialValue ;
55
+
51
56
let isItemDisabled = false ;
52
- let givenItemValue = null ;
53
- let valuePropIndex = null ;
54
- let _value ;
57
+
58
+ // user adds value prop on Item component
59
+ let givenItemValue : string | null = null ;
60
+
55
61
let hasEmptyComp = false ;
56
62
let hasErrorComp = false ;
57
63
58
- const childrenToProcess = (
59
- Array . isArray ( myChildren ) ? [ ...myChildren ] : [ myChildren ]
60
- ) as Array < JSXNode > ;
64
+ findComponent ( HComboboxItem , ( itemProps ) => {
65
+ itemProps . _index = currItemIndex ;
66
+
67
+ isItemDisabled = itemProps . disabled === true ;
68
+
69
+ if ( itemProps . value ) {
70
+ givenItemValue = itemProps . value as string ;
71
+ }
72
+
73
+ // the default case isn't handled here, so we need to process the children to get to the label component
74
+ if ( itemProps . children ) {
75
+ return processChildren ( itemProps . children as JSXChildren ) ;
76
+ }
77
+ } ) ;
78
+
79
+ findComponent ( HComboboxItemLabel , ( labelProps ) => {
80
+ const displayValue = labelProps . children as string ;
61
81
62
- while ( childrenToProcess . length ) {
63
- const child = childrenToProcess . shift ( ) ;
82
+ // distinct value, or the display value is the same as the value
83
+ const value = ( givenItemValue !== null ? givenItemValue : displayValue ) as string ;
64
84
65
- if ( ! child ) {
66
- continue ;
85
+ itemsMap . set ( currItemIndex , { value, displayValue, disabled : isItemDisabled } ) ;
86
+
87
+ if ( props . value && props . multiple ) {
88
+ throw new Error (
89
+ `Qwik UI: When in multiple selection mode, the value prop is disabled. Use the bind:value prop's initial signal value instead.` ,
90
+ ) ;
67
91
}
68
92
69
- if ( Array . isArray ( child ) ) {
70
- childrenToProcess . unshift ( ...child ) ;
71
- continue ;
93
+ // if the current option value is equal to the initial value
94
+ if ( value === props . value ) {
95
+ // minus one because it is incremented already in SelectOption
96
+ initialIndex = currItemIndex ;
97
+ initialValue = value ;
72
98
}
73
99
74
- switch ( child . type ) {
75
- case HComboboxItem : {
76
- // get the index of the current option
77
- child . props . _index = currItemIndex ;
78
-
79
- isItemDisabled = child . props . disabled === true ;
80
-
81
- if ( child . props . value ) {
82
- givenItemValue = child . props . value ;
83
- }
84
-
85
- // the default case isn't handled here, so we need to process the children to get to the label component
86
- if ( child . props . children ) {
87
- const childChildren = Array . isArray ( child . props . children )
88
- ? [ ...child . props . children ]
89
- : [ child . props . children ] ;
90
- childrenToProcess . unshift ( ...childChildren ) ;
91
- }
92
-
93
- break ;
94
- }
95
-
96
- case HComboboxItemLabel : {
97
- const displayValue = child . props . children as string ;
98
-
99
- // distinct value, or the display value is the same as the value
100
- const value = ( givenItemValue !== null ? givenItemValue : displayValue ) as string ;
101
-
102
- itemsMap . set ( currItemIndex , { value, displayValue, disabled : isItemDisabled } ) ;
103
-
104
- if ( props . value && props . multiple ) {
105
- throw new Error (
106
- `Qwik UI: When in multiple selection mode, the value prop is disabled. Use the bind:value prop's initial signal value instead.` ,
107
- ) ;
108
- }
109
-
110
- // if the current option value is equal to the initial value
111
- if ( value === props . value ) {
112
- // minus one because it is incremented already in SelectOption
113
- valuePropIndex = currItemIndex ;
114
- _value = value ;
115
- }
116
-
117
- const isString = typeof child . props . children === 'string' ;
118
-
119
- if ( ! isString ) {
120
- throw new Error (
121
- `Qwik UI: select item label passed was not a string. It was a ${ typeof child
122
- . props . children } .`,
123
- ) ;
124
- }
125
-
126
- // increment after processing children
127
- currItemIndex ++ ;
128
-
129
- break ;
130
- }
131
-
132
- case HComboboxEmpty : {
133
- hasEmptyComp = true ;
134
- break ;
135
- }
136
-
137
- case HComboboxErrorMessage : {
138
- hasErrorComp = true ;
139
- break ;
140
- }
141
-
142
- default : {
143
- if ( child ) {
144
- const anyChildren = Array . isArray ( child . children )
145
- ? [ ...child . children ]
146
- : [ child . children ] ;
147
- childrenToProcess . unshift ( ...( anyChildren as JSXNode [ ] ) ) ;
148
- }
149
-
150
- break ;
151
- }
100
+ const isString = typeof labelProps . children === 'string' ;
101
+
102
+ if ( ! isString ) {
103
+ throw new Error (
104
+ `Qwik UI: select item label passed was not a string. It was a ${ typeof labelProps . children } .` ,
105
+ ) ;
152
106
}
153
- }
107
+
108
+ // increment after processing children
109
+ currItemIndex ++ ;
110
+ } ) ;
111
+
112
+ findComponent ( HComboboxEmpty , ( ) => {
113
+ hasEmptyComp = true ;
114
+ } ) ;
115
+
116
+ findComponent ( HComboboxErrorMessage , ( ) => {
117
+ hasErrorComp = true ;
118
+ } ) ;
119
+
120
+ processChildren ( children ) ;
154
121
155
122
return (
156
123
< HComboboxRootImpl
157
124
{ ...rest }
158
- _valuePropIndex = { valuePropIndex }
159
- _value = { _value }
125
+ initialIndex = { initialIndex }
126
+ initialValue = { initialValue }
160
127
_itemsMap = { itemsMap }
161
128
hasEmptyComp = { hasEmptyComp }
162
129
hasErrorComp = { hasErrorComp }
163
130
>
164
- { props . children }
131
+ { children }
165
132
</ HComboboxRootImpl >
166
133
) ;
167
134
} ;
0 commit comments