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:
parent
1cb1a8420c
commit
4b0a7d4554
@ -16,13 +16,23 @@ import { onAbort } from './helpers.js';
|
|||||||
//TODO: cleanUp when event before abort?
|
//TODO: cleanUp when event before abort?
|
||||||
on.connected= function(listener, options){
|
on.connected= function(listener, options){
|
||||||
return function registerElement(element){
|
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));
|
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;
|
return element;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
on.disconnected= function(listener, options){
|
on.disconnected= function(listener, options){
|
||||||
return function registerElement(element){
|
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));
|
const c= onAbort(options && options.signal, ()=> c_ch_o.offDisconnected(element, listener));
|
||||||
if(c) c_ch_o.onDisconnected(element, listener);
|
if(c) c_ch_o.onDisconnected(element, listener);
|
||||||
return element;
|
return element;
|
||||||
|
@ -1,49 +1,112 @@
|
|||||||
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();
|
||||||
Object.assign(S, {
|
Object.assign(S, {
|
||||||
customElementParams(_this){
|
customElementParams(_this){
|
||||||
console.log("zde");
|
const observedProperties= store.get(_this.constructor).observedProperties;
|
||||||
return getAttributes(_this);
|
observedProperties.forEach(p=> _this[p]);
|
||||||
|
return store.has(_this) ? store.get(_this) : getAttributes(_this);
|
||||||
},
|
},
|
||||||
customElementPrototype(cls){
|
customElementPrototype(cls){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const store= new WeakMap();
|
|
||||||
/**
|
/**
|
||||||
* Compatible with `npx-wca test/components/webComponent.js`
|
* Compatible with `npx-wca test/components/webComponent.js`
|
||||||
* @prop {string} test
|
|
||||||
* */
|
* */
|
||||||
class CustomHTMLTestElement extends HTMLElement{
|
export class CustomHTMLTestElement extends HTMLElement{
|
||||||
static get tagName(){
|
|
||||||
return "custom-test";
|
|
||||||
}
|
|
||||||
static get observedAttributes(){
|
static get observedAttributes(){
|
||||||
return [ "name" ];
|
return [ "name" ];
|
||||||
}
|
}
|
||||||
constructor(){
|
|
||||||
super();
|
|
||||||
customElementInit(this, this.attachShadow({ mode: "open" }));
|
|
||||||
}
|
|
||||||
connectedCallback(){
|
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);
|
customElementsAssign(
|
||||||
customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement);
|
CustomHTMLTestElement,
|
||||||
|
reflectObservedAttributes,
|
||||||
|
lifecycleToEvents(true),
|
||||||
|
attrsPropsToSignals([ "test" ])
|
||||||
|
);
|
||||||
|
customElements.define("custom-test", CustomHTMLTestElement);
|
||||||
|
|
||||||
function render({ name }, host){
|
function customElementRender(_this, root, render){
|
||||||
return el("p", name);
|
|
||||||
}
|
|
||||||
function customElementInit(_this, root= _this){
|
|
||||||
const host= (...a)=> a.length ? a[0](_this) : _this;
|
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);
|
const attrs= S.customElementParams ? S.customElementParams(_this) : getAttributes(_this);
|
||||||
root.appendChild(render(attrs, host));
|
root.appendChild(render(attrs, host));
|
||||||
}
|
}
|
||||||
function getAttributes(_this){
|
function getAttributes(_this){
|
||||||
return Object.fromEntries(_this.getAttributeNames().map(n=> [ n, _this.getAttribute(n) ]));
|
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 });
|
||||||
|
}
|
||||||
|
@ -2,11 +2,11 @@ import { style, el } from './exports.js';
|
|||||||
document.head.append(style.element);
|
document.head.append(style.element);
|
||||||
import { fullNameComponent } from './components/fullNameComponent.js';
|
import { fullNameComponent } from './components/fullNameComponent.js';
|
||||||
import { todosComponent } from './components/todosComponent.js';
|
import { todosComponent } from './components/todosComponent.js';
|
||||||
import "./components/webComponent.js";
|
import { CustomHTMLTestElement } from "./components/webComponent.js";
|
||||||
|
|
||||||
document.body.append(
|
document.body.append(
|
||||||
el("h1", "Experiments:"),
|
el("h1", "Experiments:"),
|
||||||
el(fullNameComponent),
|
el(fullNameComponent),
|
||||||
el(todosComponent),
|
el(todosComponent),
|
||||||
el("custom-test", { name: "attr" })
|
el(customElements.getName(CustomHTMLTestElement), { name: "attr" })
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user