1- import { type JSXNode , Component } from '@builder.io/qwik' ;
1+ import { Component , JSXChildren } from '@builder.io/qwik' ;
22import { HComboboxRootImpl , HComboboxRootImplProps } from './combobox-root' ;
33import { HComboboxItem as InternalComboboxItem } from './combobox-item' ;
44import { HComboboxItemLabel as InternalComboboxItemLabel } from './combobox-item-label' ;
55import { HComboboxEmpty as InternalComboboxEmpty } from './combobox-empty' ;
66import { HComboboxErrorMessage } from './combobox-error-message' ;
7+ import { findComponent , processChildren } from '../../utils/inline-component' ;
78
89export type TItemsMap = Map <
910 number ,
@@ -13,8 +14,8 @@ export type TItemsMap = Map<
1314export type InternalComboboxProps = {
1415 /** When a value is passed, we check if it's an actual item value, and get its index at pre-render time.
1516 **/
16- _valuePropIndex ?: number | null ;
17- _value ?: string ;
17+ initialIndex ?: number | null ;
18+ initialValue ?: string ;
1819
1920 /** Checks if the consumer added the label in their JSX */
2021 _label ?: boolean ;
@@ -35,7 +36,7 @@ export const HComboboxRoot: Component<InternalComboboxProps & HComboboxRootImplP
3536 props : InternalComboboxProps & HComboboxRootImplProps ,
3637) => {
3738 const {
38- children : myChildren ,
39+ children,
3940 comboboxItemComponent : UserItem ,
4041 comboboxItemLabelComponent : UserItemLabel ,
4142 ...rest
@@ -47,121 +48,87 @@ export const HComboboxRoot: Component<InternalComboboxProps & HComboboxRootImplP
4748
4849 // source of truth
4950 const itemsMap = new Map ( ) ;
51+
5052 let currItemIndex = 0 ;
53+ let initialIndex = null ;
54+ let initialValue ;
55+
5156 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+
5561 let hasEmptyComp = false ;
5662 let hasErrorComp = false ;
5763
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 ;
6181
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 ;
6484
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+ ) ;
6791 }
6892
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 ;
7298 }
7399
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+ ) ;
152106 }
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 ) ;
154121
155122 return (
156123 < HComboboxRootImpl
157124 { ...rest }
158- _valuePropIndex = { valuePropIndex }
159- _value = { _value }
125+ initialIndex = { initialIndex }
126+ initialValue = { initialValue }
160127 _itemsMap = { itemsMap }
161128 hasEmptyComp = { hasEmptyComp }
162129 hasErrorComp = { hasErrorComp }
163130 >
164- { props . children }
131+ { children }
165132 </ HComboboxRootImpl >
166133 ) ;
167134} ;
0 commit comments