mirror of
https://github.com/jaandrle/deka-dom-el
synced 2024-11-22 16:55:23 +01:00
Compare commits
3 Commits
14427882ed
...
51ccd11f82
Author | SHA1 | Date | |
---|---|---|---|
51ccd11f82 | |||
7e4c804184 | |||
277ad6a7f5 |
46
dist/dde-with-observables.js
vendored
46
dist/dde-with-observables.js
vendored
File diff suppressed because one or more lines are too long
40
dist/dde.js
vendored
40
dist/dde.js
vendored
File diff suppressed because one or more lines are too long
26
dist/esm-with-observables.d.ts
vendored
26
dist/esm-with-observables.d.ts
vendored
@ -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;
|
||||||
|
|
||||||
attribute(name: string, initial?: string): Observable<string, {}>;
|
observedAttributes(custom_element: HTMLElement): Record<string, Observable<any, any>>;
|
||||||
}
|
}
|
||||||
export const observable: observable;
|
export const observable: observable;
|
||||||
export const O: observable;
|
export const O: observable;
|
||||||
@ -64,16 +64,11 @@ 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;
|
||||||
@ -112,7 +107,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 & ddePublicElementTagNameMap
|
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
|
||||||
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,
|
||||||
@ -239,9 +234,22 @@ export const scope: {
|
|||||||
pop(): ReturnType<Array<Scope>["pop"]>,
|
pop(): ReturnType<Array<Scope>["pop"]>,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TypeScript MEH // TODO for SVG */
|
export function customElementRender<
|
||||||
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
|
EL extends HTMLElement,
|
||||||
|
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>; }
|
||||||
|
8
dist/esm-with-observables.js
vendored
8
dist/esm-with-observables.js
vendored
File diff suppressed because one or more lines are too long
26
dist/esm.d.ts
vendored
26
dist/esm.d.ts
vendored
@ -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;
|
||||||
|
|
||||||
attribute(name: string, initial?: string): Observable<string, {}>;
|
observedAttributes(custom_element: HTMLElement): Record<string, Observable<any, any>>;
|
||||||
}
|
}
|
||||||
export const observable: observable;
|
export const observable: observable;
|
||||||
export const O: observable;
|
export const O: observable;
|
||||||
@ -64,16 +64,11 @@ 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;
|
||||||
@ -112,7 +107,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 & ddePublicElementTagNameMap
|
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
|
||||||
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,
|
||||||
@ -239,9 +234,22 @@ export const scope: {
|
|||||||
pop(): ReturnType<Array<Scope>["pop"]>,
|
pop(): ReturnType<Array<Scope>["pop"]>,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TypeScript MEH // TODO for SVG */
|
export function customElementRender<
|
||||||
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
|
EL extends HTMLElement,
|
||||||
|
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
2
dist/esm.js
vendored
File diff suppressed because one or more lines are too long
@ -81,24 +81,11 @@ 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
|
||||||
? memo("view", ()=> el("input", { value: textContent(), type: "text" }, onedited))
|
? el("input", { value: textContent(), type: "text" }, onedited)
|
||||||
: memo("edit", ()=> el("span", { textContent, onclick: is_editable.bind(null, true) }))
|
: 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
12
index.d.ts
vendored
@ -1,16 +1,11 @@
|
|||||||
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;
|
||||||
@ -48,7 +43,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 & ddePublicElementTagNameMap
|
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
|
||||||
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,
|
||||||
@ -187,9 +182,10 @@ 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 // TODO for SVG */
|
/* TypeScript MEH */
|
||||||
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>; }
|
||||||
|
12
package.json
12
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "deka-dom-el",
|
"name": "deka-dom-el",
|
||||||
"version": "0.7.7",
|
"version": "0.7.8",
|
||||||
"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,18 +59,24 @@
|
|||||||
"size-limit": [
|
"size-limit": [
|
||||||
{
|
{
|
||||||
"path": "./index.js",
|
"path": "./index.js",
|
||||||
"limit": "10 kB",
|
"limit": "10.5 kB",
|
||||||
"gzip": false,
|
"gzip": false,
|
||||||
"brotli": false
|
"brotli": false
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./observables.js",
|
"path": "./observables.js",
|
||||||
"limit": "11.5 kB",
|
"limit": "12 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"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
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({
|
||||||
@ -11,20 +12,27 @@ export function customElementRender(custom_element, render, props= observedAttri
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
export function lifecycleToEvents(class_declaration){
|
export function lifecycleToEvents(class_declaration){
|
||||||
for (const name of [ "connected", "disconnected" ])
|
wrapMethod(class_declaration.prototype, "connectedCallback", function(target, thisArg, detail){
|
||||||
wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){
|
target.apply(thisArg, detail);
|
||||||
target.apply(thisArg, detail);
|
thisArg.dispatchEvent(new Event("dde:connected"));
|
||||||
thisArg.dispatchEvent(new Event("dde:"+name));
|
});
|
||||||
});
|
if(!class_declaration.prototype[keyDM])
|
||||||
const name= "attributeChanged";
|
class_declaration.prototype[keyDM]= "dde";
|
||||||
wrapMethod(class_declaration.prototype, name+"Callback", function(target, thisArg, detail){
|
wrapMethod(class_declaration.prototype, "disconnectedCallback", 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:"+name, {
|
thisArg.dispatchEvent(new CustomEvent("dde:attributeChanged", {
|
||||||
detail: [ attribute, value ]
|
detail: [ attribute, value ]
|
||||||
}));
|
}));
|
||||||
target.apply(thisArg, detail);
|
target.apply(thisArg, detail);
|
||||||
});
|
});
|
||||||
class_declaration.prototype.__dde_lifecycleToEvents= true;
|
class_declaration.prototype[keyLTE]= true;
|
||||||
return class_declaration;
|
return class_declaration;
|
||||||
}
|
}
|
||||||
export { lifecycleToEvents as customElementWithDDE };
|
export { lifecycleToEvents as customElementWithDDE };
|
||||||
|
@ -26,3 +26,5 @@ 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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export { registerReactivity } from './observables-common.js';
|
export { registerReactivity } from './observables-common.js';
|
||||||
import { enviroment as env } from './dom-common.js';
|
import { enviroment as env, keyDM, keyLTE } from './dom-common.js';
|
||||||
|
|
||||||
export function dispatchEvent(name, options, host){
|
export function dispatchEvent(name, options, host){
|
||||||
if(!options) options= {};
|
if(!options) options= {};
|
||||||
@ -26,17 +26,19 @@ 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= {};
|
||||||
options.once= true;
|
if(typeof options.once !== "boolean")
|
||||||
|
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.__dde_lifecycleToEvents) return element;
|
if(element[keyLTE]) 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));
|
||||||
@ -49,12 +51,14 @@ on.disconnected= function(listener, options){
|
|||||||
const name= "disconnected";
|
const name= "disconnected";
|
||||||
if(typeof options !== "object")
|
if(typeof options !== "object")
|
||||||
options= {};
|
options= {};
|
||||||
options.once= true;
|
if(typeof options.once !== "boolean")
|
||||||
|
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.__dde_lifecycleToEvents) return element;
|
if(element[keyLTE]) 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);
|
||||||
@ -77,7 +81,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.__dde_lifecycleToEvents || els_attribute_store.has(element))
|
if(element[keyLTE] || els_attribute_store.has(element))
|
||||||
return element;
|
return element;
|
||||||
|
|
||||||
if(!env.M) return element;
|
if(!env.M) return element;
|
||||||
@ -171,13 +175,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, filter){
|
async function collectChildren(element){
|
||||||
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) || filter(el)) continue;
|
if(el===element || !(el instanceof Node)) continue;
|
||||||
if(element.contains(el))
|
if(element.contains(el))
|
||||||
out.push(el);
|
out.push(el);
|
||||||
}
|
}
|
||||||
@ -186,7 +190,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, el=> !el.isConnectedd).then(observerAdded);
|
if(is_root) collectChildren(element).then(observerAdded);
|
||||||
if(!store.has(element)) continue;
|
if(!store.has(element)) continue;
|
||||||
|
|
||||||
const ls= store.get(element);
|
const ls= store.get(element);
|
||||||
@ -203,17 +207,25 @@ 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, el=> el.isConnectedd).then(observerRemoved);
|
if(is_root) collectChildren(element).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);
|
||||||
element.dispatchEvent(new Event("dde:disconnected"));
|
if(element[keyDM]==="dde")
|
||||||
|
(queueMicrotask || setTimeout)(dispatch);
|
||||||
store.delete(element);
|
else
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
if(!mark_start.parentNode || !mark_end.parentNode) // isConnected or wasn’t yet rendered
|
||||||
return removeObservableListener(o, reRenderReactiveElement);
|
return removeObservableListener(o, reRenderReactiveElement);
|
||||||
scope.push(current);
|
scope.push(current);
|
||||||
let els= map(v);
|
let els= map(v);
|
||||||
@ -107,12 +107,21 @@ 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= {
|
||||||
@ -152,7 +161,11 @@ 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=> set(key, attr);
|
const l= 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();
|
||||||
|
Loading…
Reference in New Issue
Block a user