Something went wrong. Try again.
Experiment to rebuild Diffuse using web applets.
Something went wrong. Try again.
3.7 kB · 151 lines
TypeScript
at s3
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152import type { Applet, AppletEvent } from "@web-applets/sdk";
import { applets } from "@web-applets/sdk";import { type ElementConfigurator, h } from "spellcaster/hyperscript.js";import { effect, isSignal, Signal, signal } from "spellcaster/spellcaster.js";import { xxh32 } from "xxh32";
////////////////////////////////////////////// 🪟 Applet initialiser////////////////////////////////////////////export async function applet<D>( src: string, opts: { addSlashSuffix?: boolean; context?: Window; container?: HTMLElement | Element; id?: string; setHeight?: boolean; } = {},): Promise<Applet<D>> { src = `${src}${ src.endsWith("/") ? "" : opts.addSlashSuffix === undefined || opts.addSlashSuffix === true ? "/" : "" }`;
const existingFrame: HTMLIFrameElement | null = (opts.context || window).document.querySelector( `[src="${src}"]`, );
let frame;
if (existingFrame) { frame = existingFrame; } else { frame = document.createElement("iframe"); frame.src = src; if (opts.id) frame.id = opts.id;
if (opts.container) { opts.container.appendChild(frame); } else { (opts.context || window).document.body.appendChild(frame); } }
if (frame.contentWindow === null) { throw new Error("iframe does not have a contentWindow"); }
const applet = await applets .connect<D>(frame.contentWindow, { context: opts.context, }) .catch((err) => { console.error("Error connecting to " + src, err); throw err; });
if (opts.setHeight) { applet.onresize = () => { frame.height = `${applet.height}px`; frame.classList.add("has-loaded"); }; } else { if (frame.contentDocument?.readyState === "complete") { frame.classList.add("has-loaded"); }
frame.addEventListener("load", () => { frame.classList.add("has-loaded"); }); }
return applet;}
////////////////////////////////////////////// 🔮 Reactive state management////////////////////////////////////////////export function reactive<D, T>( applet: Applet<D>, dataFn: (data: D) => T, effectFn: (t: T) => void,) { const [getter, setter] = signal(dataFn(applet.data));
effect(() => { effectFn(getter()); return undefined; });
applet.addEventListener("data", (event: AppletEvent) => { setter(dataFn(event.data)); });}
////////////////////////////////////////////// 🛠️////////////////////////////////////////////export function addScope<O extends object>(astroScope: string, object: O): O { return { ...object, attrs: { ...((object as any).attrs || {}), [`data-astro-cid-${astroScope}`]: "", }, };}
export function comparable(value: unknown) { return xxh32(JSON.stringify(value));}
export function hs( tag: string, astroScope: string, props?: Record<string, unknown> | Signal<Record<string, unknown>>, configure?: ElementConfigurator,) { const propsWithScope = props && isSignal(props) ? () => addScope(astroScope, props()) : addScope(astroScope, props || {});
return h(tag, propsWithScope, configure);}
export function isPrimitive(test: unknown) { return test !== Object(test);}
export function waitUntilAppletIsReady(applet: Applet): Promise<void> { return new Promise((resolve) => { if (applet.data?.ready === true) { resolve(); return; }
const callback = (event: AppletEvent) => { if (event.data?.ready === true) { applet.removeEventListener("data", callback); resolve(); } };
applet.addEventListener("data", callback); });}