diff --git a/docs/global.css b/docs/global.css index 4491981..6858d3c 100644 --- a/docs/global.css +++ b/docs/global.css @@ -145,6 +145,7 @@ main > *{ --shiki-token-punctuation: var(--code); --shiki-token-link: #EE0000; white-space: pre; + overflow: scroll; } .code[data-js=todo]{ border: 1px solid var(--border); @@ -164,4 +165,7 @@ main > *{ .CodeMirror, .CodeMirror-gutters { background: #212121 !important; border: 1px solid white; +} +.notice h3{ + margin-top: 0; } \ No newline at end of file diff --git a/docs/p02-elements.html b/docs/p02-elements.html index 8b82638..4c882e2 100644 --- a/docs/p02-elements.html +++ b/docs/p02-elements.html @@ -1,4 +1,14 @@ -`deka-dom-el` — Elements

`deka-dom-el` — Elements

Basic concepts of elements modifications and creations.

Native JavaScript DOM elements creations

Let’s go through all patterns we would like to use and what needs to be improved for better experience.

# Creating element(s) (with custom attributes)

You can create a native DOM element by using the document.createElement(). It is also possible to provide a some attribute(s) declaratively using Object.assign(). More precisely, this way you can sets some IDL also known as a JavaScript property.

document.body.append( +`deka-dom-el` — Elements

`deka-dom-el` — Elements

Basic concepts of elements modifications and creations.

Native JavaScript DOM elements creations

Let’s go through all patterns we would like to use and what needs to be improved for better experience.

// when NPM +import { assign, el, elNS } from "deka-dom-el"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js + +// “internal” utils +import { + assignAttribute, + classListDeclarative, + chainableAppend +} from "deka-dom-el"; +

# Creating element(s) (with custom attributes)

You can create a native DOM element by using the document.createElement(). It is also possible to provide a some attribute(s) declaratively using Object.assign(). More precisely, this way you can sets some IDL also known as a JavaScript property.

document.body.append( document.createElement("div") ); console.log( @@ -130,4 +140,4 @@ document.body.append( console.log( document.body.innerHTML.includes("<svg></svg><math></math>") ) -

Mnemonic

  • assign(<element>, ...<idl-objects>): <element> — assign properties to the element
  • el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name> — simple element containing only text
  • el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name> — element with more properties
  • el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function> — using component represented by function
  • el(<...>, <...>, ...<addons>) — see following page
  • elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments> — typically SVG elements
\ No newline at end of file +

# Mnemonic

\ No newline at end of file diff --git a/docs/p03-events.html b/docs/p03-events.html index 22ebbe3..693090e 100644 --- a/docs/p03-events.html +++ b/docs/p03-events.html @@ -1,4 +1,11 @@ -`deka-dom-el` — Events and Addons

`deka-dom-el` — Events and Addons

Using not only events in UI declaratively.

Listenning to the native DOM events and other Addons

We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called Addon to incorporate not only this in UI templates declaratively.

# Events and listenners

In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +`deka-dom-el` — Events and Addons

`deka-dom-el` — Events and Addons

Using not only events in UI declaratively.

Listenning to the native DOM events and other Addons

We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called Addon to incorporate not only this in UI templates declaratively.

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

# Events and listenners

In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; const log= mark=> console.log.bind(console, mark); const button= el("button", "Test click"); @@ -87,4 +94,4 @@ function dde(){ function ddeOptions(){ dispatchEvent("test", { bubbles: true })(this, "hi"); } -

Mnemonic

  • on(<event>, <listener>[, <options>])(<element>) — just <element>.addEventListener(<event>, <listener>[, <options>])
  • on.<live-cycle>(<event>, <listener>[, <options>])(<element>) — corresponds to custom elemnets callbacks <live-cycle>Callback(...){...}. To connect to custom element see following page, else it is simulated by MutationObserver.
  • dispatchEvent(<event>[, <options>])(element) — just <element>.dispatchEvent(new Event(<event>[, <options>]))
  • dispatchEvent(<event>[, <options>])(element, detail) — just <element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))
\ No newline at end of file +

# Mnemonic

\ No newline at end of file diff --git a/docs/p04-signals.html b/docs/p04-signals.html index 8075cbb..69973a3 100644 --- a/docs/p04-signals.html +++ b/docs/p04-signals.html @@ -1,4 +1,14 @@ -`deka-dom-el` — Signals and reactivity

`deka-dom-el` — Signals and reactivity

Handling reactivity in UI via signals.

Using signals to manage reactivity

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, signals may be a viable approach.

import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +`deka-dom-el` — Signals and reactivity

`deka-dom-el` — Signals and reactivity

Handling reactivity in UI via signals.

Using signals to manage reactivity

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, signals may be a viable approach.

// when NPM +import { S } from "deka-dom-el/signals"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js + +/** + * @type {ddeSignal} + * */ +/** + * @type {ddeActions} + * */ +

# Introducing signals

Using signals, we split program logic into the three parts. Firstly (α), we create a variable (constant) representing reactive value. Somewhere later, we can register (β) a logic reacting to the signal value changes. Similarly, in a remaining part (γ), we can update the signal value.

import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; // α — `signal` represents a reactive value const signal= S(0); // β — just reacts on signal changes @@ -6,7 +16,7 @@ S.on(signal, console.log); // γ — just updates the value signal(signal()+1); setInterval(()=> signal(signal()+1), 5000); -

# Introducing signals

Using signals, we split program logic into the three parts. Firstly (α), we create a variable (constant) representing reactive value. Somewhere later, we can register (β) a logic reacting to the signal value changes. Similarly, in a remaining part (γ), we can update the signal value.

All this is just an example of Event-driven programming and Publish–subscribe pattern (compare for example with fpubsub library). All three parts can be in some manner independent and still connected to the same reactive entity.

Signals are implemented in the library as functions. To see current value of signal, just call it without any arguments console.log(signal()). To update the signal value, pass any argument signal('a new value'). For listenning the signal value changes, use S.on(signal, console.log).

Similarly to the on function to register DOM events listener. You can use AbortController/AbortSignal to off/stop listenning. For representing “live” piece of code computation pattern:

import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

All this is just an example of Event-driven programming and Publish–subscribe pattern (compare for example with fpubsub library). All three parts can be in some manner independent and still connected to the same reactive entity.

Signals are implemented in the library as functions. To see current value of signal, just call it without any arguments console.log(signal()). To update the signal value, pass any argument signal('a new value'). For listenning the signal value changes, use S.on(signal, console.log).

Similarly to the on function to register DOM events listener. You can use AbortController/AbortSignal to off/stop listenning. For representing “live” piece of code computation pattern:

import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; const signal= S(0); // computation pattern const double= S(()=> 2*signal()); @@ -22,4 +32,4 @@ ac.signal.addEventListener("abort", ()=> setTimeout(()=> clearInterval(id), 2*interval)); setTimeout(()=> ac.abort(), 3*interval) -

Mnemonic

  • S(<value>) — signal: reactive value
  • S(()=> <computation>) — signal: reactive value dependent on calculation using other signals
  • S.on(<signal>, <listener>[, <options>]) — listen to the signal value changes
  • S.clear(...<signals>) — off and clear signals
  • S(<value>, <actions>) — signal: pattern to create complex reactive objects/arrays
  • S.action(<signal>, <action-name>, ...<action-arguments>) — invoke an action for given signal
\ No newline at end of file +

# Mnemonic

\ No newline at end of file diff --git a/docs_src/components/code.html.js b/docs_src/components/code.html.js index 69fd7cc..119a087 100644 --- a/docs_src/components/code.html.js +++ b/docs_src/components/code.html.js @@ -14,6 +14,7 @@ ${host}{ --shiki-token-punctuation: var(--code); --shiki-token-link: #EE0000; white-space: pre; + overflow: scroll; } ${host}[data-js=todo]{ border: 1px solid var(--border); @@ -30,11 +31,13 @@ import { el } from "deka-dom-el"; * @param {object} attrs * @param {string} [attrs.id] * @param {string} [attrs.className] - * @param {string} attrs.content Example code file path + * @param {URL} [attrs.src] Example code file path + * @param {string} [attrs.content] Example code * @param {"js"|"ts"|"html"|"css"} [attrs.language="js"] Language of the code * @param {string} [attrs.page_id] ID of the page, if setted it registers shiki * */ -export function code({ id, content, language= "js", className= "code", page_id }){ +export function code({ id, src, content, language= "js", className= host.slice(1), page_id }){ + if(src) content= s.cat(src); let dataJS; if(page_id){ registerClientPart(page_id); diff --git a/docs_src/components/examples/elements/intro.js b/docs_src/components/examples/elements/intro.js new file mode 100644 index 0000000..027f37e --- /dev/null +++ b/docs_src/components/examples/elements/intro.js @@ -0,0 +1,10 @@ +// when NPM +import { assign, el, elNS } from "deka-dom-el"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js + +// “internal” utils +import { + assignAttribute, + classListDeclarative, + chainableAppend +} from "deka-dom-el"; diff --git a/docs_src/components/examples/events/intro.js b/docs_src/components/examples/events/intro.js new file mode 100644 index 0000000..199ecbb --- /dev/null +++ b/docs_src/components/examples/events/intro.js @@ -0,0 +1,7 @@ +// when NPM +import { on, dispatchEvent } from "deka-dom-el"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js + +/** + * @type {ddeElementAddon} + * */ diff --git a/docs_src/components/examples/signals/intro.js b/docs_src/components/examples/signals/intro.js index f9b6d52..32dc961 100644 --- a/docs_src/components/examples/signals/intro.js +++ b/docs_src/components/examples/signals/intro.js @@ -1,8 +1,10 @@ +// when NPM import { S } from "deka-dom-el/signals"; -// α — `signal` represents a reactive value -const signal= S(0); -// β — just reacts on signal changes -S.on(signal, console.log); -// γ — just updates the value -signal(signal()+1); -setInterval(()=> signal(signal()+1), 5000); +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js + +/** + * @type {ddeSignal} + * */ +/** + * @type {ddeActions} + * */ diff --git a/docs_src/components/examples/signals/signals.js b/docs_src/components/examples/signals/signals.js new file mode 100644 index 0000000..f9b6d52 --- /dev/null +++ b/docs_src/components/examples/signals/signals.js @@ -0,0 +1,8 @@ +import { S } from "deka-dom-el/signals"; +// α — `signal` represents a reactive value +const signal= S(0); +// β — just reacts on signal changes +S.on(signal, console.log); +// γ — just updates the value +signal(signal()+1); +setInterval(()=> signal(signal()+1), 5000); diff --git a/docs_src/components/mnemonicUl.html.js b/docs_src/components/mnemonicUl.html.js new file mode 100644 index 0000000..716d453 --- /dev/null +++ b/docs_src/components/mnemonicUl.html.js @@ -0,0 +1,19 @@ +import { styles } from "../ssr.js"; +import { h3 } from "./pageUtils.html.js"; +const host= ".notice"; +styles.css` +${host} h3{ + margin-top: 0; +} +`; +import { el, simulateSlots } from "deka-dom-el"; +/** @param {Object} props @param {string} props.textContent */ +export function mnemonicUl({ textContent= "" }){ + if(textContent) textContent= " – "+textContent + return simulateSlots(el("div", { className: "notice" }).append( + el(h3, "Mnemonic"+textContent), + el("ul").append( + el("slot") + ) + )); +} diff --git a/docs_src/p02-elements.html.js b/docs_src/p02-elements.html.js index beaa3a2..469f531 100644 --- a/docs_src/p02-elements.html.js +++ b/docs_src/p02-elements.html.js @@ -3,6 +3,8 @@ import { simplePage } from "./layout/simplePage.html.js"; import { el } from "deka-dom-el"; import { example } from "./components/example.html.js"; import { h3 } from "./components/pageUtils.html.js"; +import { mnemonicUl } from "./components/mnemonicUl.html.js"; +import { code } from "./components/code.html.js"; /** @param {string} url */ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.d.ts").PageAttrs} attrs */ @@ -11,6 +13,8 @@ export function page({ pkg, info }){ return el(simplePage, { info, pkg }).append( el("h2", "Native JavaScript DOM elements creations"), el("p", "Let’s go through all patterns we would like to use and what needs to be improved for better experience."), + + el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), el(h3, "Creating element(s) (with custom attributes)"), el("p").append( @@ -112,28 +116,25 @@ export function page({ pkg, info }){ ), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), - el("div", { className: "notice" }).append( - el("p", "Mnemonic"), - el("ul").append( - el("li").append( - el("code", "assign(, ...): "), " — assign properties to the element", - ), - el("li").append( - el("code", "el(, )[.append(...)]: "), " — simple element containing only text", - ), - el("li").append( - el("code", "el(, )[.append(...)]: "), " — element with more properties", - ), - el("li").append( - el("code", "el(, )[.append(...)]: "), " — using component represented by function", - ), - el("li").append( - el("code", "el(<...>, <...>, ...)"), " — see following page" - ), - el("li").append( - el("code", "elNS()()[.append(...)]: "), " — typically SVG elements", - ) + el(mnemonicUl).append( + el("li").append( + el("code", "assign(, ...): "), " — assign properties to the element", + ), + el("li").append( + el("code", "el(, )[.append(...)]: "), " — simple element containing only text", + ), + el("li").append( + el("code", "el(, )[.append(...)]: "), " — element with more properties", + ), + el("li").append( + el("code", "el(, )[.append(...)]: "), " — using component represented by function", + ), + el("li").append( + el("code", "el(<...>, <...>, ...)"), " — see following page" + ), + el("li").append( + el("code", "elNS()()[.append(...)]: "), " — typically SVG elements", ) - ), + ) ); } diff --git a/docs_src/p03-events.html.js b/docs_src/p03-events.html.js index 0223fdd..8fe799d 100644 --- a/docs_src/p03-events.html.js +++ b/docs_src/p03-events.html.js @@ -3,6 +3,8 @@ import { simplePage } from "./layout/simplePage.html.js"; import { el } from "deka-dom-el"; import { example } from "./components/example.html.js"; import { h3 } from "./components/pageUtils.html.js"; +import { mnemonicUl } from "./components/mnemonicUl.html.js"; +import { code } from "./components/code.html.js"; /** @param {string} url */ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.d.ts").PageAttrs} attrs */ @@ -17,6 +19,8 @@ export function page({ pkg, info }){ " incorporate not only this in UI templates declaratively." ), + el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), + el(h3, "Events and listenners"), el("p").append( "In JavaScript you can listen to the native DOM events of the given element by using ", @@ -109,23 +113,20 @@ export function page({ pkg, info }){ el("p", "The library also provides a method to dispatch the events."), el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), - el("div", { className: "notice" }).append( - el("p", "Mnemonic"), - el("ul").append( - el("li").append( - el("code", "on(, [, ])()"), " — just ", el("code", ".addEventListener(, [, ])") - ), - el("li").append( - el("code", "on.(, [, ])()"), " — corresponds to custom elemnets callbacks ", el("code", "Callback(...){...}"), - ". To connect to custom element see following page, else it is simulated by MutationObserver." - ), - el("li").append( - el("code", "dispatchEvent([, ])(element)"), " — just ", el("code", ".dispatchEvent(new Event([, ]))") - ), - el("li").append( - el("code", "dispatchEvent([, ])(element, detail)"), " — just ", el("code", ".dispatchEvent(new CustomEvent(, { detail, ... }))") - ), - ) + el(mnemonicUl).append( + el("li").append( + el("code", "on(, [, ])()"), " — just ", el("code", ".addEventListener(, [, ])") + ), + el("li").append( + el("code", "on.(, [, ])()"), " — corresponds to custom elemnets callbacks ", el("code", "Callback(...){...}"), + ". To connect to custom element see following page, else it is simulated by MutationObserver." + ), + el("li").append( + el("code", "dispatchEvent([, ])(element)"), " — just ", el("code", ".dispatchEvent(new Event([, ]))") + ), + el("li").append( + el("code", "dispatchEvent([, ])(element, detail)"), " — just ", el("code", ".dispatchEvent(new CustomEvent(, { detail, ... }))") + ), ), ); } diff --git a/docs_src/p04-signals.html.js b/docs_src/p04-signals.html.js index 783a6bd..afb943c 100644 --- a/docs_src/p04-signals.html.js +++ b/docs_src/p04-signals.html.js @@ -3,6 +3,8 @@ import { simplePage } from "./layout/simplePage.html.js"; import { el } from "deka-dom-el"; import { example } from "./components/example.html.js"; import { h3 } from "./components/pageUtils.html.js"; +import { mnemonicUl } from "./components/mnemonicUl.html.js"; +import { code } from "./components/code.html.js"; /** @param {string} url */ const fileURL= url=> new URL(url, import.meta.url); @@ -17,7 +19,7 @@ export function page({ pkg, info }){ " If we desire to solve the issue in a declarative manner,", " signals may be a viable approach.", ), - el(example, { src: fileURL("./components/examples/signals/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), el(h3, "Introducing signals"), el("p").append( @@ -27,6 +29,7 @@ export function page({ pkg, info }){ " to the signal value changes. Similarly, in a remaining part (γ), we", " can update the signal value." ), + el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), el("p").append( "All this is just an example of ", el("a", { textContent: "Event-driven programming", href: "https://en.wikipedia.org/wiki/Event-driven_programming", title: "Wikipedia: Event-driven programming" }), @@ -48,27 +51,24 @@ export function page({ pkg, info }){ " ", el("em", "off"), "/stop listenning. For representing “live” piece of code computation pattern:" ), el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), - el("div", { className: "notice" }).append( - el("p", "Mnemonic"), - el("ul").append( - el("li").append( - el("code", "S()"), " — signal: reactive value", - ), - el("li").append( - el("code", "S(()=> )"), " — signal: reactive value dependent on calculation using other signals", - ), - el("li").append( - el("code", "S.on(, [, ])"), " — listen to the signal value changes", - ), - el("li").append( - el("code", "S.clear(...)"), " — off and clear signals", - ), - el("li").append( - el("code", "S(, )"), " — signal: pattern to create complex reactive objects/arrays", - ), - el("li").append( - el("code", "S.action(, , ...)"), " — invoke an action for given signal" - ) + el(mnemonicUl).append( + el("li").append( + el("code", "S()"), " — signal: reactive value", + ), + el("li").append( + el("code", "S(()=> )"), " — signal: reactive value dependent on calculation using other signals", + ), + el("li").append( + el("code", "S.on(, [, ])"), " — listen to the signal value changes", + ), + el("li").append( + el("code", "S.clear(...)"), " — off and clear signals", + ), + el("li").append( + el("code", "S(, )"), " — signal: pattern to create complex reactive objects/arrays", + ), + el("li").append( + el("code", "S.action(, , ...)"), " — invoke an action for given signal" ) ), ); diff --git a/package.json b/package.json index 3fd49c1..bf1c578 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "deka-dom-el", - "version": "0.7.1", + "version": "0.7.2", "description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.", "author": "Jan Andrle ", "license": "MIT",