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

💥 docs observables

This commit is contained in:
Jan Andrle 2023-11-29 18:25:21 +01:00
parent 420defe4a2
commit 01f102c149
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
28 changed files with 1009 additions and 618 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,68 @@
export type Observable<V, A>= (set?: V)=> V & A;
type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof observable._ | void;
//type SymbolObservable= Symbol;
type SymbolOnclear= symbol;
type Actions<V>= Record<string | SymbolOnclear, Action<V>>;
interface observable{
_: Symbol
/**
* Simple example:
* ```js
* const hello= S("Hello Observable");
* ```
* simple todo observable:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed observable:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name()+" "+surname());
* ```
* @param value Initial observable value. Or function computing value from other observables.
* @param actions Use to define actions on the observable. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the observable is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Observable<V, A>;
/**
* Computations observable. This creates a observable which is computed from other observables.
* */
<V>(computation: ()=> V): Observable<V, {}>
action<S extends Observable<any, Actions<any>>, A extends (S extends Observable<any, infer A> ? A : never), N extends keyof A>(
observable: S,
name: N,
...params: A[N] extends (...args: infer P)=> any ? P : never
): void;
clear(...observables: Observable<any, any>[]): void;
on<T>(observable: Observable<T, any>, onchange: (a: T)=> void, options?: AddEventListenerOptions): void;
symbols: {
//observable: SymbolObservable;
onclear: SymbolOnclear;
}
/**
* Reactive element, which is rendered based on the given observable.
* ```js
* S.el(observable, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
attribute(name: string, initial?: string): Observable<string, {}>;
}
export const observable: observable;
export const O: observable;
declare global {
type ddeObservable<T, A= {}>= Observable<T, A>;
type ddeAction<V>= Action<V>
type ddeActions<V>= Actions<V>
}
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global { declare global {
interface ddePublicElementTagNameMap{ interface ddePublicElementTagNameMap{
@ -19,20 +84,21 @@ type AttrsModified= {
/** /**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/ */
style: string | Partial<CSSStyleDeclaration> style: string | Partial<CSSStyleDeclaration> | Observable<string, any> | Partial<{ [K in keyof CSSStyleDeclaration]: Observable<CSSStyleDeclaration[K], any> }>
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others.
*/ */
classList: Record<string,-1|0|1|boolean>, classList: Record<string,-1|0|1|boolean|Observable<-1|0|1|boolean, any>>,
/** /**
* By default simiral to `className`, but also supports `string[]` * By default simiral to `className`, but also supports `string[]`
* */ * */
className: string | (string|boolean|undefined)[]; className: string | (string|boolean|undefined|Observable<string|boolean|undefined, any>)[];
/** /**
* Sets `aria-*` simiraly to `dataset` * Sets `aria-*` simiraly to `dataset`
* */ * */
ariaset: Record<string,string>, ariaset: Record<string,string|Observable<string, any>>,
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string> & Record<`.${string}`, any> } & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string|Observable<string, any>> & Record<`.${string}`, any>
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>;
/** /**
* Just element attributtes * Just element attributtes
* *
@ -41,17 +107,28 @@ type AttrsModified= {
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private * @private
*/ */
type ElementAttributes<T extends SupportedElement>= Omit<T,keyof AttrsModified> & AttrsModified; type ElementAttributes<T extends SupportedElement>= Partial<_fromElsInterfaces<T> & { [K in keyof _fromElsInterfaces<T>]: Observable<_fromElsInterfaces<T>[K], any> } & AttrsModified>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El
export function assign<El extends SupportedElement>(element: El, ...attrs_array: Partial<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= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap type ExtendedHTMLElementTagNameMap= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>( export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG, tag_name: TAG,
attrs?: string | Partial<ElementAttributes<ExtendedHTMLElementTagNameMap[TAG]>>, attrs?: ElementAttributes<EL>,
...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[TAG]>[] ...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): ExtendedHTMLElementTagNameMap[TAG] ): EL
export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG,
attrs?: string | Observable<string, any>,
...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): EL
export function el<T>( export function el<T>(
tag_name?: "<>", tag_name?: "<>",
): ddeDocumentFragment ): ddeDocumentFragment
@ -63,12 +140,7 @@ export function el<
attrs?: A | string, attrs?: A | string,
...addons: ddeElementAddon<ReturnType<C>>[] ...addons: ddeElementAddon<ReturnType<C>>[]
): ReturnType<C> ): ReturnType<C>
export { el as createElement }
export function el(
tag_name: string,
attrs?: string | Record<string, any>,
...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement
export function elNS( export function elNS(
namespace: "http://www.w3.org/2000/svg" namespace: "http://www.w3.org/2000/svg"
@ -91,6 +163,7 @@ export function elNS(
attrs?: string | Record<string, any>, attrs?: string | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[] ...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement )=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL
@ -250,71 +323,6 @@ declare global{
"ul": ddeHTMLUListElement; "ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement; "video": ddeHTMLVideoElement;
} }
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGElementTagNameMap { interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement; "a": ddeSVGAElement;
"animate": ddeSVGAnimateElement; "animate": ddeSVGAnimateElement;
@ -380,6 +388,72 @@ declare global{
"use": ddeSVGUseElement; "use": ddeSVGUseElement;
"view": ddeSVGViewElement; "view": ddeSVGViewElement;
} }
}
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; } interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; }
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; } interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; } interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; }
@ -443,68 +517,3 @@ declare global{
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; } interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; }
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; } interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; } interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; }
}
export type Observable<V, A>= (set?: V)=> V & A;
type Action<V>= (this: { value: V }, ...a: any[])=> typeof observable._ | void;
type SymbolOnclear= Symbol;
type SymbolObservable= Symbol;
type Actions<V>= Record<string, Action<V>>;
interface observable{
_: Symbol
/**
* Simple example:
* ```js
* const hello= S("Hello Observable");
* ```
* simple todo observable:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed observable:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name()+" "+surname());
* ```
* @param value Initial observable value. Or function computing value from other observables.
* @param actions Use to define actions on the observable. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the observable is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Observable<V, A>;
/**
* Computations observable. This creates a observable which is computed from other observables.
* */
<V>(computation: ()=> V): Observable<V, {}>
action<S extends Observable<any, Actions<any>>, A extends (S extends Observable<any, infer A> ? A : never), N extends keyof A>(
observable: S,
name: N,
...params: A[N] extends (...args: infer P)=> any ? P : never
): void;
clear(...observables: Observable<any, any>[]): void;
on<T>(observable: Observable<T, any>, onchange: (a: T)=> void, options?: AddEventListenerOptions): void;
symbols: {
observable: SymbolObservable;
onclear: SymbolOnclear;
}
/**
* Reactive element, which is rendered based on the given observable.
* ```js
* S.el(observable, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment;
attribute(name: string, initial?: string): Observable<string, {}>;
}
export const observable: observable;
export const O: observable;
declare global {
type ddeObservable<T, A= {}>= Observable<T, A>;
type ddeActions<V>= Actions<V>
}

File diff suppressed because one or more lines are too long

239
dist/esm.d.ts vendored
View File

@ -1,3 +1,68 @@
export type Observable<V, A>= (set?: V)=> V & A;
type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof observable._ | void;
//type SymbolObservable= Symbol;
type SymbolOnclear= symbol;
type Actions<V>= Record<string | SymbolOnclear, Action<V>>;
interface observable{
_: Symbol
/**
* Simple example:
* ```js
* const hello= S("Hello Observable");
* ```
* simple todo observable:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed observable:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name()+" "+surname());
* ```
* @param value Initial observable value. Or function computing value from other observables.
* @param actions Use to define actions on the observable. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the observable is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Observable<V, A>;
/**
* Computations observable. This creates a observable which is computed from other observables.
* */
<V>(computation: ()=> V): Observable<V, {}>
action<S extends Observable<any, Actions<any>>, A extends (S extends Observable<any, infer A> ? A : never), N extends keyof A>(
observable: S,
name: N,
...params: A[N] extends (...args: infer P)=> any ? P : never
): void;
clear(...observables: Observable<any, any>[]): void;
on<T>(observable: Observable<T, any>, onchange: (a: T)=> void, options?: AddEventListenerOptions): void;
symbols: {
//observable: SymbolObservable;
onclear: SymbolOnclear;
}
/**
* Reactive element, which is rendered based on the given observable.
* ```js
* S.el(observable, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
attribute(name: string, initial?: string): Observable<string, {}>;
}
export const observable: observable;
export const O: observable;
declare global {
type ddeObservable<T, A= {}>= Observable<T, A>;
type ddeAction<V>= Action<V>
type ddeActions<V>= Actions<V>
}
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global { declare global {
interface ddePublicElementTagNameMap{ interface ddePublicElementTagNameMap{
@ -19,20 +84,21 @@ type AttrsModified= {
/** /**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/ */
style: string | Partial<CSSStyleDeclaration> style: string | Partial<CSSStyleDeclaration> | Observable<string, any> | Partial<{ [K in keyof CSSStyleDeclaration]: Observable<CSSStyleDeclaration[K], any> }>
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others.
*/ */
classList: Record<string,-1|0|1|boolean>, classList: Record<string,-1|0|1|boolean|Observable<-1|0|1|boolean, any>>,
/** /**
* By default simiral to `className`, but also supports `string[]` * By default simiral to `className`, but also supports `string[]`
* */ * */
className: string | (string|boolean|undefined)[]; className: string | (string|boolean|undefined|Observable<string|boolean|undefined, any>)[];
/** /**
* Sets `aria-*` simiraly to `dataset` * Sets `aria-*` simiraly to `dataset`
* */ * */
ariaset: Record<string,string>, ariaset: Record<string,string|Observable<string, any>>,
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string> & Record<`.${string}`, any> } & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string|Observable<string, any>> & Record<`.${string}`, any>
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>;
/** /**
* Just element attributtes * Just element attributtes
* *
@ -41,17 +107,28 @@ type AttrsModified= {
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private * @private
*/ */
type ElementAttributes<T extends SupportedElement>= Omit<T,keyof AttrsModified> & AttrsModified; type ElementAttributes<T extends SupportedElement>= Partial<_fromElsInterfaces<T> & { [K in keyof _fromElsInterfaces<T>]: Observable<_fromElsInterfaces<T>[K], any> } & AttrsModified>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El
export function assign<El extends SupportedElement>(element: El, ...attrs_array: Partial<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= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap type ExtendedHTMLElementTagNameMap= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>( export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG, tag_name: TAG,
attrs?: string | Partial<ElementAttributes<ExtendedHTMLElementTagNameMap[TAG]>>, attrs?: ElementAttributes<EL>,
...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[TAG]>[] ...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): ExtendedHTMLElementTagNameMap[TAG] ): EL
export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG,
attrs?: string | Observable<string, any>,
...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): EL
export function el<T>( export function el<T>(
tag_name?: "<>", tag_name?: "<>",
): ddeDocumentFragment ): ddeDocumentFragment
@ -63,12 +140,7 @@ export function el<
attrs?: A | string, attrs?: A | string,
...addons: ddeElementAddon<ReturnType<C>>[] ...addons: ddeElementAddon<ReturnType<C>>[]
): ReturnType<C> ): ReturnType<C>
export { el as createElement }
export function el(
tag_name: string,
attrs?: string | Record<string, any>,
...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement
export function elNS( export function elNS(
namespace: "http://www.w3.org/2000/svg" namespace: "http://www.w3.org/2000/svg"
@ -91,6 +163,7 @@ export function elNS(
attrs?: string | Record<string, any>, attrs?: string | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[] ...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement )=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL
@ -250,71 +323,6 @@ declare global{
"ul": ddeHTMLUListElement; "ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement; "video": ddeHTMLVideoElement;
} }
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGElementTagNameMap { interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement; "a": ddeSVGAElement;
"animate": ddeSVGAnimateElement; "animate": ddeSVGAnimateElement;
@ -380,6 +388,72 @@ declare global{
"use": ddeSVGUseElement; "use": ddeSVGUseElement;
"view": ddeSVGViewElement; "view": ddeSVGViewElement;
} }
}
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; } interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; }
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; } interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; } interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; }
@ -443,4 +517,3 @@ declare global{
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; } interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; }
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; } interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; } interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; }
}

View File

@ -18,7 +18,7 @@ body {
@media (min-width:768px) { @media (min-width:768px) {
body{ body{
grid-template-rows: auto auto; grid-template-rows: auto auto;
grid-template-columns: calc(var(--body-max-width) / 3) auto; grid-template-columns: calc(10 * var(--body-max-width) / 27) auto;
grid-template-areas: grid-template-areas:
"header header" "header header"
"sidebar content" "sidebar content"

View File

@ -1,7 +1,11 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Basic concepts of elements modifications and creations."><title>`deka-dom-el` — Elements</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Elements</h1><p>Basic concepts of elements modifications and creations.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables.">4. Observables and reactivity</a></nav><main><h2>Native JavaScript DOM elements creations</h2><p>Lets go through all patterns we would like to use and what needs to be improved for better experience.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// when NPM <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Basic concepts of elements modifications and creations."><title>`deka-dom-el` — Elements</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Elements</h1><p>Basic concepts of elements modifications and creations.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables.">4. Observables and reactivity</a></nav><main><h2>Native JavaScript DOM elements creations</h2><p>Lets go through all patterns we would like to use and what needs to be improved for better experience.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
import { assign, el, elNS } from "deka-dom-el"; import {
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js assign,
el, createElement,
elNS, createElementNS
} from "deka-dom-el";
el===createElement
elNS===createElementNS
// “internal” utils // “internal” utils
import { import {
assignAttribute, assignAttribute,
@ -140,4 +144,4 @@ document.body.append(
console.log( console.log(
document.body.innerHTML.includes("&lt;svg&gt;&lt;/svg&gt;&lt;math&gt;&lt;/math&gt;") document.body.innerHTML.includes("&lt;svg&gt;&lt;/svg&gt;&lt;math&gt;&lt;/math&gt;")
) )
</code></div><script>Flems(document.getElementById("code-example-1-bcjydb50gdc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { elNS, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst elSVG= elNS(\\\"http://www.w3.org/2000/svg\\\");\\nconst elMath= elNS(\\\"http://www.w3.org/1998/Math/MathML\\\");\\ndocument.body.append(\\n\\telSVG(\\\"svg\\\"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement\\n\\telMath(\\\"math\\\") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes\\n);\\n\\nconsole.log(\\n\\tdocument.body.innerHTML.includes(\\\"<svg></svg><math></math>\\\")\\n)\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonicUl" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>assign(&lt;element&gt;, ...&lt;idl-objects&gt;): &lt;element&gt;</code> — assign properties to the element</li><li><code>el(&lt;tag-name&gt;, &lt;primitive&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — simple element containing only text</li><li><code>el(&lt;tag-name&gt;, &lt;idl-object&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — element with more properties</li><li><code>el(&lt;function&gt;, &lt;function-argument(s)&gt;)[.append(...)]: &lt;element-returned-by-function&gt;</code> — using component represented by function</li><li><code>el(&lt;...&gt;, &lt;...&gt;, ...&lt;addons&gt;)</code> — see following page</li><li><code>elNS(&lt;namespace&gt;)(&lt;as-el-see-above&gt;)[.append(...)]: &lt;element-based-on-arguments&gt;</code> — typically SVG elements</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="./" title="Introducing a&nbsp;library."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Introduction (previous)</a><a rel="next" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Events and Addons</a></div></main></body></html> </code></div><script>Flems(document.getElementById("code-example-1-bcjydb50gdc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { elNS, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst elSVG= elNS(\\\"http://www.w3.org/2000/svg\\\");\\nconst elMath= elNS(\\\"http://www.w3.org/1998/Math/MathML\\\");\\ndocument.body.append(\\n\\telSVG(\\\"svg\\\"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement\\n\\telMath(\\\"math\\\") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes\\n);\\n\\nconsole.log(\\n\\tdocument.body.innerHTML.includes(\\\"<svg></svg><math></math>\\\")\\n)\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonic" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>assign(&lt;element&gt;, ...&lt;idl-objects&gt;): &lt;element&gt;</code> — assign properties to the element</li><li><code>el(&lt;tag-name&gt;, &lt;primitive&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — simple element containing only text</li><li><code>el(&lt;tag-name&gt;, &lt;idl-object&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — element with more properties</li><li><code>el(&lt;function&gt;, &lt;function-argument(s)&gt;)[.append(...)]: &lt;element-returned-by-function&gt;</code> — using component represented by function</li><li><code>el(&lt;...&gt;, &lt;...&gt;, ...&lt;addons&gt;)</code> — see following page</li><li><code>elNS(&lt;namespace&gt;)(&lt;as-el-see-above&gt;)[.append(...)]: &lt;element-based-on-arguments&gt;</code> — typically SVG elements</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="./" title="Introducing a&nbsp;library."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Introduction (previous)</a><a rel="next" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Events and Addons</a></div></main></body></html>

View File

@ -1,10 +1,7 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Using not only events in UI declaratively."><title>`deka-dom-el` — Events and Addons</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Events and Addons</h1><p>Using not only events in UI declaratively.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively." class="current">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables.">4. Observables and reactivity</a></nav><main><h2>Listenning to the native DOM events and other Addons</h2><p>We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called <em>Addon</em> to incorporate not only this in UI templates declaratively.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// when NPM <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Using not only events in UI declaratively."><title>`deka-dom-el` — Events and Addons</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Events and Addons</h1><p>Using not only events in UI declaratively.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively." class="current">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables.">4. Observables and reactivity</a></nav><main><h2>Listenning to the native DOM events and other Addons</h2><p>We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called <em>Addon</em> to incorporate not only this in UI templates declaratively.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
import { on, dispatchEvent } from "deka-dom-el"; import { on, dispatchEvent } from "deka-dom-el";
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
/** /** @type {ddeElementAddon} */
* @type {ddeElementAddon}
* */
</code></div><h3 id="h-events-and-listenners"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-events-and-listenners" tabindex="-1">#</a> Events and listenners</h3><p>In JavaScript you can listen to the native DOM events of the given element by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener" title="addEventListener on MDN"><code>element.addEventListener(type, listener, options)</code></a>. The library provides an alternative (<code>on</code>) accepting the differen order of the arguments:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1wmddlo83w68" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; </code></div><h3 id="h-events-and-listenners"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-events-and-listenners" tabindex="-1">#</a> Events and listenners</h3><p>In JavaScript you can listen to the native DOM events of the given element by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener" title="addEventListener on MDN"><code>element.addEventListener(type, listener, options)</code></a>. The library provides an alternative (<code>on</code>) accepting the differen order of the arguments:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1wmddlo83w68" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const log= mark=&gt; console.log.bind(console, mark); const log= mark=&gt; console.log.bind(console, mark);
@ -94,4 +91,4 @@ function dde(){
function ddeOptions(){ function ddeOptions(){
dispatchEvent("test", { bubbles: true })(this, "hi"); dispatchEvent("test", { bubbles: true })(this, "hi");
} }
</code></div><script>Flems(document.getElementById("code-example-2-b6a1hbrxh7s"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on, dispatchEvent } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Listenning to `test` event.\\\", on(\\\"test\\\", console.log)).append(\\n\\t\\tel(\\\"br\\\"),\\n\\t\\tel(\\\"button\\\", \\\"native\\\", on(\\\"click\\\", native)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde\\\", on(\\\"click\\\", dde)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde with options\\\", on(\\\"click\\\", ddeOptions))\\n\\t)\\n);\\nfunction native(){\\n\\tthis.dispatchEvent(\\n\\t\\tnew CustomEvent(\\\"test\\\",\\n\\t\\t\\t{ bubbles: true, detail: \\\"hi\\\" }\\n\\t\\t)\\n\\t);\\n}\\nfunction dde(){\\n\\tdispatchEvent(\\\"test\\\")(this.parentElement, \\\"hi\\\");\\n}\\nfunction ddeOptions(){\\n\\tdispatchEvent(\\\"test\\\", { bubbles: true })(this, \\\"hi\\\");\\n}\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonicUl" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>on(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — just <code>&lt;element&gt;.addEventListener(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])</code></li><li><code>on.&lt;live-cycle&gt;(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — corresponds to custom elemnets callbacks <code>&lt;live-cycle&gt;Callback(...){...}</code>. To connect to custom element see following page, else it is simulated by MutationObserver.</li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element)</code> — just <code>&lt;element&gt;.dispatchEvent(new Event(&lt;event&gt;[, &lt;options&gt;]))</code></li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element, detail)</code> — just <code>&lt;element&gt;.dispatchEvent(new CustomEvent(&lt;event&gt;, { detail, ...&lt;options&gt; }))</code></li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p02-elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Elements (previous)</a><a rel="next" href="p04-observables" title="Handling reactivity in UI via observables."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Observables and reactivity</a></div></main></body></html> </code></div><script>Flems(document.getElementById("code-example-2-b6a1hbrxh7s"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on, dispatchEvent } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Listenning to `test` event.\\\", on(\\\"test\\\", console.log)).append(\\n\\t\\tel(\\\"br\\\"),\\n\\t\\tel(\\\"button\\\", \\\"native\\\", on(\\\"click\\\", native)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde\\\", on(\\\"click\\\", dde)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde with options\\\", on(\\\"click\\\", ddeOptions))\\n\\t)\\n);\\nfunction native(){\\n\\tthis.dispatchEvent(\\n\\t\\tnew CustomEvent(\\\"test\\\",\\n\\t\\t\\t{ bubbles: true, detail: \\\"hi\\\" }\\n\\t\\t)\\n\\t);\\n}\\nfunction dde(){\\n\\tdispatchEvent(\\\"test\\\")(this.parentElement, \\\"hi\\\");\\n}\\nfunction ddeOptions(){\\n\\tdispatchEvent(\\\"test\\\", { bubbles: true })(this, \\\"hi\\\");\\n}\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonic" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>on(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — just <code>&lt;element&gt;.addEventListener(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])</code></li><li><code>on.&lt;live-cycle&gt;(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — corresponds to custom elemnets callbacks <code>&lt;live-cycle&gt;Callback(...){...}</code>. To connect to custom element see following page, else it is simulated by MutationObserver.</li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element)</code> — just <code>&lt;element&gt;.dispatchEvent(new Event(&lt;event&gt;[, &lt;options&gt;]))</code></li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element, detail)</code> — just <code>&lt;element&gt;.dispatchEvent(new CustomEvent(&lt;event&gt;, { detail, ...&lt;options&gt; }))</code></li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p02-elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Elements (previous)</a><a rel="next" href="p04-observables" title="Handling reactivity in UI via observables."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Observables and reactivity</a></div></main></body></html>

View File

@ -1,22 +1,22 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Handling reactivity in UI via observables."><title>`deka-dom-el` — Observables and reactivity</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Observables and reactivity</h1><p>Handling reactivity in UI via observables.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables." class="current">4. Observables and reactivity</a></nav><main><h2>Using observables to manage reactivity</h2><p>How a program responds to variable data or user interactions is one of the fundamental problems of programming. If we desire to solve the issue in a declarative manner, observables may be a viable approach.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// when NPM <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Handling reactivity in UI via observables."><title>`deka-dom-el` — Observables and reactivity</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://cdn.jsdelivr.net/npm/shiki" defer=""></script><script type="module" src="code.js.js"></script><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Observables and reactivity</h1><p>Handling reactivity in UI via observables.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-observables" title="Handling reactivity in UI via observables." class="current">4. Observables and reactivity</a></nav><main><h2>Using observables to manage reactivity</h2><p>How a program responds to variable data or user interactions is one of the fundamental problems of programming. If we desire to solve the issue in a declarative manner, observables may be a viable approach.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
import { O } from "deka-dom-el/observables"; import { O, observable } from "deka-dom-el/observables";
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js O===observable
/** @type {ddeObservable} */
/** /** @type {ddeAction} */
* @type {ddeObservable} /** @type {ddeActions} */
* */
/**
* @type {ddeActions}
* */
</code></div><h3 id="h-introducing-observables"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-introducing-observables" tabindex="-1">#</a> Introducing observables</h3><p>Using observables, we split program logic into the three parts. Firstly (α), we create a&nbsp;variable (constant) representing reactive value. Somewhere later, we can register (β) a&nbsp;logic reacting to the observable value changes. Similarly, in a&nbsp;remaining part (γ), we can update the observable value.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-v1fw44pkzuo" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; </code></div><h3 id="h-introducing-observables"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-introducing-observables" tabindex="-1">#</a> Introducing observables</h3><p>Using observables, we split program logic into the three parts. Firstly (α), we create a&nbsp;variable (constant) representing reactive value. Somewhere later, we can register (β) a&nbsp;logic reacting to the observable value changes. Similarly, in a&nbsp;remaining part (γ), we can update the observable value.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-v1fw44pkzuo" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
// α — `observable` represents a&nbsp;reactive value // α — `observable` represents a&nbsp;reactive value
const observable= O(0); const observable= O(0);
// β — just reacts on observable changes // β — just reacts on observable changes
O.on(observable, console.log); O.on(observable, console.log);
// γ — just updates the value // γ — just updates the value
observable(observable()+1); const update= ()=&gt; observable(observable()+1);
setInterval(()=&gt; observable(observable()+1), 5000);
</code></div><script>Flems(document.getElementById("code-example-1-v1fw44pkzuo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\n// α — `observable` represents a reactive value\\nconst observable= O(0);\\n// β — just reacts on observable changes\\nO.on(observable, console.log);\\n// γ — just updates the value\\nobservable(observable()+1);\\nsetInterval(()=> observable(observable()+1), 5000);\\n\"}],\"toolbar\":false}"));</script><p>All this is just an&nbsp;example of <a href="https://en.wikipedia.org/wiki/Event-driven_programming" title="Wikipedia: Event-driven programming">Event-driven programming</a> and <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" title="Wikipedia: Publishsubscribe pattern">Publishsubscribe pattern</a> (compare for example with <a href="https://www.npmjs.com/package/fpubsub" title="NPM package: fpubsub">fpubsub library</a>). All three parts can be in some manner independent and still connected to the same reactive entity.</p><p>Observables are implemented in the library as functions. To see current value of observable, just call it without any arguments <code>console.log(observable())</code>. To update the observable value, pass any argument <code>observable('a new value')</code>. For listenning the observable value changes, use <code>O.on(observable, console.log)</code>.</p><p>Similarly to the <code>on</code> function to register DOM events listener. You can use <code>AbortController</code>/<code>AbortSignal</code> to <em>off</em>/stop listenning. For representing “live” piece of code computation pattern:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1ti9ynadhw5c" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; update();
const interval= 5*1000;
setTimeout(clearInterval, 10*interval,
setInterval(update, interval));
</code></div><script>Flems(document.getElementById("code-example-1-v1fw44pkzuo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\n// α — `observable` represents a reactive value\\nconst observable= O(0);\\n// β — just reacts on observable changes\\nO.on(observable, console.log);\\n// γ — just updates the value\\nconst update= ()=> observable(observable()+1);\\n\\nupdate();\\nconst interval= 5*1000;\\nsetTimeout(clearInterval, 10*interval,\\n\\tsetInterval(update, interval));\\n\"}],\"toolbar\":false}"));</script><p>All this is just an&nbsp;example of <a href="https://en.wikipedia.org/wiki/Event-driven_programming" title="Wikipedia: Event-driven programming">Event-driven programming</a> and <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" title="Wikipedia: Publishsubscribe pattern">Publishsubscribe pattern</a> (compare for example with <a href="https://www.npmjs.com/package/fpubsub" title="NPM package: fpubsub">fpubsub library</a>). All three parts can be in some manner independent and still connected to the same reactive entity.</p><p>Observables are implemented in the library as functions. To see current value of observable, just call it without any arguments <code>console.log(observable())</code>. To update the observable value, pass any argument <code>observable('a new value')</code>. For listenning the observable value changes, use <code>O.on(observable, console.log)</code>.</p><p>Similarly to the <code>on</code> function to register DOM events listener. You can use <code>AbortController</code>/<code>AbortSignal</code> to <em>off</em>/stop listenning. In example, you also found the way for representing “live” piece of code computation pattern (derived observable):</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1ti9ynadhw5c" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const observable= O(0); const observable= O(0);
// computation pattern // computation pattern
const double= O(()=&gt; 2*observable()); const double= O(()=&gt; 2*observable());
@ -26,10 +26,125 @@ O.on(observable, v=&gt; console.log("observable", v), { signal: ac.signal });
O.on(double, v=&gt; console.log("double", v), { signal: ac.signal }); O.on(double, v=&gt; console.log("double", v), { signal: ac.signal });
observable(observable()+1); observable(observable()+1);
const interval= 5000; const interval= 5 * 1000;
const id= setInterval(()=&gt; observable(observable()+1), interval); const id= setInterval(()=&gt; observable(observable()+1), interval);
ac.signal.addEventListener("abort", ac.signal.addEventListener("abort",
()=&gt; setTimeout(()=&gt; clearInterval(id), 2*interval)); ()=&gt; setTimeout(()=&gt; clearInterval(id), 2*interval));
setTimeout(()=&gt; ac.abort(), 3*interval) setTimeout(()=&gt; ac.abort(), 3*interval)
</code></div><script>Flems(document.getElementById("code-example-1-1ti9ynadhw5c"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst observable= O(0);\\n// computation pattern\\nconst double= O(()=> 2*observable());\\n\\nconst ac= new AbortController();\\nO.on(observable, v=> console.log(\\\"observable\\\", v), { signal: ac.signal });\\nO.on(double, v=> console.log(\\\"double\\\", v), { signal: ac.signal });\\n\\nobservable(observable()+1);\\nconst interval= 5000;\\nconst id= setInterval(()=> observable(observable()+1), interval);\\nac.signal.addEventListener(\\\"abort\\\",\\n\\t()=> setTimeout(()=> clearInterval(id), 2*interval));\\n\\nsetTimeout(()=> ac.abort(), 3*interval)\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonicUl" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>O(&lt;value&gt;)</code> — observable: reactive value</li><li><code>O(()=&gt; &lt;computation&gt;)</code> — observable: reactive value dependent on calculation using other observables</li><li><code>O.on(&lt;observable&gt;, &lt;listener&gt;[, &lt;options&gt;])</code> — listen to the observable value changes</li><li><code>O.clear(...&lt;observables&gt;)</code> — off and clear observables</li><li><code>O(&lt;value&gt;, &lt;actions&gt;)</code> — observable: pattern to create complex reactive objects/arrays</li><li><code>O.action(&lt;observable&gt;, &lt;action-name&gt;, ...&lt;action-arguments&gt;)</code> — invoke an&nbsp;action for given observable</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Events and Addons (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--></div></main></body></html> </code></div><script>Flems(document.getElementById("code-example-1-1ti9ynadhw5c"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst observable= O(0);\\n// computation pattern\\nconst double= O(()=> 2*observable());\\n\\nconst ac= new AbortController();\\nO.on(observable, v=> console.log(\\\"observable\\\", v), { signal: ac.signal });\\nO.on(double, v=> console.log(\\\"double\\\", v), { signal: ac.signal });\\n\\nobservable(observable()+1);\\nconst interval= 5 * 1000;\\nconst id= setInterval(()=> observable(observable()+1), interval);\\nac.signal.addEventListener(\\\"abort\\\",\\n\\t()=> setTimeout(()=> clearInterval(id), 2*interval));\\n\\nsetTimeout(()=> ac.abort(), 3*interval)\\n\"}],\"toolbar\":false}"));</script><h3 id="h-observables-and-actions"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-observables-and-actions" tabindex="-1">#</a> Observables and actions</h3><p><code>O(/* primitive */)</code> allows you to declare simple reactive variables, typically around <em>immutable</em> <a title="Primitive | MDN" href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive">primitive types</a>. However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-ny81g2qun6o" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const observable= O(0, {
increaseOnlyOdd(add){
console.info(add);
if(add%2 === 0) return this.stopPropagation();
this.value+= add;
}
});
O.on(observable, console.log);
const oninterval= ()=&gt;
O.action(observable, "increaseOnlyOdd", Math.floor(Math.random()*100));
const interval= 5*1000;
setTimeout(
clearInterval,
10*interval,
setInterval(oninterval, interval)
);
</code></div><script>Flems(document.getElementById("code-example-1-ny81g2qun6o"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst observable= O(0, {\\n\\tincreaseOnlyOdd(add){\\n\\t\\tconsole.info(add);\\n\\t\\tif(add%2 === 0) return this.stopPropagation();\\n\\t\\tthis.value+= add;\\n\\t}\\n});\\nO.on(observable, console.log);\\nconst oninterval= ()=>\\n\\tO.action(observable, \\\"increaseOnlyOdd\\\", Math.floor(Math.random()*100));\\n\\nconst interval= 5*1000;\\nsetTimeout(\\n\\tclearInterval,\\n\\t10*interval,\\n\\tsetInterval(oninterval, interval)\\n);\\n\"}],\"toolbar\":false}"));</script><p>…but typical user-case is object/array (maps, sets and other mutable objects):</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-ihanc6k9v9c" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const todos= O([], {
push(item){
this.value.push(O(item));
},
pop(){
const removed= this.value.pop();
if(removed) O.clear(removed);
},
[O.symbols.onclear](){ // this covers `O.clear(todos)`
O.clear(...this.value);
}
});
import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
/** @type {ddeElementAddon&lt;HTMLFormElement&gt;} */
const onsubmit= on("submit", function(event){
event.preventDefault();
const data= new FormData(this);
switch (data.get("op")){
case "A"/*dd*/:
O.action(todos, "push", data.get("todo"));
break;
case "E"/*dit*/: {
const last= todos().at(-1);
if(!last) break;
last(data.get("todo"));
break;
}
case "R"/*emove*/:
O.action(todos, "pop");
break;
}
});
document.body.append(
el("ul").append(
O.el(todos, todos=&gt;
todos.map(textContent=&gt; el("li", textContent)))
),
el("form", null, onsubmit).append(
el("input", { type: "text", name: "todo", placeholder: "Todos text" }),
el(radio, { textContent: "Add", checked: true }),
el(radio, { textContent: "Edit last" }),
el(radio, { textContent: "Remove" }),
el("button", "Submit")
)
);
document.head.append(
el("style", "form{ display: flex; flex-flow: column nowrap; }")
);
function radio({ textContent, checked= false }){
return el("label").append(
el("input", { type: "radio", name: "op", value: textContent[0], checked }),
" ",textContent
)
}
</code></div><script>Flems(document.getElementById("code-example-1-ihanc6k9v9c"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst todos= O([], {\\n\\tpush(item){\\n\\t\\tthis.value.push(O(item));\\n\\t},\\n\\tpop(){\\n\\t\\tconst removed= this.value.pop();\\n\\t\\tif(removed) O.clear(removed);\\n\\t},\\n\\t[O.symbols.onclear](){ // this covers `O.clear(todos)`\\n\\t\\tO.clear(...this.value);\\n\\t}\\n});\\n\\nimport { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\n/** @type {ddeElementAddon<HTMLFormElement>} */\\nconst onsubmit= on(\\\"submit\\\", function(event){\\n\\tevent.preventDefault();\\n\\tconst data= new FormData(this);\\n\\tswitch (data.get(\\\"op\\\")){\\n\\t\\tcase \\\"A\\\"/*dd*/:\\n\\t\\t\\tO.action(todos, \\\"push\\\", data.get(\\\"todo\\\"));\\n\\t\\t\\tbreak;\\n\\t\\tcase \\\"E\\\"/*dit*/: {\\n\\t\\t\\tconst last= todos().at(-1);\\n\\t\\t\\tif(!last) break;\\n\\t\\t\\tlast(data.get(\\\"todo\\\"));\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tcase \\\"R\\\"/*emove*/:\\n\\t\\t\\tO.action(todos, \\\"pop\\\");\\n\\t\\t\\tbreak;\\n\\t}\\n});\\ndocument.body.append(\\n\\tel(\\\"ul\\\").append(\\n\\t\\tO.el(todos, todos=>\\n\\t\\t\\ttodos.map(textContent=> el(\\\"li\\\", textContent)))\\n\\t),\\n\\tel(\\\"form\\\", null, onsubmit).append(\\n\\t\\tel(\\\"input\\\", { type: \\\"text\\\", name: \\\"todo\\\", placeholder: \\\"Todos text\\\" }),\\n\\t\\tel(radio, { textContent: \\\"Add\\\", checked: true }),\\n\\t\\tel(radio, { textContent: \\\"Edit last\\\" }),\\n\\t\\tel(radio, { textContent: \\\"Remove\\\" }),\\n\\t\\tel(\\\"button\\\", \\\"Submit\\\")\\n\\t)\\n);\\ndocument.head.append(\\n\\tel(\\\"style\\\", \\\"form{ display: flex; flex-flow: column nowrap; }\\\")\\n);\\nfunction radio({ textContent, checked= false }){\\n\\treturn el(\\\"label\\\").append(\\n\\t\\tel(\\\"input\\\", { type: \\\"radio\\\", name: \\\"op\\\", value: textContent[0], checked }),\\n\\t\\t\\\" \\\",textContent\\n\\t)\\n}\\n\"}],\"toolbar\":false}"));</script><p>In some way, you can compare it with <a href="https://react.dev/reference/react/useReducer" title="useReducer hook | React docs">useReducer</a> hook from React. So, the <code>O(&lt;data&gt;, &lt;actions&gt;)</code> pattern creates a&nbsp;store “machine”. We can then invoke (dispatch) registered action by calling <code>O.action(&lt;observable&gt;, &lt;name&gt;, ...&lt;args&gt;)</code> after the action call the observable calls all its listeners. This can be stopped by calling <code>this.stopPropagation()</code> in the method representing the given action. As it can be seen in examples, the “store” value is available also in the function for given action (<code>this.value</code>).</p><h3 id="h-reactive-dom-attributes-and-elements"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-reactive-dom-attributes-and-elements" tabindex="-1">#</a> Reactive DOM attributes and elements</h3><p>There are on basic level two distinc situation to mirror dynamic value into the DOM/UI</p><ol><li>to change some attribute(s) of existing element(s)</li><li>to generate elements itself dynamically this covers conditions and loops</li></ol><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-ehcq40v0h5k" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const count= O(0);
import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
document.body.append(
el("p", O(()=&gt; "Currently: "+count())),
el("p", { classList: { red: O(()=&gt; count()%2) }, dataset: { count }, textContent: "Attributes example" })
);
document.head.append(
el("style", ".red { color: red; }")
);
const interval= 5 * 1000;
setTimeout(clearInterval, 10*interval,
setInterval(()=&gt; count(count()+1), interval));
</code></div><script>Flems(document.getElementById("code-example-1-ehcq40v0h5k"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst count= O(0);\\n\\nimport { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", O(()=> \\\"Currently: \\\"+count())),\\n\\tel(\\\"p\\\", { classList: { red: O(()=> count()%2) }, dataset: { count }, textContent: \\\"Attributes example\\\" })\\n);\\ndocument.head.append(\\n\\tel(\\\"style\\\", \\\".red { color: red; }\\\")\\n);\\n\\nconst interval= 5 * 1000;\\nsetTimeout(clearInterval, 10*interval,\\n\\tsetInterval(()=> count(count()+1), interval));\\n\"}],\"toolbar\":false}"));</script><p>To derived attribute based on value of observable variable just use the observable as a&nbsp;value of the attribute (<code>assign(element, { attribute: O('value') })</code>). <code>assign</code>/<code>el</code> provides ways to glue reactive attributes/classes more granularly into the DOM. Just use dedicated build-in attributes <code>dataset</code>, <code>ariaset</code> and <code>classList</code>.</p><p>For computation, you can use the derived observable (see above) like <code>assign(element, { textContent: O(()=&gt; 'Hello '+WorldObservable()) })</code>.</p><p>To represent part of the template filled dynamically based on the observable value use <code>O.el(observable, DOMgenerator)</code>. This was already used in the todo example above or see:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-2-8r8qappf8mo" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const count= O(0, {
add(){ this.value= this.value + Math.round(Math.random()*10); }
});
const numbers= O([ count() ], {
push(next){ this.value.push(next); }
});
import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
document.body.append(
O.el(count, count=&gt; count%2
? el("p", "Last number is odd.")
: el()
),
el("p", "Lucky numbers:"),
el("ul").append(
O.el(numbers, numbers=&gt; numbers.toReversed()
.map(n=&gt; el("li", n)))
)
);
const interval= 5*1000;
setTimeout(clearInterval, 10*interval, setInterval(function(){
O.action(count, "add");
O.action(numbers, "push", count());
}, interval));
</code></div><script>Flems(document.getElementById("code-example-2-8r8qappf8mo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst count= O(0, {\\n\\tadd(){ this.value= this.value + Math.round(Math.random()*10); }\\n});\\nconst numbers= O([ count() ], {\\n\\tpush(next){ this.value.push(next); }\\n});\\n\\nimport { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tO.el(count, count=> count%2\\n\\t\\t? el(\\\"p\\\", \\\"Last number is odd.\\\")\\n\\t\\t: el()\\n\\t),\\n\\tel(\\\"p\\\", \\\"Lucky numbers:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tO.el(numbers, numbers=> numbers.toReversed()\\n\\t\\t\\t.map(n=> el(\\\"li\\\", n)))\\n\\t)\\n);\\n\\nconst interval= 5*1000;\\nsetTimeout(clearInterval, 10*interval, setInterval(function(){\\n\\tO.action(count, \\\"add\\\");\\n\\tO.action(numbers, \\\"push\\\", count());\\n}, interval));\\n\"}],\"toolbar\":false}"));</script><div class="notice"><!--<dde:mark type="component" name="mnemonic" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>O(&lt;value&gt;)</code> — observable: reactive value</li><li><code>O(()=&gt; &lt;computation&gt;)</code> — observable: reactive value dependent on calculation using other observables</li><li><code>O.on(&lt;observable&gt;, &lt;listener&gt;[, &lt;options&gt;])</code> — listen to the observable value changes</li><li><code>O.clear(...&lt;observables&gt;)</code> — off and clear observables</li><li><code>O(&lt;value&gt;, &lt;actions&gt;)</code> — observable: pattern to create complex reactive objects/arrays</li><li><code>O.action(&lt;observable&gt;, &lt;action-name&gt;, ...&lt;action-arguments&gt;)</code> — invoke an&nbsp;action for given observable</li><li><code>O.el(&lt;observable&gt;, &lt;function-returning-dom&gt;)</code> — render partial dom structure (template) based on the current observable value</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Events and Addons (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--></div></main></body></html>

View File

@ -1,7 +1,11 @@
// when NPM // use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
import { assign, el, elNS } from "deka-dom-el"; import {
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js assign,
el, createElement,
elNS, createElementNS
} from "deka-dom-el";
el===createElement
elNS===createElementNS
// “internal” utils // “internal” utils
import { import {
assignAttribute, assignAttribute,

View File

@ -1,7 +1,4 @@
// when NPM // use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
import { on, dispatchEvent } from "deka-dom-el"; import { on, dispatchEvent } from "deka-dom-el";
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js
/** /** @type {ddeElementAddon} */
* @type {ddeElementAddon}
* */

View File

@ -0,0 +1,18 @@
import { O } from "deka-dom-el/observables";
const observable= O(0, {
increaseOnlyOdd(add){
console.info(add);
if(add%2 === 0) return this.stopPropagation();
this.value+= add;
}
});
O.on(observable, console.log);
const oninterval= ()=>
O.action(observable, "increaseOnlyOdd", Math.floor(Math.random()*100));
const interval= 5*1000;
setTimeout(
clearInterval,
10*interval,
setInterval(oninterval, interval)
);

View File

@ -0,0 +1,56 @@
import { O } from "deka-dom-el/observables";
const todos= O([], {
push(item){
this.value.push(O(item));
},
pop(){
const removed= this.value.pop();
if(removed) O.clear(removed);
},
[O.symbols.onclear](){ // this covers `O.clear(todos)`
O.clear(...this.value);
}
});
import { el, on } from "deka-dom-el";
/** @type {ddeElementAddon<HTMLFormElement>} */
const onsubmit= on("submit", function(event){
event.preventDefault();
const data= new FormData(this);
switch (data.get("op")){
case "A"/*dd*/:
O.action(todos, "push", data.get("todo"));
break;
case "E"/*dit*/: {
const last= todos().at(-1);
if(!last) break;
last(data.get("todo"));
break;
}
case "R"/*emove*/:
O.action(todos, "pop");
break;
}
});
document.body.append(
el("ul").append(
O.el(todos, todos=>
todos.map(textContent=> el("li", textContent)))
),
el("form", null, onsubmit).append(
el("input", { type: "text", name: "todo", placeholder: "Todos text" }),
el(radio, { textContent: "Add", checked: true }),
el(radio, { textContent: "Edit last" }),
el(radio, { textContent: "Remove" }),
el("button", "Submit")
)
);
document.head.append(
el("style", "form{ display: flex; flex-flow: column nowrap; }")
);
function radio({ textContent, checked= false }){
return el("label").append(
el("input", { type: "radio", name: "op", value: textContent[0], checked }),
" ",textContent
)
}

View File

@ -8,7 +8,7 @@ O.on(observable, v=> console.log("observable", v), { signal: ac.signal });
O.on(double, v=> console.log("double", v), { signal: ac.signal }); O.on(double, v=> console.log("double", v), { signal: ac.signal });
observable(observable()+1); observable(observable()+1);
const interval= 5000; const interval= 5 * 1000;
const id= setInterval(()=> observable(observable()+1), interval); const id= setInterval(()=> observable(observable()+1), interval);
ac.signal.addEventListener("abort", ac.signal.addEventListener("abort",
()=> setTimeout(()=> clearInterval(id), 2*interval)); ()=> setTimeout(()=> clearInterval(id), 2*interval));

View File

@ -0,0 +1,15 @@
import { O } from "deka-dom-el/observables";
const count= O(0);
import { el } from "deka-dom-el";
document.body.append(
el("p", O(()=> "Currently: "+count())),
el("p", { classList: { red: O(()=> count()%2) }, dataset: { count }, textContent: "Attributes example" })
);
document.head.append(
el("style", ".red { color: red; }")
);
const interval= 5 * 1000;
setTimeout(clearInterval, 10*interval,
setInterval(()=> count(count()+1), interval));

View File

@ -0,0 +1,26 @@
import { O } from "deka-dom-el/observables";
const count= O(0, {
add(){ this.value= this.value + Math.round(Math.random()*10); }
});
const numbers= O([ count() ], {
push(next){ this.value.push(next); }
});
import { el } from "deka-dom-el";
document.body.append(
O.el(count, count=> count%2
? el("p", "Last number is odd.")
: el()
),
el("p", "Lucky numbers:"),
el("ul").append(
O.el(numbers, numbers=> numbers.toReversed()
.map(n=> el("li", n)))
)
);
const interval= 5*1000;
setTimeout(clearInterval, 10*interval, setInterval(function(){
O.action(count, "add");
O.action(numbers, "push", count());
}, interval));

View File

@ -1,10 +1,6 @@
// when NPM // use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
import { O } from "deka-dom-el/observables"; import { O, observable } from "deka-dom-el/observables";
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js O===observable
/** @type {ddeObservable} */
/** /** @type {ddeAction} */
* @type {ddeObservable} /** @type {ddeActions} */
* */
/**
* @type {ddeActions}
* */

View File

@ -4,5 +4,9 @@ const observable= O(0);
// β — just reacts on observable changes // β — just reacts on observable changes
O.on(observable, console.log); O.on(observable, console.log);
// γ — just updates the value // γ — just updates the value
observable(observable()+1); const update= ()=> observable(observable()+1);
setInterval(()=> observable(observable()+1), 5000);
update();
const interval= 5*1000;
setTimeout(clearInterval, 10*interval,
setInterval(update, interval));

View File

@ -0,0 +1,25 @@
import { el } from "deka-dom-el";
import { mnemonicUl } from "../mnemonicUl.html.js";
export function mnemonic(){
return mnemonicUl().append(
el("li").append(
el("code", "assign(<element>, ...<idl-objects>): <element>"), " — assign properties to the element",
),
el("li").append(
el("code", "el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name>"), " — simple element containing only text",
),
el("li").append(
el("code", "el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name>"), " — element with more properties",
),
el("li").append(
el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), " — using component represented by function",
),
el("li").append(
el("code", "el(<...>, <...>, ...<addons>)"), " — see following page"
),
el("li").append(
el("code", "elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments>"), " — typically SVG elements",
)
);
}

View File

@ -0,0 +1,20 @@
import { el } from "deka-dom-el";
import { mnemonicUl } from "../mnemonicUl.html.js";
export function mnemonic(){
return mnemonicUl().append(
el("li").append(
el("code", "on(<event>, <listener>[, <options>])(<element>)"), " — just ", el("code", "<element>.addEventListener(<event>, <listener>[, <options>])")
),
el("li").append(
el("code", "on.<live-cycle>(<event>, <listener>[, <options>])(<element>)"), " — corresponds to custom elemnets callbacks ", el("code", "<live-cycle>Callback(...){...}"),
". To connect to custom element see following page, else it is simulated by MutationObserver."
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element)"), " — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))")
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), " — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))")
),
);
}

View File

@ -0,0 +1,28 @@
import { el } from "deka-dom-el";
import { mnemonicUl } from "../mnemonicUl.html.js";
export function mnemonic(){
return mnemonicUl().append(
el("li").append(
el("code", "O(<value>)"), " — observable: reactive value",
),
el("li").append(
el("code", "O(()=> <computation>)"), " — observable: reactive value dependent on calculation using other observables",
),
el("li").append(
el("code", "O.on(<observable>, <listener>[, <options>])"), " — listen to the observable value changes",
),
el("li").append(
el("code", "O.clear(...<observables>)"), " — off and clear observables",
),
el("li").append(
el("code", "O(<value>, <actions>)"), " — observable: pattern to create complex reactive objects/arrays",
),
el("li").append(
el("code", "O.action(<observable>, <action-name>, ...<action-arguments>)"), " — invoke an action for given observable"
),
el("li").append(
el("code", "O.el(<observable>, <function-returning-dom>)"), " — render partial dom structure (template) based on the current observable value",
)
);
}

View File

@ -7,8 +7,8 @@ ${host} h3{
} }
`; `;
import { el, simulateSlots } from "deka-dom-el"; import { el, simulateSlots } from "deka-dom-el";
/** @param {Object} props @param {string} props.textContent */ /** @param {Object} [props] @param {string} [props.textContent] */
export function mnemonicUl({ textContent= "" }){ export function mnemonicUl({ textContent= "" }= {}){
if(textContent) textContent= " "+textContent if(textContent) textContent= " "+textContent
return simulateSlots(el("div", { className: "notice" }).append( return simulateSlots(el("div", { className: "notice" }).append(
el(h3, "Mnemonic"+textContent), el(h3, "Mnemonic"+textContent),

View File

@ -20,7 +20,7 @@ body {
@media (min-width:768px) { @media (min-width:768px) {
body{ body{
grid-template-rows: auto auto; grid-template-rows: auto auto;
grid-template-columns: calc(var(--body-max-width) / 3) auto; grid-template-columns: calc(10 * var(--body-max-width) / 27) auto;
grid-template-areas: grid-template-areas:
"header header" "header header"
"sidebar content" "sidebar content"

View File

@ -3,7 +3,7 @@ import { simplePage } from "./layout/simplePage.html.js";
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { example } from "./components/example.html.js"; import { example } from "./components/example.html.js";
import { h3 } from "./components/pageUtils.html.js"; import { h3 } from "./components/pageUtils.html.js";
import { mnemonicUl } from "./components/mnemonicUl.html.js"; import { mnemonic } from "./components/mnemonic/elements-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
@ -116,25 +116,6 @@ export function page({ pkg, info }){
), ),
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
el(mnemonicUl).append( el(mnemonic)
el("li").append(
el("code", "assign(<element>, ...<idl-objects>): <element>"), " — assign properties to the element",
),
el("li").append(
el("code", "el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name>"), " — simple element containing only text",
),
el("li").append(
el("code", "el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name>"), " — element with more properties",
),
el("li").append(
el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), " — using component represented by function",
),
el("li").append(
el("code", "el(<...>, <...>, ...<addons>)"), " — see following page"
),
el("li").append(
el("code", "elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments>"), " — typically SVG elements",
)
)
); );
} }

View File

@ -3,7 +3,7 @@ import { simplePage } from "./layout/simplePage.html.js";
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { example } from "./components/example.html.js"; import { example } from "./components/example.html.js";
import { h3 } from "./components/pageUtils.html.js"; import { h3 } from "./components/pageUtils.html.js";
import { mnemonicUl } from "./components/mnemonicUl.html.js"; import { mnemonic } from "./components/mnemonic/events-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
@ -113,20 +113,6 @@ export function page({ pkg, info }){
el("p", "The library also provides a method to dispatch the events."), el("p", "The library also provides a method to dispatch the events."),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el(mnemonicUl).append( el(mnemonic)
el("li").append(
el("code", "on(<event>, <listener>[, <options>])(<element>)"), " — just ", el("code", "<element>.addEventListener(<event>, <listener>[, <options>])")
),
el("li").append(
el("code", "on.<live-cycle>(<event>, <listener>[, <options>])(<element>)"), " — corresponds to custom elemnets callbacks ", el("code", "<live-cycle>Callback(...){...}"),
". To connect to custom element see following page, else it is simulated by MutationObserver."
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element)"), " — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))")
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), " — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))")
),
),
); );
} }

View File

@ -3,7 +3,7 @@ import { simplePage } from "./layout/simplePage.html.js";
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { example } from "./components/example.html.js"; import { example } from "./components/example.html.js";
import { h3 } from "./components/pageUtils.html.js"; import { h3 } from "./components/pageUtils.html.js";
import { mnemonicUl } from "./components/mnemonicUl.html.js"; import { mnemonic } from "./components/mnemonic/observables-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
@ -48,28 +48,54 @@ export function page({ pkg, info }){
el("p").append( el("p").append(
"Similarly to the ", el("code", "on"), " function to register DOM events listener.", "Similarly to the ", el("code", "on"), " function to register DOM events listener.",
" You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to", " You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to",
" ", el("em", "off"), "/stop listenning. For representing “live” piece of code computation pattern:" " ", el("em", "off"), "/stop listenning. In example, you also found the way for representing",
" “live” piece of code computation pattern (derived observable):"
), ),
el(example, { src: fileURL("./components/examples/observables/computations-abort.js"), page_id }), el(example, { src: fileURL("./components/examples/observables/computations-abort.js"), page_id }),
el(mnemonicUl).append(
el("li").append( el(h3, "Observables and actions"),
el("code", "O(<value>)"), " — observable: reactive value", el("p").append(
el("code", "O(/* primitive */)"), " allows you to declare simple reactive variables, typically",
" around ", el("em", "immutable"), " ", el("a", { textContent: "primitive types", title: "Primitive | MDN", href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive" }), ".",
" ",
"However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures."
), ),
el("li").append( el(example, { src: fileURL("./components/examples/observables/actions-demo.js"), page_id }),
el("code", "O(()=> <computation>)"), " — observable: reactive value dependent on calculation using other observables", el("p", "…but typical user-case is object/array (maps, sets and other mutable objects):"),
el(example, { src: fileURL("./components/examples/observables/actions-todos.js"), page_id }),
el("p").append(
"In some way, you can compare it with ", el("a", { textContent: "useReducer", href: "https://react.dev/reference/react/useReducer", title: "useReducer hook | React docs" }),
" hook from React. So, the ", el("code", "O(<data>, <actions>)"), " pattern creates",
" a store “machine”. We can then invoke (dispatch) registered action by calling",
" ", el("code", "O.action(<observable>, <name>, ...<args>)"), " after the action call",
" the observable calls all its listeners. This can be stopped by calling ", el("code", "this.stopPropagation()"),
" in the method representing the given action. As it can be seen in examples, the “store” value is",
" available also in the function for given action (", el("code", "this.value"), ")."
), ),
el("li").append(
el("code", "O.on(<observable>, <listener>[, <options>])"), " — listen to the observable value changes", el(h3, "Reactive DOM attributes and elements"),
el("p", "There are on basic level two distinc situation to mirror dynamic value into the DOM/UI"),
el("ol").append(
el("li", "to change some attribute(s) of existing element(s)"),
el("li", "to generate elements itself dynamically this covers conditions and loops")
), ),
el("li").append( el(example, { src: fileURL("./components/examples/observables/dom-attrs.js"), page_id }),
el("code", "O.clear(...<observables>)"), " — off and clear observables", el("p").append(
"To derived attribute based on value of observable variable just use the observable as",
" a value of the attribute (", el("code", "assign(element, { attribute: O('value') })"), ").",
" ", el("code", "assign"), "/", el("code", "el"), " provides ways to glue reactive attributes/classes",
" more granularly into the DOM. Just use dedicated build-in attributes ", el("code", "dataset"), ", ",
el("code", "ariaset"), " and ", el("code", "classList"), "."
), ),
el("li").append( el("p").append(
el("code", "O(<value>, <actions>)"), " — observable: pattern to create complex reactive objects/arrays", "For computation, you can use the derived observable (see above) like ", el("code", "assign(element, { textContent: O(()=> 'Hello '+WorldObservable()) })"), "."
), ),
el("li").append( el("p").append(
el("code", "O.action(<observable>, <action-name>, ...<action-arguments>)"), " — invoke an action for given observable" "To represent part of the template filled dynamically based on the observable value use ", el("code", "O.el(observable, DOMgenerator)"), ".",
) " This was already used in the todo example above or see:"
), ),
el(example, { src: fileURL("./components/examples/observables/dom-el.js"), page_id }),
el(mnemonic)
); );
} }

176
index.d.ts vendored
View File

@ -1,3 +1,5 @@
import { Observable } from "./observables";
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
declare global { declare global {
interface ddePublicElementTagNameMap{ interface ddePublicElementTagNameMap{
@ -18,20 +20,21 @@ type AttrsModified= {
/** /**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/ */
style: string | Partial<CSSStyleDeclaration> style: string | Partial<CSSStyleDeclaration> | Observable<string, any> | Partial<{ [K in keyof CSSStyleDeclaration]: Observable<CSSStyleDeclaration[K], any> }>
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others.
*/ */
classList: Record<string,-1|0|1|boolean>, classList: Record<string,-1|0|1|boolean|Observable<-1|0|1|boolean, any>>,
/** /**
* By default simiral to `className`, but also supports `string[]` * By default simiral to `className`, but also supports `string[]`
* */ * */
className: string | (string|boolean|undefined)[]; className: string | (string|boolean|undefined|Observable<string|boolean|undefined, any>)[];
/** /**
* Sets `aria-*` simiraly to `dataset` * Sets `aria-*` simiraly to `dataset`
* */ * */
ariaset: Record<string,string>, ariaset: Record<string,string|Observable<string, any>>,
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string> & Record<`.${string}`, any> } & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string|Observable<string, any>> & Record<`.${string}`, any>
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>;
/** /**
* Just element attributtes * Just element attributtes
* *
@ -40,17 +43,28 @@ type AttrsModified= {
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private * @private
*/ */
type ElementAttributes<T extends SupportedElement>= Omit<T,keyof AttrsModified> & AttrsModified; type ElementAttributes<T extends SupportedElement>= Partial<_fromElsInterfaces<T> & { [K in keyof _fromElsInterfaces<T>]: Observable<_fromElsInterfaces<T>[K], any> } & AttrsModified>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El
export function assign<El extends SupportedElement>(element: El, ...attrs_array: Partial<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= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap type ExtendedHTMLElementTagNameMap= ddeHTMLElementTagNameMap & CustomElementTagNameMap & ddePublicElementTagNameMap
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>( export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG, tag_name: TAG,
attrs?: string | Partial<ElementAttributes<ExtendedHTMLElementTagNameMap[TAG]>>, attrs?: ElementAttributes<EL>,
...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[TAG]>[] ...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): ExtendedHTMLElementTagNameMap[TAG] ): EL
export function el<
TAG extends string,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : ddeHTMLElement)
>(
tag_name: TAG,
attrs?: string | Observable<string, any>,
...addons: ddeElementAddon<TAG extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TAG] : EL>[]
): EL
export function el<T>( export function el<T>(
tag_name?: "<>", tag_name?: "<>",
): ddeDocumentFragment ): ddeDocumentFragment
@ -62,12 +76,7 @@ export function el<
attrs?: A | string, attrs?: A | string,
...addons: ddeElementAddon<ReturnType<C>>[] ...addons: ddeElementAddon<ReturnType<C>>[]
): ReturnType<C> ): ReturnType<C>
export { el as createElement }
export function el(
tag_name: string,
attrs?: string | Record<string, any>,
...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement
export function elNS( export function elNS(
namespace: "http://www.w3.org/2000/svg" namespace: "http://www.w3.org/2000/svg"
@ -90,6 +99,7 @@ export function elNS(
attrs?: string | Record<string, any>, attrs?: string | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[] ...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement )=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL
@ -249,71 +259,6 @@ declare global{
"ul": ddeHTMLUListElement; "ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement; "video": ddeHTMLVideoElement;
} }
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGElementTagNameMap { interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement; "a": ddeSVGAElement;
"animate": ddeSVGAnimateElement; "animate": ddeSVGAnimateElement;
@ -379,6 +324,72 @@ declare global{
"use": ddeSVGUseElement; "use": ddeSVGUseElement;
"view": ddeSVGViewElement; "view": ddeSVGViewElement;
} }
}
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; } interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; }
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; } interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; } interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; }
@ -442,4 +453,3 @@ declare global{
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; } interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; }
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; } interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; } interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; }
}

13
observables.d.ts vendored
View File

@ -1,8 +1,8 @@
export type Observable<V, A>= (set?: V)=> V & A; export type Observable<V, A>= (set?: V)=> V & A;
type Action<V>= (this: { value: V }, ...a: any[])=> typeof observable._ | void; type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof observable._ | void;
type SymbolOnclear= Symbol; //type SymbolObservable= Symbol;
type SymbolObservable= Symbol; type SymbolOnclear= symbol;
type Actions<V>= Record<string, Action<V>>; type Actions<V>= Record<string | SymbolOnclear, Action<V>>;
interface observable{ interface observable{
_: Symbol _: Symbol
/** /**
@ -42,7 +42,7 @@ interface observable{
clear(...observables: Observable<any, any>[]): void; clear(...observables: Observable<any, any>[]): void;
on<T>(observable: Observable<T, any>, onchange: (a: T)=> void, options?: AddEventListenerOptions): void; on<T>(observable: Observable<T, any>, onchange: (a: T)=> void, options?: AddEventListenerOptions): void;
symbols: { symbols: {
observable: SymbolObservable; //observable: SymbolObservable;
onclear: SymbolOnclear; onclear: SymbolOnclear;
} }
/** /**
@ -52,7 +52,7 @@ interface observable{
* S.el(listS, list=> list.map(li=> el("li", li))); * S.el(listS, list=> list.map(li=> el("li", li)));
* ``` * ```
* */ * */
el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[]): DocumentFragment; el<S extends any>(observable: Observable<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
attribute(name: string, initial?: string): Observable<string, {}>; attribute(name: string, initial?: string): Observable<string, {}>;
} }
@ -60,5 +60,6 @@ export const observable: observable;
export const O: observable; export const O: observable;
declare global { declare global {
type ddeObservable<T, A= {}>= Observable<T, A>; type ddeObservable<T, A= {}>= Observable<T, A>;
type ddeAction<V>= Action<V>
type ddeActions<V>= Actions<V> type ddeActions<V>= Actions<V>
} }

View File

@ -60,7 +60,7 @@ observable.on= function on(o, listener, options= {}){
//TODO cleanup when observable removed //TODO cleanup when observable removed
}; };
observable.symbols= { observable.symbols= {
observable: mark, //observable: mark,
onclear: Symbol.for("Observable.onclear") onclear: Symbol.for("Observable.onclear")
}; };
observable.clear= function(...observables){ observable.clear= function(...observables){