diff --git a/islands/Suspens.tsx b/islands/Suspens.tsx new file mode 100644 index 0000000..d2e2c80 --- /dev/null +++ b/islands/Suspens.tsx @@ -0,0 +1,50 @@ +// import { Suspense } from '@univoq // Error - mismatch in imports version +import { JSX } from 'preact' +import { useSignal } from '@preact/signals' + +function RenderError( + { error, fallback }: { error: Error; fallback: Fallback | undefined }, +) { + if (fallback) { + return fallback({ error }) + } + + return ( + +
{String(error)}
+
+ ) +} + +type Fallback = ({ error }: { error: Error }) => JSX.Element + +export default function Suspense( + { loader, fallback, signal, children }: { + loader: JSX.Element + children: Promise + fallback?: Fallback + signal?: AbortSignal + }, +) { + const displayed = useSignal(loader) + + signal?.addEventListener('abort', () => { + try { + signal.throwIfAborted() + } catch (error) { + displayed.value = RenderError({ error, fallback }) + } + }) + + children + .then((element) => { + if (signal?.aborted) return + displayed.value = element + }) + .catch((error) => { + if (signal?.aborted) return + displayed.value = RenderError({ error, fallback }) + }) + + return <>{displayed} +}