mirror of
https://github.com/jaandrle/deka-dom-el
synced 2024-11-24 01:29:36 +01:00
Compare commits
3 Commits
64a03c8ba5
...
98d9d6a5b1
Author | SHA1 | Date | |
---|---|---|---|
98d9d6a5b1 | |||
0d70189908 | |||
324727cc0a |
16
dist/dde-with-signals.js
vendored
16
dist/dde-with-signals.js
vendored
File diff suppressed because one or more lines are too long
2
dist/dde.js
vendored
2
dist/dde.js
vendored
File diff suppressed because one or more lines are too long
3
dist/esm-with-signals.d.ts
vendored
3
dist/esm-with-signals.d.ts
vendored
@ -37,14 +37,13 @@ type ElementAttributes<T extends keyof ElementTagNameMap | ElementTagNameMap[key
|
||||
Omit<ElementTagNameMap[T],"classList"|"className"> & AttrsModified :
|
||||
Omit<T,"classList"|"className"> & AttrsModified;
|
||||
export function assign<El extends Element>(element: El, ...attrs_array: Partial<ElementAttributes<El>>[]): El
|
||||
type TagNameFragment= "<>";
|
||||
export function el<TAG extends keyof ElementTagNameMap>(
|
||||
tag_name: TAG,
|
||||
attrs?: Partial<ElementAttributes<ElementTagNameMap[TAG]>>,
|
||||
...extenders: ddeElementExtender<ElementTagNameMap[TAG]>[]
|
||||
): ElementTagNameMap[TAG]
|
||||
export function el<T>(
|
||||
tag_name: TagNameFragment,
|
||||
tag_name?: "<>",
|
||||
): DocumentFragment
|
||||
export function el<
|
||||
A extends ddeComponentAttributes,
|
||||
|
8
dist/esm-with-signals.js
vendored
8
dist/esm-with-signals.js
vendored
File diff suppressed because one or more lines are too long
3
dist/esm.d.ts
vendored
3
dist/esm.d.ts
vendored
@ -37,14 +37,13 @@ type ElementAttributes<T extends keyof ElementTagNameMap | ElementTagNameMap[key
|
||||
Omit<ElementTagNameMap[T],"classList"|"className"> & AttrsModified :
|
||||
Omit<T,"classList"|"className"> & AttrsModified;
|
||||
export function assign<El extends Element>(element: El, ...attrs_array: Partial<ElementAttributes<El>>[]): El
|
||||
type TagNameFragment= "<>";
|
||||
export function el<TAG extends keyof ElementTagNameMap>(
|
||||
tag_name: TAG,
|
||||
attrs?: Partial<ElementAttributes<ElementTagNameMap[TAG]>>,
|
||||
...extenders: ddeElementExtender<ElementTagNameMap[TAG]>[]
|
||||
): ElementTagNameMap[TAG]
|
||||
export function el<T>(
|
||||
tag_name: TagNameFragment,
|
||||
tag_name?: "<>",
|
||||
): DocumentFragment
|
||||
export function el<
|
||||
A extends ddeComponentAttributes,
|
||||
|
2
dist/esm.js
vendored
2
dist/esm.js
vendored
File diff suppressed because one or more lines are too long
@ -1,21 +1,32 @@
|
||||
:root {
|
||||
color-scheme: dark light;
|
||||
@import url(https://cdn.simplecss.org/simple.min.css);
|
||||
:root{
|
||||
--body-max-width: 45rem;
|
||||
--marked: #fb3779;
|
||||
--code: #0d47a1;
|
||||
--accent: #d81b60;
|
||||
}
|
||||
*, ::before, ::after { box-sizing: border-box; }
|
||||
body > * {
|
||||
margin-inline: max(.5rem, calc(50% - var(--body-max-width) / 2));
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
@media (prefers-color-scheme:dark) {
|
||||
::backdrop, :root {
|
||||
--accent: #f06292;
|
||||
--code: #62c1f0;
|
||||
}
|
||||
}
|
||||
body {
|
||||
grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr;
|
||||
}
|
||||
h1{
|
||||
text-align: center;
|
||||
text-wrap: balanc;
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
.note{
|
||||
font-size: .9rem;
|
||||
font-style: italic;
|
||||
}
|
||||
.example{
|
||||
--body-max-width: 80rem;
|
||||
height: 25rem;
|
||||
grid-column: 1/4;
|
||||
width: 100%;
|
||||
max-width: calc(9/5 * var(--body-max-width));
|
||||
height: calc(3/5 * var(--body-max-width));
|
||||
margin-inline: auto;
|
||||
}
|
108
docs/index.html
108
docs/index.html
@ -1,7 +1,7 @@
|
||||
<!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"/>--><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"/>--><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="body"/>--><h1>`deka-dom-el` — Introduction/Guide</h1><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces.The main goals are:</p><ul><li>provide a small wrapper around the native JavaScript DOM</li><li>keep library size under 10kB</li><li>zero dependencies (if possible)</li><li>prefer a 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"/>--><div id="code-vup3z" 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 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="body" host="this"/>--><h1>`deka-dom-el` — Introduction/Guide</h1><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces. The main goals are:</p><ul><li>provide a 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 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-hrmiy" 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);
|
||||
document.body.append(
|
||||
el("<>").append(
|
||||
el().append(
|
||||
el("p", S(()=>
|
||||
"Hello World "+"🎉".repeat(clicks())
|
||||
)),
|
||||
@ -12,4 +12,106 @@ document.body.append(
|
||||
})
|
||||
)
|
||||
);
|
||||
</code></pre></div><script>Flems(document.getElementById("code-vup3z"), 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><script src="https://cdn.jsdelivr.net/npm/shiki"></script><script src="index.js" type="module"></script></body></html>
|
||||
</code></pre></div><script>Flems(document.getElementById("code-hrmiy"), 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>Let’s 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 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-x0k3n" class="example"><pre><code class="language-javascript">document.body.append(
|
||||
document.createElement("div")
|
||||
);
|
||||
console.log(
|
||||
"Emty div is generated inside <body>:",
|
||||
document.body.innerHTML.includes("<div></div>")
|
||||
);
|
||||
|
||||
document.body.append(
|
||||
Object.assign(
|
||||
document.createElement("p"),
|
||||
{ textContent: "Element’s text content.", style: "color: coral;" }
|
||||
)
|
||||
);
|
||||
</code></pre></div><script>Flems(document.getElementById("code-x0k3n"), 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: \\\"Element’s 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-tz88s" 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-tz88s"), 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 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 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 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 element’s <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-8doer" 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-8doer"), 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-9pfmb" 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("<div></div><span></span><main></main>"));
|
||||
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-9pfmb"), 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-ya3r1" 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 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-ya3r1"), 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-5abxx" 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-5abxx"), 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>
|
@ -1,9 +1,12 @@
|
||||
let is_register= false;
|
||||
let is_registered= false;
|
||||
import { styles } from "../index.css.js";
|
||||
export const css= styles().scope(example).css`
|
||||
:host{
|
||||
--body-max-width: 80rem;
|
||||
height: 25rem;
|
||||
grid-column: 1/4;
|
||||
width: 100%;
|
||||
max-width: calc(9/5 * var(--body-max-width));
|
||||
height: calc(3/5 * var(--body-max-width));
|
||||
margin-inline: auto;
|
||||
}
|
||||
`
|
||||
import { el } from "deka-dom-el";
|
||||
@ -15,13 +18,10 @@ export function example({ src, language= "javascript" }){
|
||||
.toString()
|
||||
.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);
|
||||
return el("<>").append(
|
||||
return el().append(
|
||||
el("div", { id, className: example.name }).append(
|
||||
el("pre").append(
|
||||
el("code", {
|
||||
className: "language-"+language,
|
||||
textContent: code
|
||||
})
|
||||
el("code", { className: "language-"+language, textContent: code })
|
||||
)
|
||||
),
|
||||
elCode({ id, content: code })
|
||||
@ -35,9 +35,9 @@ function elCode({ id, content }){
|
||||
return el("script", `Flems(document.getElementById("${id}"), JSON.parse(${JSON.stringify(options)}));`);
|
||||
}
|
||||
function register(){
|
||||
if(is_register) return;
|
||||
if(is_registered) return;
|
||||
document.head.append(
|
||||
el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" })
|
||||
);
|
||||
is_register= true;
|
||||
is_registered= true;
|
||||
}
|
||||
|
24
docs_src/components/examples/dekaAppend.js
Normal file
24
docs_src/components/examples/dekaAppend.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { el } from "../../../index-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 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")
|
||||
)
|
||||
)
|
||||
);
|
25
docs_src/components/examples/dekaAssign.js
Normal file
25
docs_src/components/examples/dekaAssign.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { assignAttribute, classListDeclarative } from "../../../index-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
|
||||
);
|
17
docs_src/components/examples/dekaBasicComponent.js
Normal file
17
docs_src/components/examples/dekaBasicComponent.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { el } from "../../../index-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)
|
||||
);
|
||||
}
|
11
docs_src/components/examples/dekaCreateElement.js
Normal file
11
docs_src/components/examples/dekaCreateElement.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { el, assign } from "../../../index-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 } }
|
||||
)
|
||||
);
|
@ -1,7 +1,7 @@
|
||||
import { el, S } from "../../../index-with-signals.js";
|
||||
const clicks= S(0);
|
||||
document.body.append(
|
||||
el("<>").append(
|
||||
el().append(
|
||||
el("p", S(()=>
|
||||
"Hello World "+"🎉".repeat(clicks())
|
||||
)),
|
||||
|
11
docs_src/components/examples/nativeAppend.js
Normal file
11
docs_src/components/examples/nativeAppend.js
Normal file
@ -0,0 +1,11 @@
|
||||
document.body.append(
|
||||
document.createElement("div"),
|
||||
document.createElement("span"),
|
||||
document.createElement("main")
|
||||
);
|
||||
console.log(document.body.innerHTML.includes("<div></div><span></span><main></main>"));
|
||||
const template= document.createElement("main").append(
|
||||
document.createElement("div"),
|
||||
document.createElement("span"),
|
||||
);
|
||||
console.log(typeof template==="undefined");
|
14
docs_src/components/examples/nativeCreateElement.js
Normal file
14
docs_src/components/examples/nativeCreateElement.js
Normal file
@ -0,0 +1,14 @@
|
||||
document.body.append(
|
||||
document.createElement("div")
|
||||
);
|
||||
console.log(
|
||||
"Emty div is generated inside <body>:",
|
||||
document.body.innerHTML.includes("<div></div>")
|
||||
);
|
||||
|
||||
document.body.append(
|
||||
Object.assign(
|
||||
document.createElement("p"),
|
||||
{ textContent: "Element’s text content.", style: "color: coral;" }
|
||||
)
|
||||
);
|
@ -28,17 +28,25 @@ export function css(...a){
|
||||
}
|
||||
export function styles(){ return Object.assign(Object.create(s), { content: "" }); }
|
||||
export const common= css`
|
||||
:root {
|
||||
color-scheme: dark light;
|
||||
@import url(https://cdn.simplecss.org/simple.min.css);
|
||||
:root{
|
||||
--body-max-width: 45rem;
|
||||
--marked: #fb3779;
|
||||
--code: #0d47a1;
|
||||
--accent: #d81b60;
|
||||
}
|
||||
*, ::before, ::after { box-sizing: border-box; }
|
||||
body > * {
|
||||
margin-inline: max(.5rem, calc(50% - var(--body-max-width) / 2));
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
@media (prefers-color-scheme:dark) {
|
||||
::backdrop, :root {
|
||||
--accent: #f06292;
|
||||
--code: #62c1f0;
|
||||
}
|
||||
}
|
||||
body {
|
||||
grid-template-columns: 1fr min(var(--body-max-width), 90%) 1fr;
|
||||
}
|
||||
h1{
|
||||
text-align: center;
|
||||
text-wrap: balanc;
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
`;
|
||||
|
@ -21,15 +21,15 @@ export const css= styles()
|
||||
`
|
||||
.include(example_css);
|
||||
export function body(pkg){
|
||||
return el("<>").append(
|
||||
return el().append(
|
||||
el("h1", pageName(pkg)),
|
||||
el("p").append(
|
||||
"The library tries to provide pure JavaScript tool(s) to create reactive interfaces.",
|
||||
"The library tries to provide pure JavaScript tool(s) to create reactive interfaces. ",
|
||||
"The main goals are:"
|
||||
),
|
||||
el("ul").append(
|
||||
el("li", "provide a small wrapper around the native JavaScript DOM"),
|
||||
el("li", "keep library size under 10kB"),
|
||||
el("li", "provide a small wrappers/utilities around the native JavaScript DOM"),
|
||||
el("li", "keep library size around 10kB at maximum (if possible)"),
|
||||
el("li", "zero dependencies (if possible)"),
|
||||
el("li", "prefer a declarative/functional approach"),
|
||||
el("li", "unopinionated (allow alternative methods)"),
|
||||
@ -43,7 +43,94 @@ export function body(pkg){
|
||||
}),
|
||||
".",
|
||||
),
|
||||
el(example, { src: "./components/examples/helloWorld.js" })
|
||||
el(example, { src: "./components/examples/helloWorld.js" }),
|
||||
|
||||
|
||||
el("h2", "Native JavaScript DOM elements creations"),
|
||||
el("p", "Let’s go through all patterns we would like to use and what needs to be improved for better experience."),
|
||||
|
||||
el("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 element’s ", 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.")
|
||||
);
|
||||
}
|
||||
function pageName(pkg){
|
||||
|
@ -12,7 +12,7 @@ import { el } from "deka-dom-el";
|
||||
* @param {object} def
|
||||
* */
|
||||
export function head({ id, title, description, pkg, path_target }){
|
||||
return el("<>").append(
|
||||
return el().append(
|
||||
el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
||||
el("link", { rel: "stylesheet", href: stylesheetHref(path_target, id) }),
|
||||
|
||||
@ -23,7 +23,7 @@ export function head({ id, title, description, pkg, path_target }){
|
||||
);
|
||||
}
|
||||
function metaTwitter({ name, description, homepage }){
|
||||
return el("<>").append(
|
||||
return el().append(
|
||||
el("meta", { name: "twitter:card", content: "summary_large_image" }),
|
||||
//el("meta", { name: "twitter:domain", content: "" }),
|
||||
el("meta", { name: "twitter:url", content: homepage }),
|
||||
@ -34,7 +34,7 @@ function metaTwitter({ name, description, homepage }){
|
||||
);
|
||||
}
|
||||
function metaFacebook({ name, description, homepage }){
|
||||
return el("<>").append(
|
||||
return el().append(
|
||||
el("meta", { name: "og:url", content: homepage }),
|
||||
el("meta", { name: "og:title", content: name }),
|
||||
el("meta", { name: "og:description", content: description }),
|
||||
|
3
index.d.ts
vendored
3
index.d.ts
vendored
@ -38,14 +38,13 @@ type ElementAttributes<T extends keyof ElementTagNameMap | ElementTagNameMap[key
|
||||
Omit<T,"classList"|"className"> & AttrsModified;
|
||||
export function assign<El extends Element>(element: El, ...attrs_array: Partial<ElementAttributes<El>>[]): El
|
||||
|
||||
type TagNameFragment= "<>";
|
||||
export function el<TAG extends keyof ElementTagNameMap>(
|
||||
tag_name: TAG,
|
||||
attrs?: Partial<ElementAttributes<ElementTagNameMap[TAG]>>,
|
||||
...extenders: ddeElementExtender<ElementTagNameMap[TAG]>[]
|
||||
): ElementTagNameMap[TAG]
|
||||
export function el<T>(
|
||||
tag_name: TagNameFragment,
|
||||
tag_name?: "<>",
|
||||
): DocumentFragment
|
||||
|
||||
export function el<
|
||||
|
@ -48,7 +48,7 @@
|
||||
"latedef": "true",
|
||||
"maxparams": 5,
|
||||
"maxdepth": 3,
|
||||
"maxcomplexity": 12,
|
||||
"maxcomplexity": 14,
|
||||
"globals": {
|
||||
"requestIdleCallback": false,
|
||||
"AbortController": false,
|
||||
|
@ -52,14 +52,14 @@ export function createElement(tag, attributes, ...connect){
|
||||
scoped= 1;
|
||||
scope.push({ scope: tag, host: c=> c ? (scoped===1 ? connect.unshift(c) : c(el_host), undefined) : el_host });
|
||||
el= tag(attributes || undefined);
|
||||
const el_mark= document.createComment(`<dde:mark type="component" name="${tag.name}"/>`);
|
||||
const is_fragment= el instanceof DocumentFragment;
|
||||
const el_mark= document.createComment(`<dde:mark type="component" name="${tag.name}" host="${is_fragment ? "this" : "parentElement"}"/>`);
|
||||
el.prepend(el_mark);
|
||||
if(el instanceof DocumentFragment)
|
||||
el_host= el_mark;
|
||||
if(is_fragment) el_host= el_mark;
|
||||
break;
|
||||
}
|
||||
case tag==="#text": el= assign.call(this, document.createTextNode(""), attributes); break;
|
||||
case tag==="<>": el= assign.call(this, document.createDocumentFragment(), attributes); break;
|
||||
case tag==="<>" || !tag: el= assign.call(this, document.createDocumentFragment(), attributes); break;
|
||||
case namespace!=="html": el= assign.call(this, document.createElementNS(namespace, tag), attributes); break;
|
||||
case !el: el= assign.call(this, document.createElement(tag), attributes);
|
||||
}
|
||||
@ -84,7 +84,6 @@ export function assign(element, ...attributes){
|
||||
return element;
|
||||
}
|
||||
export function assignAttribute(element, key, value){
|
||||
/* jshint maxcomplexity:14 */
|
||||
const { setRemoveAttr, s }= assignContext(element, this);
|
||||
const _this= this;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user