Experiment to rebuild Diffuse using web applets.
1import { Signal } from "signal-polyfill";
2
3// SIGNAL
4
5export type Signal<T> = () => T;
6
7export const signal = <T>(initial: T): [Signal<T>, (value: T) => void] => {
8 const state = new Signal.State(initial);
9 const get = () => state.get();
10 const set = (value: T) => state.set(value);
11 return [get, set];
12};
13
14// EFFECT
15
16export const throttled = (
17 job: () => void,
18 queue: (callback: () => void) => void = queueMicrotask,
19): (() => void) => {
20 let isScheduled = false;
21
22 const perform = () => {
23 job();
24 isScheduled = false;
25 };
26
27 const schedule = () => {
28 if (!isScheduled) {
29 isScheduled = true;
30 queue(perform);
31 }
32 };
33
34 return schedule;
35};
36
37const watcher = new Signal.subtle.Watcher(
38 throttled(() => {
39 for (const signal of watcher.getPending()) {
40 signal.get();
41 }
42 watcher.watch();
43 }),
44);
45
46export type Cancel = () => void;
47
48export const effect = (perform: () => Cancel | void) => {
49 let cleanup: Cancel | undefined;
50
51 const signal = new Signal.Computed(() => {
52 cleanup?.();
53 cleanup = perform() ?? undefined;
54 });
55
56 watcher.watch(signal);
57 signal.get();
58
59 const dispose = () => {
60 cleanup?.();
61 watcher.unwatch(signal);
62 };
63
64 return dispose;
65};