@@ -39,14 +39,15 @@ import {
3939 QBackRefs ,
4040 QContainerAttr ,
4141 QDefaultSlot ,
42+ QScopedStyle ,
4243 QSlot ,
4344 QTemplate ,
4445 Q_PREFIX ,
4546 dangerouslySetInnerHTML ,
4647} from '../shared/utils/markers' ;
47- import { isPromise } from '../shared/utils/promises' ;
48+ import { isPromise , retryOnPromise } from '../shared/utils/promises' ;
4849import { isSlotProp } from '../shared/utils/prop' ;
49- import { hasClassAttr } from '../shared/utils/scoped-styles' ;
50+ import { addComponentStylePrefix , hasClassAttr } from '../shared/utils/scoped-styles' ;
5051import { serializeAttribute } from '../shared/utils/styles' ;
5152import { isArray , type ValueOrPromise } from '../shared/utils/types' ;
5253import { trackSignalAndAssignHost } from '../use/use-core' ;
@@ -182,19 +183,24 @@ export const vnode_diff = (
182183 EffectSubscriptionProp . CONSUMER
183184 ] ;
184185 if ( currentSignal !== unwrappedSignal ) {
186+ const vHost = ( vNewNode || vCurrent ) ! ;
185187 descend (
186- trackSignalAndAssignHost (
187- unwrappedSignal ,
188- ( vNewNode || vCurrent ) ! ,
189- EffectProperty . VNODE ,
190- container
188+ resolveSignalAndDescend (
189+ retryOnPromise ( ( ) =>
190+ trackSignalAndAssignHost (
191+ unwrappedSignal ,
192+ vHost ,
193+ EffectProperty . VNODE ,
194+ container
195+ )
196+ )
191197 ) ,
192198 true
193199 ) ;
194200 }
195201 } else if ( isPromise ( jsxValue ) ) {
196202 expectVirtual ( VirtualType . Awaited , null ) ;
197- asyncQueue . push ( jsxValue , vNewNode || vCurrent ) ;
203+ asyncQueue . push ( jsxValue , vNewNode || vCurrent , null ) ;
198204 } else if ( isJSXNode ( jsxValue ) ) {
199205 const type = jsxValue . type ;
200206 if ( typeof type === 'string' ) {
@@ -246,6 +252,14 @@ export const vnode_diff = (
246252 }
247253 }
248254
255+ function resolveSignalAndDescend ( value : any ) {
256+ if ( isPromise ( value ) ) {
257+ asyncQueue . push ( value , vNewNode || vCurrent , null ) ;
258+ return null ;
259+ }
260+ return value ;
261+ }
262+
249263 function advance ( ) {
250264 if ( ! shouldAdvance ) {
251265 shouldAdvance = true ;
@@ -532,13 +546,27 @@ export const vnode_diff = (
532546 while ( asyncQueue . length ) {
533547 const jsxNode = asyncQueue . shift ( ) as ValueOrPromise < JSXNodeInternal > ;
534548 const vHostNode = asyncQueue . shift ( ) as VNode ;
549+ const styleScopedId = asyncQueue . shift ( ) as string | null ;
535550 if ( isPromise ( jsxNode ) ) {
536- return jsxNode . then ( ( jsxNode ) => {
537- diff ( jsxNode , vHostNode ) ;
538- return drainAsyncQueue ( ) ;
539- } ) ;
551+ return jsxNode
552+ . then ( ( jsxNode ) => {
553+ if ( styleScopedId ) {
554+ vnode_diff ( container , jsxNode , vHostNode , addComponentStylePrefix ( styleScopedId ) ) ;
555+ } else {
556+ diff ( jsxNode , vHostNode ) ;
557+ }
558+ return drainAsyncQueue ( ) ;
559+ } )
560+ . catch ( ( e ) => {
561+ container . handleError ( e , vHostNode ) ;
562+ return drainAsyncQueue ( ) ;
563+ } ) ;
540564 } else {
541- diff ( jsxNode , vHostNode ) ;
565+ if ( styleScopedId ) {
566+ vnode_diff ( container , jsxNode , vHostNode , addComponentStylePrefix ( styleScopedId ) ) ;
567+ } else {
568+ diff ( jsxNode , vHostNode ) ;
569+ }
542570 }
543571 }
544572 }
@@ -594,6 +622,21 @@ export const vnode_diff = (
594622 ) : boolean {
595623 const element = createElementWithNamespace ( elementName ) ;
596624
625+ function setAttribute ( key : string , value : any , vHost : ElementVNode ) {
626+ value = serializeAttribute ( key , value , scopedStyleIdPrefix ) ;
627+ if ( value != null ) {
628+ if ( vHost . flags & VNodeFlags . NS_svg ) {
629+ // only svg elements can have namespace attributes
630+ const namespace = getAttributeNamespace ( key ) ;
631+ if ( namespace ) {
632+ element . setAttributeNS ( namespace , key , String ( value ) ) ;
633+ return ;
634+ }
635+ }
636+ element . setAttribute ( key , String ( value ) ) ;
637+ }
638+ }
639+
597640 const { constProps } = jsx ;
598641 let needsQDispatchEventPatch = false ;
599642 if ( constProps ) {
@@ -637,15 +680,19 @@ export const vnode_diff = (
637680 }
638681
639682 if ( isSignal ( value ) ) {
640- value = trackSignalAndAssignHost (
641- value as Signal < unknown > ,
642- vNewNode as ElementVNode ,
643- key ,
644- container ,
645- CONST_SUBSCRIPTION_DATA
683+ const vHost = vNewNode as ElementVNode ;
684+ const signal = value as Signal < unknown > ;
685+ value = retryOnPromise ( ( ) =>
686+ trackSignalAndAssignHost ( signal , vHost , key , container , CONST_SUBSCRIPTION_DATA )
646687 ) ;
647688 }
648689
690+ if ( isPromise ( value ) ) {
691+ const vHost = vNewNode as ElementVNode ;
692+ value . then ( ( resolvedValue ) => setAttribute ( key , resolvedValue , vHost ) ) ;
693+ continue ;
694+ }
695+
649696 if ( key === dangerouslySetInnerHTML ) {
650697 if ( value ) {
651698 element . innerHTML = String ( value ) ;
@@ -665,18 +712,7 @@ export const vnode_diff = (
665712 continue ;
666713 }
667714
668- value = serializeAttribute ( key , value , scopedStyleIdPrefix ) ;
669- if ( value != null ) {
670- if ( vNewNode ! . flags & VNodeFlags . NS_svg ) {
671- // only svg elements can have namespace attributes
672- const namespace = getAttributeNamespace ( key ) ;
673- if ( namespace ) {
674- element . setAttributeNS ( namespace , key , String ( value ) ) ;
675- continue ;
676- }
677- }
678- element . setAttribute ( key , String ( value ) ) ;
679- }
715+ setAttribute ( key , value , vNewNode as ElementVNode ) ;
680716 }
681717 }
682718 const key = jsx . key ;
@@ -803,6 +839,14 @@ export const vnode_diff = (
803839 let dstIdx = 0 ;
804840 let patchEventDispatch = false ;
805841
842+ const setAttribute = ( key : string , value : any , vHost : ElementVNode ) => {
843+ vHost . setAttr (
844+ key ,
845+ value !== null ? serializeAttribute ( key , value , scopedStyleIdPrefix ) : null ,
846+ journal
847+ ) ;
848+ } ;
849+
806850 const record = ( key : string , value : any ) => {
807851 if ( key . startsWith ( ':' ) ) {
808852 vnode . setProp ( key , value ) ;
@@ -837,12 +881,16 @@ export const vnode_diff = (
837881 // Only if we want to track the signal again
838882 clearEffectSubscription ( container , currentEffect ) ;
839883 }
840- value = trackSignalAndAssignHost (
841- unwrappedSignal ,
842- vnode ,
843- key ,
844- container ,
845- NON_CONST_SUBSCRIPTION_DATA
884+
885+ const vHost = vnode as ElementVNode ;
886+ value = retryOnPromise ( ( ) =>
887+ trackSignalAndAssignHost (
888+ unwrappedSignal ,
889+ vHost ,
890+ key ,
891+ container ,
892+ NON_CONST_SUBSCRIPTION_DATA
893+ )
846894 ) ;
847895 } else {
848896 if ( currentEffect ) {
@@ -853,11 +901,13 @@ export const vnode_diff = (
853901 }
854902 }
855903
856- vnode . setAttr (
857- key ,
858- value !== null ? serializeAttribute ( key , value , scopedStyleIdPrefix ) : null ,
859- journal
860- ) ;
904+ if ( isPromise ( value ) ) {
905+ const vHost = vnode as ElementVNode ;
906+ value . then ( ( resolvedValue ) => setAttribute ( key , resolvedValue , vHost ) ) ;
907+ return ;
908+ }
909+
910+ setAttribute ( key , value , vnode ) ;
861911 } ;
862912
863913 const recordJsxEvent = ( key : string , value : any ) => {
@@ -1169,6 +1219,8 @@ export const vnode_diff = (
11691219 const lookupKeysAreEqual = lookupKey === vNodeLookupKey ;
11701220 const hashesAreEqual = componentHash === vNodeComponentHash ;
11711221
1222+ const jsxChildren = jsxNode . children ;
1223+
11721224 if ( ! lookupKeysAreEqual ) {
11731225 const createNew = ( ) => {
11741226 insertNewComponent ( host , componentQRL , jsxProps ) ;
@@ -1280,7 +1332,7 @@ export const vnode_diff = (
12801332 jsxNode . props
12811333 ) ;
12821334
1283- asyncQueue . push ( jsxOutput , host ) ;
1335+ asyncQueue . push ( jsxOutput , host , null ) ;
12841336 }
12851337 }
12861338 }
0 commit comments