export class InputCell {
constructor(value) {
this.value = value;
this.dependents = new Set();
}
setValue(value) {
if (this.value === value) return;
this.value = value;
const computeCells = this.getComputeCells();
computeCells.forEach(cell => cell.storeValue());
computeCells.forEach(cell => cell.update());
}
getComputeCells() {
const cells = [];
const visit = (node) => {
if (node instanceof ComputeCell && !cells.includes(node)) {
cells.push(node);
}
node.dependents.forEach(visit);
};
this.dependents.forEach(visit);
return cells.sort((a, b) => a.level - b.level);
}
}
export class ComputeCell {
constructor(dependencies, fn) {
this.dependencies = dependencies;
this.fn = fn;
this.dependents = new Set();
this.callbacks = new Set();
this.level = Math.max(0, ...dependencies.map(d => d.level ?? 0)) + 1;
dependencies.forEach(d => d.dependents.add(this));
this.storeValue();
}
storeValue() {
this.oldValue = this.value;
this.value = this.fn(this.dependencies);
}
update() {
const newValue = this.fn(this.dependencies);
if (newValue !== this.value) {
this.value = newValue;
if (this.value !== this.oldValue) {
this.callbacks.forEach(cb => cb.fire(this));
}
}
}
addCallback(cb) {
this.callbacks.add(cb);
}
removeCallback(cb) {
this.callbacks.delete(cb);
}
}
export class CallbackCell {
constructor(fn) {
this.fn = fn;
this.values = [];
}
fire(cell) {
this.values.push(this.fn(cell));
}
}