1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-07-01 04:12:14 +02:00

v0.7.1 (dispatchEvent, docs)

This commit is contained in:
2023-11-21 17:19:59 +01:00
parent ae0455f913
commit 96c84227e9
19 changed files with 227 additions and 80 deletions

View File

@ -0,0 +1,14 @@
import { el, on, dispatchEvent } from "deka-dom-el";
document.body.append(
el("p", "Listenning to `test` event.", on("test", console.log)).append(
el("br"),
el("button", "native", on("click", native)),
" ",
el("button", "dde", on("click", dde)),
" ",
el("button", "dde with options", on("click", ddeOptions))
)
);
function native(){ this.dispatchEvent(new CustomEvent("test", { bubbles: true, detail: "hi" })); }
function dde(){ dispatchEvent("test")(this.parentElement, "hi"); }
function ddeOptions(){ dispatchEvent("test", { bubbles: true })(this, "hi"); }

View File

@ -0,0 +1,18 @@
import { el, on } from "deka-dom-el";
const paragraph= el("p", "See live-cycle events in console.",
el=> log({ type: "dde:created", detail: el }),
on.connected(log),
on.disconnected(log),
on.attributeChanged(log));
document.body.append(
paragraph,
el("button", "Update attribute", on("click", ()=> paragraph.setAttribute("test", Math.random().toString()))),
" ",
el("button", "Remove", on("click", ()=> paragraph.remove()))
);
/** @param {Partial<CustomEvent>} event */
function log({ type, detail }){
console.log({ _this: this, type, detail });
}

View File

@ -15,6 +15,18 @@ styles.scope(prevNext).css`
}
`;
import { el } from "../../index.js";
/**
* @param {Object} attrs
* @param {string} attrs.textContent
* @param {string} [attrs.id]
* */
export function h3({ textContent, id }){
if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
return el("h3", { id }).append(
el("a", { textContent: "§", href: "#"+id, tabIndex: -1 }),
" ", textContent
);
}
/**
* @param {import("../types.d.ts").Info} page
* */

View File

@ -3,7 +3,7 @@ import { el } from "deka-dom-el";
import { header } from "./layout/head.html.js";
import { example } from "./components/example.html.js";
import { prevNext } from "./components/prevNext.html.js";
import { h3, prevNext } from "./components/pageUtils.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
@ -17,7 +17,7 @@ export function page({ pkg, info }){
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(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(
@ -83,7 +83,7 @@ export function page({ pkg, info }){
),
el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }),
el("h3", "Native JavaScript templating"),
el(h3, "Native JavaScript templating"),
el("p", "By default, the native JS has no good way to define HTML template using DOM API:"),
el(example, { src: fileURL("./components/examples/elements/nativeAppend.js"), page_id }),
el("p").append(
@ -92,7 +92,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }),
el("h3", "Basic (state-less) components"),
el(h3, "Basic (state-less) components"),
el("p").append(
"You can use functions for encapsulation (repeating) logic. ",
"The ", el("code", "el"), " accepts function as first argument. ",
@ -109,7 +109,7 @@ export function page({ pkg, info }){
" and keep track of the native API (things are best remembered through regular use).",
),
el("h3", "Creating non-HTML elements"),
el(h3, "Creating non-HTML elements"),
el("p").append(
"Similarly to the native DOM API (", el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS", title: "MDN" }).append(el("code", "document.createElementNS")), ") for non-HTML elements",
" we need to tell JavaScript which kind of the element to create.",

View File

@ -3,7 +3,7 @@ import { el } from "deka-dom-el";
import { header } from "./layout/head.html.js";
import { example } from "./components/example.html.js";
import { prevNext } from "./components/prevNext.html.js";
import { h3, prevNext } from "./components/pageUtils.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
@ -22,7 +22,7 @@ export function page({ pkg, info }){
" incorporate not only this in UI templates declaratively."
),
el("h3", "Events and listenners"),
el(h3, "Events and listenners"),
el("p").append(
"In JavaScript you can listen to the native DOM events of the given element by using ",
el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener", title: "addEventListener on MDN" }).append(
@ -34,18 +34,33 @@ export function page({ pkg, info }){
),
el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }),
el("p").append(
"…this is actually one of the two differences. The another one is that", el("code", "on"),
"…this is actually one of the two differences. The another one is that ", el("code", "on"),
" accepts only object as the ", el("code", "options"), " (but it is still optional)."
),
el("p").append(
el("p", { className: "notice" }).append(
"The other difference is that there is ", el("strong", "no"), " ", el("code", "off"), " function.",
" ",
"You can remove listener declaratively using ", el("a", { textContent: "AbortSignal", href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal", title: "part of addEventListener on MDN" }),
":"
),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
el("div", { className: "notice" }).append(
el("p", "So, there are (typically) three ways to handle events. You can use:"),
el("ul").append(
el("li").append( el("code", `el("button", { textContent: "click me", "=onclick": "console.log(event)" })`)),
el("li").append( el("code", `el("button", { textContent: "click me", onclick: console.log })`)),
el("li").append( el("code", `el("button", { textContent: "click me" }, on("click", console.log))`))
),
el("p").append(
"In the first example we force to use HTML attribute (it corresponds to ", el("code", `<button onclick="console.log(event)">click me</button>`), ").",
" ",
el("em", "Side note: this can be useful in case of SSR."),
" ",
"To study difference, you can read a nice summary here: ", el("a", { href: "https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944", textContent: "GIST @WebReflection/web_events.md" }), "."
)
),
el("h3", "Addons"),
el(h3, "Addons"),
el("p").append(
"From practical point of view, ", el("em", "Addons"), " are just functions that accept any html element",
" as their first parameter. You can see that the ", el("code", "on(…)"), " fullfills this requirement."
@ -60,11 +75,44 @@ export function page({ pkg, info }){
" ",
"Also notice, you can use Addons to get element reference.",
),
el("h3", "Life cycle events"),
el("p", "Addons are called immediately when the element is created, event it is not connected to live DOM yet."),
// todo
el(h3, "Life-cycle events"),
el("p").append(
"Addons are called immediately when the element is created, even it is not connected to live DOM yet.",
" ",
"Therefore, you can understand the Addon to be “oncreate” event."
),
el("p").append(
"The library provide three additional live-cycle events corresponding to how they are named in",
" a case of custom elements: ", el("code", "on.connected"), ", ", el("code", "on.disconnected"),
" and ", el("code", "on.attributeChanged"), "."
),
el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
el("p").append(
"For Custom elements, we will later introduce a way to replace ", el("code", "*Callback"),
" syntax with ", el("code", "dde:*"), " events. The ", el("code", "on.*"), " functions then",
" listen to the appropriate Custom Elements events (see ", el("a", { textContent: "Custom element lifecycle callbacks | MDN", href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks" }), ")."
),
el("p").append(
"But, in case of regular elemnets the ", el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" }).append(el("code", "MutationObserver"), " | MDN"),
" is internaly used to track these events. Therefore, there are some drawbacks:",
),
el("ul").append(
el("li").append(
"To proper listener registration, you need to use ", el("code", "on.*"), " not `on(\"dde:*\", …)`!"
),
el("li").append(
"Use sparingly! Internally, library must loop of all registered events and fires event properly.",
" ",
el("strong", "It is good practice to use the fact that if an element is removed, its children are also removed!"),
" ",
"In this spirit, we will introduce later the ", el("strong", "host"), " syntax to register",
" clean up procedures when the component is removed from the app."
),
),
// dispatchEvent
el(h3, "Final notes"),
el("p", "The library also provides a method to dispatch the events."),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el(prevNext, info)
)

View File

@ -3,7 +3,7 @@ import { el } from "deka-dom-el";
import { header } from "./layout/head.html.js";
import { example } from "./components/example.html.js";
import { prevNext } from "./components/prevNext.html.js";
import { prevNext } from "./components/pageUtils.html.js";
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){