|
56 | 56 | // Generate a unique identifier for each loading state, to prevent cancelled navigations from updating the view |
57 | 57 | const change: ViewChangeEvent = $derived(new ViewChangeEvent({ view: { id: view.id, name: view.name }, route })); |
58 | 58 |
|
59 | | - // Extract routing state |
60 | | - let routing: boolean | undefined = $state(); |
| 59 | + // Debounce routing state |
| 60 | + let isRouting: boolean | undefined = $state(); |
61 | 61 | const setRouting = debounce((val: boolean) => { |
62 | | - routing = val; |
63 | | - return routing; |
64 | | - }, 0); |
65 | | - $effect(() => { |
| 62 | + isRouting = val; |
| 63 | + return isRouting; |
| 64 | + }, typeof transition?.delay === 'number' ? transition?.delay : transition?.delay?.routing ?? 0); |
| 65 | +
|
| 66 | + $effect.pre(() => { |
66 | 67 | setRouting(!!router?.routing?.active); |
67 | 68 | }); |
68 | 69 |
|
| 70 | + // Debounce loading state |
| 71 | + let isLoading: boolean | undefined = $state(); |
| 72 | + const setLoading = debounce((val: boolean) => { |
| 73 | + isLoading = val; |
| 74 | + return isLoading; |
| 75 | + }, typeof transition?.delay === 'number' ? transition?.delay : transition?.delay?.loading ?? 0); |
| 76 | +
|
| 77 | + $effect.pre(() => { |
| 78 | + setLoading(!!view.loading); |
| 79 | + }); |
| 80 | +
|
69 | 81 | // Delay properties update until component is resolved |
70 | 82 | let _properties: ComponentProps | undefined = $state(); |
71 | 83 |
|
|
74 | 86 |
|
75 | 87 | // Routed component to be rendered (loading, error, or resolved component) |
76 | 88 | const routedComponent = $derived.by<IComponentOrSnippet | undefined>(() => { |
77 | | - if (routing && routingSnippet) return routingSnippet; |
78 | | - else if (view.loading && loading) return loading; |
79 | | - else if (view.loading && loadingSnippet) return loadingSnippet; |
| 89 | + if (isRouting && routingSnippet) return routingSnippet; |
| 90 | + else if (isLoading && loading) return loading; |
| 91 | + else if (isLoading && loadingSnippet) return loadingSnippet; |
80 | 92 | else if (view.error && error) return error; |
81 | 93 | else if (view.error && errorSnippet) return errorSnippet; |
82 | 94 | else if (resolvedComponent) return resolvedComponent; |
83 | 95 | }); |
84 | 96 |
|
85 | 97 | // Routed snippet properties |
86 | 98 | const routedProps = $derived.by(() => { |
87 | | - if (routedComponent === errorSnippet) return view.error; |
88 | | - if (routedComponent === routingSnippet) return router.routing; |
89 | | - if (routedComponent === loadingSnippet) return route; |
| 99 | + if (routingSnippet === routedComponent) return router.routing; |
| 100 | + if ([loadingSnippet, loading].includes(routedComponent)) return route; |
| 101 | + if ([errorSnippet, error].includes(routedComponent)) return view.error; |
90 | 102 | return _properties; |
91 | 103 | }); |
92 | 104 |
|
93 | 105 | // Trigger transition on route change or component update |
94 | 106 | const transitionKey = $derived.by(() => { |
95 | | - const _keys = [routedComponent]; |
| 107 | + const _keys: any[] = [routedComponent]; |
96 | 108 | if (transition?.updateOnPropsChange) _keys.push(_properties); |
97 | 109 | return _keys; |
98 | 110 | }); |
|
108 | 120 | }, |
109 | 121 | onLoading: () => { |
110 | 122 | if (change.uuid !== _uuid) return; |
| 123 | + if (loading || loadingSnippet) resolvedComponent = undefined; |
111 | 124 | return untrack(() => view.load()); |
112 | 125 | }, |
113 | 126 | onLoaded: (_component?: AnyComponent | AnySnippet) => { |
|
120 | 133 | onError: (err: unknown) => { |
121 | 134 | if (change.uuid !== _uuid) return; |
122 | 135 | if (force) resolvedID = _uuid; |
| 136 | + if (error || errorSnippet) resolvedComponent = undefined; |
123 | 137 | return untrack(() => view.fail(err)); |
124 | 138 | }, |
125 | 139 | }; |
|
0 commit comments