From 10021cb8beed79c35048d91d334255da78bd317e Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Fri, 17 Nov 2023 16:15:26 +0100 Subject: [PATCH] :sparkles: :pencil2: update elemnts and add events page --- docs/elements.html | 25 ++++++++++++++------ docs/events.html | 1 + docs/index.html | 4 ++-- docs_src/components/examples/dekaElNS.js | 11 +++++++++ docs_src/elements.html.js | 19 ++++++++++++--- docs_src/events.html.js | 30 ++++++++++++++++++++++++ docs_src/index.html.js | 24 +++++++++++++++++++ docs_src/ssr.js | 5 ++-- 8 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 docs/events.html create mode 100644 docs_src/components/examples/dekaElNS.js create mode 100644 docs_src/events.html.js diff --git a/docs/elements.html b/docs/elements.html index 3c6909e..b9f34d2 100644 --- a/docs/elements.html +++ b/docs/elements.html @@ -1,4 +1,4 @@ -`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.

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.

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( @@ -12,7 +12,7 @@ document.body.append( { textContent: "Element’s text content.", style: "color: coral;" } ) ); -

To make this easier, you can use the el function. Internally in basic examples, it is wrapper around assign(document.createElement(…), { … }).

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

To make this easier, you can use the el function. Internally in basic examples, it is wrapper around assign(document.createElement(…), { … }).

import { el, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; const color= "lightcoral"; document.body.append( el("p", { textContent: "Hello (first time)", style: { color } }) @@ -23,7 +23,7 @@ document.body.append( { textContent: "Hello (second time)", style: { color } } ) ); -

The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.

You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:

  • It is possible to sets data-*/aria-* attributes using object notation.
  • In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
  • You can use string or object as a value for style property.
  • className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
  • Use classList to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.
  • The assign also accepts the undefined as a value for any property to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed as it can be confusing. For example, natievly the element’s id is removed by setting the IDL to an empty string.

For processing, the assign internally uses assignAttribute and classListDeclarative.

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

The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.

You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:

  • It is possible to sets data-*/aria-* attributes using object notation.
  • In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
  • You can use string or object as a value for style property.
  • className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
  • Use classList to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.
  • The assign also accepts the undefined as a value for any property to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed as it can be confusing. For example, natievly the element’s id is removed by setting the IDL to an empty string.

For processing, the assign internally uses assignAttribute and classListDeclarative.

import { assignAttribute, classListDeclarative } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; const paragraph= document.createElement("p"); assignAttribute(paragraph, "textContent", "Hello, world!"); @@ -48,7 +48,7 @@ console.log(paragraph.outerHTML); document.body.append( paragraph ); -

Native JavaScript templating

By default, the native JS has no good way to define HTML template using DOM API:

document.body.append( +

Native JavaScript templating

By default, the native JS has no good way to define HTML template using DOM API:

document.body.append( document.createElement("div"), document.createElement("span"), document.createElement("main") @@ -59,7 +59,7 @@ const template= document.createElement("main").append( document.createElement("span"), ); console.log(typeof template==="undefined"); -

This library therefore overwrites the append method of created elements to always return parent element.

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

This library therefore overwrites the append method of created elements to always return parent element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; document.head.append( el("style").append( "tr, td{ border: 1px solid red; padding: 1em; }", @@ -83,7 +83,7 @@ document.body.append( ) ) ); -

Basic (state-less) components

You can use functions for encapsulation (repeating) logic. The el accepts function as first argument. In that case, the function should return dom elements and the second argument for el is argument for given element.

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

Basic (state-less) components

You can use functions for encapsulation (repeating) logic. The el accepts function as first argument. In that case, the function should return dom elements and the second argument for el is argument for given element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; document.head.append( el("style").append( ".class1{ font-weight: bold; }", @@ -100,4 +100,15 @@ function component({ className, textContent }){ el("p", textContent) ); } -

It is nice to use similar naming convention as native DOM API.

Creating non-HTML elements

\ No newline at end of file +

As you can see, in case of state-less/basic components there is no difference between calling component function directly or using el function.

It is nice to use similar naming convention as native DOM API. This allows us to use the destructuring assignment syntax and keep track of the native API (things are best remembered through regular use).

Creating non-HTML elements

Similarly to the native DOM API (document.createElementNS) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the elNS function:

import { elNS, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +const elSVG= elNS("http://www.w3.org/2000/svg"); +const elMath= elNS("http://www.w3.org/1998/Math/MathML"); +document.body.append( + elSVG("svg"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement + elMath("math") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes +); + +console.log( + document.body.innerHTML.includes("<svg></svg><math></math>") +) +
\ No newline at end of file diff --git a/docs/events.html b/docs/events.html new file mode 100644 index 0000000..1a4343f --- /dev/null +++ b/docs/events.html @@ -0,0 +1 @@ +`deka-dom-el` — Events and Modifiers

`deka-dom-el` — Events and Modifiers

Using not only events in UI declaratively.

Listenning to the native DOM events and other Modifiers

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

Add events listeners

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index d31b9b3..db41075 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ -`deka-dom-el` — Introduction

`deka-dom-el` — Introduction

Introducing a library and motivations.

The library tries to provide pure JavaScript tool(s) to create reactive interfaces.

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

`deka-dom-el` — Introduction

Introducing a library.

The library tries to provide pure JavaScript tool(s) to create reactive interfaces.

We start with creating and modifying a static elemnets and end up with UI templates. From document.createElement to el. Then we go through the native events system and the way to include it declaratively in UI templates. From element.addEventListener to on.

Next step is providing interactivity not only for our UI templates. We introduce signals (S) and how them incorporate to UI templates.

Now we will clarify how the signals are incorporated into our templates with regard to application performance. This is not the only reason the library uses scopes. We will look at how they work in components represented in JavaScript by functions.

import { el, S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; const clicks= S(0); document.body.append( el().append( @@ -12,4 +12,4 @@ document.body.append( }) ) ); -
\ No newline at end of file +
\ No newline at end of file diff --git a/docs_src/components/examples/dekaElNS.js b/docs_src/components/examples/dekaElNS.js new file mode 100644 index 0000000..745dbd2 --- /dev/null +++ b/docs_src/components/examples/dekaElNS.js @@ -0,0 +1,11 @@ +import { elNS, assign } from "../../../index-with-signals.js"; +const elSVG= elNS("http://www.w3.org/2000/svg"); +const elMath= elNS("http://www.w3.org/1998/Math/MathML"); +document.body.append( + elSVG("svg"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement + elMath("math") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes +); + +console.log( + document.body.innerHTML.includes("") +) diff --git a/docs_src/elements.html.js b/docs_src/elements.html.js index 20394e0..d76d672 100644 --- a/docs_src/elements.html.js +++ b/docs_src/elements.html.js @@ -28,7 +28,7 @@ export function page({ pkg, info }){ title: "MDN page about Interface Description Language" }).append( el("abbr", { textContent: "IDL", title: "Interface Description Language" }) - ), "." + ), " also known as a JavaScript property." ), el(example, { src: fileURL("./components/examples/nativeCreateElement.js"), page_id }), el("p").append( @@ -94,10 +94,23 @@ export function page({ pkg, info }){ "In that case, the function should return dom elements and the second argument for ", el("code", "el"), " is argument for given element." ), el(example, { src: fileURL("./components/examples/dekaBasicComponent.js"), page_id }), - el("p", "It is nice to use similar naming convention as native DOM API."), + el("p").append( + "As you can see, in case of state-less/basic components there is no difference", + " between calling component function directly or using ", el("code", "el"), " function.", + ), + el("p", { className: "notice" }).append( + "It is nice to use similar naming convention as native DOM API. ", + "This allows us to use ", el("a", { textContent: "the destructuring assignment syntax", href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment", title: "Destructuring assignment | MDN" }), + " and keep track of the native API (things are best remembered through regular use).", + ), el("h3", "Creating non-HTML elements"), - // example & notes + el("p").append( + "Similarly to the native DOM API (", el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS", title: "MDN" }).append(el("code", "document.createElementNS")), ") for non-HTML elements", + " we need to tell JavaScript which kind of the element to create.", + " We can use the ", el("code", "elNS"), " function:" + ), + el(example, { src: fileURL("./components/examples/dekaElNS.js"), page_id }), el(prevNext, info) ) diff --git a/docs_src/events.html.js b/docs_src/events.html.js new file mode 100644 index 0000000..a19b4d1 --- /dev/null +++ b/docs_src/events.html.js @@ -0,0 +1,30 @@ +import "./global.css.js"; +import { el } from "deka-dom-el"; +import { example } from "./components/example.html.js"; + +/** @param {string} url */ +const fileURL= url=> new URL(url, import.meta.url); +import { header } from "./layout/head.html.js"; +import { prevNext } from "./components/prevNext.html.js"; +/** @param {import("./types.d.ts").PageAttrs} attrs */ +export function page({ pkg, info }){ + const page_id= info.id; + return el().append( + el(header, { info, pkg }), + el("main").append( + el("h2", "Listenning to the native DOM events and other Modifiers"), + el("p").append( + "We quickly introduce helper to listening to the native DOM events.", + " ", + "And library syntax/pattern so-called ", el("em", "Modifier"), " to", + " incorporate not only this in UI templates declaratively." + ), + + el("h3", "Add events listeners"), + el("p").append( + ), + + el(prevNext, info) + ) + ); +} diff --git a/docs_src/index.html.js b/docs_src/index.html.js index d5f36df..25ef0fb 100644 --- a/docs_src/index.html.js +++ b/docs_src/index.html.js @@ -11,6 +11,30 @@ export function page({ pkg, info }){ el(header, { info, pkg }), el("main").append( el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces."), + el("p").append( + "We start with creating and modifying a static elemnets and end up with UI templates.", + " ", + el("i").append( + "From ", el("code", "document.createElement"), " to ", el("code", "el"), "." + ), + " ", + "Then we go through the native events system and the way to include it declaratively in UI templates.", + " ", + el("i").append( + "From ", el("code", "element.addEventListener"), " to ", el("code", "on"), "." + ), + ), + el("p").append( + "Next step is providing interactivity not only for our UI templates.", + " ", + "We introduce signals (", el("code", "S"), ") and how them incorporate to UI templates.", + ), + el("p").append( + "Now we will clarify how the signals are incorporated into our templates with regard ", + "to application performance. This is not the only reason the library uses ", + el("code", "scope"), "s. We will look at how they work in components represented ", + "in JavaScript by functions." + ), el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id }), el(prevNext, info) ) diff --git a/docs_src/ssr.js b/docs_src/ssr.js index 5a8eff8..890f048 100644 --- a/docs_src/ssr.js +++ b/docs_src/ssr.js @@ -3,8 +3,9 @@ export const path_target= { css: "docs/" }; export const pages= [ - { id: "index", href: "./", title: "Introduction", description: "Introducing a library and motivations." }, - { id: "elements", href: "elements", title: "Elements", description: "Basic concepts of elements modifications and creations." } + { id: "index", href: "./", title: "Introduction", description: "Introducing a library." }, + { id: "elements", href: "elements", title: "Elements", description: "Basic concepts of elements modifications and creations." }, + { id: "events", href: "events", title: "Events and Modifiers", description: "Using not only events in UI declaratively." }, ]; /** * @typedef registerClientFile