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

Compare commits

..

2 Commits

Author SHA1 Message Date
3866b29436
🔨 ElementExtender → ElementModifier 2023-11-07 17:30:15 +01:00
2c844a0ca9
docs + ssr fixes 2023-11-07 15:10:55 +01:00
17 changed files with 719 additions and 311 deletions

View File

@ -1,23 +1,49 @@
#!/usr/bin/env nodejsscript #!/usr/bin/env nodejsscript
/* 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("Preparing…");
const path_target= { const path_target= {
root: "docs/", root: "docs/",
html: "docs/index.html",
css: "docs/" css: "docs/"
}; };
import { createHTMl } from "./docs/jsdom.js"; import { createHTMl } from "./docs/jsdom.js";
const ssr= createHTMl("");
import { register } from "../jsdom.js"; import { register } from "../jsdom.js";
const { el }= await register(ssr.dom);
echo("Loading components…");
const pkg= s.cat("package.json").xargs(JSON.parse); const pkg= s.cat("package.json").xargs(JSON.parse);
const { page, css }= await import("../docs_src/index.html.js"); //→ TODO: important to mention in docs!!! 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){
const { id }= info;
echo(`Generating ${id}.html…`);
const ssr= createHTMl("");
const { el }= await register(ssr.dom);
const { page, css }= await import(`../docs_src/${id}.html.js`); //→ TODO: important to mention in docs!!!
document.body.append( document.body.append(
el(page, { pkg, path_target }), el(page, { pkg, info, path_target, pages, registerClientFile }),
el("script", { src: "https://cdn.jsdelivr.net/npm/shiki" }),
el("script", { src: "index.js", type: "module" })
); );
s.echo(ssr.serialize()).to(path_target.html); echo.use("-R", `Writing ${id}.html…`);
s.echo(css.content).to(path_target.css+"index.css"); s.echo(ssr.serialize()).to(path_target.root+id+".html");
s.echo(css.content).to(path_target.css+id+".css");
}
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
);
}

125
docs/elements.css Normal file
View File

@ -0,0 +1,125 @@
@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;
}
.note{
font-size: .9rem;
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;
}

103
docs/elements.html Normal file
View File

@ -0,0 +1,103 @@
<!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-hk0h5" class="example"><pre><code class="language-javascript">document.body.append(
document.createElement("div")
);
console.log(
"Emty div is generated inside &lt;body&gt;:",
document.body.innerHTML.includes("&lt;div&gt;&lt;/div&gt;")
);
document.body.append(
Object.assign(
document.createElement("p"),
{ textContent: "Elements text content.", style: "color: coral;" }
)
);
</code></pre></div><script>Flems(document.getElementById("code-hk0h5"), 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-smzmf" 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";
const color= "lightcoral";
document.body.append(
el("p", { textContent: "Hello (first time)", style: { color } })
);
document.body.append(
assign(
document.createElement("p"),
{ textContent: "Hello (second time)", style: { color } }
)
);
</code></pre></div><script>Flems(document.getElementById("code-smzmf"), 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-r0ona" 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";
const paragraph= document.createElement("p");
assignAttribute(paragraph, "textContent", "Hello, world!");
assignAttribute(paragraph, "style", { color: "navy" });
assignAttribute(paragraph, "dataTest1", "v1");
assignAttribute(paragraph, "dataset", { test2: "v2" });
assignAttribute(paragraph, "ariaLabel", "v1");
assignAttribute(paragraph, "ariaset", { role: "none" });
classListDeclarative(paragraph, {
classAdd: true,
classRemove: false,
classAdd1: 1,
classRemove1: 0,
classToggle: -1
});
console.log(paragraph.outerHTML);
document.body.append(
paragraph
);
</code></pre></div><script>Flems(document.getElementById("code-r0ona"), 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-1ytxj" class="example"><pre><code class="language-javascript">document.body.append(
document.createElement("div"),
document.createElement("span"),
document.createElement("main")
);
console.log(document.body.innerHTML.includes("&lt;div&gt;&lt;/div&gt;&lt;span&gt;&lt;/span&gt;&lt;main&gt;&lt;/main&gt;"));
const template= document.createElement("main").append(
document.createElement("div"),
document.createElement("span"),
);
console.log(typeof template==="undefined");
</code></pre></div><script>Flems(document.getElementById("code-1ytxj"), 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 ooverwrites the <code>append</code> method to always return parent element.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-eynbh" class="example"><pre><code class="language-javascript">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; }",
"table{ border-collapse: collapse; }"
)
);
document.body.append(
el("p", "Example of a&nbsp;complex template. Using for example nesting lists:"),
el("ul").append(
el("li", "List item 1"),
el("li").append(
el("ul").append(
el("li", "Nested list item 1"),
)
)
),
el("table").append(
el("tr").append(
el("td", "Row 1 Col 1"),
el("td", "Row 1 Col 2")
)
)
);
</code></pre></div><script>Flems(document.getElementById("code-eynbh"), 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-1tggr" class="example"><pre><code class="language-javascript">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; }",
".class2{ color: purple; }"
)
);
document.body.append(
el(component, { className: "class2", textContent: "Hello World!" }),
component({ className: "class2", textContent: "Hello World!" })
);
function component({ className, textContent }){
return el("div", { className: [ "class1", className ] }).append(
el("p", textContent)
);
}
</code></pre></div><script>Flems(document.getElementById("code-1tggr"), 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>

View File

@ -6,17 +6,100 @@
--accent: #d81b60; --accent: #d81b60;
} }
@media (prefers-color-scheme:dark) { @media (prefers-color-scheme:dark) {
::backdrop, :root { :root {
--accent: #f06292; --accent: #f06292;
--code: #62c1f0; --code: #62c1f0;
} }
} }
body { 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; grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr;
} }
nav a.current { main > *{
color: var(--accent) !important; grid-column: 2;
border-color: var(--accent) !important;
} }
.icon { .icon {
vertical-align: sub; vertical-align: sub;
@ -34,7 +117,7 @@ nav a.current {
font-style: italic; font-style: italic;
} }
.example{ .example{
grid-column: 1/4; grid-column: 1/-1;
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));

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 basic concepts."><!--<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/Guide</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"/>--><header><!--<dde:mark type="component" name="header" host="parentElement"/>--><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></nav><h1>`deka-dom-el` — Introduction/Guide</h1><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces. </p></header><p>The main goals are:</p><ul><li>provide a&nbsp;small wrappers/utilities around the native JavaScript DOM</li><li>keep library size around 10kB at maximum (if possible)</li><li>zero dependencies (if possible)</li><li>prefer a&nbsp;declarative/functional approach</li><li>unopinionated (allow alternative methods)</li></ul><p class="note">It is, in fact, an reimplementation of <a href="https://github.com/jaandrle/dollar_dom_component" title="GitHub repository of library. Motto: Functional DOM components without JSX and virtual DOM.">jaandrle/dollar_dom_component</a>.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-tbn7w" 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"><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><p>The main goals are:</p><ul><li>provide a&nbsp;small wrappers/utilities around the native JavaScript DOM</li><li>keep library size around 10kB at maximum (if possible)</li><li>zero dependencies (if possible)</li><li>prefer a&nbsp;declarative/functional approach</li><li>unopinionated (allow alternative methods)</li></ul><p class="note">It is, in fact, an reimplementation of <a href="https://github.com/jaandrle/dollar_dom_component" title="GitHub repository of library. Motto: Functional DOM components without JSX and virtual DOM.">jaandrle/dollar_dom_component</a>.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-p1z06" 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";
const clicks= S(0); const clicks= S(0);
document.body.append( document.body.append(
el().append( el().append(
@ -12,106 +12,4 @@ document.body.append(
}) })
) )
); );
</code></pre></div><script>Flems(document.getElementById("code-tbn7w"), 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><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-6qkk3" class="example"><pre><code class="language-javascript">document.body.append( </code></pre></div><script>Flems(document.getElementById("code-p1z06"), 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>
document.createElement("div")
);
console.log(
"Emty div is generated inside &lt;body&gt;:",
document.body.innerHTML.includes("&lt;div&gt;&lt;/div&gt;")
);
document.body.append(
Object.assign(
document.createElement("p"),
{ textContent: "Elements text content.", style: "color: coral;" }
)
);
</code></pre></div><script>Flems(document.getElementById("code-6qkk3"), 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-neqkq" 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";
const color= "lightcoral";
document.body.append(
el("p", { textContent: "Hello (first time)", style: { color } })
);
document.body.append(
assign(
document.createElement("p"),
{ textContent: "Hello (second time)", style: { color } }
)
);
</code></pre></div><script>Flems(document.getElementById("code-neqkq"), 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-vc3nn" 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";
const paragraph= document.createElement("p");
assignAttribute(paragraph, "textContent", "Hello, world!");
assignAttribute(paragraph, "style", { color: "navy" });
assignAttribute(paragraph, "dataTest1", "v1");
assignAttribute(paragraph, "dataset", { test2: "v2" });
assignAttribute(paragraph, "ariaLabel", "v1");
assignAttribute(paragraph, "ariaset", { role: "none" });
classListDeclarative(paragraph, {
classAdd: true,
classRemove: false,
classAdd1: 1,
classRemove1: 0,
classToggle: -1
});
console.log(paragraph.outerHTML);
document.body.append(
paragraph
);
</code></pre></div><script>Flems(document.getElementById("code-vc3nn"), 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-hn5qm" class="example"><pre><code class="language-javascript">document.body.append(
document.createElement("div"),
document.createElement("span"),
document.createElement("main")
);
console.log(document.body.innerHTML.includes("&lt;div&gt;&lt;/div&gt;&lt;span&gt;&lt;/span&gt;&lt;main&gt;&lt;/main&gt;"));
const template= document.createElement("main").append(
document.createElement("div"),
document.createElement("span"),
);
console.log(typeof template==="undefined");
</code></pre></div><script>Flems(document.getElementById("code-hn5qm"), 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 ooverwrites the <code>append</code> method to always return parent element.</p><!--<dde:mark type="component" name="example" host="this"/>--><div id="code-ek9lw" class="example"><pre><code class="language-javascript">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; }",
"table{ border-collapse: collapse; }"
)
);
document.body.append(
el("p", "Example of a&nbsp;complex template. Using for example nesting lists:"),
el("ul").append(
el("li", "List item 1"),
el("li").append(
el("ul").append(
el("li", "Nested list item 1"),
)
)
),
el("table").append(
el("tr").append(
el("td", "Row 1 Col 1"),
el("td", "Row 1 Col 2")
)
)
);
</code></pre></div><script>Flems(document.getElementById("code-ek9lw"), 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-r6cen" class="example"><pre><code class="language-javascript">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; }",
".class2{ color: purple; }"
)
);
document.body.append(
el(component, { className: "class2", textContent: "Hello World!" }),
component({ className: "class2", textContent: "Hello World!" })
);
function component({ className, textContent }){
return el("div", { className: [ "class1", className ] }).append(
el("p", textContent)
);
}
</code></pre></div><script>Flems(document.getElementById("code-r6cen"), 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><script src="https://cdn.jsdelivr.net/npm/shiki"></script><script src="index.js" type="module"></script></body></html>

View File

@ -1,8 +1,8 @@
let is_registered= false; let is_registered= {};
import { styles } from "../index.css.js"; import { styles } from "../index.css.js";
export const css= styles().scope(example).css` export const css= styles().scope(example).css`
:host{ :host{
grid-column: 1/4; grid-column: 1/-1;
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));
@ -10,12 +10,17 @@ export const css= styles().scope(example).css`
} }
` `
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
export function example({ src, language= "javascript" }){ /**
register(); * Prints code to the page and registers flems to make it interactive.
const cwd= "components"; * @param {object} attrs
src= "."+src.slice(src.indexOf(cwd)+cwd.length); * @param {URL} attrs.src Example code file path
const code= s.cat(new URL(src, import.meta.url)) * @param {string} [attrs.language="javascript"] Language of the code
.toString() * @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 }){
registerClientPart(page_id, registerClientFile);
const code= 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(
@ -34,10 +39,17 @@ function elCode({ id, content }){
}); });
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 register(){ function registerClientPart(page_id, registerClientFile){
if(is_registered) 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 }),
); );
is_registered= true; //★ egisterClientFile(
//★ new URL("./example.js.js", import.meta.url),
//★ el("script", { type: "module" })
//★ ;
is_registered[page_id]= true;
} }

108
docs_src/elements.html.js Normal file
View File

@ -0,0 +1,108 @@
import { el } from "deka-dom-el";
import { styles, common } from "./index.css.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);
import { header } from "./layout/head.html.js";
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info, path_target, pages, registerClientFile }){
const page_id= info.id;
return el().append(
el(header, { info, pkg, path_target, pages }),
el("main").append(
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("h3", "Creating element(s) (with custom attributes)"),
el("p").append(
"You can create a native DOM element by using the ",
el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement", title: "MDN documentation for document.createElement()" }).append(
el("code", "document.createElement()")
), ". ",
"It is also possible to provide a some attribute(s) declaratively using ", el("code", "Object.assign()"), ". ",
"More precisely, this way you can sets some ",
el("a", {
href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
title: "MDN page about Interface Description Language"
}).append(
el("abbr", { textContent: "IDL", title: "Interface Description Language" })
), "."
),
el(example, { src: new URL("./components/examples/nativeCreateElement.js", import.meta.url), page_id, registerClientFile }),
el("p").append(
"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(…), { … })"), "."
),
el(example, { src: new URL("./components/examples/dekaCreateElement.js", import.meta.url), page_id, registerClientFile }),
el("p").append(
"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. ",
"Function prefers IDL and fallback to the ", el("code", "element.setAttribute"), " if there is no writable property in the element prototype."
),
el("p").append(
"You can study all JavaScript elements interfaces to the corresponding HTML elements. ",
"All HTML elements inherits from ", el("a", { textContent: "HTMLElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" }), ". ",
"To see all available IDLs for example for paragraphs, see ", el("a", { textContent: "HTMLParagraphElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement" }), ". ",
"Moreover, the ", el("code", "assign"), " provides a way to sets declaratively some convenient properties:"
),
el("ul").append(
el("li").append(
"It is possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attributes using object notation."
),
el("li").append(
"In opposite, it is also possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attribute using camelCase notation."
),
el("li").append(
"You can use string or object as a value for ", el("code", "style"), " property."
),
el("li").append(
el("code", "className"), " (IDL preffered)/", el("code", "class"), " are ways to add CSS class to the element. ",
"You can use string (similarly to ", el("code", "class=\"…\"") ," syntax in HTML) or array of strings. ",
"This is handy to concat conditional classes."
),
el("li").append(
"Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.",
),
el("li").append(
"The ", el("code", "assign"), " also accepts the ", el("code", "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. ",
el("em").append(
"For example, natievly the elements ", el("code", "id"), " is removed by setting the IDL to an empty string."
)
)
),
el("p").append(
"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("h3", "Native JavaScript templating"),
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("p").append(
"This library therefore ooverwrites the ", el("code", "append"), " method to always return parent element."
),
el(example, { src: new URL("./components/examples/dekaAppend.js", import.meta.url), page_id, registerClientFile }),
el("h2", "Creating advanced (reactive) templates and components"),
el("h3", "Basic components"),
el("p").append(
"You can use functions for encapsulation (repeating) logic. ",
"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."
),
el(example, { src: new URL("./components/examples/dekaBasicComponent.js", import.meta.url), page_id, registerClientFile }),
el("p", "It is nice to use similar naming convention as native DOM API.")
)
);
}

View File

@ -36,17 +36,100 @@ export const common= css`
--accent: #d81b60; --accent: #d81b60;
} }
@media (prefers-color-scheme:dark) { @media (prefers-color-scheme:dark) {
::backdrop, :root { :root {
--accent: #f06292; --accent: #f06292;
--code: #62c1f0; --code: #62c1f0;
} }
} }
body { 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; grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr;
} }
nav a.current { main > *{
color: var(--accent) !important; grid-column: 2;
border-color: var(--accent) !important;
} }
.icon { .icon {
vertical-align: sub; vertical-align: sub;

View File

@ -12,14 +12,13 @@ export const css= styles()
.include(example_css); .include(example_css);
import { header } from "./layout/head.html.js"; import { header } from "./layout/head.html.js";
export function page({ pkg, path_target }){ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info, path_target, pages, registerClientFile }){
const page_id= info.id;
return el().append( return el().append(
el(header, { el(header, { info, pkg, path_target, pages }),
id: "index", el("main").append(
title: "Introduction/Guide", el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces. "),
description: "Introducing basic concepts.",
pkg, path_target
}),
el("p", "The main goals are:"), el("p", "The main goals are:"),
el("ul").append( el("ul").append(
el("li", "provide a small wrappers/utilities around the native JavaScript DOM"), el("li", "provide a small wrappers/utilities around the native JavaScript DOM"),
@ -37,93 +36,7 @@ export function page({ pkg, path_target }){
}), }),
".", ".",
), ),
el(example, { src: "./components/examples/helloWorld.js" }), el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id, registerClientFile }),
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("h3", "Creating element(s) (with custom attributes)"),
el("p").append(
"You can create a native DOM element by using the ",
el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement", title: "MDN documentation for document.createElement()" }).append(
el("code", "document.createElement()")
), ". ",
"It is also possible to provide a some attribute(s) declaratively using ", el("code", "Object.assign()"), ". ",
"More precisely, this way you can sets some ",
el("a", {
href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
title: "MDN page about Interface Description Language"
}).append(
el("abbr", { textContent: "IDL", title: "Interface Description Language" })
), "."
),
el(example, { src: "./components/examples/nativeCreateElement.js" }),
el("p").append(
"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(…), { … })"), "."
),
el(example, { src: "./components/examples/dekaCreateElement.js" }),
el("p").append(
"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. ",
"Function prefers IDL and fallback to the ", el("code", "element.setAttribute"), " if there is no writable property in the element prototype."
),
el("p").append(
"You can study all JavaScript elements interfaces to the corresponding HTML elements. ",
"All HTML elements inherits from ", el("a", { textContent: "HTMLElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" }), ". ",
"To see all available IDLs for example for paragraphs, see ", el("a", { textContent: "HTMLParagraphElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement" }), ". ",
"Moreover, the ", el("code", "assign"), " provides a way to sets declaratively some convenient properties:"
),
el("ul").append(
el("li").append(
"It is possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attributes using object notation."
),
el("li").append(
"In opposite, it is also possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attribute using camelCase notation."
),
el("li").append(
"You can use string or object as a value for ", el("code", "style"), " property."
),
el("li").append(
el("code", "className"), " (IDL preffered)/", el("code", "class"), " are ways to add CSS class to the element. ",
"You can use string (similarly to ", el("code", "class=\"…\"") ," syntax in HTML) or array of strings. ",
"This is handy to concat conditional classes."
),
el("li").append(
"Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.",
),
el("li").append(
"The ", el("code", "assign"), " also accepts the ", el("code", "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. ",
el("em").append(
"For example, natievly the elements ", el("code", "id"), " is removed by setting the IDL to an empty string."
) )
)
),
el("p").append(
"For processing, the ", el("code", "assign"), " internally uses ", el("code", "assignAttribute"), " and ", el("code", "classListDeclarative"), "."
),
el(example, { src: "./components/examples/dekaAssign.js" }),
el("h3", "Native JavaScript templating"),
el("p", "By default, the native JS has no good way to define HTML template using DOM API:"),
el(example, { src: "./components/examples/nativeAppend.js" }),
el("p").append(
"This library therefore ooverwrites the ", el("code", "append"), " method to always return parent element."
),
el(example, { src: "./components/examples/dekaAppend.js" }),
el("h2", "Creating advanced (reactive) templates and components"),
el("h3", "Basic components"),
el("p").append(
"You can use functions for encapsulation (repeating) logic. ",
"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."
),
el(example, { src: "./components/examples/dekaBasicComponent.js" }),
el("p", "It is nice to use similar naming convention as native DOM API.")
); );
} }

11
docs_src/jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"include": [ "*.js", "**/*.js", "../node_modules/nodejsscript/index.d.ts" ],
"compilerOptions": {
"module": "NodeNext",
"noEmit": true,
"allowJs": true,
"checkJs": true,
"downlevelIteration": true,
"maxNodeModuleJsDepth": 1
}
}

View File

@ -1,62 +1,34 @@
import { el, scope } from "deka-dom-el"; import { el, scope } from "deka-dom-el";
/** /**
* @param {object} def * @param {object} def
* @param {string} def.id Page `id` is used as stylesheet name. * @param {import("../types.d.ts").Info} def.info
* @param {string} def.title Page `title` is also used as `h1`
* @param {string} def.description Page 'description'.
* @param {object} def.pkg Package information. * @param {object} def.pkg Package information.
* @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 {{ root: string, css: string}} def.path_target Final URL where the page will be rendered.
* @param {object} def * @param {import("../types.js").Pages} def.pages
* */ * */
export function header({ id, title, description, pkg, path_target }){ export function header({ info: { id, title, description }, pkg, path_target, pages }){
title= `\`${pkg.name}\`${title}`; title= `\`${pkg.name}\`${title}`;
document.head.append(head({ id, title, description, pkg, path_target })); document.head.append(head({ id, title, description, pkg, path_target }));
return el("header").append( return el().append(
el("header").append(
el("h1", title),
el("p", description)
),
el("nav").append( el("nav").append(
el("a", { href: pkg.homepage }).append( el("a", { href: pkg.homepage }).append(
el(iconGitHub), el(iconGitHub),
"GitHub" "GitHub"
)
), ),
el("h1", title), ...pages.map((p, i)=> el("a", {
el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces. ") href: p.id==="index" ? "./" : p.id,
); textContent: (i+1) + ". " + p.title,
} title: p.description,
function iconGitHub(){ classList: { current: p.id===id }
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 }){ function head({ id, title, description, pkg, path_target }){
@ -93,3 +65,37 @@ function metaFacebook({ name, description, homepage }){
function stylesheetHref(path_target, name){ function stylesheetHref(path_target, name){
return path_target.css.replace(path_target.root, "")+name+".css"; return path_target.css.replace(path_target.root, "")+name+".css";
} }
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("") })
);
}

21
docs_src/types.d.ts vendored Normal file
View File

@ -0,0 +1,21 @@
/** See `package.json` */
export type Pkg= Record<string, string>
export type Info= {
id: string,
title: string,
description: string,
}
export type Pages=Info[];
export type PathTarget= {
root: string,
css: string
}
export type registerClientFile= import("../bs/docs.js").registerClientFile;
export type PageAttrs= {
pkg: Pkg,
info: Info,
pages: Pages,
path_target: PathTarget,
registerClientFile: registerClientFile
}

36
index.d.ts vendored
View File

@ -1,8 +1,8 @@
declare global { declare global {
type ddeComponentAttributes= Record<any, any> | undefined | string; type ddeComponentAttributes= Record<any, any> | undefined | string;
type ddeElementExtender<El extends Element>= (element: El)=> El; type ddeElementModifier<El extends HTMLElement | SVGElement | Comment | DocumentFragment>= (element: El)=> El;
} }
type ElementTagNameMap= HTMLElementTagNameMap & SVGElementTagNameMap & { type ElementTagNameMap= HTMLElementTagNameMap & { // & SVGElementTagNameMap
'#text': Text '#text': Text
} }
type Element= ElementTagNameMap[keyof ElementTagNameMap]; type Element= ElementTagNameMap[keyof ElementTagNameMap];
@ -14,7 +14,7 @@ type AttrsModified= {
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others.
*/ */
classList: Record<string,-1|0|1>, classList: Record<string,-1|0|1|boolean>,
/** /**
* By default simiral to `className`, but also supports `string[]` * By default simiral to `className`, but also supports `string[]`
* */ * */
@ -41,7 +41,7 @@ export function assign<El extends Element>(element: El, ...attrs_array: Partial<
export function el<TAG extends keyof ElementTagNameMap>( export function el<TAG extends keyof ElementTagNameMap>(
tag_name: TAG, tag_name: TAG,
attrs?: Partial<ElementAttributes<ElementTagNameMap[TAG]>>, attrs?: Partial<ElementAttributes<ElementTagNameMap[TAG]>>,
...extenders: ddeElementExtender<ElementTagNameMap[TAG]>[] ...modifiers: ddeElementModifier<ElementTagNameMap[TAG]>[]
): ElementTagNameMap[TAG] ): ElementTagNameMap[TAG]
export function el<T>( export function el<T>(
tag_name?: "<>", tag_name?: "<>",
@ -49,33 +49,39 @@ export function el<T>(
export function el< export function el<
A extends ddeComponentAttributes, A extends ddeComponentAttributes,
C extends (attr: A)=> Element>( C extends (attr: A)=> Element | DocumentFragment>(
fComponent: C, fComponent: C,
attrs?: A, attrs?: A,
...extenders: ddeElementExtender<ReturnType<C>>[] ...modifiers: ddeElementModifier<ReturnType<C>>[]
): ReturnType<C> ): ReturnType<C>
export function el(
tag_name: string,
attrs?: Record<string, any>,
...modifiers: ddeElementModifier<HTMLElement | SVGElement>[]
): HTMLElement
export function dispatchEvent(element: HTMLElement, name: keyof DocumentEventMap): void; export function dispatchEvent(element: HTMLElement, name: keyof DocumentEventMap): void;
export function dispatchEvent(element: HTMLElement, name: string, data: any): void; export function dispatchEvent(element: HTMLElement, name: string, data: any): void;
interface On{ interface On{
< <
EE extends ddeElementExtender<Element>, EE extends ddeElementModifier<Element>,
El extends ( EE extends ddeElementExtender<infer El> ? El : never ), El extends ( EE extends ddeElementModifier<infer El> ? El : never ),
Event extends keyof DocumentEventMap>( Event extends keyof DocumentEventMap>(
type: Event, type: Event,
listener: (this: El, ev: DocumentEventMap[Event]) => any, listener: (this: El, ev: DocumentEventMap[Event]) => any,
options?: AddEventListenerOptions options?: AddEventListenerOptions
) : EE; ) : EE;
connected< connected<
EE extends ddeElementExtender<Element>, EE extends ddeElementModifier<Element>,
El extends ( EE extends ddeElementExtender<infer El> ? El : never ) El extends ( EE extends ddeElementModifier<infer El> ? El : never )
>( >(
listener: (el: El) => any, listener: (el: El) => any,
options?: AddEventListenerOptions options?: AddEventListenerOptions
) : EE; ) : EE;
disconnected< disconnected<
EE extends ddeElementExtender<Element>, EE extends ddeElementModifier<Element>,
El extends ( EE extends ddeElementExtender<infer El> ? El : never ) El extends ( EE extends ddeElementModifier<infer El> ? El : never )
>( >(
listener: (el: El) => any, listener: (el: El) => any,
options?: AddEventListenerOptions options?: AddEventListenerOptions
@ -83,6 +89,12 @@ interface On{
} }
export const on: On; export const on: On;
export const scope: {
namespace: string,
host: ddeElementModifier<any>,
elNamespace: (ns: string)=> ({ append(...els: (HTMLElement | SVGElement)[]): HTMLElement | SVGElement | DocumentFragment })
};
//TODO for SVG //TODO for SVG
declare global{ declare global{
interface HTMLDivElement{ append(...nodes: (Node | string)[]): HTMLDivElement; } interface HTMLDivElement{ append(...nodes: (Node | string)[]): HTMLDivElement; }

View File

@ -1,3 +1,4 @@
if(typeof document.createDocumentFragment().append()==="undefined")
[ HTMLElement, SVGElement, DocumentFragment ].forEach(c=> { [ HTMLElement, SVGElement, DocumentFragment ].forEach(c=> {
const { append }= c.prototype; const { append }= c.prototype;
c.prototype.append= function(...els){ append.apply(this, els); return this; }; c.prototype.append= function(...els){ append.apply(this, els); return this; };

View File

@ -19,6 +19,12 @@ export function register(dom, keys_aditional= []){
globalThis.window= w; globalThis.window= w;
w.console= globalThis.console; w.console= globalThis.console;
} }
if(typeof document.createDocumentFragment().append()==="undefined")
[ HTMLElement, SVGElement, DocumentFragment ].forEach(c=> {
const { append }= c.prototype;
c.prototype.append= function(...els){ append.apply(this, els); return this; };
});
dom_last= dom;
return import("./index.js"); return import("./index.js");
} }

View File

@ -39,7 +39,7 @@ export const scope= {
}, },
pop(){ return scopes.pop(); }, pop(){ return scopes.pop(); },
}; };
export function createElement(tag, attributes, ...connect){ export function createElement(tag, attributes, ...modifiers){
const s= signals(this); const s= signals(this);
const { namespace }= scope; const { namespace }= scope;
let scoped= 0; let scoped= 0;
@ -50,7 +50,7 @@ export function createElement(tag, attributes, ...connect){
switch(true){ switch(true){
case typeof tag==="function": { case typeof tag==="function": {
scoped= 1; scoped= 1;
scope.push({ scope: tag, host: c=> c ? (scoped===1 ? connect.unshift(c) : c(el_host), undefined) : el_host }); scope.push({ scope: tag, host: c=> c ? (scoped===1 ? modifiers.unshift(c) : c(el_host), undefined) : el_host });
el= tag(attributes || undefined); el= tag(attributes || undefined);
const is_fragment= el instanceof DocumentFragment; const is_fragment= el instanceof DocumentFragment;
const el_mark= document.createComment(`<dde:mark type="component" name="${tag.name}" host="${is_fragment ? "this" : "parentElement"}"/>`); const el_mark= document.createComment(`<dde:mark type="component" name="${tag.name}" host="${is_fragment ? "this" : "parentElement"}"/>`);
@ -64,7 +64,7 @@ export function createElement(tag, attributes, ...connect){
case !el: el= assign.call(this, document.createElement(tag), attributes); case !el: el= assign.call(this, document.createElement(tag), attributes);
} }
if(!el_host) el_host= el; if(!el_host) el_host= el;
connect.forEach(c=> c(el_host)); modifiers.forEach(c=> c(el_host));
if(scoped) scope.pop(); if(scoped) scope.pop();
scoped= 2; scoped= 2;
return el; return el;