1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-22 07:49:38 +01:00

💥 📝

This commit is contained in:
Jan Andrle 2023-11-10 17:15:59 +01:00
parent 4d3a513713
commit 2569b9cd45
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
30 changed files with 420 additions and 361 deletions

View File

@ -2,48 +2,25 @@
/* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */ /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */
echo("Building static documentation files…"); echo("Building static documentation files…");
echo("Preparing…"); echo("Preparing…");
const path_target= { import { path_target, pages, styles, dispatchEvent } from "../docs_src/ssr.js";
root: "docs/",
css: "docs/"
};
import { createHTMl } from "./docs/jsdom.js"; import { createHTMl } from "./docs/jsdom.js";
import { register } from "../jsdom.js"; import { register } from "../jsdom.js";
const pkg= s.cat("package.json").xargs(JSON.parse); const pkg= s.cat("package.json").xargs(JSON.parse);
const pages= [
{ id: "index", title: "Introduction", description: "Introducing a library and motivations." },
{ id: "elements", title: "Elements", description: "Basic concepts of elements modifications and creations." }
];
for(const info of pages){ for(const info of pages){
const { id }= info; const { id }= info;
echo(`Generating ${id}.html…`); echo(`Generating ${id}.html…`);
const ssr= createHTMl(""); const ssr= createHTMl("");
const { el }= await register(ssr.dom); const { el }= await register(ssr.dom);
const { page, css }= await import(`../docs_src/${id}.html.js`); //→ TODO: important to mention in docs!!! const { page }= await import(`../docs_src/${id}.html.js`); //→ TODO: important to mention in docs!!!
document.body.append( document.body.append(
el(page, { pkg, info, path_target, pages, registerClientFile }), el(page, { pkg, info }),
); );
echo.use("-R", `Writing ${id}.html…`); echo.use("-R", `Writing ${id}.html…`);
dispatchEvent("oneachrender", document);
s.echo(ssr.serialize()).to(path_target.root+id+".html"); s.echo(ssr.serialize()).to(path_target.root+id+".html");
s.echo(css.content).to(path_target.css+id+".css");
} }
s.echo(styles.content).to(path_target.css+styles.name);
dispatchEvent("onssrend");
echo("Done"); echo("Done");
/**
* @typedef registerClientFile
* @type {function}
* @param {URL} url
* @param {HTMLScriptElement|HTMLLinkElement} [element_head]
* */
function registerClientFile(url, element_head){
const file_name= url.pathname.split("/").pop();
s.cat(url).to(path_target.root+file_name);
if(!element_head) return;
element_head[element_head instanceof HTMLScriptElement ? "src" : "href"]= file_name;
document.head.append(
element_head
);
}

File diff suppressed because one or more lines are too long

18
dist/dde.js vendored

File diff suppressed because one or more lines are too long

View File

@ -121,7 +121,7 @@ interface On{
) : EE; ) : EE;
} }
export const on: On; export const on: On;
type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, prevent: boolean, inherit_host: boolean, } type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, custom_element: false | HTMLElement, prevent: boolean }
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ /** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: { export const scope: {
current: Scope, current: Scope,
@ -431,6 +431,10 @@ declare global{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */ /** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<DocumentFragment>; append: ddeAppend<DocumentFragment>;
} }
interface SVGElement{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<SVGElement>;
}
} }
export type Signal<V, A>= (set?: V)=> V & A; export type Signal<V, A>= (set?: V)=> V & A;
type Action<V>= (this: { value: V }, ...a: any[])=> typeof S._ | void; type Action<V>= (this: { value: V }, ...a: any[])=> typeof S._ | void;

File diff suppressed because one or more lines are too long

6
dist/esm.d.ts vendored
View File

@ -121,7 +121,7 @@ interface On{
) : EE; ) : EE;
} }
export const on: On; export const on: On;
type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, prevent: boolean, inherit_host: boolean, } type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, custom_element: false | HTMLElement, prevent: boolean }
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ /** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: { export const scope: {
current: Scope, current: Scope,
@ -431,4 +431,8 @@ declare global{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */ /** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<DocumentFragment>; append: ddeAppend<DocumentFragment>;
} }
interface SVGElement{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<SVGElement>;
}
} }

2
dist/esm.js vendored

File diff suppressed because one or more lines are too long

12
docs/code.js.js Normal file
View File

@ -0,0 +1,12 @@
const highlighter= await shiki.getHighlighter({
theme: "css-variables",
langs: ["js", "ts", "css", "html", "shell"],
});
const codeBlocks= document.querySelectorAll('code[class*="language-"]');
codeBlocks.forEach((block)=> {
const lang= block.className.replace("language-", "");
block.parentElement.dataset.js= "done";
const html= highlighter.codeToHtml(block.textContent, { lang });
block.innerHTML= html;
});

View File

@ -1,4 +1,4 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="elements.css"><meta name="description" content="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="metaTwitter" host="this"/>--><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"/>--><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"><title>`deka-dom-el` — Elements</title><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script></head><body><!--<dde:mark type="component" name="page" host="this"/>--><!--<dde:mark type="component" name="header" host="this"/>--><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"/>--><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 and motivations.">1. Introduction</a><a href="elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</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><h3>Creating element(s) (with custom attributes)</h3><p>You can create a native DOM element by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" title="MDN documentation for document.createElement()"><code>document.createElement()</code></a>. It is also possible to provide a&nbsp;some attribute(s) declaratively using <code>Object.assign()</code>. More precisely, this way you can sets some <a href="https://developer.mozilla.org/en-US/docs/Glossary/IDL" title="MDN page about Interface Description Language"><abbr title="Interface Description Language">IDL</abbr></a>.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-m4hdt" class="example"><pre><code class="language-javascript">document.body.append( <!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="true"/>--><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="true"/>--><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="true"/>--><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://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="true"/>--><!--<dde:mark type="component" name="header" host="this" ssr="true"/>--><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="true"/>--><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 and motivations.">1. Introduction</a><a href="elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</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><h3>Creating element(s) (with custom attributes)</h3><p>You can create a native DOM element by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" title="MDN documentation for document.createElement()"><code>document.createElement()</code></a>. It is also possible to provide a&nbsp;some attribute(s) declaratively using <code>Object.assign()</code>. More precisely, this way you can sets some <a href="https://developer.mozilla.org/en-US/docs/Glossary/IDL" title="MDN page about Interface Description Language"><abbr title="Interface Description Language">IDL</abbr></a>.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-e263u" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">document.body.append(
document.createElement("div") document.createElement("div")
); );
console.log( console.log(
@ -12,7 +12,7 @@ document.body.append(
{ textContent: "Elements text content.", style: "color: coral;" } { textContent: "Elements text content.", style: "color: coral;" }
) )
); );
</code></pre></div><script>Flems(document.getElementById("code-m4hdt"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"document.body.append(\\n\\tdocument.createElement(\\\"div\\\")\\n);\\nconsole.log(\\n\\t\\\"Emty div is generated inside <body>:\\\",\\n\\tdocument.body.innerHTML.includes(\\\"<div></div>\\\")\\n);\\n\\ndocument.body.append(\\n\\tObject.assign(\\n\\t\\tdocument.createElement(\\\"p\\\"),\\n\\t\\t{ textContent: \\\"Elements text content.\\\", style: \\\"color: coral;\\\" }\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><p>To make this easier, you can use the <code>el</code> function. Internally in basic examples, it is wrapper around <code>assign(document.createElement(…), { … })</code>.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-5855d" class="example"><pre><code class="language-javascript">import { el, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-e263u"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"document.body.append(\\n\\tdocument.createElement(\\\"div\\\")\\n);\\nconsole.log(\\n\\t\\\"Emty div is generated inside <body>:\\\",\\n\\tdocument.body.innerHTML.includes(\\\"<div></div>\\\")\\n);\\n\\ndocument.body.append(\\n\\tObject.assign(\\n\\t\\tdocument.createElement(\\\"p\\\"),\\n\\t\\t{ textContent: \\\"Elements text content.\\\", style: \\\"color: coral;\\\" }\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><p>To make this easier, you can use the <code>el</code> function. Internally in basic examples, it is wrapper around <code>assign(document.createElement(…), { … })</code>.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-xpmns" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">import { el, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const color= "lightcoral"; const color= "lightcoral";
document.body.append( document.body.append(
el("p", { textContent: "Hello (first time)", style: { color } }) el("p", { textContent: "Hello (first time)", style: { color } })
@ -23,7 +23,7 @@ document.body.append(
{ textContent: "Hello (second time)", style: { color } } { textContent: "Hello (second time)", style: { color } }
) )
); );
</code></pre></div><script>Flems(document.getElementById("code-5855d"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst color= \\\"lightcoral\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", { textContent: \\\"Hello (first time)\\\", style: { color } })\\n);\\ndocument.body.append(\\n\\tassign(\\n\\t\\tdocument.createElement(\\\"p\\\"),\\n\\t\\t{ textContent: \\\"Hello (second time)\\\", style: { color } }\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><p>The <code>assign</code> function provides improved behaviour of <code>Object.assign()</code>. You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the <code>element.setAttribute</code> if there is no writable property in the element prototype.</p><p>You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement">HTMLElement</a>. To see all available IDLs for example for paragraphs, see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement">HTMLParagraphElement</a>. Moreover, the <code>assign</code> provides a&nbsp;way to sets declaratively some convenient properties:</p><ul><li>It is possible to sets <code>data-*</code>/<code>aria-*</code> attributes using object notation.</li><li>In opposite, it is also possible to sets <code>data-*</code>/<code>aria-*</code> attribute using camelCase notation.</li><li>You can use string or object as a&nbsp;value for <code>style</code> property.</li><li><code>className</code> (IDL preffered)/<code>class</code> are ways to add CSS class to the element. You can use string (similarly to <code>class="…"</code> syntax in HTML) or array of strings. This is handy to concat conditional classes.</li><li>Use <code>classList</code> to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.</li><li>The <code>assign</code> also accepts the <code>undefined</code> as a&nbsp;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. <em>For example, natievly the elements <code>id</code> is removed by setting the IDL to an empty string.</em></li></ul><p>For processing, the <code>assign</code> internally uses <code>assignAttribute</code> and <code>classListDeclarative</code>.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-5f8sp" class="example"><pre><code class="language-javascript">import { assignAttribute, classListDeclarative } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-xpmns"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst color= \\\"lightcoral\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", { textContent: \\\"Hello (first time)\\\", style: { color } })\\n);\\ndocument.body.append(\\n\\tassign(\\n\\t\\tdocument.createElement(\\\"p\\\"),\\n\\t\\t{ textContent: \\\"Hello (second time)\\\", style: { color } }\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><p>The <code>assign</code> function provides improved behaviour of <code>Object.assign()</code>. You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the <code>element.setAttribute</code> if there is no writable property in the element prototype.</p><p>You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement">HTMLElement</a>. To see all available IDLs for example for paragraphs, see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement">HTMLParagraphElement</a>. Moreover, the <code>assign</code> provides a&nbsp;way to sets declaratively some convenient properties:</p><ul><li>It is possible to sets <code>data-*</code>/<code>aria-*</code> attributes using object notation.</li><li>In opposite, it is also possible to sets <code>data-*</code>/<code>aria-*</code> attribute using camelCase notation.</li><li>You can use string or object as a&nbsp;value for <code>style</code> property.</li><li><code>className</code> (IDL preffered)/<code>class</code> are ways to add CSS class to the element. You can use string (similarly to <code>class="…"</code> syntax in HTML) or array of strings. This is handy to concat conditional classes.</li><li>Use <code>classList</code> to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.</li><li>The <code>assign</code> also accepts the <code>undefined</code> as a&nbsp;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. <em>For example, natievly the elements <code>id</code> is removed by setting the IDL to an empty string.</em></li></ul><p>For processing, the <code>assign</code> internally uses <code>assignAttribute</code> and <code>classListDeclarative</code>.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-htu1k" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">import { assignAttribute, classListDeclarative } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const paragraph= document.createElement("p"); const paragraph= document.createElement("p");
assignAttribute(paragraph, "textContent", "Hello, world!"); assignAttribute(paragraph, "textContent", "Hello, world!");
@ -48,7 +48,7 @@ console.log(paragraph.outerHTML);
document.body.append( document.body.append(
paragraph paragraph
); );
</code></pre></div><script>Flems(document.getElementById("code-5f8sp"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { assignAttribute, classListDeclarative } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= document.createElement(\\\"p\\\");\\n\\nassignAttribute(paragraph, \\\"textContent\\\", \\\"Hello, world!\\\");\\nassignAttribute(paragraph, \\\"style\\\", { color: \\\"navy\\\" });\\n\\nassignAttribute(paragraph, \\\"dataTest1\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"dataset\\\", { test2: \\\"v2\\\" });\\n\\nassignAttribute(paragraph, \\\"ariaLabel\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"ariaset\\\", { role: \\\"none\\\" });\\n\\n\\nclassListDeclarative(paragraph, {\\n\\tclassAdd: true,\\n\\tclassRemove: false,\\n\\tclassAdd1: 1,\\n\\tclassRemove1: 0,\\n\\tclassToggle: -1\\n});\\n\\nconsole.log(paragraph.outerHTML);\\ndocument.body.append(\\n\\tparagraph\\n);\\n\"}],\"toolbar\":false}"));</script><h3>Native JavaScript templating</h3><p>By default, the native JS has no good way to define HTML template using DOM API:</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-48dwd" class="example"><pre><code class="language-javascript">document.body.append( </code></div><script>Flems(document.getElementById("code-htu1k"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { assignAttribute, classListDeclarative } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= document.createElement(\\\"p\\\");\\n\\nassignAttribute(paragraph, \\\"textContent\\\", \\\"Hello, world!\\\");\\nassignAttribute(paragraph, \\\"style\\\", { color: \\\"navy\\\" });\\n\\nassignAttribute(paragraph, \\\"dataTest1\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"dataset\\\", { test2: \\\"v2\\\" });\\n\\nassignAttribute(paragraph, \\\"ariaLabel\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"ariaset\\\", { role: \\\"none\\\" });\\n\\n\\nclassListDeclarative(paragraph, {\\n\\tclassAdd: true,\\n\\tclassRemove: false,\\n\\tclassAdd1: 1,\\n\\tclassRemove1: 0,\\n\\tclassToggle: -1\\n});\\n\\nconsole.log(paragraph.outerHTML);\\ndocument.body.append(\\n\\tparagraph\\n);\\n\"}],\"toolbar\":false}"));</script><h3>Native JavaScript templating</h3><p>By default, the native JS has no good way to define HTML template using DOM API:</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-8845d" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">document.body.append(
document.createElement("div"), document.createElement("div"),
document.createElement("span"), document.createElement("span"),
document.createElement("main") document.createElement("main")
@ -59,7 +59,7 @@ const template= document.createElement("main").append(
document.createElement("span"), document.createElement("span"),
); );
console.log(typeof template==="undefined"); console.log(typeof template==="undefined");
</code></pre></div><script>Flems(document.getElementById("code-48dwd"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"document.body.append(\\n\\tdocument.createElement(\\\"div\\\"),\\n\\tdocument.createElement(\\\"span\\\"),\\n\\tdocument.createElement(\\\"main\\\")\\n);\\nconsole.log(document.body.innerHTML.includes(\\\"<div></div><span></span><main></main>\\\"));\\nconst template= document.createElement(\\\"main\\\").append(\\n\\tdocument.createElement(\\\"div\\\"),\\n\\tdocument.createElement(\\\"span\\\"),\\n);\\nconsole.log(typeof template===\\\"undefined\\\");\\n\"}],\"toolbar\":false}"));</script><p>This library therefore overwrites the <code>append</code> method of created elements to always return parent element.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-k8b3j" class="example"><pre><code class="language-javascript">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-8845d"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"document.body.append(\\n\\tdocument.createElement(\\\"div\\\"),\\n\\tdocument.createElement(\\\"span\\\"),\\n\\tdocument.createElement(\\\"main\\\")\\n);\\nconsole.log(document.body.innerHTML.includes(\\\"<div></div><span></span><main></main>\\\"));\\nconst template= document.createElement(\\\"main\\\").append(\\n\\tdocument.createElement(\\\"div\\\"),\\n\\tdocument.createElement(\\\"span\\\"),\\n);\\nconsole.log(typeof template===\\\"undefined\\\");\\n\"}],\"toolbar\":false}"));</script><p>This library therefore overwrites the <code>append</code> method of created elements to always return parent element.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-5w6nn" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
document.head.append( document.head.append(
el("style").append( el("style").append(
"tr, td{ border: 1px solid red; padding: 1em; }", "tr, td{ border: 1px solid red; padding: 1em; }",
@ -83,7 +83,7 @@ document.body.append(
) )
) )
); );
</code></pre></div><script>Flems(document.getElementById("code-k8b3j"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\"tr, td{ border: 1px solid red; padding: 1em; }\\\",\\n\\t\\t\\\"table{ border-collapse: collapse; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Example of a complex template. Using for example nesting lists:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tel(\\\"li\\\", \\\"List item 1\\\"),\\n\\t\\tel(\\\"li\\\").append(\\n\\t\\t\\tel(\\\"ul\\\").append(\\n\\t\\t\\t\\tel(\\\"li\\\", \\\"Nested list item 1\\\"),\\n\\t\\t\\t)\\n\\t\\t)\\n\\t),\\n\\tel(\\\"table\\\").append(\\n\\t\\tel(\\\"tr\\\").append(\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 1\\\"),\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 2\\\")\\n\\t\\t)\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><h2>Creating advanced (reactive) templates and components</h2><h3>Basic components</h3><p>You can use functions for encapsulation (repeating) logic. The <code>el</code> accepts function as first argument. In that case, the function should return dom elements and the second argument for <code>el</code> is argument for given element.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-4qwvd" class="example"><pre><code class="language-javascript">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-5w6nn"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\"tr, td{ border: 1px solid red; padding: 1em; }\\\",\\n\\t\\t\\\"table{ border-collapse: collapse; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Example of a complex template. Using for example nesting lists:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tel(\\\"li\\\", \\\"List item 1\\\"),\\n\\t\\tel(\\\"li\\\").append(\\n\\t\\t\\tel(\\\"ul\\\").append(\\n\\t\\t\\t\\tel(\\\"li\\\", \\\"Nested list item 1\\\"),\\n\\t\\t\\t)\\n\\t\\t)\\n\\t),\\n\\tel(\\\"table\\\").append(\\n\\t\\tel(\\\"tr\\\").append(\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 1\\\"),\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 2\\\")\\n\\t\\t)\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><h3>Basic (state-less) components</h3><p>You can use functions for encapsulation (repeating) logic. The <code>el</code> accepts function as first argument. In that case, the function should return dom elements and the second argument for <code>el</code> is argument for given element.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-qvyuf" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
document.head.append( document.head.append(
el("style").append( el("style").append(
".class1{ font-weight: bold; }", ".class1{ font-weight: bold; }",
@ -100,4 +100,4 @@ function component({ className, textContent }){
el("p", textContent) el("p", textContent)
); );
} }
</code></pre></div><script>Flems(document.getElementById("code-4qwvd"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\".class1{ font-weight: bold; }\\\",\\n\\t\\t\\\".class2{ color: purple; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(component, { className: \\\"class2\\\", textContent: \\\"Hello World!\\\" }),\\n\\tcomponent({ className: \\\"class2\\\", textContent: \\\"Hello World!\\\" })\\n);\\n\\nfunction component({ className, textContent }){\\n\\treturn el(\\\"div\\\", { className: [ \\\"class1\\\", className ] }).append(\\n\\t\\tel(\\\"p\\\", textContent)\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>It is nice to use similar naming convention as native DOM API.</p></main></body></html> </code></div><script>Flems(document.getElementById("code-qvyuf"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\".class1{ font-weight: bold; }\\\",\\n\\t\\t\\\".class2{ color: purple; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(component, { className: \\\"class2\\\", textContent: \\\"Hello World!\\\" }),\\n\\tcomponent({ className: \\\"class2\\\", textContent: \\\"Hello World!\\\" })\\n);\\n\\nfunction component({ className, textContent }){\\n\\treturn el(\\\"div\\\", { className: [ \\\"class1\\\", className ] }).append(\\n\\t\\tel(\\\"p\\\", textContent)\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>It is nice to use similar naming convention as native DOM API.</p><h3>Creating non-HTML elements</h3><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr="true"/>--><a rel="prev" href="./" title="Introducing a&nbsp;library and motivations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr="true"/>-->Introduction (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr="true"/>--></div></main></body></html>

View File

@ -40,7 +40,7 @@ body > nav{
body > nav { body > nav {
font-size: 1rem; font-size: 1rem;
line-height: 2; line-height: 2;
padding:1rem 0 0 0 padding: 1rem 0 0 0;
} }
body > nav ol, body > nav ol,
body > nav ul { body > nav ul {
@ -52,7 +52,7 @@ body > nav ul {
justify-content: center; justify-content: center;
list-style-type: none; list-style-type: none;
margin: 0; margin: 0;
padding:0 padding: 0;
} }
body > nav ol li, body > nav ol li,
body > nav ul li { body > nav ul li {
@ -96,10 +96,13 @@ body > nav a:hover{
main{ main{
grid-area: content; grid-area: content;
display: grid; display: grid;
grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr; grid-template-columns:
[full-main-start] 1fr
[main-start] min(var(--body-max-width), 90%) [main-end]
1fr [full-main-end];
} }
main > *{ main > *{
grid-column: 2; grid-column: main;
} }
.icon { .icon {
vertical-align: sub; vertical-align: sub;
@ -116,10 +119,49 @@ main > *{
font-size: .9rem; font-size: .9rem;
font-style: italic; font-style: italic;
} }
.code{
--shiki-color-text: #e9eded;
--shiki-color-background: #212121;
--shiki-token-constant: #82b1ff;
--shiki-token-string: #c3e88d;
--shiki-token-comment: #546e7a;
--shiki-token-keyword: #c792ea;
--shiki-token-parameter: #AA0000;
--shiki-token-function: #80cbae;
--shiki-token-string-expression: #c3e88d;
--shiki-token-punctuation: var(--code);
--shiki-token-link: #EE0000;
white-space: pre;
}
.code[data-js=todo]{
border: 1px solid var(--border);
border-radius: var(--standard-border-radius);
margin-bottom: 1rem;
margin-top: 18.4px;
padding: 1rem 1.4rem;
}
.example{ .example{
grid-column: 1/-1; grid-column: full-main;
width: 100%; width: 100%;
max-width: calc(9/5 * var(--body-max-width)); max-width: calc(9/5 * var(--body-max-width));
height: calc(3/5 * var(--body-max-width)); height: calc(3/5 * var(--body-max-width));
margin-inline: auto; margin-inline: auto;
} }
.CodeMirror, .CodeMirror-gutters {
background: #212121 !important;
border: 1px solid white;
}
.prevNext{
display: grid;
grid-template-columns: 1fr 2fr 1fr;
margin-top: 1rem;
border-top: 1px solid var(--border);
}
.prevNext [rel=prev]{
grid-column: 1;
}
.prevNext [rel=next]{
grid-column: 3;
text-align: right;
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="index.css"><meta name="description" content="Introducing a&nbsp;library and motivations."><!--<dde:mark type="component" name="metaTwitter" host="this"/>--><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"/>--><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"><title>`deka-dom-el` — Introduction</title><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script></head><body><!--<dde:mark type="component" name="page" host="this"/>--><!--<dde:mark type="component" name="header" host="this"/>--><header><h1>`deka-dom-el` — Introduction</h1><p>Introducing a&nbsp;library and motivations.</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"/>--><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 and motivations." class="current">1. Introduction</a><a href="elements" title="Basic concepts of elements modifications and creations.">2. Elements</a></nav><main><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces. </p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-duj4w" class="example"><pre><code class="language-javascript">import { el, S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Introducing a&nbsp;library and motivations."><title>`deka-dom-el` — Introduction</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr="true"/>--><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="true"/>--><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="true"/>--><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://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="true"/>--><!--<dde:mark type="component" name="header" host="this" ssr="true"/>--><header><h1>`deka-dom-el` — Introduction</h1><p>Introducing a&nbsp;library and motivations.</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="true"/>--><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 and motivations." class="current">1. Introduction</a><a href="elements" title="Basic concepts of elements modifications and creations.">2. Elements</a></nav><main><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces.</p><!--<dde:mark type="component" name="example" host="this" ssr="true"/>--><div id="code-dn64k" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr="true"/>--><code class="language-js">import { el, S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const clicks= S(0); const clicks= S(0);
document.body.append( document.body.append(
el().append( el().append(
@ -12,4 +12,4 @@ document.body.append(
}) })
) )
); );
</code></pre></div><script>Flems(document.getElementById("code-duj4w"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, S } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst clicks= S(0);\\ndocument.body.append(\\n\\tel().append(\\n\\t\\tel(\\\"p\\\", S(()=>\\n\\t\\t\\t\\\"Hello World \\\"+\\\"🎉\\\".repeat(clicks())\\n\\t\\t)),\\n\\t\\tel(\\\"button\\\", {\\n\\t\\t\\ttype: \\\"button\\\",\\n\\t\\t\\tonclick: ()=> clicks(clicks()+1),\\n\\t\\t\\ttextContent: \\\"Fire\\\"\\n\\t\\t})\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script></main></body></html> </code></div><script>Flems(document.getElementById("code-dn64k"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, S } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst clicks= S(0);\\ndocument.body.append(\\n\\tel().append(\\n\\t\\tel(\\\"p\\\", S(()=>\\n\\t\\t\\t\\\"Hello World \\\"+\\\"🎉\\\".repeat(clicks())\\n\\t\\t)),\\n\\t\\tel(\\\"button\\\", {\\n\\t\\t\\ttype: \\\"button\\\",\\n\\t\\t\\tonclick: ()=> clicks(clicks()+1),\\n\\t\\t\\ttextContent: \\\"Fire\\\"\\n\\t\\t})\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr="true"/>--><!--<dde:mark type="component" name="pageLink" host="this" ssr="true"/>--><a rel="next" href="elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr="true"/>-->(next) Elements</a></div></main></body></html>

View File

@ -0,0 +1,59 @@
import { registerClientFile, styles } from "../ssr.js";
styles.scope(code).css`
:host{
--shiki-color-text: #e9eded;
--shiki-color-background: #212121;
--shiki-token-constant: #82b1ff;
--shiki-token-string: #c3e88d;
--shiki-token-comment: #546e7a;
--shiki-token-keyword: #c792ea;
--shiki-token-parameter: #AA0000;
--shiki-token-function: #80cbae;
--shiki-token-string-expression: #c3e88d;
--shiki-token-punctuation: var(--code);
--shiki-token-link: #EE0000;
white-space: pre;
}
:host[data-js=todo]{
border: 1px solid var(--border);
border-radius: var(--standard-border-radius);
margin-bottom: 1rem;
${/* to fix shift when → dataJS=done */""}
margin-top: 18.4px;
padding: 1rem 1.4rem;
}
`;
import { el } from "deka-dom-el";
/**
* Prints code to the page and registers flems to make it interactive.
* @param {object} attrs
* @param {string} [attrs.id]
* @param {string} [attrs.className]
* @param {string} attrs.content Example code file path
* @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 }){
let dataJS;
if(page_id){
registerClientPart(page_id);
dataJS= "todo";
}
return el("div", { id, className, dataJS }).append(
el("code", { className: "language-"+language, textContent: content })
);
}
let is_registered= {};
/** @param {string} page_id */
function registerClientPart(page_id){
if(is_registered[page_id]) return;
document.head.append(
el("script", { src: "https://cdn.jsdelivr.net/npm/shiki", defer: true }),
);
registerClientFile(
new URL("./code.js.js", import.meta.url),
el("script", { type: "module" })
);
is_registered[page_id]= true;
}

View File

@ -0,0 +1,12 @@
const highlighter= await shiki.getHighlighter({
theme: "css-variables",
langs: ["js", "ts", "css", "html", "shell"],
});
const codeBlocks= document.querySelectorAll('code[class*="language-"]');
codeBlocks.forEach((block)=> {
const lang= block.className.replace("language-", "");
block.parentElement.dataset.js= "done";
const html= highlighter.codeToHtml(block.textContent, { lang });
block.innerHTML= html;
});

View File

@ -1,59 +1,50 @@
let is_registered= {}; import { styles } from "../ssr.js";
import { styles } from "../index.css.js"; styles.scope(example).css`
export const css= styles().scope(example).css`
:host{ :host{
grid-column: 1/-1; grid-column: full-main;
width: 100%; width: 100%;
max-width: calc(9/5 * var(--body-max-width)); max-width: calc(9/5 * var(--body-max-width));
height: calc(3/5 * var(--body-max-width)); height: calc(3/5 * var(--body-max-width));
margin-inline: auto; margin-inline: auto;
} }
.CodeMirror, .CodeMirror-gutters {
background: #212121 !important;
border: 1px solid white;
}
` `
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { code } from "./code.html.js";
/** /**
* Prints code to the page and registers flems to make it interactive. * Prints code to the page and registers flems to make it interactive.
* @param {object} attrs * @param {object} attrs
* @param {URL} attrs.src Example code file path * @param {URL} attrs.src Example code file path
* @param {string} [attrs.language="javascript"] Language of the code * @param {"js"|"ts"|"html"|"css"} [attrs.language="js"] Language of the code
* @param {string} attrs.page_id ID of the page * @param {string} attrs.page_id ID of the page
* @param {import("../types.d.ts").registerClientFile} attrs.registerClientFile
* */ * */
export function example({ src, language= "javascript", page_id, registerClientFile }){ export function example({ src, language= "js", page_id }){
registerClientPart(page_id, registerClientFile); registerClientPart(page_id);
const code= s.cat(src).toString() const content= s.cat(src).toString()
.replaceAll(' from "../../../index-with-signals.js";', ' from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";'); .replaceAll(' from "../../../index-with-signals.js";', ' from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";');
const id= "code-"+Math.random().toString(36).slice(2, 7); const id= "code-"+Math.random().toString(36).slice(2, 7);
return el().append( return el().append(
el("div", { id, className: example.name }).append( el(code, { id, content, language, className: example.name }),
el("pre").append( elCode({ id, content, extension: "."+language })
el("code", { className: "language-"+language, textContent: code })
)
),
elCode({ id, content: code })
); );
} }
function elCode({ id, content }){ function elCode({ id, content, extension: name }){
const options= JSON.stringify({ const options= JSON.stringify({
files: [{ name: ".js", content }], files: [{ name, content }],
toolbar: false toolbar: false
}); });
return el("script", `Flems(document.getElementById("${id}"), JSON.parse(${JSON.stringify(options)}));`); return el("script", `Flems(document.getElementById("${id}"), JSON.parse(${JSON.stringify(options)}));`);
} }
function registerClientPart(page_id, registerClientFile){ let is_registered= {};
/** @param {string} page_id */
function registerClientPart(page_id){
if(is_registered[page_id]) return; if(is_registered[page_id]) return;
//★ Highlite code when no flems?
document.head.append( document.head.append(
el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" }), el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" }),
//★ el("script", { src: "https://cdn.jsdelivr.net/npm/shiki", defer: true }),
); );
const d= el("div");
/** @param {HTMLDivElement} a */
const f= (a)=> a;
f(d); //←
//★ egisterClientFile(
//★ new URL("./example.js.js", import.meta.url),
//★ el("script", { type: "module" })
//★ ;
is_registered[page_id]= true; is_registered[page_id]= true;
} }

View File

@ -1,19 +0,0 @@
const langs= {
javascript: 'js',
js: 'js',
html: 'html',
};
const highlighter= await shiki.getHighlighter({
theme: 'css-variables',
langs: ['js', 'html', 'shell'],
});
const codeBlocks= document.querySelectorAll('pre code[class*="language-"]');
codeBlocks.forEach((block)=> {
const lang= block.className.replace('language-', '');
const html= highlighter.codeToHtml(block.textContent, {
lang: langs[lang] || lang,
});
block.innerHTML= html;
});

View File

@ -0,0 +1,41 @@
import { pages, styles } from "../ssr.js";
styles.scope(prevNext).css`
:host{
display: grid;
grid-template-columns: 1fr 2fr 1fr;
margin-top: 1rem;
border-top: 1px solid var(--border);
}
:host [rel=prev]{
grid-column: 1;
}
:host [rel=next]{
grid-column: 3;
text-align: right;
}
`;
import { el } from "../../index.js";
/**
* @param {import("../types.d.ts").Info} page
* */
export function prevNext(page){
const page_index= pages.indexOf(page);
return el("div", { className: prevNext.name }).append(
el(pageLink, { rel: "prev", page: pages[page_index-1] }),
el(pageLink, { rel: "next", page: pages[page_index+1] })
);
}
/**
* @param {Object} attrs
* @param {"prev"|"next"} attrs.rel
* @param {import("../types.d.ts").Info} [attrs.page]
* */
function pageLink({ rel, page }){
if(!page) return el();
let { href, title, description }= page;
return el("a", { rel, href, title: description }).append(
rel==="next" ?"(next) " : "",
title,
rel==="prev" ? " (previous)" : "",
);
}

View File

@ -1,22 +1,16 @@
import "./global.css.js";
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { styles, common } from "./index.css.js"; import { example } from "./components/example.html.js";
import { example, css as example_css } from "./components/example.html.js";
export const css= styles()
.include(common)
.css`
.note{
font-size: .9rem;
font-style: italic;
}
`
.include(example_css);
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
import { header } from "./layout/head.html.js"; import { header } from "./layout/head.html.js";
import { prevNext } from "./components/prevNext.html.js";
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info, path_target, pages, registerClientFile }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el().append( return el().append(
el(header, { info, pkg, path_target, pages }), el(header, { info, pkg }),
el("main").append( el("main").append(
el("h2", "Native JavaScript DOM elements creations"), el("h2", "Native JavaScript DOM elements creations"),
el("p", "Lets go through all patterns we would like to use and what needs to be improved for better experience."), el("p", "Lets go through all patterns we would like to use and what needs to be improved for better experience."),
@ -36,12 +30,12 @@ export function page({ pkg, info, path_target, pages, registerClientFile }){
el("abbr", { textContent: "IDL", title: "Interface Description Language" }) el("abbr", { textContent: "IDL", title: "Interface Description Language" })
), "." ), "."
), ),
el(example, { src: new URL("./components/examples/nativeCreateElement.js", import.meta.url), page_id, registerClientFile }), el(example, { src: fileURL("./components/examples/nativeCreateElement.js"), page_id }),
el("p").append( el("p").append(
"To make this easier, you can use the ", el("code", "el"), " function. ", "To make this easier, you can use the ", el("code", "el"), " function. ",
"Internally in basic examples, it is wrapper around ", el("code", "assign(document.createElement(…), { … })"), "." "Internally in basic examples, it is wrapper around ", el("code", "assign(document.createElement(…), { … })"), "."
), ),
el(example, { src: new URL("./components/examples/dekaCreateElement.js", import.meta.url), page_id, registerClientFile }), el(example, { src: fileURL("./components/examples/dekaCreateElement.js"), page_id }),
el("p").append( el("p").append(
"The ", el("code", "assign"), " function provides improved behaviour of ", el("code", "Object.assign()"), ". ", "The ", el("code", "assign"), " function provides improved behaviour of ", el("code", "Object.assign()"), ". ",
"You can declaratively sets any IDL and attribute of the given element. ", "You can declaratively sets any IDL and attribute of the given element. ",
@ -82,27 +76,30 @@ export function page({ pkg, info, path_target, pages, registerClientFile }){
el("p").append( el("p").append(
"For processing, the ", el("code", "assign"), " internally uses ", el("code", "assignAttribute"), " and ", el("code", "classListDeclarative"), "." "For processing, the ", el("code", "assign"), " internally uses ", el("code", "assignAttribute"), " and ", el("code", "classListDeclarative"), "."
), ),
el(example, { src: new URL("./components/examples/dekaAssign.js", import.meta.url), page_id, registerClientFile }), el(example, { src: fileURL("./components/examples/dekaAssign.js"), page_id }),
el("h3", "Native JavaScript templating"), el("h3", "Native JavaScript templating"),
el("p", "By default, the native JS has no good way to define HTML template using DOM API:"), el("p", "By default, the native JS has no good way to define HTML template using DOM API:"),
el(example, { src: new URL("./components/examples/nativeAppend.js", import.meta.url), page_id, registerClientFile }), el(example, { src: fileURL("./components/examples/nativeAppend.js"), page_id }),
el("p").append( el("p").append(
"This library therefore overwrites the ", el("code", "append"), " method of created elements to always return parent element." "This library therefore overwrites the ", el("code", "append"), " method of created elements to always return parent element."
), ),
el(example, { src: new URL("./components/examples/dekaAppend.js", import.meta.url), page_id, registerClientFile }), el(example, { src: fileURL("./components/examples/dekaAppend.js"), page_id }),
el("h2", "Creating advanced (reactive) templates and components"), el("h3", "Basic (state-less) components"),
el("h3", "Basic components"),
el("p").append( el("p").append(
"You can use functions for encapsulation (repeating) logic. ", "You can use functions for encapsulation (repeating) logic. ",
"The ", el("code", "el"), " accepts function as first argument. ", "The ", el("code", "el"), " accepts function as first argument. ",
"In that case, the function should return dom elements and the second argument for ", el("code", "el"), " is argument for given element." "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: new URL("./components/examples/dekaBasicComponent.js", import.meta.url), page_id, registerClientFile }), 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", "It is nice to use similar naming convention as native DOM API."),
el("h3", "Creating non-HTML elements"),
// example & notes
el(prevNext, info)
) )
); );
} }

View File

@ -1,3 +1,5 @@
import { styles } from "./ssr.js";
styles.scope(import.meta.url).css`
@import url(https://cdn.simplecss.org/simple.min.css); @import url(https://cdn.simplecss.org/simple.min.css);
:root{ :root{
--body-max-width: 45rem; --body-max-width: 45rem;
@ -40,7 +42,7 @@ body > nav{
body > nav { body > nav {
font-size: 1rem; font-size: 1rem;
line-height: 2; line-height: 2;
padding:1rem 0 0 0 padding: 1rem 0 0 0;
} }
body > nav ol, body > nav ol,
body > nav ul { body > nav ul {
@ -52,7 +54,7 @@ body > nav ul {
justify-content: center; justify-content: center;
list-style-type: none; list-style-type: none;
margin: 0; margin: 0;
padding:0 padding: 0;
} }
body > nav ol li, body > nav ol li,
body > nav ul li { body > nav ul li {
@ -96,10 +98,13 @@ body > nav a:hover{
main{ main{
grid-area: content; grid-area: content;
display: grid; display: grid;
grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr; grid-template-columns:
[full-main-start] 1fr
[main-start] min(var(--body-max-width), 90%) [main-end]
1fr [full-main-end];
} }
main > *{ main > *{
grid-column: 2; grid-column: main;
} }
.icon { .icon {
vertical-align: sub; vertical-align: sub;
@ -116,10 +121,4 @@ main > *{
font-size: .9rem; font-size: .9rem;
font-style: italic; font-style: italic;
} }
.example{ `;
grid-column: 1/-1;
width: 100%;
max-width: calc(9/5 * var(--body-max-width));
height: calc(3/5 * var(--body-max-width));
margin-inline: auto;
}

View File

@ -1,145 +0,0 @@
const scopes= new WeakSet();
const s= {
scope(s){
if(!scopes.has(s)){
scopes.add(s);
this.host= s.name;
}
return this;
},
css(...a){
let c= css(...a);
if(this.host){
c= c.replaceAll(":host", "."+this.host);
this.host= "";
}
if(this.content) this.content+= "\n";
this.content+= c;
return this;
},
include(...i){
if(this.content) this.content+= "\n";
this.content+= i.map(i=> typeof i === "string" ? i : i.content).join("\n");
return this;
}
};
export function css(...a){
return String.raw(...a).trim();
}
export function styles(){ return Object.assign(Object.create(s), { content: "" }); }
export const common= css`
@import url(https://cdn.simplecss.org/simple.min.css);
:root{
--body-max-width: 45rem;
--marked: #fb3779;
--code: #0d47a1;
--accent: #d81b60;
}
@media (prefers-color-scheme:dark) {
:root {
--accent: #f06292;
--code: #62c1f0;
}
}
body {
grid-template-columns: 100%;
grid-template-areas: "header" "sidebar" "content";
}
@media (min-width:768px) {
body{
grid-template-rows: auto auto;
grid-template-columns: calc(var(--body-max-width) / 3) auto;
grid-template-areas:
"header header"
"sidebar content"
}
}
body > *{
grid-column: unset;
}
body > header{
grid-area: header;
padding: 0;
}
body > nav{
grid-area: sidebar;
background-color: var(--accent-bg);
display: flex;
flex-flow: column nowrap;
}
body > nav {
font-size:1rem;
line-height:2;
padding:1rem 0 0 0
}
body > nav ol,
body > nav ul {
align-content:space-around;
align-items:center;
display:flex;
flex-direction:row;
flex-wrap:wrap;
justify-content:center;
list-style-type:none;
margin:0;
padding:0
}
body > nav ol li,
body > nav ul li {
display:inline-block
}
body > nav a,
body > nav a:visited {
margin: 0 .5rem 1rem .5rem;
border: 1px solid currentColor;
border-radius: var(--standard-border-radius);
color: var(--text-light);
display: inline-block;
padding: .1rem 1rem;
text-decoration: none;
cursor: pointer;
transition: all .15s;
}
body > nav a.current,
body > nav a[aria-current=page] {
background-color: var(--bg);
color: var(--text);
}
body > nav a:hover{
background-color: var(--bg);
color: var(--accent);
}
@media only screen and (max-width:720px) {
body > nav{
flex-flow: row wrap;
padding-block: .5rem;
}
body > nav a {
border:none;
text-decoration:underline;
margin-block: .1rem;
padding-block:.1rem;
line-height: 1rem;
font-size: .9rem;
}
}
main{
grid-area: content;
display: grid;
grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr;
}
main > *{
grid-column: 2;
}
.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;
}
`;

View File

@ -1,25 +1,18 @@
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { styles, common } from "./index.css.js"; import "./global.css.js";
import { example, css as example_css } from "./components/example.html.js"; import { example } from "./components/example.html.js";
export const css= styles()
.include(common)
.css`
.note{
font-size: .9rem;
font-style: italic;
}
`
.include(example_css);
import { header } from "./layout/head.html.js"; import { header } from "./layout/head.html.js";
import { prevNext } from "./components/prevNext.html.js";
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info, path_target, pages, registerClientFile }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el().append( return el().append(
el(header, { info, pkg, path_target, pages }), el(header, { info, pkg }),
el("main").append( el("main").append(
el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces."), el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces."),
el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id, registerClientFile }), el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id }),
el(prevNext, info)
) )
); );
} }

View File

@ -1,4 +1,5 @@
import { el, elNS, scope } from "deka-dom-el"; import { el, elNS } from "deka-dom-el";
import { pages } from "../ssr.js";
/** /**
* @param {object} def * @param {object} def
* @param {import("../types.d.ts").Info} def.info * @param {import("../types.d.ts").Info} def.info
@ -6,12 +7,12 @@ import { el, elNS, scope } from "deka-dom-el";
* @param {string} def.pkg.name * @param {string} def.pkg.name
* @param {string} def.pkg.description * @param {string} def.pkg.description
* @param {string} def.pkg.homepage * @param {string} def.pkg.homepage
* @param {{ root: string, css: string}} def.path_target Final URL where the page will be rendered.
* @param {import("../types.js").Pages} def.pages
* */ * */
export function header({ info: { id, title, description }, pkg, path_target, pages }){ export function header({ info: { href, title, description }, pkg }){
title= `\`${pkg.name}\`${title}`; title= `\`${pkg.name}\`${title}`;
document.head.append(head({ id, title, description, pkg, path_target })); document.head.append(
head({ title, description, pkg })
);
return el().append( return el().append(
el("header").append( el("header").append(
el("h1", title), el("h1", title),
@ -23,23 +24,29 @@ export function header({ info: { id, title, description }, pkg, path_target, pag
"GitHub" "GitHub"
), ),
...pages.map((p, i)=> el("a", { ...pages.map((p, i)=> el("a", {
href: p.id==="index" ? "./" : p.id, href: p.href==="index" ? "./" : p.href,
textContent: (i+1) + ". " + p.title, textContent: (i+1) + ". " + p.title,
title: p.description, title: p.description,
classList: { current: p.id===id } classList: { current: p.href===href }
})) }))
) )
); );
} }
function head({ id, title, description, pkg, path_target }){ function head({ title, description, pkg }){
return el().append( return el().append(
el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
el("link", { rel: "stylesheet", href: stylesheetHref(path_target, id) }),
el("meta", { name: "description", content: description }), el("meta", { name: "description", content: description }),
el("title", title),
el(metaAuthor),
el(metaTwitter, pkg), el(metaTwitter, pkg),
el(metaFacebook, pkg), el(metaFacebook, pkg),
el("title", title), );
}
function metaAuthor(){
return el().append(
el("meta", { name: "author", content: "Jan Andrle" }),
el("link", { type: "text/plain", rel: "author", href: "https://jaandrle.github.io/humans.txt" }),
el("meta", { name: "generator", content: "deka-dom-el" }),
); );
} }
function metaTwitter({ name, description, homepage }){ function metaTwitter({ name, description, homepage }){
@ -62,9 +69,6 @@ function metaFacebook({ name, description, homepage }){
el("meta", { name: "og:creator", content: "@jaandrle" }), el("meta", { name: "og:creator", content: "@jaandrle" }),
); );
} }
function stylesheetHref(path_target, name){
return path_target.css.replace(path_target.root, "")+name+".css";
}
function iconGitHub(){ function iconGitHub(){
const el= elNS("http://www.w3.org/2000/svg"); const el= elNS("http://www.w3.org/2000/svg");
return el("svg", { className: "icon", viewBox: "0 0 32 32" }).append( return el("svg", { className: "icon", viewBox: "0 0 32 32" }).append(

77
docs_src/ssr.js Normal file
View File

@ -0,0 +1,77 @@
export const path_target= {
root: "docs/",
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." }
];
/**
* @typedef registerClientFile
* @type {function}
* @param {URL} url
* @param {HTMLScriptElement|HTMLLinkElement} [element_head]
* */
export function registerClientFile(url, element_head){
const file_name= url.pathname.split("/").pop();
s.cat(url).to(path_target.root+file_name);
if(!element_head) return;
element_head[element_head instanceof HTMLScriptElement ? "src" : "href"]= file_name;
document.head.append(
element_head
);
}
const events= {
oneachrender: new Set(),
onssrend: new Set()
};
/** @param {keyof typeof events} name @param {function} listener */
export function addEventListener(name, listener){
events[name].add(listener);
}
/** @param {keyof typeof events} name @param {any} a */
export function dispatchEvent(name, a){
const ls= events[name];
ls.forEach(l=> l(a));
if(name!=="oneachrender")
ls.clear();
}
const scopes= new Set();
export const styles= {
element: null,
name: "global.css",
get location(){ return path_target.css.replace(path_target.root, "")+this.name; },
content: "",
skip: false,
/** @param {function|string} s */
scope(s){
if(scopes.has(s)){ this.skip= true; return this; }
scopes.add(s);
if(typeof s==="function") this.host= s.name;
return this;
},
/** @param {Parameters<typeof String.raw>} a */
css(...a){
if(this.skip){ this.skip= false; return this; }
let c= css(...a);
if(this.host){
c= c.replaceAll(":host", "."+this.host);
this.host= "";
}
if(this.content) this.content+= "\n";
this.content+= c;
return this;
}
};
addEventListener("onssrend", ()=> scopes.clear());
addEventListener("oneachrender", ()=> document.head.append(
Object.assign(document.createElement("link"), { rel: "stylesheet", href: styles.location })
));
/** @type {typeof String.raw} */
function css(...a){ return String.raw(...a).trim(); }

1
docs_src/types.d.ts vendored
View File

@ -2,6 +2,7 @@
export type Pkg= Record<string, string> export type Pkg= Record<string, string>
export type Info= { export type Info= {
id: string, id: string,
href: string,
title: string, title: string,
description: string, description: string,
} }

View File

@ -48,7 +48,7 @@ lifecycleToEvents(CustomHTMLTestElement)
customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement); customElements.define(CustomHTMLTestElement.tagName, CustomHTMLTestElement);
function customElementRender(_this, render){ function customElementRender(_this, render){
scope.push({ scope: _this, host: (...a)=> a.length ? a[0](_this) : _this, inherit_host: true }); scope.push({ scope: _this, host: (...a)=> a.length ? a[0](_this) : _this, custom_element: _this });
const out= render(_this); const out= render(_this);
scope.pop(); scope.pop();
return out; return out;

6
index.d.ts vendored
View File

@ -127,7 +127,7 @@ interface On{
} }
export const on: On; export const on: On;
type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, prevent: boolean, inherit_host: boolean, } type Scope= { scope: Node | Function | Object, host: ddeElementModifier<any>, custom_element: false | HTMLElement, prevent: boolean }
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ /** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: { export const scope: {
current: Scope, current: Scope,
@ -438,4 +438,8 @@ declare global{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */ /** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<DocumentFragment>; append: ddeAppend<DocumentFragment>;
} }
interface SVGElement{
/** Elements returned by {@link el} return parent element for `.append` method. **Regullarly created elements are untouched.** */
append: ddeAppend<SVGElement>;
}
} }

2
jsdom.d.ts vendored
View File

@ -1,6 +1,6 @@
import { el, assign, on } from "./index.d"; import { el, assign, on } from "./index.d";
export * from "./index.d"; export * from "./index.d";
export function register(dom: typeof document): Promise<{ export function register(dom: JSDOM): Promise<{
el: typeof el, el: typeof el,
assign: typeof assign, assign: typeof assign,
on: typeof on on: typeof on

View File

@ -1,8 +1,9 @@
//TODO: https://www.npmjs.com/package/html-element //TODO: https://www.npmjs.com/package/html-element
import { prop_process } from './src/dom-common.js'; import { enviroment } from './src/dom-common.js';
const { setDeleteAttr }= prop_process; enviroment.ssr= true;
const { setDeleteAttr }= enviroment;
/** @param {HTMLElement} obj */ /** @param {HTMLElement} obj */
prop_process.setDeleteAttr= function(obj, prop, value){ enviroment.setDeleteAttr= function(obj, prop, value){
if("value"===prop) return obj.setAttribute(prop, value); if("value"===prop) return obj.setAttribute(prop, value);
if("checked"!==prop) return setDeleteAttr(obj, prop, value); if("checked"!==prop) return setDeleteAttr(obj, prop, value);
if(value) return obj.setAttribute(prop, ""); if(value) return obj.setAttribute(prop, "");

View File

@ -1,4 +1,4 @@
export const prop_process= { setDeleteAttr }; export const enviroment= { setDeleteAttr, ssr: false };
import { isUndef } from './helpers.js'; import { isUndef } from './helpers.js';
function setDeleteAttr(obj, prop, val){ function setDeleteAttr(obj, prop, val){
/* Issue /* Issue

View File

@ -1,11 +1,12 @@
import { signals } from "./signals-common.js"; import { signals } from "./signals-common.js";
import { enviroment } from './dom-common.js';
/** @type {{ scope: object, prevent: boolean, host: function }[]} */ /** @type {{ scope: object, prevent: boolean, host: function }[]} */
const scopes= [ { const scopes= [ {
scope: document.body, scope: document.body,
host: c=> c ? c(document.body) : document.body, host: c=> c ? c(document.body) : document.body,
custom_element: false,
prevent: true, prevent: true,
inherit_host: false,
} ]; } ];
export const scope= { export const scope= {
get current(){ return scopes[scopes.length-1]; }, get current(){ return scopes[scopes.length-1]; },
@ -25,7 +26,7 @@ export const scope= {
}; };
let namespace; let namespace;
export function createElement(tag, attributes, ...modifiers){ export function createElement(tag, attributes, ...modifiers){
/* jshint maxcomplexity: 16 */ /* jshint maxcomplexity: 15 */
const s= signals(this); const s= signals(this);
let scoped= 0; let scoped= 0;
let el, el_host; let el, el_host;
@ -35,15 +36,14 @@ export function createElement(tag, attributes, ...modifiers){
switch(true){ switch(true){
case typeof tag==="function": { case typeof tag==="function": {
scoped= 1; scoped= 1;
const { inherit_host, host: hostParent }= scope.current; scope.push({ scope: tag, host: c=> c ? (scoped===1 ? modifiers.unshift(c) : c(el_host), undefined) : el_host });
const host= inherit_host ? hostParent : c=> c ? (scoped===1 ? modifiers.unshift(c) : c(el_host), undefined) : el_host;
scope.push({ scope: tag, host, inherit_host });
el= tag(attributes || undefined); el= tag(attributes || undefined);
const is_fragment= el instanceof DocumentFragment; const is_fragment= el instanceof DocumentFragment;
if(el.nodeName==="#comment") break;
const el_mark= createElement.mark({ const el_mark= createElement.mark({
type: "component", type: "component",
name: tag.name, name: tag.name,
host: is_fragment ? "this" : ( el.nodeName==="#comment" ? "previousLater" : "parentElement" ) host: is_fragment ? "this" : "parentElement",
}); });
el.prepend(el_mark); el.prepend(el_mark);
if(is_fragment) el_host= el_mark; if(is_fragment) el_host= el_mark;
@ -66,6 +66,7 @@ export function createElement(tag, attributes, ...modifiers){
* @param {boolean} [is_open=false] * @param {boolean} [is_open=false]
* */ * */
createElement.mark= function(attrs, is_open= false){ createElement.mark= function(attrs, is_open= false){
if(enviroment.ssr) attrs.ssr= true;
attrs= Object.entries(attrs).map(([ n, v ])=> n+`="${v}"`).join(" "); attrs= Object.entries(attrs).map(([ n, v ])=> n+`="${v}"`).join(" ");
const end= is_open ? "" : "/"; const end= is_open ? "" : "/";
const out= document.createComment(`<dde:mark ${attrs}${end}>`); const out= document.createComment(`<dde:mark ${attrs}${end}>`);
@ -91,8 +92,7 @@ export function createElementNS(ns){
} }
export { createElementNS as elNS }; export { createElementNS as elNS };
import { prop_process } from './dom-common.js'; const { setDeleteAttr }= enviroment;
const { setDeleteAttr }= prop_process;
const assign_context= new WeakMap(); const assign_context= new WeakMap();
export function assign(element, ...attributes){ export function assign(element, ...attributes){
if(!attributes.length) return element; if(!attributes.length) return element;

View File

@ -13,14 +13,17 @@ export function on(event, listener, options){
const c_ch_o= connectionsChangesObserverConstructor(); const c_ch_o= connectionsChangesObserverConstructor();
const els_attribute_store= new WeakSet(); const els_attribute_store= new WeakSet();
import { scope } from "./dom.js";
import { onAbort } from './helpers.js'; import { onAbort } from './helpers.js';
//TODO: cleanUp when event before abort? //TODO: cleanUp when event before abort?
on.connected= function(listener, options){ on.connected= function(listener, options){
const { custom_element }= scope.current;
const name= "connected"; const name= "connected";
if(typeof options !== "object") if(typeof options !== "object")
options= {}; options= {};
options.once= true; options.once= true;
return function registerElement(element){ return function registerElement(element){
if(custom_element) element= custom_element;
const event= "dde:"+name; const event= "dde:"+name;
element.addEventListener(event, listener, options); element.addEventListener(event, listener, options);
if(element.__dde_lifecycleToEvents) return element; if(element.__dde_lifecycleToEvents) return element;
@ -32,11 +35,13 @@ on.connected= function(listener, options){
}; };
}; };
on.disconnected= function(listener, options){ on.disconnected= function(listener, options){
const { custom_element }= scope.current;
const name= "disconnected"; const name= "disconnected";
if(typeof options !== "object") if(typeof options !== "object")
options= {}; options= {};
options.once= true; options.once= true;
return function registerElement(element){ return function registerElement(element){
if(custom_element) element= custom_element;
const event= "dde:"+name; const event= "dde:"+name;
element.addEventListener(event, listener, options); element.addEventListener(event, listener, options);
if(element.__dde_lifecycleToEvents) return element; if(element.__dde_lifecycleToEvents) return element;