~james/core

core/web/src/lib/components/ui/Pending.svelte -rw-r--r-- 1.2 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script lang="ts">
	import { browser } from "$app/env";
	import type { Snippet } from "svelte";

	interface Props {
		/** omit to fill in silently, the boundary still owns the suspension */
		skeleton?: Snippet;
		/** without it the error propagates to the nearest +error.svelte */
		failed?: Snippet<[error: unknown]>;
		/** a new value remounts the boundary, so it shows the skeleton instead of holding the old content */
		key?: unknown;
		children: Snippet;
	}

	let { skeleton, failed: failedProp, key, children }: Props = $props();
</script>

<!-- keep the browser check, svelte throws the real children away on ssr if pending is set -->
<!-- failed has to be a direct child of the boundary to register as its snippet -->
{#key key}
	{#if failedProp}
		<svelte:boundary pending={browser ? gated : undefined}>
			{@render children()}
			{#snippet failed(error: unknown)}
				{@render failedProp(error)}
			{/snippet}
		</svelte:boundary>
	{:else}
		<svelte:boundary pending={browser ? gated : undefined}>
			{@render children()}
		</svelte:boundary>
	{/if}
{/key}

<!-- no delay here: load.ts already held the navigation for the window -->
{#snippet gated()}
	{#if skeleton}
		{@render skeleton()}
	{/if}
{/snippet}