@benev/slate
Version:
frontend web stuff
93 lines • 3.09 kB
JavaScript
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