vasille
Version:
The first Developer eXperience Orientated front-end framework (core library).
114 lines (113 loc) • 3.17 kB
JavaScript
import { Destroyable } from "./destroyable.js";
import { Expression } from "../value/expression.js";
import { Reference } from "../value/reference.js";
import { OwningPointer, Pointer } from "../value/pointer.js";
/**
* A reactive object
* @class Reactive
* @extends Destroyable
*/
export class Reactive extends Destroyable {
constructor(input) {
super();
/**
* A list of user-defined bindings
* @type {Set}
*/
this.bindings = new Set();
this.input = input;
this.state = {};
}
/**
* Create a reference
* @param value {*} value to reference
* @param name {string} used for debugging internal state
*/
ref(value, name) {
const ref = new Reference(value);
this.bindings.add(ref);
if (name) {
this.addState("ref", name, ref);
}
return ref;
}
/**
* Create a forward-only pointer
* @param value {IValue} value to point
* @param name {string} used for debugging internal state
*/
forward(value, name) {
const mirror = new Pointer(value);
this.bindings.add(mirror);
if (name) {
this.addState("forward", name, mirror);
}
return mirror;
}
/**
* Creates a pointer
* @param value {*} default value to point
* @param name {string} used for debugging internal state
*/
own(value, name) {
const pointer = new OwningPointer(value);
this.bindings.add(pointer);
/* istanbul ignore else */
if (name) {
this.addState("own", name, pointer);
}
return pointer;
}
/**
* Register a model/dependency
*/
register(data, name) {
this.bindings.add(data);
if (name) {
this.addState("model", name, data);
}
return data;
}
release(data) {
this.bindings.delete(data);
}
/**
* Creates a watcher
* @param func {function} function to run on any argument change
* @param values
*/
watch(func, values) {
this.bindings.add(new Expression(func, values));
}
/**
* Creates a computed value
* @param func {function} function to run on any argument change
* @param values
* @param name {string} used for debugging internal state
* @return {IValue} the created ivalue
*/
expr(func, values, name) {
const res = new Expression(func, values);
this.bindings.add(res);
if (name) {
this.addState("expr", name, res);
}
return res;
}
runOnDestroy(func) {
if (this.onDestroy) {
console.warn(new Error("You rewrite onDestroy existing handler"));
console.log(this.onDestroy);
}
this.onDestroy = func;
}
addState(method, name, state) {
this.state[name === "#" ? `#${Object.keys(this.state).length}` : name] = [method, state];
}
destroy() {
super.destroy();
this.bindings.forEach(binding => binding.destroy());
this.bindings.clear();
this.onDestroy?.();
}
}