UNPKG

@benev/slate

Version:
93 lines 3.09 kB
import { deep } from "../tools/deep/deep.js"; import { accessed } from "./parts/accessed_symbol.js"; import { debounce } from "../tools/debounce/debounce.js"; import { SignalCircularError } from "./parts/circular_error.js"; export class Signal { static unwrap = ((anything) => { return anything instanceof Signal ? anything.value : anything; }); #value; #lock = false; #wait; #listeners = new Set(); [accessed] = false; constructor(v) { this.#value = v; this.#wait = Promise.resolve(v); } /** @deprecated use `on` method instead */ subscribe(listener) { return this.on(listener); } on(listener) { this.#listeners.add(listener); return () => void this.#listeners.delete(listener); } once(listener) { const actual_listener = v => { listener(v); this.#listeners.delete(actual_listener); }; this.#listeners.add(actual_listener); return () => void this.#listeners.delete(actual_listener); } clear() { return this.#listeners.clear(); } #invoke_listeners = debounce(0, () => { const value = this.#value; this.#lock = true; for (const listener of this.#listeners) listener(value); this.#lock = false; return value; }); async publish() { this.#wait = this.#invoke_listeners(); await this.#wait; } get wait() { return this.#wait; } get value() { this[accessed] = true; return this.#value; } set value(v) { if (this.#lock) throw new SignalCircularError("you can't set a signal in a signal's subscription listener (infinite loop forbidden)"); if (this.#value !== v) { this.#value = v; this.publish(); } } /** set the signal value and publish, only if a deep change is detected (uses deep.equal to scan whole object trees) */ setDeep(v) { if (this.#lock) throw new SignalCircularError("you can't set a signal in a signal's subscription listener (infinite loop forbidden)"); if (!deep.equal(v, this.#value)) { this.#value = v; this.publish(); } } /** set the signal value and publish, even if there's no change detected */ setAndPublish(v) { if (this.#lock) throw new SignalCircularError("you can't set a signal in a signal's subscription listener (infinite loop forbidden)"); this.#value = v; this.publish(); } /** set the signal value, but do not publish (perhaps to prevent views rerendering) */ setWithoutPublish(v) { if (this.#lock) throw new SignalCircularError("you can't set a signal in a signal's subscription listener (infinite loop forbidden)"); this.#value = v; } /** @deprecated use `setWithoutPublish` instead */ setValueNoPublish(v) { return this.setWithoutPublish(v); } } //# sourceMappingURL=signal.js.map