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

add custom HTML element helpers

This commit is contained in:
Jan Andrle 2023-09-11 18:31:23 +02:00
parent 1cb1a8420c
commit 4b0a7d4554
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
3 changed files with 99 additions and 26 deletions

View File

@ -16,13 +16,23 @@ import { onAbort } from './helpers.js';
//TODO: cleanUp when event before abort?
on.connected= function(listener, options){
return function registerElement(element){
if(typeof element.connectedCallback === "function"){
element.addEventListener("dde:connected", listener, options);
return element;
}
const c= onAbort(options && options.signal, ()=> c_ch_o.offConnected(element, listener));
if(c) c_ch_o.onConnected(element, listener);
if(!c) return element;
if(element.isConnected) listener(new Event("dde:connected"));
else c_ch_o.onConnected(element, listener);
return element;
};
};
on.disconnected= function(listener, options){
return function registerElement(element){
if(typeof element.disconnectedCallback === "function"){
element.addEventListener("dde:disconnected", listener, options);
return element;
}
const c= onAbort(options && options.signal, ()=> c_ch_o.offDisconnected(element, listener));
if(c) c_ch_o.onDisconnected(element, listener);
return element;

View File

@ -1,49 +1,112 @@
import { el } from "../../index.js";
import { S } from "../../src/signals.js";
const store= new WeakMap();
Object.assign(S, {
customElementParams(_this){
console.log("zde");
return getAttributes(_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= new WeakMap();
/**
* Compatible with `npx-wca test/components/webComponent.js`
* @prop {string} test
* */
class CustomHTMLTestElement extends HTMLElement{
static get tagName(){
return "custom-test";
}
export class CustomHTMLTestElement extends HTMLElement{
static get observedAttributes(){
return [ "name" ];
}
constructor(){
super();
customElementInit(this, this.attachShadow({ mode: "open" }));
}
connectedCallback(){
customElementRender(this, render);
customElementRender(this, this.attachShadow({ mode: "open" }), this.render);
}
render({ name, test }, host){
host(on.connected(console.log));
return el("p", { className: test, textContent: name });
}
}
S.customElementPrototype(CustomHTMLTestElement);
customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement);
customElementsAssign(
CustomHTMLTestElement,
reflectObservedAttributes,
lifecycleToEvents(true),
attrsPropsToSignals([ "test" ])
);
customElements.define("custom-test", CustomHTMLTestElement);
function render({ name }, host){
return el("p", name);
}
function customElementInit(_this, root= _this){
function customElementRender(_this, root, render){
const host= (...a)=> a.length ? a[0](_this) : _this;
store.set(_this, { host, root });
}
function customElementRender(_this, render){
const { host, root }= store.get(_this);
const attrs= S.customElementParams ? S.customElementParams(_this) : getAttributes(_this);
root.appendChild(render(attrs, host));
}
function getAttributes(_this){
return Object.fromEntries(_this.getAttributeNames().map(n=> [ n, _this.getAttribute(n) ]));
}
/** @returns {HTMLElement} */
function customElementsAssign(class_base, ...automatize){
automatize.forEach(a=> a(class_base, getStore));
function getStore(t){
if(store.has(t)) return store.get(t);
const s= {};
store.set(t, s);
return s;
}
}
function reflectObservedAttributes(c){
for(const name of c.observedAttributes)
Reflect.defineProperty(c.prototype, name, {
get(){ return this.getAttribute(name); },
set(value){ this.setAttribute(name, value); }
});
}
function lifecycleToEvents(is_attrs){
return function(c){
wrapMethod(c.prototype, "connectedCallback", function(target, thisArg, detail){
target.apply(thisArg, detail);
thisArg.dispatchEvent(new Event("dde:connected"));
});
wrapMethod(c.prototype, "disconnectedCallback", function(target, thisArg, detail){
target.apply(thisArg, detail);
thisArg.dispatchEvent(new Event("dde:disconnected"));
});
if(is_attrs)
wrapMethod(c.prototype, "attributeChangedCallback", function(target, thisArg, detail){
thisArg.dispatchEvent(new CustomEvent("dde:attribute", { detail }));
target.apply(thisArg, detail);
});
};
}
function attrsPropsToSignals(props= []){
return function(c, getStore){
const store= getStore(c);
store.observedProperties= props;
wrapMethod(c.prototype, "attributeChangedCallback", function(target, thisArg, detail){
const [ name, _, value ]= detail;
const s= getStore(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= 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);
}
});
}
};
}
function wrapMethod(obj, method, apply){
obj[method]= new Proxy(obj[method] || (()=> {}), { apply });
}

View File

@ -2,11 +2,11 @@ import { style, el } from './exports.js';
document.head.append(style.element);
import { fullNameComponent } from './components/fullNameComponent.js';
import { todosComponent } from './components/todosComponent.js';
import "./components/webComponent.js";
import { CustomHTMLTestElement } from "./components/webComponent.js";
document.body.append(
el("h1", "Experiments:"),
el(fullNameComponent),
el(todosComponent),
el("custom-test", { name: "attr" })
el(customElements.getName(CustomHTMLTestElement), { name: "attr" })
);