// This is a simple mimic of svelte/store. export type Subscriber = (value: T) => void; export type Unsubscriber = () => void; export type Updater = (value: T) => T; export type StartStopNotifier = (set: Subscriber) => Unsubscriber | void; export interface Readable { readonly value: T; subscribe(this: void, run: Subscriber): Unsubscriber; reaction(this: void, run: Subscriber): Unsubscriber; dispose(value?: T): void; } export interface Writable extends Readable { set(this: void, value: T): void; update(this: void, updater: Updater): void; } // eslint-disable-next-line @typescript-eslint/no-empty-function function noop() {} function safe_not_equal(a: unknown, b: unknown) { return a != a ? b == b : a !== b || (a && typeof a === "object") || typeof a === "function"; } export function readable(value: T, start: StartStopNotifier = noop): Readable { let stop: Unsubscriber | undefined; const subscribers = new Set>(); function set(new_value: T) { if (safe_not_equal(value, new_value)) { value = new_value; if (stop) { for (const run of subscribers) { run(value); } } } } function subscribe(run: Subscriber) { subscribers.add(run); if (subscribers.size === 1) { stop = start(set) || noop; } run(value); return () => { subscribers.delete(run); if (subscribers.size === 0) { stop && stop(); stop = undefined; } }; } function reaction(run: Subscriber) { subscribers.add(run); if (subscribers.size === 1) { stop = start(set) || noop; } return () => { subscribers.delete(run); if (subscribers.size === 0) { stop && stop(); stop = undefined; } }; } function dispose(new_value?: T) { if (new_value !== undefined) { set(new_value); } subscribers.clear(); stop && stop(); stop = undefined; } return { get value() { if (subscribers.size === 0) { stop = start(set) || noop; stop(); stop = undefined; } return value; }, subscribe, reaction, dispose, }; } export function writable(value: T, start: StartStopNotifier = noop, set: Subscriber): Writable { const internal = readable(value, start); return { get value() { return internal.value; }, subscribe: internal.subscribe, reaction: internal.reaction, set, update(fn: Updater) { set(fn(internal.value)); }, dispose: internal.dispose, }; }