75 lines
2.4 KiB
JavaScript
75 lines
2.4 KiB
JavaScript
import {render} from "../vdom";
|
|
|
|
|
|
/**
|
|
* The decorators proposal has changed since @babel implemented it. This code will need to change at some point...
|
|
*/
|
|
export function State() {
|
|
return function decorator(target){
|
|
let key = target.key;
|
|
let descriptor = target.descriptor;
|
|
let value = undefined;
|
|
let {get: oldGet, set: oldSet} = descriptor;
|
|
|
|
// Add a getter/setter or replace if they're already there with something that intercepts it (this gets a whole lot easyer in the new proposal if i'm not mistaken)
|
|
descriptor['get'] = oldGet || (function(){
|
|
return value
|
|
});
|
|
descriptor['set'] = function(newValue){
|
|
if(newValue!==descriptor.get.call(this)){
|
|
value = newValue;
|
|
this.markDirty && this.markDirty();
|
|
}
|
|
if(oldSet) return oldSet.call(this, newValue);
|
|
};
|
|
|
|
// CAUTION: this is dangerous. We need intend to conver regular fields to get/set methods here.
|
|
delete descriptor.writable;
|
|
target.kind = 'method'; // update to get and set if need be..
|
|
|
|
// CAUTION: this is again dangerous, the initialize function should be called right before the constructor, but after it was fully defined.
|
|
if(target.initializer){
|
|
value = target.initializer(target);
|
|
delete target.initializer;
|
|
}
|
|
|
|
return target;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This CustomElement class is to avoid having to do an ugly workaround in every custom-element:
|
|
* Which would be replacing 'HTMLElement' with '(class extends HTMLElement{})'
|
|
*
|
|
* Also, it is a good starting point for implementing render() functionality, listening to props, state changes, events and whatnot (use decorators)
|
|
*/
|
|
export class CustomElement extends HTMLElement {
|
|
connectedCallback() {
|
|
this.update();
|
|
}
|
|
disconnectedCallback(){
|
|
|
|
}
|
|
|
|
#markedDirty;
|
|
#renderedVNode;
|
|
update(){
|
|
if (this.render) {
|
|
let newVNode = this.render();
|
|
render(newVNode, {
|
|
host: this,
|
|
oldVNode: this.#renderedVNode,
|
|
});
|
|
this.#renderedVNode = newVNode;
|
|
}
|
|
this.#markedDirty=false;
|
|
}
|
|
markDirty() {
|
|
if (!this.#markedDirty) {
|
|
this.#markedDirty = requestAnimationFrame(() => this.update());
|
|
}
|
|
}
|
|
}
|
|
|