1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-21 23:39:37 +01:00

Add attrsPropsToSignals

This commit is contained in:
Jan Andrle 2023-09-12 15:26:06 +02:00
parent ff22eed991
commit a7b3ea633b
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB

View File

@ -1,64 +1,56 @@
import { el } from "../../index.js"; import { el } from "../../index.js";
import { S } from "../../src/signals.js"; import { S } from "../../src/signals.js";
const store= new WeakMap(); const { hasOwnProperty }= Object.prototype;
Object.assign(S, {
customElementParams(_this){
const observedProperties= store.get(_this.constructor).observedProperties;
observedProperties.forEach(p=> _this[p]);
return store.has(_this) ? store.get(_this) : getAttributes(_this);
},
customElementPrototype(cls){
}
});
const store= attrsPropsToSignals([ "test" ]);
/** /**
* Compatible with `npx-wca test/components/webComponent.js` * Compatible with `npx-wca test/components/webComponent.js`
* */ * */
export class CustomHTMLTestElement extends HTMLElement{ export class CustomHTMLTestElement extends HTMLElement{
static get observedAttributes(){ static get observedAttributes(){
return [ "name" ]; return [ "name", "pre-name" ];
} }
connectedCallback(){ connectedCallback(){
customElementRender(this, this.attachShadow({ mode: "open" }), this.render); this.attachShadow({ mode: "open" }).append(
customElementRender(this, store.toRender(this), this.render)
);
} }
render({ name, test }, host){ render({ name, test, preName }, host){
host(on.connected(console.log)); host(on.connected(console.log));
return el("p", { className: test, textContent: name }); return el("p").append(
el("#text", { textContent: name }),
el("#text", { textContent: test }),
el("#text", { textContent: preName }),
);
} }
} }
customElementsAssign( customElementsAssign(
CustomHTMLTestElement, CustomHTMLTestElement,
reflectObservedAttributes, reflectObservedAttributes,
lifecycleToEvents(true), lifecycleToEvents(false),
attrsPropsToSignals([ "test" ]) store.connect
); );
customElements.define("custom-test", CustomHTMLTestElement); customElements.define("custom-test", CustomHTMLTestElement);
function customElementRender(_this, root, render){ function customElementRender(_this, attrs, render){
const host= (...a)=> a.length ? a[0](_this) : _this; const host= (...a)=> a.length ? a[0](_this) : _this;
const attrs= S.customElementParams ? S.customElementParams(_this) : getAttributes(_this); return render(attrs, host);
root.appendChild(render(attrs, host));
}
function getAttributes(_this){
return Object.fromEntries(_this.getAttributeNames().map(n=> [ n, _this.getAttribute(n) ]));
} }
/** @returns {HTMLElement} */ /** @returns {HTMLElement} */
function customElementsAssign(class_base, ...automatize){ function customElementsAssign(class_base, ...automatize){
automatize.forEach(a=> a(class_base, getStore)); automatize.forEach(a=> a(class_base));
function getStore(t){
if(store.has(t)) return store.get(t);
const s= {};
store.set(t, s);
return s;
}
} }
function reflectObservedAttributes(c){ function reflectObservedAttributes(c){
for(const name of c.observedAttributes) for(const name of c.observedAttributes){
Reflect.defineProperty(c.prototype, name, { const name_camel= name.replace(/([a-z])-([a-z])/g, (_, l, r)=> l+r.toUpperCase());
if(hasOwnProperty.call(c.prototype, name_camel))
continue;
Reflect.defineProperty(c.prototype, name_camel, {
get(){ return this.getAttribute(name); }, get(){ return this.getAttribute(name); },
set(value){ this.setAttribute(name, value); } set(value){ this.setAttribute(name, value); }
}); });
}
} }
function lifecycleToEvents(is_attrs){ function lifecycleToEvents(is_attrs){
return function(c){ return function(c){
@ -78,34 +70,51 @@ function lifecycleToEvents(is_attrs){
}; };
} }
function attrsPropsToSignals(props= []){ function attrsPropsToSignals(props= []){
return function(c, getStore){ const store_attrs= new WeakMap();
const store= getStore(c); const store_props= new WeakMap();
store.observedProperties= props; return {
wrapMethod(c.prototype, "attributeChangedCallback", function(target, thisArg, detail){ toRender(target){
const [ name, _, value ]= detail; const out= {};
const s= getStore(thisArg); const sattrs= get(store_attrs, target);
if(s[name]) s[name](value); target.constructor.observedAttributes.forEach(function(name){
else s[name]= S(value); const name_camel= name.replace(/([a-z])-([a-z])/g, (_, l, r)=> l+r.toUpperCase());
if(!hasOwnProperty.call(sattrs, name)) sattrs[name]= S(undefined);
target.apply(thisArg, detail); out[name_camel]= sattrs[name];
});
for(const name of props){
Reflect.defineProperty(c.prototype, name, {
get(){
const s= getStore(this);
if(s[name]) return s[name]();
const out= S(undefined);
s[name]= out;
return out();
},
set(value){
const s= getStore(this);
if(s[name]) s[name](value);
else s[name]= S(value);
}
}); });
const sprops= get(store_props, target);
props.forEach(p=> !hasOwnProperty.call(sprops, p) && (sprops[p]= S(undefined)));
return Object.assign(out, sprops);
},
connect(c){
wrapMethod(c.prototype, "attributeChangedCallback", function(target, thisArg, detail){
const [ name, _, value ]= detail;
const s= get(store_attrs, thisArg);
if(s[name]) s[name](value);
else s[name]= S(value);
target.apply(thisArg, detail);
});
for(const name of props){
Reflect.defineProperty(c.prototype, name, {
get(){
const s= get(store_props, this);
if(s[name]) return s[name]();
},
set(value){
const s= get(store_props, this);
if(s[name]) s[name](value);
else s[name]= S(value);
}
});
}
} }
}; };
function get(store, t){
if(store.has(t)) return store.get(t);
const s= {};
store.set(t, s);
return s;
}
} }
function wrapMethod(obj, method, apply){ function wrapMethod(obj, method, apply){
obj[method]= new Proxy(obj[method] || (()=> {}), { apply }); obj[method]= new Proxy(obj[method] || (()=> {}), { apply });