import { render } from 'lit-html';
function requestRender(ctx: any) {
if (ctx.isConnected) {
if (ctx.__wait) {
} else {
ctx.__wait = true;
requestAnimationFrame(() => {
Promise.resolve(true);
ctx.render();
ctx.__wait = false;
});
}
}
}
/**
* @property decorator
* todo add more options
*/
export function property(): Function {
return function reg(_class: Function, prop: string): void {
Object.defineProperty(_class, prop, {
get: function() {
return this['_' + prop];
},
set: function(x: any) {
const oldValue = this['_' + prop];
this['_' + prop] = x;
if (this.valuesChanged && oldValue !== x) {
this.valuesChanged('property', prop, oldValue, x);
}
if (oldValue !== x) {
requestRender(this);
}
}
});
};
}
/**
* @attibute- decorator
* //todo add option and allow user to set attibute to follow, and own validate if changed
*/
export function attribute(): Function {
return function reg(_class: Function, prop: string): void {
Object.defineProperty(_class, prop, {
get: function() {
return this['_' + prop];
},
set: function(x: any) {
const oldValue = this['_' + prop];
this['_' + prop] = x;
if (this.valuesChanged && oldValue !== x) {
this.valuesChanged('property', prop, oldValue, x);
}
if (oldValue !== x) {
requestRender(this);
}
}
});
// replace uppercase with lower and add '-'
const attribute = prop
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/\s+/g, '-')
.toLowerCase();
//create a map so we can find it later
if (!(_class)._observedAttributesMap) {
(_class)._observedAttributesMap = new Map();
}
(_class)._observedAttributesMap.set(attribute, prop);
// add to observedAttributes
if ((_class)._observedAttributes) {
(_class)._observedAttributes.push(attribute);
} else {
(_class)._observedAttributes = [];
(_class)._observedAttributes.push(attribute);
}
};
}
export function customElement(elementName: string, extended?: ElementDefinitionOptions) {
return function reg(elementClass: any) {
Object.defineProperty(elementClass, 'observedAttributes', {
get: function() {
return elementClass.prototype['_observedAttributes'];
}
});
const base = class extends elementClass {
constructor(){
super();
}
render(...result: any[]) {
render(super.render.call(this, ...result), this, { eventContext: this });
if (super.updated) {
//delay so it actually get a chance to update
setTimeout(() => {
super.updated();
});
}
}
connectedCallback() {
if (super.connectedCallback) {
super.connectedCallback.call(this);
}
this.render(this);
}
disconnectedCallback() {
if (super.disconnectedCallback) {
super.disconnectedCallback.call(this);
}
}
attributeChangedCallback(name: string, oldValue: string, newValue: string) {
//get map
const nameProp = this['_observedAttributesMap'].get(name);
this[nameProp] = newValue || '';
// if normal attributeChanged is set
if (super.attributeChangedCallback) {
super.attributeChangedCallback.call(this, name, oldValue, newValue);
}
//if our simpler method is set
if (super.valuesChangedMethod) {
super.valuesChangedMethod('attribute', name, oldValue, newValue);
}
requestRender(this);
}
};
if (!customElements.get(elementName)) {
if (extended) {
customElements.define(elementName, base, extended);
} else {
customElements.define(elementName, base);
}
} else {
if ((globalThis).hmrCache) {
if (extended) {
customElements.define(elementName, base, extended);
} else {
customElements.define(elementName, base);
}
}
}
};
}