1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-24 09:29:37 +01:00

S.attribute is the best option

This commit is contained in:
Jan Andrle 2023-11-22 21:29:40 +01:00
parent 10ed0802f2
commit efc5c34fc4
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
10 changed files with 58 additions and 53 deletions

File diff suppressed because one or more lines are too long

13
dist/dde.js vendored

File diff suppressed because one or more lines are too long

View File

@ -521,7 +521,7 @@ interface S {
* */ * */
el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment; el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment;
fromAttribute<T>(element: HTMLElement, name: string, value?: T): Signal<T, {}>; attribute(name: string, initial?: string): Signal<string, {}>;
} }
export const S: S; export const S: S;
declare global { declare global {

File diff suppressed because one or more lines are too long

2
dist/esm.js vendored

File diff suppressed because one or more lines are too long

View File

@ -13,19 +13,19 @@ export class CustomHTMLTestElement extends HTMLElement{
connectedCallback(){ connectedCallback(){
if(!this.hasAttribute("pre-name")) this.setAttribute("pre-name", "default"); if(!this.hasAttribute("pre-name")) this.setAttribute("pre-name", "default");
this.attachShadow({ mode: "open" }).append( this.attachShadow({ mode: "open" }).append(
customElementRender(this, this.render, observedAttributes(S)) customElementRender(this, this.render)
); );
} }
render({ name, preName }){ render({ test }){
const { host }= scope;
const { test }= host();
console.log(scope.state); console.log(scope.state);
host( scope.host(
on.connected(()=> console.log(CustomHTMLTestElement)), on.connected(()=> console.log(CustomHTMLTestElement)),
on.attributeChanged(e=> console.log(e)), on.attributeChanged(e=> console.log(e)),
on.disconnected(()=> console.log(CustomHTMLTestElement)) on.disconnected(()=> console.log(CustomHTMLTestElement))
); );
const name= S.attribute("name");
const preName= S.attribute("pre-name");
console.log({ name, test, preName}); console.log({ name, test, preName});
return el("p").append( return el("p").append(
@ -46,7 +46,7 @@ export class CustomHTMLTestElement extends HTMLElement{
lifecycleToEvents(CustomHTMLTestElement) lifecycleToEvents(CustomHTMLTestElement)
customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement); customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement);
function customElementRender(_this, render, props){ function customElementRender(_this, render, props= _this){
console.log(_this.shadowRoot, _this.childList); console.log(_this.shadowRoot, _this.childList);
scope.push({ scope: _this, host: (...c)=> c.length ? c.forEach(c=> c(_this)) : _this, custom_element: _this }); scope.push({ scope: _this, host: (...c)=> c.length ? c.forEach(c=> c(_this)) : _this, custom_element: _this });
if(typeof props==="function") props= props(_this); if(typeof props==="function") props= props(_this);
@ -54,17 +54,6 @@ function customElementRender(_this, render, props){
scope.pop(); scope.pop();
return out; return out;
} }
function observedAttributes(options, element){
const fromAttribute= typeof options==="undefined" ? (_1, _2, v)=> v : ( options.fromAttribute || options );
if(!element) return observedAttributes.bind(null, fromAttribute)
return Object.fromEntries(
element.constructor.observedAttributes
.map(name=> [
name.replace(/-./g, m=> m.slice(1).toUpperCase()),
fromAttribute(element, name, element.getAttribute(name))
])
);
}
function lifecycleToEvents(class_declaration){ function lifecycleToEvents(class_declaration){
for (const name of [ "connected", "disconnected" ]) for (const name of [ "connected", "disconnected" ])
wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){ wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){

View File

@ -58,7 +58,7 @@
"size-limit": [ "size-limit": [
{ {
"path": "./index.js", "path": "./index.js",
"limit": "8 kB", "limit": "8.5 kB",
"gzip": false "gzip": false
}, },
{ {

2
signals.d.ts vendored
View File

@ -54,7 +54,7 @@ interface S {
* */ * */
el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment; el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment;
fromAttribute<T>(element: HTMLElement, name: string, value?: T): Signal<T, {}>; attribute(name: string, initial?: string): Signal<string, {}>;
} }
export const S: S; export const S: S;
declare global { declare global {

View File

@ -151,6 +151,11 @@ export function empty(el){
Array.from(el.children).forEach(el=> el.remove()); Array.from(el.children).forEach(el=> el.remove());
return el; return el;
} }
export function elementAttribute(element, op, key, value){
if(element instanceof HTMLElement)
return element[op+"Attribute"](key, value);
return element[op+"AttributeNS"](null, key, value);
}
import { isUndef } from "./helpers.js"; import { isUndef } from "./helpers.js";
//TODO add cache? `(Map/Set)<el.tagName+key,isUndef>` //TODO add cache? `(Map/Set)<el.tagName+key,isUndef>`
function isPropSetter(el, key){ function isPropSetter(el, key){

View File

@ -85,7 +85,7 @@ S.clear= function(...signals){
} }
}; };
const key_reactive= "__dde_reactive"; const key_reactive= "__dde_reactive";
import { el } from "./dom.js"; import { el, elementAttribute } from "./dom.js";
import { scope } from "./dom.js"; import { scope } from "./dom.js";
S.el= function(signal, map){ S.el= function(signal, map){
const mark_start= el.mark({ type: "reactive" }, false); const mark_start= el.mark({ type: "reactive" }, false);
@ -113,9 +113,20 @@ S.el= function(signal, map){
}; };
import { on } from "./events.js"; import { on } from "./events.js";
const key_attributes= "__dde_attributes"; const key_attributes= "__dde_attributes";
S.fromAttribute= function(element, name, value){ S.attribute= function(name, initial= null){
if(!element[key_attributes]){ // needs registration //TODO host=element & reuse existing
element[key_attributes]= {}; const out= S(initial);
let element;
scope.host(el=> {
element= el;
if(elementAttribute(element, "has", name)) out(elementAttribute(element, "get", name));
else if(initial!==null) elementAttribute(element, "set", name, initial);
if(el[key_attributes]){
el[key_attributes][name]= out;
return;
}
element[key_attributes]= { [name]: out };
on.attributeChanged(function attributeChangeToSignal({ detail }){ on.attributeChanged(function attributeChangeToSignal({ detail }){
/*! This maps attributes to signals (`S.attribute`). /*! This maps attributes to signals (`S.attribute`).
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
@ -128,14 +139,12 @@ S.fromAttribute= function(element, name, value){
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
S.clear(...Object.values(element[key_attributes])); S.clear(...Object.values(element[key_attributes]));
})(element); })(element);
} });
const store= element[key_attributes];
const out= Reflect.has(store, name) ? Reflect.get(store, name) : (store[name]= S(value));
return new Proxy(out, { return new Proxy(out, {
apply(target, _, args){ apply(target, _, args){
if(!args.length) return target(); if(!args.length) return target();
const value= args[0]; const value= args[0];
return element.setAttribute(name, value); return elementAttribute(element, "set", name, value);
} }
}); });
}; };