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

Compare commits

..

No commits in common. "51ccd11f82a104774c8eef44dddcadd75b91406c" and "14427882ed0742669dd37cb27449867f1a953f41" have entirely different histories.

13 changed files with 117 additions and 157 deletions

File diff suppressed because one or more lines are too long

40
dist/dde.js vendored

File diff suppressed because one or more lines are too long

View File

@ -54,7 +54,7 @@ interface observable{
* */ * */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Observable<any, any>>; attribute(name: string, initial?: string): Observable<string, {}>;
} }
export const observable: observable; export const observable: observable;
export const O: observable; export const O: observable;
@ -64,11 +64,16 @@ declare global {
type ddeActions<V>= Actions<V> type ddeActions<V>= Actions<V>
} }
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global {
interface ddePublicElementTagNameMap{
}
}
type SupportedElement= type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap] HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
| SVGElementTagNameMap[keyof SVGElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap]
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap]
| CustomElementTagNameMap[keyof CustomElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap]
| ddePublicElementTagNameMap[keyof ddePublicElementTagNameMap];
declare global { declare global {
type ddeComponentAttributes= Record<any, any> | undefined; type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void; type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void;
@ -107,7 +112,7 @@ export function classListDeclarative<El extends SupportedElement>(element: El, c
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT] export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any` type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any`
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap & string, TAG extends keyof ExtendedHTMLElementTagNameMap & string,
@ -234,22 +239,9 @@ export const scope: {
pop(): ReturnType<Array<Scope>["pop"]>, pop(): ReturnType<Array<Scope>["pop"]>,
}; };
export function customElementRender< /* TypeScript MEH // TODO for SVG */
EL extends HTMLElement, type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
P extends any = Record<string, any>
>(
custom_element: EL,
render: (props: P)=> SupportedElement,
props?: P | ((...args: any[])=> P)
): EL
export function customElementWithDDE<EL extends HTMLElement>(custom_element: EL): EL
export function lifecycleToEvents<EL extends HTMLElement>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/* TypeScript MEH */
declare global{ declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; } interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; }
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; } interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; } interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; }

File diff suppressed because one or more lines are too long

26
dist/esm.d.ts vendored
View File

@ -54,7 +54,7 @@ interface observable{
* */ * */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Observable<any, any>>; attribute(name: string, initial?: string): Observable<string, {}>;
} }
export const observable: observable; export const observable: observable;
export const O: observable; export const O: observable;
@ -64,11 +64,16 @@ declare global {
type ddeActions<V>= Actions<V> type ddeActions<V>= Actions<V>
} }
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global {
interface ddePublicElementTagNameMap{
}
}
type SupportedElement= type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap] HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
| SVGElementTagNameMap[keyof SVGElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap]
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap]
| CustomElementTagNameMap[keyof CustomElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap]
| ddePublicElementTagNameMap[keyof ddePublicElementTagNameMap];
declare global { declare global {
type ddeComponentAttributes= Record<any, any> | undefined; type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void; type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void;
@ -107,7 +112,7 @@ export function classListDeclarative<El extends SupportedElement>(element: El, c
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT] export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any` type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any`
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap & string, TAG extends keyof ExtendedHTMLElementTagNameMap & string,
@ -234,22 +239,9 @@ export const scope: {
pop(): ReturnType<Array<Scope>["pop"]>, pop(): ReturnType<Array<Scope>["pop"]>,
}; };
export function customElementRender< /* TypeScript MEH // TODO for SVG */
EL extends HTMLElement, type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
P extends any = Record<string, any>
>(
custom_element: EL,
render: (props: P)=> SupportedElement,
props?: P | ((...args: any[])=> P)
): EL
export function customElementWithDDE<EL extends HTMLElement>(custom_element: EL): EL
export function lifecycleToEvents<EL extends HTMLElement>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/* TypeScript MEH */
declare global{ declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; } interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; }
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; } interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; } interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; }

2
dist/esm.js vendored

File diff suppressed because one or more lines are too long

View File

@ -81,11 +81,24 @@ function todoComponent({ textContent, value }){
textContent(ev.target.value); textContent(ev.target.value);
is_editable(false); is_editable(false);
}); });
const memo= initMemo(host);
return el("li").append( return el("li").append(
O.el(is_editable, is=> is O.el(is_editable, is=> is
? el("input", { value: textContent(), type: "text" }, onedited) ? memo("view", ()=> el("input", { value: textContent(), type: "text" }, onedited))
: el("span", { textContent, onclick: is_editable.bind(null, true) }) : memo("edit", ()=> el("span", { textContent, onclick: is_editable.bind(null, true) }))
), ),
el("button", { type: "button", value, textContent: "-" }, onclick) el("button", { type: "button", value, textContent: "-" }, onclick)
); );
} }
function initMemo(host){
const memos= new Map();
host(on.disconnected(()=> memos.clear()));
return function useMemo(key, fn){
let memo= memos.get(key);
if(!memo){
memo= fn();
memos.set(key, memo);
}
return memo;
}
}

12
index.d.ts vendored
View File

@ -1,11 +1,16 @@
import { Observable } from "./observables"; import { Observable } from "./observables";
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global {
interface ddePublicElementTagNameMap{
}
}
type SupportedElement= type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap] HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
| SVGElementTagNameMap[keyof SVGElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap]
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap]
| CustomElementTagNameMap[keyof CustomElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap]
| ddePublicElementTagNameMap[keyof ddePublicElementTagNameMap];
declare global { declare global {
type ddeComponentAttributes= Record<any, any> | undefined; type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void; type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void;
@ -43,7 +48,7 @@ export function classListDeclarative<El extends SupportedElement>(element: El, c
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT] export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any` type textContent= string | ( (set?: string)=> string ); // TODO: for some reason `Observable<string, any>` leads to `attrs?: any`
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap & string, TAG extends keyof ExtendedHTMLElementTagNameMap & string,
@ -182,10 +187,9 @@ export function customElementWithDDE<EL extends HTMLElement>(custom_element: EL)
export function lifecycleToEvents<EL extends HTMLElement>(custom_element: EL): EL export function lifecycleToEvents<EL extends HTMLElement>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string> export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/* TypeScript MEH */ /* TypeScript MEH // TODO for SVG */
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
declare global{ declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; } interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; }
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; } interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; } interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; }

View File

@ -1,6 +1,6 @@
{ {
"name": "deka-dom-el", "name": "deka-dom-el",
"version": "0.7.8", "version": "0.7.7",
"description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.", "description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.",
"author": "Jan Andrle <andrle.jan@centrum.cz>", "author": "Jan Andrle <andrle.jan@centrum.cz>",
"license": "MIT", "license": "MIT",
@ -59,24 +59,18 @@
"size-limit": [ "size-limit": [
{ {
"path": "./index.js", "path": "./index.js",
"limit": "10.5 kB", "limit": "10 kB",
"gzip": false, "gzip": false,
"brotli": false "brotli": false
}, },
{ {
"path": "./observables.js", "path": "./observables.js",
"limit": "12 kB", "limit": "11.5 kB",
"gzip": false, "gzip": false,
"brotli": false "brotli": false
}, },
{
"path": "./index-with-observables.js",
"limit": "15 kB",
"gzip": false,
"brotli": false
},
{ {
"path": "./index-with-observables.js", "path": "./index-with-observables.js",
"limit": "5 kB" "limit": "5 kB"

View File

@ -1,4 +1,3 @@
import { keyDM, keyLTE } from "./dom-common.js";
import { scope } from "./dom.js"; import { scope } from "./dom.js";
export function customElementRender(custom_element, render, props= observedAttributes){ export function customElementRender(custom_element, render, props= observedAttributes){
scope.push({ scope.push({
@ -12,27 +11,20 @@ export function customElementRender(custom_element, render, props= observedAttri
return out; return out;
} }
export function lifecycleToEvents(class_declaration){ export function lifecycleToEvents(class_declaration){
wrapMethod(class_declaration.prototype, "connectedCallback", function(target, thisArg, detail){ for (const name of [ "connected", "disconnected" ])
target.apply(thisArg, detail); wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){
thisArg.dispatchEvent(new Event("dde:connected")); target.apply(thisArg, detail);
}); thisArg.dispatchEvent(new Event("dde:"+name));
if(!class_declaration.prototype[keyDM]) });
class_declaration.prototype[keyDM]= "dde"; const name= "attributeChanged";
wrapMethod(class_declaration.prototype, "disconnectedCallback", function(target, thisArg, detail){ wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){
target.apply(thisArg, detail);
const dispatch= ()=> thisArg.dispatchEvent(new Event("dde:disconnected"));
if(thisArg[keyDM]!=="dde")
return dispatch();
(queueMicrotask || setTimeout)(()=> !thisArg.isConnected && dispatch());
});
wrapMethod(class_declaration.prototype, "attributeChangedCallback", function(target, thisArg, detail){
const [ attribute, , value ]= detail; const [ attribute, , value ]= detail;
thisArg.dispatchEvent(new CustomEvent("dde:attributeChanged", { thisArg.dispatchEvent(new CustomEvent("dde:"+name, {
detail: [ attribute, value ] detail: [ attribute, value ]
})); }));
target.apply(thisArg, detail); target.apply(thisArg, detail);
}); });
class_declaration.prototype[keyLTE]= true; class_declaration.prototype.__dde_lifecycleToEvents= true;
return class_declaration; return class_declaration;
} }
export { lifecycleToEvents as customElementWithDDE }; export { lifecycleToEvents as customElementWithDDE };

View File

@ -26,5 +26,3 @@ function setDeleteAttr(obj, prop, val){
if(Reflect.get(obj, prop)==="undefined") if(Reflect.get(obj, prop)==="undefined")
return Reflect.set(obj, prop, ""); return Reflect.set(obj, prop, "");
} }
export const keyLTE= "__dde_lifecycleToEvents"; //boolean
export const keyDM= "__dde_disconnect_mode"; //native (unset) | dde | skip

View File

@ -1,5 +1,5 @@
export { registerReactivity } from './observables-common.js'; export { registerReactivity } from './observables-common.js';
import { enviroment as env, keyDM, keyLTE } from './dom-common.js'; import { enviroment as env } from './dom-common.js';
export function dispatchEvent(name, options, host){ export function dispatchEvent(name, options, host){
if(!options) options= {}; if(!options) options= {};
@ -26,19 +26,17 @@ const els_attribute_store= new WeakSet();
import { scope } from "./dom.js"; import { scope } from "./dom.js";
import { onAbort } from './helpers.js'; import { onAbort } from './helpers.js';
//TODO: cleanUp when event before abort? //TODO: cleanUp when event before abort?
//TODO: docs (e.g.) https://nolanlawson.com/2024/01/13/web-component-gotcha-constructor-vs-connectedcallback/
on.connected= function(listener, options){ on.connected= function(listener, options){
const { custom_element }= scope.current; const { custom_element }= scope.current;
const name= "connected"; const name= "connected";
if(typeof options !== "object") if(typeof options !== "object")
options= {}; options= {};
if(typeof options.once !== "boolean") options.once= true;
options.once= true;
return function registerElement(element){ return function registerElement(element){
if(custom_element) element= custom_element; if(custom_element) element= custom_element;
const event= "dde:"+name; const event= "dde:"+name;
element.addEventListener(event, listener, options); element.addEventListener(event, listener, options);
if(element[keyLTE]) return element; if(element.__dde_lifecycleToEvents) return element;
if(element.isConnected) return ( element.dispatchEvent(new Event(event)), element ); if(element.isConnected) return ( element.dispatchEvent(new Event(event)), element );
const c= onAbort(options.signal, ()=> c_ch_o.offConnected(element, listener)); const c= onAbort(options.signal, ()=> c_ch_o.offConnected(element, listener));
@ -51,14 +49,12 @@ on.disconnected= function(listener, options){
const name= "disconnected"; const name= "disconnected";
if(typeof options !== "object") if(typeof options !== "object")
options= {}; options= {};
if(typeof options.once !== "boolean") options.once= true;
options.once= true;
return function registerElement(element){ return function registerElement(element){
if(custom_element) element= custom_element; if(custom_element) element= custom_element;
if(!element[keyDM]) element[keyDM]= "dde";
const event= "dde:"+name; const event= "dde:"+name;
element.addEventListener(event, listener, options); element.addEventListener(event, listener, options);
if(element[keyLTE]) return element; if(element.__dde_lifecycleToEvents) return element;
const c= onAbort(options.signal, ()=> c_ch_o.offDisconnected(element, listener)); const c= onAbort(options.signal, ()=> c_ch_o.offDisconnected(element, listener));
if(c) c_ch_o.onDisconnected(element, listener); if(c) c_ch_o.onDisconnected(element, listener);
@ -81,7 +77,7 @@ on.attributeChanged= function(listener, options){
return function registerElement(element){ return function registerElement(element){
const event= "dde:"+name; const event= "dde:"+name;
element.addEventListener(event, listener, options); element.addEventListener(event, listener, options);
if(element[keyLTE] || els_attribute_store.has(element)) if(element.__dde_lifecycleToEvents || els_attribute_store.has(element))
return element; return element;
if(!env.M) return element; if(!env.M) return element;
@ -175,13 +171,13 @@ function connectionsChangesObserverConstructor(){
function requestIdle(){ return new Promise(function(resolve){ function requestIdle(){ return new Promise(function(resolve){
(requestIdleCallback || requestAnimationFrame)(resolve); (requestIdleCallback || requestAnimationFrame)(resolve);
}); } }); }
async function collectChildren(element){ async function collectChildren(element, filter){
if(store.size > 30)//TODO limit? if(store.size > 30)//TODO limit?
await requestIdle(); await requestIdle();
const out= []; const out= [];
if(!(element instanceof Node)) return out; if(!(element instanceof Node)) return out;
for(const el of store.keys()){ for(const el of store.keys()){
if(el===element || !(el instanceof Node)) continue; if(el===element || !(el instanceof Node) || filter(el)) continue;
if(element.contains(el)) if(element.contains(el))
out.push(el); out.push(el);
} }
@ -190,7 +186,7 @@ function connectionsChangesObserverConstructor(){
function observerAdded(addedNodes, is_root){ function observerAdded(addedNodes, is_root){
let out= false; let out= false;
for(const element of addedNodes){ for(const element of addedNodes){
if(is_root) collectChildren(element).then(observerAdded); if(is_root) collectChildren(element, el=> !el.isConnectedd).then(observerAdded);
if(!store.has(element)) continue; if(!store.has(element)) continue;
const ls= store.get(element); const ls= store.get(element);
@ -207,25 +203,17 @@ function connectionsChangesObserverConstructor(){
function observerRemoved(removedNodes, is_root){ function observerRemoved(removedNodes, is_root){
let out= false; let out= false;
for(const element of removedNodes){ for(const element of removedNodes){
if(is_root) collectChildren(element).then(observerRemoved); if(is_root) collectChildren(element, el=> el.isConnectedd).then(observerRemoved);
if(!store.has(element)) continue; if(!store.has(element)) continue;
const ls= store.get(element); const ls= store.get(element);
if(!ls.length_d) continue; if(!ls.length_d) continue;
const dispatch= dispatchRemove(element);
if(element[keyDM]==="dde") element.dispatchEvent(new Event("dde:disconnected"));
(queueMicrotask || setTimeout)(dispatch);
else store.delete(element);
dispatch();
out= true; out= true;
} }
return out; return out;
} }
function dispatchRemove(element){
return ()=> {
if(element.isConnected) return;
element.dispatchEvent(new Event("dde:disconnected"));
store.delete(element);
};
}
} }

View File

@ -96,7 +96,7 @@ observable.el= function(o, map){
out.append(mark_start, mark_end); out.append(mark_start, mark_end);
const { current }= scope; const { current }= scope;
const reRenderReactiveElement= v=> { const reRenderReactiveElement= v=> {
if(!mark_start.parentNode || !mark_end.parentNode) // isConnected or wasnt yet rendered if(!mark_start.parentNode || !mark_end.parentNode)
return removeObservableListener(o, reRenderReactiveElement); return removeObservableListener(o, reRenderReactiveElement);
scope.push(current); scope.push(current);
let els= map(v); let els= map(v);
@ -107,21 +107,12 @@ observable.el= function(o, map){
while(( el_r= mark_start.nextSibling ) !== mark_end) while(( el_r= mark_start.nextSibling ) !== mark_end)
el_r.remove(); el_r.remove();
mark_start.after(...els); mark_start.after(...els);
if(mark_start.isConnected)
requestCleanUpReactives(current.host());
}; };
addObservableListener(o, reRenderReactiveElement); addObservableListener(o, reRenderReactiveElement);
removeObservablesFromElements(o, reRenderReactiveElement, mark_start, map); removeObservablesFromElements(o, reRenderReactiveElement, mark_start, map);
reRenderReactiveElement(o()); reRenderReactiveElement(o());
return out; return out;
}; };
function requestCleanUpReactives(host){
if(!host || !host[key_reactive]) return;
(requestIdleCallback || setTimeout)(function(){
host[key_reactive]= host[key_reactive]
.filter(([ o, el ])=> el.isConnected ? true : (removeObservableListener(...o), false));
});
}
import { on } from "./events.js"; import { on } from "./events.js";
import { observedAttributes } from "./helpers.js"; import { observedAttributes } from "./helpers.js";
const observedAttributeActions= { const observedAttributeActions= {
@ -161,11 +152,7 @@ export const observables_config= {
isObservable, isObservable,
processReactiveAttribute(element, key, attrs, set){ processReactiveAttribute(element, key, attrs, set){
if(!isObservable(attrs)) return attrs; if(!isObservable(attrs)) return attrs;
const l= attr=> { const l= attr=> set(key, attr);
if(!element.isConnected)
return removeObservableListener(attrs, l);
set(key, attr);
};
addObservableListener(attrs, l); addObservableListener(attrs, l);
removeObservablesFromElements(attrs, l, element, key); removeObservablesFromElements(attrs, l, element, key);
return attrs(); return attrs();