import { createComponent } from "./component" ; import { createRoot , createSignal , untrack , createComputed , createContext , useContext , getSuspenseContext , resumeEffects , createMemo , Accessor , onCleanup , getOwner } from "../reactive/signal" ; import { HydrationContext , setHydrateContext , sharedConfig } from "./hydration" ; import type { JSX } from "../jsx" ; type SuspenseListRegistryItem = { inFallback : Accessor < boolean > ; showContent : ( v : boolean ) => void ; showFallback : ( v : boolean ) => void ; } ; type SuspenseListContextType = { register : ( inFallback : Accessor < boolean > ) => [ Accessor < boolean > , Accessor < boolean > ] ; } ; const SuspenseListContext = createContext < SuspenseListContextType > ( ) ; description export function SuspenseList ( props ) { let index = 0 , suspenseSetter , showContent , showFallback ; const listContext = useContext ( SuspenseListContext ) ; if ( listContext ) { const [ inFallback , setFallback ] = createSignal ( false ) ; suspenseSetter = setFallback ; [ showContent , showFallback ] = listContext . register ( inFallback ) ; } const registry = [ ] , comp = createComponent ( SuspenseListContext . Provider , { value : { register : ( inFallback ) => { const [ showingContent , showContent ] = createSignal ( false ) , [ showingFallback , showFallback ] = createSignal ( false ) ; registry [ index ++ ] = { inFallback , showContent , showFallback } ; return [ showingContent , showingFallback ] ; } } , get children ( ) { return props . children ; } } ) ; createComputed ( ( ) => { const reveal = props . revealOrder , tail = props . tail , visibleContent = showContent ? showContent ( ) : true , visibleFallback = showFallback ? showFallback ( ) : true , reverse = reveal === "backwards" ; if ( reveal === "together" ) { const all = registry . every ( i => ! i . inFallback ( ) ) ; suspenseSetter && suspenseSetter ( ! all ) ; registry . forEach ( i => { i . showContent ( all && visibleContent ) ; i . showFallback ( visibleFallback ) ; } ) ; return ; } let stop = false ; for ( let i = 0 , len = registry . length ; i < len ; i ++ ) { const n = reverse ? len - i - 1 : i , s = registry [ n ] . inFallback ( ) ; if ( ! stop && ! s ) { registry [ n ] . showContent ( visibleContent ) ; registry [ n ] . showFallback ( visibleFallback ) ; } else { const next = ! stop ; if ( next && suspenseSetter ) suspenseSetter ( true ) ; if ( ! tail || ( next && tail === "collapsed" ) ) { registry [ n ] . showFallback ( visibleFallback ) ; } else registry [ n ] . showFallback ( false ) ; stop = true ; registry [ n ] . showContent ( next ) ; } } if ( ! stop && suspenseSetter ) suspenseSetter ( false ) ; } ) ; return comp ; } description export function Suspense ( props ) { let counter = 0 , showContent , showFallback , ctx , p , flicker , error ; const [ inFallback , setFallback ] = createSignal < boolean > ( false ) , SuspenseContext = getSuspenseContext ( ) , store = { increment : ( ) => { if ( ++ counter === 1 ) setFallback ( true ) ; } , decrement : ( ) => { if ( -- counter === 0 ) setFallback ( false ) ; } , inFallback , effects : [ ] , resolved : false } , owner = getOwner ( ) ; if ( sharedConfig . context ) { const key = sharedConfig . context . id + sharedConfig . context . count ; p = sharedConfig . load ! ( key ) ; if ( p ) { if ( typeof p !== "object" || ! ( "then" in p ) ) p = Promise . resolve ( p ) ; const [ s , set ] = createSignal ( undefined , { equals : false } ) ; flicker = s ; p . then ( err => { if ( ( error = err ) ) return set ( ) ; sharedConfig . gather ! ( key ) ; setHydrateContext ( ctx ) ; set ( ) ; setHydrateContext ( ) ; } ) ; } } const listContext = useContext ( SuspenseListContext ) ; if ( listContext ) [ showContent , showFallback ] = listContext . register ( store . inFallback ) ; let dispose ; onCleanup ( ( ) => dispose && dispose ( ) ) ; return createComponent ( SuspenseContext . Provider , { value : store , get children ( ) { return createMemo ( ( ) => { if ( error ) throw error ; ctx = sharedConfig . context ! ; if ( flicker ) { flicker ( ) ; return ( flicker = undefined ) ; } if ( ctx && p === undefined ) setHydrateContext ( ) ; const rendered = untrack ( ( ) => props . children ) ; return createMemo ( ( ) => { const inFallback = store . inFallback ( ) , visibleContent = showContent ? showContent ( ) : true , visibleFallback = showFallback ? showFallback ( ) : true ; dispose && dispose ( ) ; if ( ( ! inFallback || p !== undefined ) && visibleContent ) { store . resolved = true ; ctx = p = undefined ; resumeEffects ( store . effects ) ; return rendered ; } if ( ! visibleFallback ) return ; return createRoot ( disposer => { dispose = disposer ; if ( ctx ) { setHydrateContext ( { id : ctx . id + "f" , count : 0 } ) ; ctx = undefined ; } return props . fallback ; } , owner ! ) ; } ) ; } ) ; } } ) ; }