From 4d56fa705e7b7e041fdf50bc425bb26d163b1366 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Mon, 6 Nov 2023 20:20:32 +0100 Subject: [PATCH] :recycle: Refactor docs --- bs/docs.js | 7 ++--- docs/index.css | 18 ++++++++++--- docs/index.html | 16 +++++------ docs_src/index.css.js | 18 ++++++++++--- docs_src/index.html.js | 29 +++++++------------- docs_src/layout/head.html.js | 52 ++++++++++++++++++++++++++++++++++-- 6 files changed, 98 insertions(+), 42 deletions(-) diff --git a/bs/docs.js b/bs/docs.js index 3f9610a..7e80fbd 100755 --- a/bs/docs.js +++ b/bs/docs.js @@ -12,12 +12,9 @@ const { el }= await register(ssr.dom); echo("Loading components…"); const pkg= s.cat("package.json").xargs(JSON.parse); -const { head, body, css }= await import("../docs_src/index.html.js"); //→ TODO: important to mention in docs!!! -document.head.append( - head(pkg, path_target) -); +const { page, css }= await import("../docs_src/index.html.js"); //→ TODO: important to mention in docs!!! document.body.append( - el(body, pkg), + el(page, { pkg, path_target }), el("script", { src: "https://cdn.jsdelivr.net/npm/shiki" }), el("script", { src: "index.js", type: "module" }) ); diff --git a/docs/index.css b/docs/index.css index c6ed18a..50640a7 100644 --- a/docs/index.css +++ b/docs/index.css @@ -14,10 +14,20 @@ body { grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr; } -h1{ - text-align: center; - text-wrap: balanc; - grid-column: 1 / 4; +nav a.current { + color: var(--accent) !important; + border-color: var(--accent) !important; +} +.icon { + vertical-align: sub; + padding-right: .25rem; + display: inline-block; + width: 1em; + height: 1.3em; + margin-right: 0.2rem; + stroke-width: 0; + stroke: currentColor; + fill: currentColor; } .note{ font-size: .9rem; diff --git a/docs/index.html b/docs/index.html index 6b22331..64568dd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ -`deka-dom-el` — Introduction/Guide

`deka-dom-el` — Introduction/Guide

The library tries to provide pure JavaScript tool(s) to create reactive interfaces. The main goals are:

It is, in fact, an reimplementation of jaandrle/dollar_dom_component.

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

`deka-dom-el` — Introduction/Guide

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

The main goals are:

  • provide a small wrappers/utilities around the native JavaScript DOM
  • keep library size around 10kB at maximum (if possible)
  • zero dependencies (if possible)
  • prefer a declarative/functional approach
  • unopinionated (allow alternative methods)

It is, in fact, an reimplementation of jaandrle/dollar_dom_component.

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,7 +12,7 @@ document.body.append(
 		})
 	)
 );
-

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(
+

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(
 	document.createElement("div")
 );
 console.log(
@@ -26,7 +26,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 } })
@@ -37,7 +37,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!");
@@ -62,7 +62,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")
@@ -73,7 +73,7 @@ const template= document.createElement("main").append(
 	document.createElement("span"),
 );
 console.log(typeof template==="undefined");
-

This library therefore ooverwrites the append method 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 ooverwrites the append method 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; }",
@@ -97,7 +97,7 @@ document.body.append(
 		)
 	)
 );
-

Creating advanced (reactive) templates and components

Basic 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";
+

Creating advanced (reactive) templates and components

Basic 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; }",
@@ -114,4 +114,4 @@ function component({ className, textContent }){
 		el("p", textContent)
 	);
 }
-

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

\ No newline at end of file +

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

\ No newline at end of file diff --git a/docs_src/index.css.js b/docs_src/index.css.js index f926eb5..36c9dbb 100644 --- a/docs_src/index.css.js +++ b/docs_src/index.css.js @@ -44,9 +44,19 @@ export const common= css` body { grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr; } -h1{ - text-align: center; - text-wrap: balanc; - grid-column: 1 / 4; +nav a.current { + color: var(--accent) !important; + border-color: var(--accent) !important; +} +.icon { + vertical-align: sub; + padding-right: .25rem; + display: inline-block; + width: 1em; + height: 1.3em; + margin-right: 0.2rem; + stroke-width: 0; + stroke: currentColor; + fill: currentColor; } `; diff --git a/docs_src/index.html.js b/docs_src/index.html.js index a6a199a..fa6cb7c 100644 --- a/docs_src/index.html.js +++ b/docs_src/index.html.js @@ -1,14 +1,4 @@ import { el } from "deka-dom-el"; -import { head as headCommon } from "./layout/head.html.js"; -export function head(pkg, path_target){ - return headCommon({ - id: "index", - title: pageName(pkg), - description: "Introducing basic concepts.", - pkg, path_target - }); -} - import { styles, common } from "./index.css.js"; import { example, css as example_css } from "./components/example.html.js"; export const css= styles() @@ -20,13 +10,17 @@ export const css= styles() } ` .include(example_css); -export function body(pkg){ + +import { header } from "./layout/head.html.js"; +export function page({ pkg, path_target }){ return el().append( - el("h1", pageName(pkg)), - el("p").append( - "The library tries to provide pure JavaScript tool(s) to create reactive interfaces. ", - "The main goals are:" - ), + el(header, { + id: "index", + title: "Introduction/Guide", + description: "Introducing basic concepts.", + pkg, path_target + }), + el("p", "The main goals are:"), el("ul").append( el("li", "provide a small wrappers/utilities around the native JavaScript DOM"), el("li", "keep library size around 10kB at maximum (if possible)"), @@ -133,6 +127,3 @@ export function body(pkg){ el("p", "It is nice to use similar naming convention as native DOM API.") ); } -function pageName(pkg){ - return `\`${pkg.name}\` — Introduction/Guide`; -} diff --git a/docs_src/layout/head.html.js b/docs_src/layout/head.html.js index 0fa6aa3..cee7df3 100644 --- a/docs_src/layout/head.html.js +++ b/docs_src/layout/head.html.js @@ -1,4 +1,4 @@ -import { el } from "deka-dom-el"; +import { el, scope } from "deka-dom-el"; /** * @param {object} def * @param {string} def.id Page `id` is used as stylesheet name. @@ -11,7 +11,55 @@ import { el } from "deka-dom-el"; * @param {{ root: string, css: string}} def.path_target Final URL where the page will be rendered. * @param {object} def * */ -export function head({ id, title, description, pkg, path_target }){ +export function header({ id, title, description, pkg, path_target }){ + title= `\`${pkg.name}\` — ${title}`; + document.head.append(head({ id, title, description, pkg, path_target })); + return el("header").append( + el("nav").append( + el("a", { href: pkg.homepage }).append( + el(iconGitHub), + "GitHub" + ) + ), + el("h1", title), + el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces. ") + ); +} +function iconGitHub(){ + scope.namespace= "svg"; + return el("svg", { className: "icon", viewBox: "0 0 32 32" }).append( + el("path", { d: [ //see https://svg-path-visualizer.netlify.app/#M16%200.395c-8.836%200-16%207.163-16%2016%200%207.069%204.585%2013.067%2010.942%2015.182%200.8%200.148%201.094-0.347%201.094-0.77%200-0.381-0.015-1.642-0.022-2.979-4.452%200.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993%200.11-0.973%200.11-0.973%201.606%200.113%202.452%201.649%202.452%201.649%201.427%202.446%203.743%201.739%204.656%201.33%200.143-1.034%200.558-1.74%201.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907%200-1.747%200.625-3.174%201.649-4.295-0.166-0.403-0.714-2.030%200.155-4.234%200%200%201.344-0.43%204.401%201.64%201.276-0.355%202.645-0.532%204.005-0.539%201.359%200.006%202.729%200.184%204.008%200.539%203.054-2.070%204.395-1.64%204.395-1.64%200.871%202.204%200.323%203.831%200.157%204.234%201.026%201.12%201.647%202.548%201.647%204.295%200%206.145-3.743%207.498-7.306%207.895%200.574%200.497%201.085%201.47%201.085%202.963%200%202.141-0.019%203.864-0.019%204.391%200%200.426%200.288%200.925%201.099%200.768%206.354-2.118%2010.933-8.113%2010.933-15.18%200-8.837-7.164-16-16-16z + "M 16,0.395", + "c -8.836,0 -16,7.163 -16,16", + "c 0,7.069 4.585,13.067 10.942,15.182", + "c 0.8,0.148 1.094,-0.347 1.094,-0.77", + "c 0,-0.381 -0.015,-1.642 -0.022,-2.979", + "c -4.452,0.968 -5.391,-1.888 -5.391,-1.888", + "c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341", + "c -1.452,-0.993 0.11,-0.973 0.11,-0.973", + "c 1.606,0.113 2.452,1.649 2.452,1.649", + "c 1.427,2.446 3.743,1.739 4.656,1.33", + "c 0.143,-1.034 0.558,-1.74 1.016,-2.14", + "c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907", + "c 0,-1.747 0.625,-3.174 1.649,-4.295", + "c -0.166,-0.403 -0.714,-2.03 0.155,-4.234", + "c 0,0 1.344,-0.43 4.401,1.64", + "c 1.276,-0.355 2.645,-0.532 4.005,-0.539", + "c 1.359,0.006 2.729,0.184 4.008,0.539", + "c 3.054,-2.07 4.395,-1.64 4.395,-1.64", + "c 0.871,2.204 0.323,3.831 0.157,4.234", + "c 1.026,1.12 1.647,2.548 1.647,4.295", + "c 0,6.145 -3.743,7.498 -7.306,7.895", + "c 0.574,0.497 1.085,1.47 1.085,2.963", + "c 0,2.141 -0.019,3.864 -0.019,4.391", + "c 0,0.426 0.288,0.925 1.099,0.768", + "c 6.354,-2.118 10.933,-8.113 10.933,-15.18", + "c 0,-8.837 -7.164,-16 -16,-16", + "Z" + ].join("") }) + ); +} +function head({ id, title, description, pkg, path_target }){ return el().append( el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), el("link", { rel: "stylesheet", href: stylesheetHref(path_target, id) }),