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

🚧 mainly wc/ce

This commit is contained in:
Jan Andrle 2023-11-22 17:39:46 +01:00
parent 56206343d1
commit 10ed0802f2
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
7 changed files with 132 additions and 82 deletions

File diff suppressed because one or more lines are too long

View File

@ -166,6 +166,34 @@ export const scope: {
pop(): ReturnType<Array<Scope>["pop"]>, pop(): ReturnType<Array<Scope>["pop"]>,
}; };
/*
* TODO TypeScript HACK (better way?)
* this doesnt works
* ```ts
* interface element<el> extends Node{
* prototype: el;
* append(...els: (SupportedElement | DocumentFragment | string | element<SupportedElement | DocumentFragment>)[]): el
* }
*
export function el<T>(
* tag_name?: "<>",
* ): element<DocumentFragment>
* ```
* as its complains here
* ```
ts
*
const d= el("div");
*
const f= (a: HTMLDivElement)=> a;
* f(d);
//←
* document.head.append( //←
* el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" }),
* );
* ```
* TODO for SVG
* */
type ddeAppend<el>= (...nodes: (Node | string)[])=> el; type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
declare global{ declare global{
interface HTMLAnchorElement{ interface HTMLAnchorElement{
@ -493,8 +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;
/** Mirrors element attributes for current host (both way). */ fromAttribute<T>(element: HTMLElement, name: string, value?: T): Signal<T, {}>;
attribute<T>(name: string, initial?: T): Signal<T, {}>
} }
export const S: S; export const S: S;
declare global { declare global {

File diff suppressed because one or more lines are too long

28
dist/esm.d.ts vendored
View File

@ -166,6 +166,34 @@ export const scope: {
pop(): ReturnType<Array<Scope>["pop"]>, pop(): ReturnType<Array<Scope>["pop"]>,
}; };
/*
* TODO TypeScript HACK (better way?)
* this doesnt works
* ```ts
* interface element<el> extends Node{
* prototype: el;
* append(...els: (SupportedElement | DocumentFragment | string | element<SupportedElement | DocumentFragment>)[]): el
* }
*
export function el<T>(
* tag_name?: "<>",
* ): element<DocumentFragment>
* ```
* as its complains here
* ```
ts
*
const d= el("div");
*
const f= (a: HTMLDivElement)=> a;
* f(d);
//←
* document.head.append( //←
* el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" }),
* );
* ```
* TODO for SVG
* */
type ddeAppend<el>= (...nodes: (Node | string)[])=> el; type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
declare global{ declare global{
interface HTMLAnchorElement{ interface HTMLAnchorElement{

View File

@ -1,14 +1,9 @@
import { el, on, scope } from "../../index.js"; import { el, on, scope } from "../../index.js";
import { S } from "../../signals.js"; import { S } from "../../signals.js";
const { hasOwnProperty }= Object.prototype;
/** /**
* @typedef CustomHTMLTestElementInterface * Compatible with `npx -y web-component-analyzer examples/components/webComponent.js`
* @type {object} * @element custom-test
* @property {string} name
* */
/**
* Compatible with `npx-wca test/components/webComponent.js`
* */ * */
export class CustomHTMLTestElement extends HTMLElement{ export class CustomHTMLTestElement extends HTMLElement{
static tagName= "custom-test"; static tagName= "custom-test";
@ -16,32 +11,34 @@ export class CustomHTMLTestElement extends HTMLElement{
return [ "name", "pre-name" ]; return [ "name", "pre-name" ];
} }
connectedCallback(){ connectedCallback(){
if(!this.hasAttribute("pre-name")) this.setAttribute("pre-name", "default");
this.attachShadow({ mode: "open" }).append( this.attachShadow({ mode: "open" }).append(
customElementRender(this, this.render) customElementRender(this, this.render, observedAttributes(S))
); );
} }
render({ test }){ render({ name, preName }){
const { host }= scope;
const { test }= host();
console.log(scope.state); console.log(scope.state);
scope.host( 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(
el("#text", name), el("#text", name),
el("#text", test),
el("#text", preName), el("#text", preName),
el("button", { type: "button", textContent: "pre-name", onclick: ()=> preName("Ahoj") }) el("button", { type: "button", textContent: "pre-name", onclick: ()=> preName("Ahoj") })
); );
} }
test= "A";
get name(){ return this.getAttribute("name"); } get name(){ return this.getAttribute("name"); }
set name(value){ this.setAttribute("name", value); } set name(value){ this.setAttribute("name", value); }
/** @attr pre-name */
get preName(){ return this.getAttribute("pre-name"); } get preName(){ return this.getAttribute("pre-name"); }
set preName(value){ this.setAttribute("pre-name", value); } set preName(value){ this.setAttribute("pre-name", value); }
} }
@ -49,12 +46,25 @@ export class CustomHTMLTestElement extends HTMLElement{
lifecycleToEvents(CustomHTMLTestElement) lifecycleToEvents(CustomHTMLTestElement)
customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement); customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement);
function customElementRender(_this, render){ function customElementRender(_this, render, props){
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 });
const out= render(_this); if(typeof props==="function") props= props(_this);
const out= 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){
@ -70,6 +80,7 @@ function lifecycleToEvents(class_declaration){
target.apply(thisArg, detail); target.apply(thisArg, detail);
}); });
class_declaration.prototype.__dde_lifecycleToEvents= true; class_declaration.prototype.__dde_lifecycleToEvents= true;
return class_declaration;
} }
function wrapMethod(obj, method, apply){ function wrapMethod(obj, method, apply){
obj[method]= new Proxy(obj[method] || (()=> {}), { apply }); obj[method]= new Proxy(obj[method] || (()=> {}), { apply });

3
signals.d.ts vendored
View File

@ -54,8 +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;
/** Mirrors element attributes for current host (both way). */ fromAttribute<T>(element: HTMLElement, name: string, value?: T): Signal<T, {}>;
attribute<T>(name: string, initial?: T): Signal<T, {}>
} }
export const S: S; export const S: S;
declare global { declare global {

View File

@ -62,50 +62,6 @@ S.symbols= {
signal: mark, signal: mark,
onclear: Symbol.for("Signal.onclear") onclear: Symbol.for("Signal.onclear")
}; };
import { on } from "./events.js";
import { scope } from "./dom.js";
const key_attributes= "__dde_attributes";
S.attribute= function(name, initial= undefined){
const out= S(initial);
let host;
scope.host(element=> {
host= element;
if(element instanceof HTMLElement){
if(element.hasAttribute(name)) out(element.getAttribute(name));
} else {
if(element.hasAttributeNS(null, name)) out(element.getAttributeNS(null, name));
}
if(element[key_attributes]){
element[key_attributes][name]= out;
return;
}
element[key_attributes]= { [name]: out };
on.attributeChanged(function attributeChangeToSignal({ detail }){
/*! This maps attributes to signals (`S.attribute`).
* Investigate `__dde_attributes` key of the element.*/
const [ name, value ]= detail;
const curr= element[key_attributes][name];
if(curr) return curr(value);
})(element);
on.disconnected(function(){
/*! This removes all signals mapped to attributes (`S.attribute`).
* Investigate `__dde_attributes` key of the element.*/
S.clear(...Object.values(element[key_attributes]));
host= null;
})(element);
return element;
});
return new Proxy(out, {
apply(target, _, args){
if(!args.length) return target();
if(!host) return;
const value= args[0];
if(host instanceof HTMLElement)
return host.setAttribute(name, value);
return host.setAttributeNS(null, name, value);
}
});
};
S.clear= function(...signals){ S.clear= function(...signals){
for(const signal of signals){ for(const signal of signals){
Reflect.deleteProperty(signal, "toJSON"); Reflect.deleteProperty(signal, "toJSON");
@ -130,6 +86,7 @@ S.clear= function(...signals){
}; };
const key_reactive= "__dde_reactive"; const key_reactive= "__dde_reactive";
import { el } from "./dom.js"; import { el } 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);
const mark_end= mark_start.end; const mark_end= mark_start.end;
@ -154,6 +111,34 @@ S.el= function(signal, map){
reRenderReactiveElement(signal()); reRenderReactiveElement(signal());
return out; return out;
}; };
import { on } from "./events.js";
const key_attributes= "__dde_attributes";
S.fromAttribute= function(element, name, value){
if(!element[key_attributes]){ // needs registration
element[key_attributes]= {};
on.attributeChanged(function attributeChangeToSignal({ detail }){
/*! This maps attributes to signals (`S.attribute`).
* Investigate `__dde_attributes` key of the element.*/
const [ name, value ]= detail;
const curr= element[key_attributes][name];
if(curr) return curr(value);
})(element);
on.disconnected(function(){
/*! This removes all signals mapped to attributes (`S.attribute`).
* Investigate `__dde_attributes` key of the element.*/
S.clear(...Object.values(element[key_attributes]));
})(element);
}
const store= element[key_attributes];
const out= Reflect.has(store, name) ? Reflect.get(store, name) : (store[name]= S(value));
return new Proxy(out, {
apply(target, _, args){
if(!args.length) return target();
const value= args[0];
return element.setAttribute(name, value);
}
});
};
import { typeOf } from './helpers.js'; import { typeOf } from './helpers.js';
export const signals_config= { export const signals_config= {