mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-03-31 11:35:52 +02:00
🔤
This commit is contained in:
parent
8415f5cf6f
commit
4dba3a292a
@ -1,7 +1,7 @@
|
||||
**Alpha**
|
||||
| [source code on GitHub](https://github.com/jaandrle/deka-dom-el)
|
||||
| [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el)
|
||||
| [](https://robinpokorny.github.io/git3moji/) <!-- editorconfig-checker-disable-line -->
|
||||
| [npm package](https://www.npmjs.com/package/deka-dom-el)
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/assets/logo.svg" alt="Deka DOM Elements Logo" width="180" height="180">
|
||||
@ -24,9 +24,6 @@ function EmojiCounter({ initial }) {
|
||||
const count = S(0);
|
||||
const emoji = S(initial);
|
||||
|
||||
/** @param {HTMLOptionElement} el */
|
||||
const isSelected= el=> (el.selected= el.value===initial);
|
||||
|
||||
// 🔄 View - UI updates automatically when signals change
|
||||
return el().append(
|
||||
el("p", {
|
||||
@ -87,7 +84,7 @@ npm install deka-dom-el --save
|
||||
…or via CDN / Direct Script:
|
||||
|
||||
For CDN links and various build formats (ESM/IIFE, with/without signals, minified/unminified), see the [interactive
|
||||
format selector](https://jaandrle.github.io/deka-dom-el/) on the documentation site.
|
||||
format selector](https://jaandrle.github.io/deka-dom-el/#h-getting-started) on the documentation site.
|
||||
|
||||
```html
|
||||
<!-- Example with IIFE build (creates a global DDE object) -->
|
||||
|
@ -81,11 +81,11 @@ function Todos(){
|
||||
)
|
||||
)
|
||||
),
|
||||
S.el(todosS, todos => !todos.length
|
||||
S.el(todosS, ({ length }) => !length
|
||||
? el()
|
||||
: el("footer", { className: "footer" }).append(
|
||||
el("span", { className: "todo-count" }).append(
|
||||
noOfLeft()
|
||||
el("strong", length + " " + (length === 1 ? "item" : "items")),
|
||||
),
|
||||
memo("filters", ()=>
|
||||
el("ul", { className: "filters" }).append(
|
||||
@ -100,7 +100,7 @@ function Todos(){
|
||||
)
|
||||
),
|
||||
),
|
||||
todos.length - todosRemainingS.get() === 0
|
||||
length - todosRemainingS.get() === 0
|
||||
? el()
|
||||
: memo("delete", () =>
|
||||
el("button",
|
||||
@ -110,13 +110,6 @@ function Todos(){
|
||||
)
|
||||
)
|
||||
);
|
||||
function noOfLeft(){
|
||||
const length = todosRemainingS.get();
|
||||
return el("strong").append(
|
||||
length + " ",
|
||||
length === 1 ? "item left" : "items left"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,11 @@ import { getLibraryUrl } from "./components/getLibraryUrl.html.js";
|
||||
/** @param {string} url */
|
||||
const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
w_mvv:{
|
||||
npm: {
|
||||
title: t`NPM package page for dd<el>`,
|
||||
href: "https://www.npmjs.com/package/deka-dom-el",
|
||||
},
|
||||
w_mvv: {
|
||||
title: t`Wikipedia: Model–view–viewmodel`,
|
||||
href: "https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel",
|
||||
},
|
||||
@ -106,6 +110,10 @@ export function page({ pkg, info }){
|
||||
`),
|
||||
el("h4", "npm installation"),
|
||||
el(code, { content: "npm install deka-dom-el --save", language: "shell", page_id }),
|
||||
el("p").append(T`
|
||||
…see ${el("a", { textContent: "package page", ...references.npm, target: "_blank" })}.
|
||||
`),
|
||||
|
||||
el("h4", "CDN / Direct Script Usage"),
|
||||
el("p").append(T`
|
||||
Use the interactive selector below to choose your preferred format:
|
||||
|
@ -311,9 +311,9 @@ export function page({ pkg, info }){
|
||||
el(code, { content: `
|
||||
// Dynamic class attributes
|
||||
el("a", {
|
||||
textContent: "All",
|
||||
className: S(()=> pageS.get() === "all" ? "selected" : ""),
|
||||
href: "#"
|
||||
textContent,
|
||||
classList: { selected: S(()=> pageS.get() === textContent.toLowerCase()) },
|
||||
href: \`#\${textContent.toLowerCase()}\`
|
||||
})
|
||||
|
||||
// Reactive classList
|
||||
@ -355,18 +355,25 @@ export function page({ pkg, info }){
|
||||
|
||||
el("h4", t`Memoizing UI Sections`),
|
||||
el(code, { content: `
|
||||
S.el(todosS, todos => memo(todos.length, length=> length
|
||||
? el("footer", { className: "footer" }).append(
|
||||
// Footer content...
|
||||
S.el(todosS, ({ length }) => !length
|
||||
? el()
|
||||
: el("footer", { className: "footer" }).append(
|
||||
// …
|
||||
memo("filters", ()=>
|
||||
// …
|
||||
el("a", {
|
||||
textContent,
|
||||
classList: { selected: S(()=> pageS.get() === textContent.toLowerCase()) },
|
||||
href: \`#\${textContent.toLowerCase()}\`
|
||||
})
|
||||
// …
|
||||
)
|
||||
: el()
|
||||
))
|
||||
`, page_id }),
|
||||
|
||||
el("p").append(T`
|
||||
By memoizing based on the todos length, the entire footer component is only re-rendered
|
||||
when todos are added or removed, not when their properties change. This improves performance
|
||||
by avoiding unnecessary DOM operations.
|
||||
We memoize the UI section and uses derived signal for the classList. Re-rendering this part is therefore
|
||||
unnecessary when the number of todos changes.
|
||||
`),
|
||||
|
||||
el("div", { className: "tip" }).append(
|
||||
@ -389,8 +396,10 @@ export function page({ pkg, info }){
|
||||
`),
|
||||
el(code, { content: `
|
||||
// Event handlers in the main component
|
||||
const onDelete = on("todo:delete", ev => S.action(todosS, "delete", ev.detail));
|
||||
const onEdit = on("todo:edit", ev => S.action(todosS, "edit", ev.detail));
|
||||
const onDelete = on("todo:delete", ev =>
|
||||
S.action(todosS, "delete", /** @type {{ detail: Todo["id"] }} */(ev).detail));
|
||||
const onEdit = on("todo:edit", ev =>
|
||||
S.action(todosS, "edit", /** @type {{ detail: Partial<Todo> & { id: Todo["id"] } }} */(ev).detail));
|
||||
`, page_id }),
|
||||
|
||||
el("h4", t`2. The TodoItem Component with Scopes and Local State`),
|
||||
@ -522,25 +531,24 @@ export function page({ pkg, info }){
|
||||
el("h4", t`Conditional Todo List`),
|
||||
el(code, { content: `
|
||||
S.el(todosS, todos => todos.length
|
||||
? el("main", { className: "main" }).append(
|
||||
? el()
|
||||
: el("main", { className: "main" }).append(
|
||||
// Main content with toggle all and todo list
|
||||
)
|
||||
: el()
|
||||
)
|
||||
`, page_id }),
|
||||
|
||||
el("h4", t`Conditional Edit Form`),
|
||||
el(code, { content: `
|
||||
S.el(isEditing, editing => editing
|
||||
? el("form", null, onSubmitEdit).append(
|
||||
S.el(isEditing, editing => !editing
|
||||
? el()
|
||||
: el("form", null, onSubmitEdit).append(
|
||||
el("input", {
|
||||
className: "edit",
|
||||
name: "edit",
|
||||
name: formEdit,
|
||||
value: title,
|
||||
"data-id": id
|
||||
}, onBlurEdit, onKeyDown, addFocus)
|
||||
)
|
||||
: el()
|
||||
)
|
||||
`, page_id }),
|
||||
|
||||
@ -630,7 +638,7 @@ export function page({ pkg, info }){
|
||||
${el("strong", "Declarative Class Management:")} Using the classList property for cleaner class handling
|
||||
`),
|
||||
el("li").append(T`
|
||||
${el("strong", "Focus Management:")} Reliable input focus with setTimeout
|
||||
${el("strong", "Focus Management:")} Reliable input focus with requestAnimationFrame
|
||||
`),
|
||||
el("li").append(T`
|
||||
${el("strong", "Persistent Storage:")} Automatically saving application state with signal listeners
|
||||
|
@ -4,7 +4,7 @@
|
||||
"description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.",
|
||||
"author": "Jan Andrle <andrle.jan@centrum.cz>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/jaandrle/deka-dom-el",
|
||||
"homepage": "https://jaandrle.github.io/deka-dom-el/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/jaandrle/deka-dom-el.git"
|
||||
|
Loading…
x
Reference in New Issue
Block a user