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

Adds Web Componens page into the doc and doc enhancements (#21)

This commit is contained in:
Jan Andrle 2024-11-22 10:20:59 +01:00 committed by GitHub
parent 9faa24b7b3
commit 0ea5234a4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 2446 additions and 1159 deletions

View File

@ -7,7 +7,7 @@ const css= echo.css`
`; `;
$.api("", true) $.api("", true)
.option("--minify", "Level of minification [ full, partial (default) ]") .option("--minify", "Level of minification [ no, full, partial (default) ]")
.action(async function main({ minify= "partial" }){ .action(async function main({ minify= "partial" }){
for(const file_root of files){ for(const file_root of files){
const file= file_root+".js"; const file= file_root+".js";
@ -17,11 +17,11 @@ $.api("", true)
"npx esbuild '::file::'", "npx esbuild '::file::'",
"--platform=neutral", "--platform=neutral",
"--bundle", "--bundle",
minify==="full" ? "--minify" : "--minify-syntax --minify-identifiers", minifyOption(minify),
"--legal-comments=inline", "--legal-comments=inline",
"--packages=external", "--packages=external",
"--outfile='::out::'" "--outfile='::out::'"
].join(" "), { file, out }); ].filter(Boolean).join(" "), { file, out });
if(esbuild_output.code) if(esbuild_output.code)
return $.exit(esbuild_output.code, echo(esbuild_output.stderr)); return $.exit(esbuild_output.code, echo(esbuild_output.stderr));
echoVariant(esbuild_output.stderr.split("\n")[1].trim()+ " (esbuild)"); echoVariant(esbuild_output.stderr.split("\n")[1].trim()+ " (esbuild)");
@ -57,6 +57,12 @@ $.api("", true)
}) })
.parse(); .parse();
/** @param {"no"|"full"|"partial"} level */
function minifyOption(level= "partial"){
if("no"===level) return undefined;
if("full"===level) return "--minify";
return "--minify-syntax --minify-identifiers";
}
function echoVariant(name){ function echoVariant(name){
return echo("%c✓ "+name, css.info+css); return echo("%c✓ "+name, css.info+css);
} }

View File

@ -61,7 +61,7 @@ function lt(t, e, n) {
return Reflect.set(t, e, ""); return Reflect.set(t, e, "");
} }
} }
var C = "__dde_lifecyclesToEvents", _ = "dde:connected", O = "dde:disconnected", M = "dde:attributeChanged"; var O = "__dde_lifecyclesToEvents", _ = "dde:connected", C = "dde:disconnected", M = "dde:attributeChanged";
// src/dom.js // src/dom.js
var A = [{ var A = [{
@ -102,50 +102,50 @@ function ht(t) {
return t.append === Y || (t.appendOriginal = t.append, t.append = Y), t; return t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;
} }
var $; var $;
function j(t, e, ...n) { function P(t, e, ...n) {
let r = W(this), o = 0, c, i; let r = W(this), o = 0, c, i;
switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) { switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) {
case typeof t == "function": { case typeof t == "function": {
o = 1, m.push({ scope: t, host: (...v) => v.length ? (o === 1 ? n.unshift(...v) : v.forEach((l) => l(i)), void 0) : i }), c = t(e || void 0); o = 1, m.push({ scope: t, host: (...v) => v.length ? (o === 1 ? n.unshift(...v) : v.forEach((h) => h(i)), void 0) : i }), c = t(e || void 0);
let a = c instanceof d.F; let a = c instanceof d.F;
if (c.nodeName === "#comment") if (c.nodeName === "#comment") break;
break; let l = P.mark({
let h = j.mark({
type: "component", type: "component",
name: t.name, name: t.name,
host: a ? "this" : "parentElement" host: a ? "this" : "parentElement"
}); });
c.prepend(h), a && (i = h); c.prepend(l), a && (i = l);
break; break;
} }
case t === "#text": case t === "#text":
c = P.call(this, d.D.createTextNode(""), e); c = j.call(this, d.D.createTextNode(""), e);
break; break;
case (t === "<>" || !t): case (t === "<>" || !t):
c = P.call(this, d.D.createDocumentFragment(), e); c = j.call(this, d.D.createDocumentFragment(), e);
break; break;
case !!$: case !!$:
c = P.call(this, d.D.createElementNS($, t), e); c = j.call(this, d.D.createElementNS($, t), e);
break; break;
case !c: case !c:
c = P.call(this, d.D.createElement(t), e); c = j.call(this, d.D.createElement(t), e);
} }
return ht(c), i || (i = c), n.forEach((a) => a(i)), o && m.pop(), o = 2, c; return ht(c), i || (i = c), n.forEach((a) => a(i)), o && m.pop(), o = 2, c;
} }
function Wt(t, e = t, n = void 0) { function Wt(t, e, n) {
typeof e != "object" && (n = e, e = t);
let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((i, a) => Reflect.set(i, a.name || r, a) && i, {}), c = T(o, r); let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((i, a) => Reflect.set(i, a.name || r, a) && i, {}), c = T(o, r);
if (t.append = new Proxy(t.append, { if (t.append = new Proxy(t.append, {
apply(i, a, h) { apply(i, a, l) {
if (!h.length) if (l[0] === e) return i.apply(t, l);
return t; if (!l.length) return t;
let v = d.D.createDocumentFragment(); let v = d.D.createDocumentFragment();
for (let l of h) { for (let h of l) {
if (!l || !l.slot) { if (!h || !h.slot) {
c && v.appendChild(l); c && v.append(h);
continue; continue;
} }
let x = l.slot, y = o[x]; let x = h.slot, w = o[x];
vt(l, "remove", "slot"), y && (bt(y, l, n), Reflect.deleteProperty(o, x)); vt(h, "remove", "slot"), w && (bt(w, h, n), Reflect.deleteProperty(o, x));
} }
return c && (o[r].replaceWith(v), Reflect.deleteProperty(o, r)), t.append = i, t; return c && (o[r].replaceWith(v), Reflect.deleteProperty(o, r)), t.append = i, t;
} }
@ -158,12 +158,12 @@ function Wt(t, e = t, n = void 0) {
function bt(t, e, n) { function bt(t, e, n) {
n && n(t, e); n && n(t, e);
try { try {
t.replaceWith(P(e, { className: [e.className, t.className], dataset: { ...t.dataset } })); t.replaceWith(j(e, { className: [e.className, t.className], dataset: { ...t.dataset } }));
} catch { } catch {
t.replaceWith(e); t.replaceWith(e);
} }
} }
j.mark = function(t, e = !1) { P.mark = function(t, e = !1) {
t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" "); t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" ");
let n = e ? "" : "/", r = d.D.createComment(`<dde:mark ${t}${d.ssr}${n}>`); let n = e ? "" : "/", r = d.D.createComment(`<dde:mark ${t}${d.ssr}${n}>`);
return e && (r.end = d.D.createComment("</dde:mark>")), r; return e && (r.end = d.D.createComment("</dde:mark>")), r;
@ -172,14 +172,13 @@ function qt(t) {
let e = this; let e = this;
return function(...r) { return function(...r) {
$ = t; $ = t;
let o = j.call(e, ...r); let o = P.call(e, ...r);
return $ = void 0, o; return $ = void 0, o;
}; };
} }
var U = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: tt } = d; var U = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: tt } = d;
function P(t, ...e) { function j(t, ...e) {
if (!e.length) if (!e.length) return t;
return t;
U.set(t, rt(t, this)); U.set(t, rt(t, this));
for (let [n, r] of Object.entries(Object.assign({}, ...e))) for (let [n, r] of Object.entries(Object.assign({}, ...e)))
nt.call(this, t, n, r); nt.call(this, t, n, r);
@ -191,13 +190,11 @@ function nt(t, e, n) {
t, t,
e, e,
n, n,
(a, h) => nt.call(c, t, a, h) (a, l) => nt.call(c, t, a, l)
); );
let [i] = e; let [i] = e;
if (i === "=") if (i === "=") return r(e.slice(1), n);
return r(e.slice(1), n); if (i === ".") return et(t, e.slice(1), n);
if (i === ".")
return et(t, e.slice(1), n);
if (/(aria|data)([A-Z])/.test(e)) if (/(aria|data)([A-Z])/.test(e))
return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n); return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n);
switch (e === "className" && (e = "class"), e) { switch (e === "className" && (e = "class"), e) {
@ -206,20 +203,19 @@ function nt(t, e, n) {
case "textContent": case "textContent":
return tt(t, e, n); return tt(t, e, n);
case "style": case "style":
if (typeof n != "object") if (typeof n != "object") break;
break; /* falls through */
case "dataset": case "dataset":
return I(o, n, et.bind(null, t[e])); return I(o, n, et.bind(null, t[e]));
case "ariaset": case "ariaset":
return I(o, n, (a, h) => r("aria-" + a, h)); return I(o, n, (a, l) => r("aria-" + a, l));
case "classList": case "classList":
return gt.call(c, t, n); return gt.call(c, t, n);
} }
return Et(t, e) ? tt(t, e, n) : r(e, n); return Et(t, e) ? tt(t, e, n) : r(e, n);
} }
function rt(t, e) { function rt(t, e) {
if (U.has(t)) if (U.has(t)) return U.get(t);
return U.get(t);
let r = (t instanceof d.S ? xt : mt).bind(null, t, "Attribute"), o = W(e); let r = (t instanceof d.S ? xt : mt).bind(null, t, "Attribute"), o = W(e);
return { setRemoveAttr: r, s: o }; return { setRemoveAttr: r, s: o };
} }
@ -238,14 +234,12 @@ function vt(t, e, n, r) {
return t instanceof d.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r); return t instanceof d.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r);
} }
function Et(t, e) { function Et(t, e) {
if (!(e in t)) if (!(e in t)) return !1;
return !1;
let n = ot(t, e); let n = ot(t, e);
return !S(n.set); return !S(n.set);
} }
function ot(t, e) { function ot(t, e) {
if (t = Object.getPrototypeOf(t), !t) if (t = Object.getPrototypeOf(t), !t) return {};
return {};
let n = Object.getOwnPropertyDescriptor(t, e); let n = Object.getOwnPropertyDescriptor(t, e);
return n || ot(t, e); return n || ot(t, e);
} }
@ -270,17 +264,17 @@ function et(t, e, n) {
} }
// src/events-observer.js // src/events-observer.js
var D = d.M ? wt() : new Proxy({}, { var D = d.M ? yt() : new Proxy({}, {
get() { get() {
return () => { return () => {
}; };
} }
}); });
function wt() { function yt() {
let t = /* @__PURE__ */ new Map(), e = !1, n = (s) => function(u) { let t = /* @__PURE__ */ new Map(), e = !1, n = (s) => function(u) {
for (let f of u) for (let f of u)
if (f.type === "childList") { if (f.type === "childList") {
if (l(f.addedNodes, !0)) { if (h(f.addedNodes, !0)) {
s(); s();
continue; continue;
} }
@ -299,8 +293,7 @@ function wt() {
f.connected.has(u) || (f.connected.add(u), f.length_c += 1); f.connected.has(u) || (f.connected.add(u), f.length_c += 1);
}, },
offConnected(s, u) { offConnected(s, u) {
if (!t.has(s)) if (!t.has(s)) return;
return;
let f = t.get(s); let f = t.get(s);
f.connected.has(u) && (f.connected.delete(u), f.length_c -= 1, o(s, f)); f.connected.has(u) && (f.connected.delete(u), f.length_c -= 1, o(s, f));
}, },
@ -310,8 +303,7 @@ function wt() {
f.disconnected.has(u) || (f.disconnected.add(u), f.length_d += 1); f.disconnected.has(u) || (f.disconnected.add(u), f.length_d += 1);
}, },
offDisconnected(s, u) { offDisconnected(s, u) {
if (!t.has(s)) if (!t.has(s)) return;
return;
let f = t.get(s); let f = t.get(s);
f.disconnected.has(u) && (f.disconnected.delete(u), f.length_d -= 1, o(s, f)); f.disconnected.has(u) && (f.disconnected.delete(u), f.length_d -= 1, o(s, f));
} }
@ -320,8 +312,7 @@ function wt() {
u.length_c || u.length_d || (t.delete(s), a()); u.length_c || u.length_d || (t.delete(s), a());
} }
function c(s) { function c(s) {
if (t.has(s)) if (t.has(s)) return t.get(s);
return t.get(s);
let u = { let u = {
connected: /* @__PURE__ */ new WeakSet(), connected: /* @__PURE__ */ new WeakSet(),
length_c: 0, length_c: 0,
@ -336,25 +327,23 @@ function wt() {
function a() { function a() {
!e || t.size || (e = !1, r.disconnect()); !e || t.size || (e = !1, r.disconnect());
} }
function h() { function l() {
return new Promise(function(s) { return new Promise(function(s) {
(requestIdleCallback || requestAnimationFrame)(s); (requestIdleCallback || requestAnimationFrame)(s);
}); });
} }
async function v(s) { async function v(s) {
t.size > 30 && await h(); t.size > 30 && await l();
let u = []; let u = [];
if (!(s instanceof Node)) if (!(s instanceof Node)) return u;
return u;
for (let f of t.keys()) for (let f of t.keys())
f === s || !(f instanceof Node) || s.contains(f) && u.push(f); f === s || !(f instanceof Node) || s.contains(f) && u.push(f);
return u; return u;
} }
function l(s, u) { function h(s, u) {
let f = !1; let f = !1;
for (let b of s) { for (let b of s) {
if (u && v(b).then(l), !t.has(b)) if (u && v(b).then(h), !t.has(b)) continue;
continue;
let N = t.get(b); let N = t.get(b);
N.length_c && (b.dispatchEvent(new Event(_)), N.connected = /* @__PURE__ */ new WeakSet(), N.length_c = 0, N.length_d || t.delete(b), f = !0); N.length_c && (b.dispatchEvent(new Event(_)), N.connected = /* @__PURE__ */ new WeakSet(), N.length_c = 0, N.length_d || t.delete(b), f = !0);
} }
@ -363,12 +352,12 @@ function wt() {
function x(s, u) { function x(s, u) {
let f = !1; let f = !1;
for (let b of s) for (let b of s)
u && v(b).then(x), !(!t.has(b) || !t.get(b).length_d) && ((globalThis.queueMicrotask || setTimeout)(y(b)), f = !0); u && v(b).then(x), !(!t.has(b) || !t.get(b).length_d) && ((globalThis.queueMicrotask || setTimeout)(w(b)), f = !0);
return f; return f;
} }
function y(s) { function w(s) {
return () => { return () => {
s.isConnected || (s.dispatchEvent(new Event(O)), t.delete(s)); s.isConnected || (s.dispatchEvent(new Event(C)), t.delete(s));
}; };
} }
} }
@ -379,24 +368,24 @@ function Zt(t, e, n, r = _t) {
scope: t, scope: t,
host: (...i) => i.length ? i.forEach((a) => a(t)) : t host: (...i) => i.length ? i.forEach((a) => a(t)) : t
}), typeof r == "function" && (r = r.call(t, t)); }), typeof r == "function" && (r = r.call(t, t));
let o = t[C]; let o = t[O];
o || yt(t); o || wt(t);
let c = n.call(t, r); let c = n.call(t, r);
return o || t.dispatchEvent(new Event(_)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(O, D.observe(e), { once: !0 }), m.pop(), e.append(c); return o || t.dispatchEvent(new Event(_)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(C, D.observe(e), { once: !0 }), m.pop(), e.append(c);
} }
function yt(t) { function wt(t) {
return J(t.prototype, "connectedCallback", function(e, n, r) { return J(t.prototype, "connectedCallback", function(e, n, r) {
e.apply(n, r), n.dispatchEvent(new Event(_)); e.apply(n, r), n.dispatchEvent(new Event(_));
}), J(t.prototype, "disconnectedCallback", function(e, n, r) { }), J(t.prototype, "disconnectedCallback", function(e, n, r) {
e.apply(n, r), (globalThis.queueMicrotask || setTimeout)( e.apply(n, r), (globalThis.queueMicrotask || setTimeout)(
() => !n.isConnected && n.dispatchEvent(new Event(O)) () => !n.isConnected && n.dispatchEvent(new Event(C))
); );
}), J(t.prototype, "attributeChangedCallback", function(e, n, r) { }), J(t.prototype, "attributeChangedCallback", function(e, n, r) {
let [o, , c] = r; let [o, , c] = r;
n.dispatchEvent(new CustomEvent(M, { n.dispatchEvent(new CustomEvent(M, {
detail: [o, c] detail: [o, c]
})), e.apply(n, r); })), e.apply(n, r);
}), t.prototype[C] = !0, t; }), t.prototype[O] = !0, t;
} }
function J(t, e, n) { function J(t, e, n) {
t[e] = new Proxy(t[e] || (() => { t[e] = new Proxy(t[e] || (() => {
@ -414,38 +403,36 @@ function Qt(t, e, n) {
return o.dispatchEvent(i); return o.dispatchEvent(i);
}; };
} }
function w(t, e, n) { function y(t, e, n) {
return function(o) { return function(o) {
return o.addEventListener(t, e, n), o; return o.addEventListener(t, e, n), o;
}; };
} }
var it = (t) => Object.assign({}, typeof t == "object" ? t : null, { once: !0 }); var it = (t) => Object.assign({}, typeof t == "object" ? t : null, { once: !0 });
w.connected = function(t, e) { y.connected = function(t, e) {
return e = it(e), function(r) { return e = it(e), function(r) {
return r.addEventListener(_, t, e), r[C] ? r : r.isConnected ? (r.dispatchEvent(new Event(_)), r) : (q(e.signal, () => D.offConnected(r, t)) && D.onConnected(r, t), r); return r.addEventListener(_, t, e), r[O] ? r : r.isConnected ? (r.dispatchEvent(new Event(_)), r) : (q(e.signal, () => D.offConnected(r, t)) && D.onConnected(r, t), r);
}; };
}; };
w.disconnected = function(t, e) { y.disconnected = function(t, e) {
return e = it(e), function(r) { return e = it(e), function(r) {
return r.addEventListener(O, t, e), r[C] || q(e.signal, () => D.offDisconnected(r, t)) && D.onDisconnected(r, t), r; return r.addEventListener(C, t, e), r[O] || q(e.signal, () => D.offDisconnected(r, t)) && D.onDisconnected(r, t), r;
}; };
}; };
var Z = /* @__PURE__ */ new WeakMap(); var Z = /* @__PURE__ */ new WeakMap();
w.disconnectedAsAbort = function(t) { y.disconnectedAsAbort = function(t) {
if (Z.has(t)) if (Z.has(t)) return Z.get(t);
return Z.get(t);
let e = new AbortController(); let e = new AbortController();
return Z.set(t, e), t(w.disconnected(() => e.abort())), e; return Z.set(t, e), t(y.disconnected(() => e.abort())), e;
}; };
var At = /* @__PURE__ */ new WeakSet(); var At = /* @__PURE__ */ new WeakSet();
w.attributeChanged = function(t, e) { y.attributeChanged = function(t, e) {
return typeof e != "object" && (e = {}), function(r) { return typeof e != "object" && (e = {}), function(r) {
if (r.addEventListener(M, t, e), r[C] || At.has(r) || !d.M) if (r.addEventListener(M, t, e), r[O] || At.has(r) || !d.M) return r;
return r;
let o = new d.M(function(i) { let o = new d.M(function(i) {
for (let { attributeName: a, target: h } of i) for (let { attributeName: a, target: l } of i)
h.dispatchEvent( l.dispatchEvent(
new CustomEvent(M, { detail: [a, h.getAttribute(a)] }) new CustomEvent(M, { detail: [a, l.getAttribute(a)] })
); );
}); });
return q(e.signal, () => o.disconnect()) && o.observe(r, { attributes: !0 }), r; return q(e.signal, () => o.disconnect()) && o.observe(r, { attributes: !0 }), r;
@ -465,12 +452,10 @@ var H = [], g = /* @__PURE__ */ new WeakMap();
function E(t, e) { function E(t, e) {
if (typeof t != "function") if (typeof t != "function")
return st(!1, t, e); return st(!1, t, e);
if (z(t)) if (z(t)) return t;
return t;
let n = st(!0), r = function() { let n = st(!0), r = function() {
let [o, ...c] = g.get(r); let [o, ...c] = g.get(r);
if (g.set(r, /* @__PURE__ */ new Set([o])), H.push(r), dt(n, t()), H.pop(), !c.length) if (g.set(r, /* @__PURE__ */ new Set([o])), H.push(r), dt(n, t()), H.pop(), !c.length) return;
return;
let i = g.get(r); let i = g.get(r);
for (let a of c) for (let a of c)
i.has(a) || L(a, r); i.has(a) || L(a, r);
@ -481,15 +466,13 @@ E.action = function(t, e, ...n) {
let r = t[p], { actions: o } = r; let r = t[p], { actions: o } = r;
if (!o || !(e in o)) if (!o || !(e in o))
throw new Error(`'${t}' has no action with name '${e}'!`); throw new Error(`'${t}' has no action with name '${e}'!`);
if (o[e].apply(r, n), r.skip) if (o[e].apply(r, n), r.skip) return delete r.skip;
return delete r.skip;
r.listeners.forEach((c) => c(r.value)); r.listeners.forEach((c) => c(r.value));
}; };
E.on = function t(e, n, r = {}) { E.on = function t(e, n, r = {}) {
let { signal: o } = r; let { signal: o } = r;
if (!(o && o.aborted)) { if (!(o && o.aborted)) {
if (Array.isArray(e)) if (Array.isArray(e)) return e.forEach((c) => t(c, n, r));
return e.forEach((c) => t(c, n, r));
Q(e, n), o && o.addEventListener("abort", () => L(e, n)); Q(e, n), o && o.addEventListener("abort", () => L(e, n));
} }
}; };
@ -504,8 +487,7 @@ E.clear = function(...t) {
} }
function e(n, r) { function e(n, r) {
r.listeners.forEach((o) => { r.listeners.forEach((o) => {
if (r.listeners.delete(o), !g.has(o)) if (r.listeners.delete(o), !g.has(o)) return;
return;
let c = g.get(o); let c = g.get(o);
c.delete(n), !(c.size > 1) && (n.clear(...c), g.delete(o)); c.delete(n), !(c.size > 1) && (n.clear(...c), g.delete(o));
}); });
@ -513,23 +495,23 @@ E.clear = function(...t) {
}; };
var R = "__dde_reactive"; var R = "__dde_reactive";
E.el = function(t, e) { E.el = function(t, e) {
let n = j.mark({ type: "reactive" }, !0), r = n.end, o = d.D.createDocumentFragment(); let n = P.mark({ type: "reactive" }, !0), r = n.end, o = d.D.createDocumentFragment();
o.append(n, r); o.append(n, r);
let { current: c } = m, i = {}, a = (h) => { let { current: c } = m, i = {}, a = (l) => {
if (!n.parentNode || !r.parentNode) if (!n.parentNode || !r.parentNode)
return L(t, a); return L(t, a);
let v = i; let v = i;
i = {}, m.push(c); i = {}, m.push(c);
let l = e(h, function(u, f) { let h = e(l, function(u, f) {
let b; let b;
return T(v, u) ? (b = v[u], delete v[u]) : b = f(), i[u] = b, b; return T(v, u) ? (b = v[u], delete v[u]) : b = f(), i[u] = b, b;
}); });
m.pop(), Array.isArray(l) || (l = [l]); m.pop(), Array.isArray(h) || (h = [h]);
let x = document.createComment(""); let x = document.createComment("");
l.push(x), n.after(...l); h.push(x), n.after(...h);
let y; let w;
for (; (y = x.nextSibling) && y !== r; ) for (; (w = x.nextSibling) && w !== r; )
y.remove(); w.remove();
x.remove(), n.isConnected && St(c.host()); x.remove(), n.isConnected && St(c.host());
}; };
return Q(t, a), ft(t, a, n, e), a(t()), o; return Q(t, a), ft(t, a, n, e), a(t()), o;
@ -539,27 +521,26 @@ function St(t) {
t[R] = t[R].filter(([e, n]) => n.isConnected ? !0 : (L(...e), !1)); t[R] = t[R].filter(([e, n]) => n.isConnected ? !0 : (L(...e), !1));
}); });
} }
var Ct = { var Ot = {
_set(t) { _set(t) {
this.value = t; this.value = t;
} }
}; };
function Ot(t) { function Ct(t) {
return function(e, n) { return function(e, n) {
let r = (...c) => c.length ? e.setAttribute(n, ...c) : K(r), o = at(r, e.getAttribute(n), Ct); let r = (...c) => c.length ? e.setAttribute(n, ...c) : K(r), o = at(r, e.getAttribute(n), Ot);
return t[n] = o, o; return t[n] = o, o;
}; };
} }
var G = "__dde_attributes"; var G = "__dde_attributes";
E.observedAttributes = function(t) { E.observedAttributes = function(t) {
let e = t[G] = {}, n = F(t, Ot(e)); let e = t[G] = {}, n = F(t, Ct(e));
return w.attributeChanged(function({ detail: o }) { return y.attributeChanged(function({ detail: o }) {
/*! This maps attributes to signals (`S.observedAttributes`). /*! This maps attributes to signals (`S.observedAttributes`).
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
let [c, i] = o, a = this[G][c]; let [c, i] = o, a = this[G][c];
if (a) if (a) return E.action(a, "_set", i);
return E.action(a, "_set", i); })(t), y.disconnected(function() {
})(t), w.disconnected(function() {
/*! This removes all signals mapped to attributes (`S.observedAttributes`). /*! This removes all signals mapped to attributes (`S.observedAttributes`).
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
E.clear(...Object.values(this[G])); E.clear(...Object.values(this[G]));
@ -568,8 +549,7 @@ E.observedAttributes = function(t) {
var ut = { var ut = {
isSignal: z, isSignal: z,
processReactiveAttribute(t, e, n, r) { processReactiveAttribute(t, e, n, r) {
if (!z(n)) if (!z(n)) return n;
return n;
let o = (c) => { let o = (c) => {
if (!t.isConnected) if (!t.isConnected)
return L(n, o); return L(n, o);
@ -581,7 +561,7 @@ var ut = {
function ft(t, e, ...n) { function ft(t, e, ...n) {
let { current: r } = m; let { current: r } = m;
r.prevent || r.host(function(o) { r.prevent || r.host(function(o) {
o[R] || (o[R] = [], w.disconnected( o[R] || (o[R] = [], y.disconnected(
() => ( () => (
/*! /*!
* Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, ?). * Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, ?).
@ -633,14 +613,12 @@ function Rt() {
return H[H.length - 1]; return H[H.length - 1];
} }
function K(t) { function K(t) {
if (!t[p]) if (!t[p]) return;
return;
let { value: e, listeners: n } = t[p], r = Rt(); let { value: e, listeners: n } = t[p], r = Rt();
return r && n.add(r), g.has(r) && g.get(r).add(t), e; return r && n.add(r), g.has(r) && g.get(r).add(t), e;
} }
function dt(t, e, n) { function dt(t, e, n) {
if (!t[p]) if (!t[p]) return;
return;
let r = t[p]; let r = t[p];
if (!(!n && r.value === e)) if (!(!n && r.value === e))
return r.value = e, r.listeners.forEach((o) => o(e)), e; return r.value = e, r.listeners.forEach((o) => o(e)), e;
@ -651,15 +629,12 @@ function Q(t, e) {
} }
function L(t, e, n) { function L(t, e, n) {
let r = t[p]; let r = t[p];
if (!r) if (!r) return;
return;
let o = r.listeners.delete(e); let o = r.listeners.delete(e);
if (n && !r.listeners.size) { if (n && !r.listeners.size) {
if (E.clear(t), !g.has(r)) if (E.clear(t), !g.has(r)) return o;
return o;
let c = g.get(r); let c = g.get(r);
if (!g.has(c)) if (!g.has(c)) return o;
return o;
g.get(c).forEach((i) => L(i, c, !0)); g.get(c).forEach((i) => L(i, c, !0));
} }
return o; return o;
@ -670,23 +645,23 @@ B(ut);
globalThis.dde= { globalThis.dde= {
S: E, S: E,
assign: P, assign: j,
assignAttribute: nt, assignAttribute: nt,
chainableAppend: ht, chainableAppend: ht,
classListDeclarative: gt, classListDeclarative: gt,
createElement: j, createElement: P,
createElementNS: qt, createElementNS: qt,
customElementRender: Zt, customElementRender: Zt,
customElementWithDDE: yt, customElementWithDDE: wt,
dispatchEvent: Qt, dispatchEvent: Qt,
el: j, el: P,
elNS: qt, elNS: qt,
elementAttribute: vt, elementAttribute: vt,
empty: Ft, empty: Ft,
isSignal: z, isSignal: z,
lifecyclesToEvents: yt, lifecyclesToEvents: wt,
observedAttributes: _t, observedAttributes: _t,
on: w, on: y,
registerReactivity: B, registerReactivity: B,
scope: m, scope: m,
signal: E, signal: E,

103
dist/dde.js vendored
View File

@ -98,15 +98,14 @@ function Q(t) {
return t.append === $ || (t.appendOriginal = t.append, t.append = $), t; return t.append === $ || (t.appendOriginal = t.append, t.append = $), t;
} }
var T; var T;
function k(t, e, ...n) { function j(t, e, ...n) {
let r = L(this), o = 0, c, f; let r = L(this), o = 0, c, f;
switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) { switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) {
case typeof t == "function": { case typeof t == "function": {
o = 1, S.push({ scope: t, host: (...b) => b.length ? (o === 1 ? n.unshift(...b) : b.forEach((l) => l(f)), void 0) : f }), c = t(e || void 0); o = 1, S.push({ scope: t, host: (...b) => b.length ? (o === 1 ? n.unshift(...b) : b.forEach((h) => h(f)), void 0) : f }), c = t(e || void 0);
let d = c instanceof a.F; let d = c instanceof a.F;
if (c.nodeName === "#comment") if (c.nodeName === "#comment") break;
break; let p = j.mark({
let p = k.mark({
type: "component", type: "component",
name: t.name, name: t.name,
host: d ? "this" : "parentElement" host: d ? "this" : "parentElement"
@ -128,20 +127,21 @@ function k(t, e, ...n) {
} }
return Q(c), f || (f = c), n.forEach((d) => d(f)), o && S.pop(), o = 2, c; return Q(c), f || (f = c), n.forEach((d) => d(f)), o && S.pop(), o = 2, c;
} }
function bt(t, e = t, n = void 0) { function bt(t, e, n) {
typeof e != "object" && (n = e, e = t);
let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((f, d) => Reflect.set(f, d.name || r, d) && f, {}), c = q(o, r); let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((f, d) => Reflect.set(f, d.name || r, d) && f, {}), c = q(o, r);
if (t.append = new Proxy(t.append, { if (t.append = new Proxy(t.append, {
apply(f, d, p) { apply(f, d, p) {
if (!p.length) if (p[0] === e) return f.apply(t, p);
return t; if (!p.length) return t;
let b = a.D.createDocumentFragment(); let b = a.D.createDocumentFragment();
for (let l of p) { for (let h of p) {
if (!l || !l.slot) { if (!h || !h.slot) {
c && b.appendChild(l); c && b.append(h);
continue; continue;
} }
let A = l.slot, _ = o[A]; let A = h.slot, _ = o[A];
tt(l, "remove", "slot"), _ && (X(_, l, n), Reflect.deleteProperty(o, A)); tt(h, "remove", "slot"), _ && (X(_, h, n), Reflect.deleteProperty(o, A));
} }
return c && (o[r].replaceWith(b), Reflect.deleteProperty(o, r)), t.append = f, t; return c && (o[r].replaceWith(b), Reflect.deleteProperty(o, r)), t.append = f, t;
} }
@ -159,7 +159,7 @@ function X(t, e, n) {
t.replaceWith(e); t.replaceWith(e);
} }
} }
k.mark = function(t, e = !1) { j.mark = function(t, e = !1) {
t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" "); t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" ");
let n = e ? "" : "/", r = a.D.createComment(`<dde:mark ${t}${a.ssr}${n}>`); let n = e ? "" : "/", r = a.D.createComment(`<dde:mark ${t}${a.ssr}${n}>`);
return e && (r.end = a.D.createComment("</dde:mark>")), r; return e && (r.end = a.D.createComment("</dde:mark>")), r;
@ -168,14 +168,13 @@ function gt(t) {
let e = this; let e = this;
return function(...r) { return function(...r) {
T = t; T = t;
let o = k.call(e, ...r); let o = j.call(e, ...r);
return T = void 0, o; return T = void 0, o;
}; };
} }
var P = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: U } = a; var P = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: U } = a;
function O(t, ...e) { function O(t, ...e) {
if (!e.length) if (!e.length) return t;
return t;
P.set(t, B(t, this)); P.set(t, B(t, this));
for (let [n, r] of Object.entries(Object.assign({}, ...e))) for (let [n, r] of Object.entries(Object.assign({}, ...e)))
z.call(this, t, n, r); z.call(this, t, n, r);
@ -190,10 +189,8 @@ function z(t, e, n) {
(d, p) => z.call(c, t, d, p) (d, p) => z.call(c, t, d, p)
); );
let [f] = e; let [f] = e;
if (f === "=") if (f === "=") return r(e.slice(1), n);
return r(e.slice(1), n); if (f === ".") return H(t, e.slice(1), n);
if (f === ".")
return H(t, e.slice(1), n);
if (/(aria|data)([A-Z])/.test(e)) if (/(aria|data)([A-Z])/.test(e))
return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n); return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n);
switch (e === "className" && (e = "class"), e) { switch (e === "className" && (e = "class"), e) {
@ -202,8 +199,8 @@ function z(t, e, n) {
case "textContent": case "textContent":
return U(t, e, n); return U(t, e, n);
case "style": case "style":
if (typeof n != "object") if (typeof n != "object") break;
break; /* falls through */
case "dataset": case "dataset":
return M(o, n, H.bind(null, t[e])); return M(o, n, H.bind(null, t[e]));
case "ariaset": case "ariaset":
@ -214,8 +211,7 @@ function z(t, e, n) {
return et(t, e) ? U(t, e, n) : r(e, n); return et(t, e) ? U(t, e, n) : r(e, n);
} }
function B(t, e) { function B(t, e) {
if (P.has(t)) if (P.has(t)) return P.get(t);
return P.get(t);
let r = (t instanceof a.S ? rt : nt).bind(null, t, "Attribute"), o = L(e); let r = (t instanceof a.S ? rt : nt).bind(null, t, "Attribute"), o = L(e);
return { setRemoveAttr: r, s: o }; return { setRemoveAttr: r, s: o };
} }
@ -234,14 +230,12 @@ function tt(t, e, n, r) {
return t instanceof a.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r); return t instanceof a.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r);
} }
function et(t, e) { function et(t, e) {
if (!(e in t)) if (!(e in t)) return !1;
return !1;
let n = I(t, e); let n = I(t, e);
return !E(n.set); return !E(n.set);
} }
function I(t, e) { function I(t, e) {
if (t = Object.getPrototypeOf(t), !t) if (t = Object.getPrototypeOf(t), !t) return {};
return {};
let n = Object.getOwnPropertyDescriptor(t, e); let n = Object.getOwnPropertyDescriptor(t, e);
return n || I(t, e); return n || I(t, e);
} }
@ -276,7 +270,7 @@ function ot() {
let t = /* @__PURE__ */ new Map(), e = !1, n = (i) => function(u) { let t = /* @__PURE__ */ new Map(), e = !1, n = (i) => function(u) {
for (let s of u) for (let s of u)
if (s.type === "childList") { if (s.type === "childList") {
if (l(s.addedNodes, !0)) { if (h(s.addedNodes, !0)) {
i(); i();
continue; continue;
} }
@ -295,8 +289,7 @@ function ot() {
s.connected.has(u) || (s.connected.add(u), s.length_c += 1); s.connected.has(u) || (s.connected.add(u), s.length_c += 1);
}, },
offConnected(i, u) { offConnected(i, u) {
if (!t.has(i)) if (!t.has(i)) return;
return;
let s = t.get(i); let s = t.get(i);
s.connected.has(u) && (s.connected.delete(u), s.length_c -= 1, o(i, s)); s.connected.has(u) && (s.connected.delete(u), s.length_c -= 1, o(i, s));
}, },
@ -306,8 +299,7 @@ function ot() {
s.disconnected.has(u) || (s.disconnected.add(u), s.length_d += 1); s.disconnected.has(u) || (s.disconnected.add(u), s.length_d += 1);
}, },
offDisconnected(i, u) { offDisconnected(i, u) {
if (!t.has(i)) if (!t.has(i)) return;
return;
let s = t.get(i); let s = t.get(i);
s.disconnected.has(u) && (s.disconnected.delete(u), s.length_d -= 1, o(i, s)); s.disconnected.has(u) && (s.disconnected.delete(u), s.length_d -= 1, o(i, s));
} }
@ -316,8 +308,7 @@ function ot() {
u.length_c || u.length_d || (t.delete(i), d()); u.length_c || u.length_d || (t.delete(i), d());
} }
function c(i) { function c(i) {
if (t.has(i)) if (t.has(i)) return t.get(i);
return t.get(i);
let u = { let u = {
connected: /* @__PURE__ */ new WeakSet(), connected: /* @__PURE__ */ new WeakSet(),
length_c: 0, length_c: 0,
@ -340,26 +331,24 @@ function ot() {
async function b(i) { async function b(i) {
t.size > 30 && await p(); t.size > 30 && await p();
let u = []; let u = [];
if (!(i instanceof Node)) if (!(i instanceof Node)) return u;
return u;
for (let s of t.keys()) for (let s of t.keys())
s === i || !(s instanceof Node) || i.contains(s) && u.push(s); s === i || !(s instanceof Node) || i.contains(s) && u.push(s);
return u; return u;
} }
function l(i, u) { function h(i, u) {
let s = !1; let s = !1;
for (let h of i) { for (let l of i) {
if (u && b(h).then(l), !t.has(h)) if (u && b(l).then(h), !t.has(l)) continue;
continue; let m = t.get(l);
let m = t.get(h); m.length_c && (l.dispatchEvent(new Event(g)), m.connected = /* @__PURE__ */ new WeakSet(), m.length_c = 0, m.length_d || t.delete(l), s = !0);
m.length_c && (h.dispatchEvent(new Event(g)), m.connected = /* @__PURE__ */ new WeakSet(), m.length_c = 0, m.length_d || t.delete(h), s = !0);
} }
return s; return s;
} }
function A(i, u) { function A(i, u) {
let s = !1; let s = !1;
for (let h of i) for (let l of i)
u && b(h).then(A), !(!t.has(h) || !t.get(h).length_d) && ((globalThis.queueMicrotask || setTimeout)(_(h)), s = !0); u && b(l).then(A), !(!t.has(l) || !t.get(l).length_d) && ((globalThis.queueMicrotask || setTimeout)(_(l)), s = !0);
return s; return s;
} }
function _(i) { function _(i) {
@ -381,20 +370,20 @@ function Dt(t, e, n, r = it) {
return o || t.dispatchEvent(new Event(g)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(y, w.observe(e), { once: !0 }), S.pop(), e.append(c); return o || t.dispatchEvent(new Event(g)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(y, w.observe(e), { once: !0 }), S.pop(), e.append(c);
} }
function ct(t) { function ct(t) {
return W(t.prototype, "connectedCallback", function(e, n, r) { return k(t.prototype, "connectedCallback", function(e, n, r) {
e.apply(n, r), n.dispatchEvent(new Event(g)); e.apply(n, r), n.dispatchEvent(new Event(g));
}), W(t.prototype, "disconnectedCallback", function(e, n, r) { }), k(t.prototype, "disconnectedCallback", function(e, n, r) {
e.apply(n, r), (globalThis.queueMicrotask || setTimeout)( e.apply(n, r), (globalThis.queueMicrotask || setTimeout)(
() => !n.isConnected && n.dispatchEvent(new Event(y)) () => !n.isConnected && n.dispatchEvent(new Event(y))
); );
}), W(t.prototype, "attributeChangedCallback", function(e, n, r) { }), k(t.prototype, "attributeChangedCallback", function(e, n, r) {
let [o, , c] = r; let [o, , c] = r;
n.dispatchEvent(new CustomEvent(D, { n.dispatchEvent(new CustomEvent(D, {
detail: [o, c] detail: [o, c]
})), e.apply(n, r); })), e.apply(n, r);
}), t.prototype[x] = !0, t; }), t.prototype[x] = !0, t;
} }
function W(t, e, n) { function k(t, e, n) {
t[e] = new Proxy(t[e] || (() => { t[e] = new Proxy(t[e] || (() => {
}), { apply: n }); }), { apply: n });
} }
@ -426,18 +415,16 @@ R.disconnected = function(t, e) {
return r.addEventListener(y, t, e), r[x] || N(e.signal, () => w.offDisconnected(r, t)) && w.onDisconnected(r, t), r; return r.addEventListener(y, t, e), r[x] || N(e.signal, () => w.offDisconnected(r, t)) && w.onDisconnected(r, t), r;
}; };
}; };
var j = /* @__PURE__ */ new WeakMap(); var W = /* @__PURE__ */ new WeakMap();
R.disconnectedAsAbort = function(t) { R.disconnectedAsAbort = function(t) {
if (j.has(t)) if (W.has(t)) return W.get(t);
return j.get(t);
let e = new AbortController(); let e = new AbortController();
return j.set(t, e), t(R.disconnected(() => e.abort())), e; return W.set(t, e), t(R.disconnected(() => e.abort())), e;
}; };
var st = /* @__PURE__ */ new WeakSet(); var st = /* @__PURE__ */ new WeakSet();
R.attributeChanged = function(t, e) { R.attributeChanged = function(t, e) {
return typeof e != "object" && (e = {}), function(r) { return typeof e != "object" && (e = {}), function(r) {
if (r.addEventListener(D, t, e), r[x] || st.has(r) || !a.M) if (r.addEventListener(D, t, e), r[x] || st.has(r) || !a.M) return r;
return r;
let o = new a.M(function(f) { let o = new a.M(function(f) {
for (let { attributeName: d, target: p } of f) for (let { attributeName: d, target: p } of f)
p.dispatchEvent( p.dispatchEvent(
@ -453,12 +440,12 @@ globalThis.dde= {
assignAttribute: z, assignAttribute: z,
chainableAppend: Q, chainableAppend: Q,
classListDeclarative: Y, classListDeclarative: Y,
createElement: k, createElement: j,
createElementNS: gt, createElementNS: gt,
customElementRender: Dt, customElementRender: Dt,
customElementWithDDE: ct, customElementWithDDE: ct,
dispatchEvent: _t, dispatchEvent: _t,
el: k, el: j,
elNS: gt, elNS: gt,
elementAttribute: tt, elementAttribute: tt,
empty: vt, empty: vt,

View File

@ -47,7 +47,7 @@ type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagName
type textContent= string | ddeSignal<string>; type textContent= string | ddeSignal<string>;
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap, TAG extends keyof ExtendedHTMLElementTagNameMap,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : HTMLElement) EL extends ExtendedHTMLElementTagNameMap[TAG]
>( >(
tag_name: TAG, tag_name: TAG,
attrs?: ElementAttributes<EL> | textContent, attrs?: ElementAttributes<EL> | textContent,
@ -58,7 +58,7 @@ export function el(
): ddeDocumentFragment ): ddeDocumentFragment
export function el( export function el(
tag_name: string, tag_name: string,
attrs?: ElementAttributes<HTMLElement>, attrs?: ElementAttributes<HTMLElement> | textContent,
...addons: ddeElementAddon<HTMLElement>[] ...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement ): ddeHTMLElement
@ -101,7 +101,18 @@ export function elNS(
export { elNS as createElementNS } export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL /**
* Mapper function (optional). Pass for coppying attributes, this is NOT implemented by {@link simulateSlots} itself!
* */
type simulateSlotsMapper= (body: HTMLSlotElement, el: HTMLElement)=> void;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL, mapper?: simulateSlotsMapper): EL
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL, mapper?: simulateSlotsMapper): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void; (element: SupportedElement, data?: any)=> void;
@ -177,12 +188,12 @@ export const scope: {
export function customElementRender< export function customElementRender<
EL extends HTMLElement, EL extends HTMLElement,
P extends any = Record<string, any> P extends any = Record<string, string | ddeSignal<string>>
>( >(
custom_element: EL, custom_element: EL,
target: ShadowRoot | EL, target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment, render: (props: P)=> SupportedElement | DocumentFragment,
props?: P | ((...args: any[])=> P) props?: P | ((el: EL)=> P)
): EL ): EL
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
@ -523,7 +534,7 @@ interface signal{
* */ * */
el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<any, any>>; observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
} }
export const signal: signal; export const signal: signal;
export const S: signal; export const S: signal;

View File

@ -59,7 +59,7 @@ function lt(t, e, n) {
return Reflect.set(t, e, ""); return Reflect.set(t, e, "");
} }
} }
var C = "__dde_lifecyclesToEvents", _ = "dde:connected", O = "dde:disconnected", M = "dde:attributeChanged"; var O = "__dde_lifecyclesToEvents", _ = "dde:connected", C = "dde:disconnected", M = "dde:attributeChanged";
// src/dom.js // src/dom.js
var A = [{ var A = [{
@ -100,50 +100,50 @@ function ht(t) {
return t.append === Y || (t.appendOriginal = t.append, t.append = Y), t; return t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;
} }
var $; var $;
function j(t, e, ...n) { function P(t, e, ...n) {
let r = W(this), o = 0, c, i; let r = W(this), o = 0, c, i;
switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) { switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) {
case typeof t == "function": { case typeof t == "function": {
o = 1, m.push({ scope: t, host: (...v) => v.length ? (o === 1 ? n.unshift(...v) : v.forEach((l) => l(i)), void 0) : i }), c = t(e || void 0); o = 1, m.push({ scope: t, host: (...v) => v.length ? (o === 1 ? n.unshift(...v) : v.forEach((h) => h(i)), void 0) : i }), c = t(e || void 0);
let a = c instanceof d.F; let a = c instanceof d.F;
if (c.nodeName === "#comment") if (c.nodeName === "#comment") break;
break; let l = P.mark({
let h = j.mark({
type: "component", type: "component",
name: t.name, name: t.name,
host: a ? "this" : "parentElement" host: a ? "this" : "parentElement"
}); });
c.prepend(h), a && (i = h); c.prepend(l), a && (i = l);
break; break;
} }
case t === "#text": case t === "#text":
c = P.call(this, d.D.createTextNode(""), e); c = j.call(this, d.D.createTextNode(""), e);
break; break;
case (t === "<>" || !t): case (t === "<>" || !t):
c = P.call(this, d.D.createDocumentFragment(), e); c = j.call(this, d.D.createDocumentFragment(), e);
break; break;
case !!$: case !!$:
c = P.call(this, d.D.createElementNS($, t), e); c = j.call(this, d.D.createElementNS($, t), e);
break; break;
case !c: case !c:
c = P.call(this, d.D.createElement(t), e); c = j.call(this, d.D.createElement(t), e);
} }
return ht(c), i || (i = c), n.forEach((a) => a(i)), o && m.pop(), o = 2, c; return ht(c), i || (i = c), n.forEach((a) => a(i)), o && m.pop(), o = 2, c;
} }
function Wt(t, e = t, n = void 0) { function Wt(t, e, n) {
typeof e != "object" && (n = e, e = t);
let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((i, a) => Reflect.set(i, a.name || r, a) && i, {}), c = T(o, r); let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((i, a) => Reflect.set(i, a.name || r, a) && i, {}), c = T(o, r);
if (t.append = new Proxy(t.append, { if (t.append = new Proxy(t.append, {
apply(i, a, h) { apply(i, a, l) {
if (!h.length) if (l[0] === e) return i.apply(t, l);
return t; if (!l.length) return t;
let v = d.D.createDocumentFragment(); let v = d.D.createDocumentFragment();
for (let l of h) { for (let h of l) {
if (!l || !l.slot) { if (!h || !h.slot) {
c && v.appendChild(l); c && v.append(h);
continue; continue;
} }
let x = l.slot, y = o[x]; let x = h.slot, w = o[x];
vt(l, "remove", "slot"), y && (bt(y, l, n), Reflect.deleteProperty(o, x)); vt(h, "remove", "slot"), w && (bt(w, h, n), Reflect.deleteProperty(o, x));
} }
return c && (o[r].replaceWith(v), Reflect.deleteProperty(o, r)), t.append = i, t; return c && (o[r].replaceWith(v), Reflect.deleteProperty(o, r)), t.append = i, t;
} }
@ -156,12 +156,12 @@ function Wt(t, e = t, n = void 0) {
function bt(t, e, n) { function bt(t, e, n) {
n && n(t, e); n && n(t, e);
try { try {
t.replaceWith(P(e, { className: [e.className, t.className], dataset: { ...t.dataset } })); t.replaceWith(j(e, { className: [e.className, t.className], dataset: { ...t.dataset } }));
} catch { } catch {
t.replaceWith(e); t.replaceWith(e);
} }
} }
j.mark = function(t, e = !1) { P.mark = function(t, e = !1) {
t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" "); t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" ");
let n = e ? "" : "/", r = d.D.createComment(`<dde:mark ${t}${d.ssr}${n}>`); let n = e ? "" : "/", r = d.D.createComment(`<dde:mark ${t}${d.ssr}${n}>`);
return e && (r.end = d.D.createComment("</dde:mark>")), r; return e && (r.end = d.D.createComment("</dde:mark>")), r;
@ -170,14 +170,13 @@ function qt(t) {
let e = this; let e = this;
return function(...r) { return function(...r) {
$ = t; $ = t;
let o = j.call(e, ...r); let o = P.call(e, ...r);
return $ = void 0, o; return $ = void 0, o;
}; };
} }
var U = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: tt } = d; var U = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: tt } = d;
function P(t, ...e) { function j(t, ...e) {
if (!e.length) if (!e.length) return t;
return t;
U.set(t, rt(t, this)); U.set(t, rt(t, this));
for (let [n, r] of Object.entries(Object.assign({}, ...e))) for (let [n, r] of Object.entries(Object.assign({}, ...e)))
nt.call(this, t, n, r); nt.call(this, t, n, r);
@ -189,13 +188,11 @@ function nt(t, e, n) {
t, t,
e, e,
n, n,
(a, h) => nt.call(c, t, a, h) (a, l) => nt.call(c, t, a, l)
); );
let [i] = e; let [i] = e;
if (i === "=") if (i === "=") return r(e.slice(1), n);
return r(e.slice(1), n); if (i === ".") return et(t, e.slice(1), n);
if (i === ".")
return et(t, e.slice(1), n);
if (/(aria|data)([A-Z])/.test(e)) if (/(aria|data)([A-Z])/.test(e))
return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n); return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n);
switch (e === "className" && (e = "class"), e) { switch (e === "className" && (e = "class"), e) {
@ -204,20 +201,19 @@ function nt(t, e, n) {
case "textContent": case "textContent":
return tt(t, e, n); return tt(t, e, n);
case "style": case "style":
if (typeof n != "object") if (typeof n != "object") break;
break; /* falls through */
case "dataset": case "dataset":
return I(o, n, et.bind(null, t[e])); return I(o, n, et.bind(null, t[e]));
case "ariaset": case "ariaset":
return I(o, n, (a, h) => r("aria-" + a, h)); return I(o, n, (a, l) => r("aria-" + a, l));
case "classList": case "classList":
return gt.call(c, t, n); return gt.call(c, t, n);
} }
return Et(t, e) ? tt(t, e, n) : r(e, n); return Et(t, e) ? tt(t, e, n) : r(e, n);
} }
function rt(t, e) { function rt(t, e) {
if (U.has(t)) if (U.has(t)) return U.get(t);
return U.get(t);
let r = (t instanceof d.S ? xt : mt).bind(null, t, "Attribute"), o = W(e); let r = (t instanceof d.S ? xt : mt).bind(null, t, "Attribute"), o = W(e);
return { setRemoveAttr: r, s: o }; return { setRemoveAttr: r, s: o };
} }
@ -236,14 +232,12 @@ function vt(t, e, n, r) {
return t instanceof d.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r); return t instanceof d.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r);
} }
function Et(t, e) { function Et(t, e) {
if (!(e in t)) if (!(e in t)) return !1;
return !1;
let n = ot(t, e); let n = ot(t, e);
return !S(n.set); return !S(n.set);
} }
function ot(t, e) { function ot(t, e) {
if (t = Object.getPrototypeOf(t), !t) if (t = Object.getPrototypeOf(t), !t) return {};
return {};
let n = Object.getOwnPropertyDescriptor(t, e); let n = Object.getOwnPropertyDescriptor(t, e);
return n || ot(t, e); return n || ot(t, e);
} }
@ -268,17 +262,17 @@ function et(t, e, n) {
} }
// src/events-observer.js // src/events-observer.js
var D = d.M ? wt() : new Proxy({}, { var D = d.M ? yt() : new Proxy({}, {
get() { get() {
return () => { return () => {
}; };
} }
}); });
function wt() { function yt() {
let t = /* @__PURE__ */ new Map(), e = !1, n = (s) => function(u) { let t = /* @__PURE__ */ new Map(), e = !1, n = (s) => function(u) {
for (let f of u) for (let f of u)
if (f.type === "childList") { if (f.type === "childList") {
if (l(f.addedNodes, !0)) { if (h(f.addedNodes, !0)) {
s(); s();
continue; continue;
} }
@ -297,8 +291,7 @@ function wt() {
f.connected.has(u) || (f.connected.add(u), f.length_c += 1); f.connected.has(u) || (f.connected.add(u), f.length_c += 1);
}, },
offConnected(s, u) { offConnected(s, u) {
if (!t.has(s)) if (!t.has(s)) return;
return;
let f = t.get(s); let f = t.get(s);
f.connected.has(u) && (f.connected.delete(u), f.length_c -= 1, o(s, f)); f.connected.has(u) && (f.connected.delete(u), f.length_c -= 1, o(s, f));
}, },
@ -308,8 +301,7 @@ function wt() {
f.disconnected.has(u) || (f.disconnected.add(u), f.length_d += 1); f.disconnected.has(u) || (f.disconnected.add(u), f.length_d += 1);
}, },
offDisconnected(s, u) { offDisconnected(s, u) {
if (!t.has(s)) if (!t.has(s)) return;
return;
let f = t.get(s); let f = t.get(s);
f.disconnected.has(u) && (f.disconnected.delete(u), f.length_d -= 1, o(s, f)); f.disconnected.has(u) && (f.disconnected.delete(u), f.length_d -= 1, o(s, f));
} }
@ -318,8 +310,7 @@ function wt() {
u.length_c || u.length_d || (t.delete(s), a()); u.length_c || u.length_d || (t.delete(s), a());
} }
function c(s) { function c(s) {
if (t.has(s)) if (t.has(s)) return t.get(s);
return t.get(s);
let u = { let u = {
connected: /* @__PURE__ */ new WeakSet(), connected: /* @__PURE__ */ new WeakSet(),
length_c: 0, length_c: 0,
@ -334,25 +325,23 @@ function wt() {
function a() { function a() {
!e || t.size || (e = !1, r.disconnect()); !e || t.size || (e = !1, r.disconnect());
} }
function h() { function l() {
return new Promise(function(s) { return new Promise(function(s) {
(requestIdleCallback || requestAnimationFrame)(s); (requestIdleCallback || requestAnimationFrame)(s);
}); });
} }
async function v(s) { async function v(s) {
t.size > 30 && await h(); t.size > 30 && await l();
let u = []; let u = [];
if (!(s instanceof Node)) if (!(s instanceof Node)) return u;
return u;
for (let f of t.keys()) for (let f of t.keys())
f === s || !(f instanceof Node) || s.contains(f) && u.push(f); f === s || !(f instanceof Node) || s.contains(f) && u.push(f);
return u; return u;
} }
function l(s, u) { function h(s, u) {
let f = !1; let f = !1;
for (let b of s) { for (let b of s) {
if (u && v(b).then(l), !t.has(b)) if (u && v(b).then(h), !t.has(b)) continue;
continue;
let N = t.get(b); let N = t.get(b);
N.length_c && (b.dispatchEvent(new Event(_)), N.connected = /* @__PURE__ */ new WeakSet(), N.length_c = 0, N.length_d || t.delete(b), f = !0); N.length_c && (b.dispatchEvent(new Event(_)), N.connected = /* @__PURE__ */ new WeakSet(), N.length_c = 0, N.length_d || t.delete(b), f = !0);
} }
@ -361,12 +350,12 @@ function wt() {
function x(s, u) { function x(s, u) {
let f = !1; let f = !1;
for (let b of s) for (let b of s)
u && v(b).then(x), !(!t.has(b) || !t.get(b).length_d) && ((globalThis.queueMicrotask || setTimeout)(y(b)), f = !0); u && v(b).then(x), !(!t.has(b) || !t.get(b).length_d) && ((globalThis.queueMicrotask || setTimeout)(w(b)), f = !0);
return f; return f;
} }
function y(s) { function w(s) {
return () => { return () => {
s.isConnected || (s.dispatchEvent(new Event(O)), t.delete(s)); s.isConnected || (s.dispatchEvent(new Event(C)), t.delete(s));
}; };
} }
} }
@ -377,24 +366,24 @@ function Zt(t, e, n, r = _t) {
scope: t, scope: t,
host: (...i) => i.length ? i.forEach((a) => a(t)) : t host: (...i) => i.length ? i.forEach((a) => a(t)) : t
}), typeof r == "function" && (r = r.call(t, t)); }), typeof r == "function" && (r = r.call(t, t));
let o = t[C]; let o = t[O];
o || yt(t); o || wt(t);
let c = n.call(t, r); let c = n.call(t, r);
return o || t.dispatchEvent(new Event(_)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(O, D.observe(e), { once: !0 }), m.pop(), e.append(c); return o || t.dispatchEvent(new Event(_)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(C, D.observe(e), { once: !0 }), m.pop(), e.append(c);
} }
function yt(t) { function wt(t) {
return J(t.prototype, "connectedCallback", function(e, n, r) { return J(t.prototype, "connectedCallback", function(e, n, r) {
e.apply(n, r), n.dispatchEvent(new Event(_)); e.apply(n, r), n.dispatchEvent(new Event(_));
}), J(t.prototype, "disconnectedCallback", function(e, n, r) { }), J(t.prototype, "disconnectedCallback", function(e, n, r) {
e.apply(n, r), (globalThis.queueMicrotask || setTimeout)( e.apply(n, r), (globalThis.queueMicrotask || setTimeout)(
() => !n.isConnected && n.dispatchEvent(new Event(O)) () => !n.isConnected && n.dispatchEvent(new Event(C))
); );
}), J(t.prototype, "attributeChangedCallback", function(e, n, r) { }), J(t.prototype, "attributeChangedCallback", function(e, n, r) {
let [o, , c] = r; let [o, , c] = r;
n.dispatchEvent(new CustomEvent(M, { n.dispatchEvent(new CustomEvent(M, {
detail: [o, c] detail: [o, c]
})), e.apply(n, r); })), e.apply(n, r);
}), t.prototype[C] = !0, t; }), t.prototype[O] = !0, t;
} }
function J(t, e, n) { function J(t, e, n) {
t[e] = new Proxy(t[e] || (() => { t[e] = new Proxy(t[e] || (() => {
@ -412,38 +401,36 @@ function Qt(t, e, n) {
return o.dispatchEvent(i); return o.dispatchEvent(i);
}; };
} }
function w(t, e, n) { function y(t, e, n) {
return function(o) { return function(o) {
return o.addEventListener(t, e, n), o; return o.addEventListener(t, e, n), o;
}; };
} }
var it = (t) => Object.assign({}, typeof t == "object" ? t : null, { once: !0 }); var it = (t) => Object.assign({}, typeof t == "object" ? t : null, { once: !0 });
w.connected = function(t, e) { y.connected = function(t, e) {
return e = it(e), function(r) { return e = it(e), function(r) {
return r.addEventListener(_, t, e), r[C] ? r : r.isConnected ? (r.dispatchEvent(new Event(_)), r) : (q(e.signal, () => D.offConnected(r, t)) && D.onConnected(r, t), r); return r.addEventListener(_, t, e), r[O] ? r : r.isConnected ? (r.dispatchEvent(new Event(_)), r) : (q(e.signal, () => D.offConnected(r, t)) && D.onConnected(r, t), r);
}; };
}; };
w.disconnected = function(t, e) { y.disconnected = function(t, e) {
return e = it(e), function(r) { return e = it(e), function(r) {
return r.addEventListener(O, t, e), r[C] || q(e.signal, () => D.offDisconnected(r, t)) && D.onDisconnected(r, t), r; return r.addEventListener(C, t, e), r[O] || q(e.signal, () => D.offDisconnected(r, t)) && D.onDisconnected(r, t), r;
}; };
}; };
var Z = /* @__PURE__ */ new WeakMap(); var Z = /* @__PURE__ */ new WeakMap();
w.disconnectedAsAbort = function(t) { y.disconnectedAsAbort = function(t) {
if (Z.has(t)) if (Z.has(t)) return Z.get(t);
return Z.get(t);
let e = new AbortController(); let e = new AbortController();
return Z.set(t, e), t(w.disconnected(() => e.abort())), e; return Z.set(t, e), t(y.disconnected(() => e.abort())), e;
}; };
var At = /* @__PURE__ */ new WeakSet(); var At = /* @__PURE__ */ new WeakSet();
w.attributeChanged = function(t, e) { y.attributeChanged = function(t, e) {
return typeof e != "object" && (e = {}), function(r) { return typeof e != "object" && (e = {}), function(r) {
if (r.addEventListener(M, t, e), r[C] || At.has(r) || !d.M) if (r.addEventListener(M, t, e), r[O] || At.has(r) || !d.M) return r;
return r;
let o = new d.M(function(i) { let o = new d.M(function(i) {
for (let { attributeName: a, target: h } of i) for (let { attributeName: a, target: l } of i)
h.dispatchEvent( l.dispatchEvent(
new CustomEvent(M, { detail: [a, h.getAttribute(a)] }) new CustomEvent(M, { detail: [a, l.getAttribute(a)] })
); );
}); });
return q(e.signal, () => o.disconnect()) && o.observe(r, { attributes: !0 }), r; return q(e.signal, () => o.disconnect()) && o.observe(r, { attributes: !0 }), r;
@ -463,12 +450,10 @@ var H = [], g = /* @__PURE__ */ new WeakMap();
function E(t, e) { function E(t, e) {
if (typeof t != "function") if (typeof t != "function")
return st(!1, t, e); return st(!1, t, e);
if (z(t)) if (z(t)) return t;
return t;
let n = st(!0), r = function() { let n = st(!0), r = function() {
let [o, ...c] = g.get(r); let [o, ...c] = g.get(r);
if (g.set(r, /* @__PURE__ */ new Set([o])), H.push(r), dt(n, t()), H.pop(), !c.length) if (g.set(r, /* @__PURE__ */ new Set([o])), H.push(r), dt(n, t()), H.pop(), !c.length) return;
return;
let i = g.get(r); let i = g.get(r);
for (let a of c) for (let a of c)
i.has(a) || L(a, r); i.has(a) || L(a, r);
@ -479,15 +464,13 @@ E.action = function(t, e, ...n) {
let r = t[p], { actions: o } = r; let r = t[p], { actions: o } = r;
if (!o || !(e in o)) if (!o || !(e in o))
throw new Error(`'${t}' has no action with name '${e}'!`); throw new Error(`'${t}' has no action with name '${e}'!`);
if (o[e].apply(r, n), r.skip) if (o[e].apply(r, n), r.skip) return delete r.skip;
return delete r.skip;
r.listeners.forEach((c) => c(r.value)); r.listeners.forEach((c) => c(r.value));
}; };
E.on = function t(e, n, r = {}) { E.on = function t(e, n, r = {}) {
let { signal: o } = r; let { signal: o } = r;
if (!(o && o.aborted)) { if (!(o && o.aborted)) {
if (Array.isArray(e)) if (Array.isArray(e)) return e.forEach((c) => t(c, n, r));
return e.forEach((c) => t(c, n, r));
Q(e, n), o && o.addEventListener("abort", () => L(e, n)); Q(e, n), o && o.addEventListener("abort", () => L(e, n));
} }
}; };
@ -502,8 +485,7 @@ E.clear = function(...t) {
} }
function e(n, r) { function e(n, r) {
r.listeners.forEach((o) => { r.listeners.forEach((o) => {
if (r.listeners.delete(o), !g.has(o)) if (r.listeners.delete(o), !g.has(o)) return;
return;
let c = g.get(o); let c = g.get(o);
c.delete(n), !(c.size > 1) && (n.clear(...c), g.delete(o)); c.delete(n), !(c.size > 1) && (n.clear(...c), g.delete(o));
}); });
@ -511,23 +493,23 @@ E.clear = function(...t) {
}; };
var R = "__dde_reactive"; var R = "__dde_reactive";
E.el = function(t, e) { E.el = function(t, e) {
let n = j.mark({ type: "reactive" }, !0), r = n.end, o = d.D.createDocumentFragment(); let n = P.mark({ type: "reactive" }, !0), r = n.end, o = d.D.createDocumentFragment();
o.append(n, r); o.append(n, r);
let { current: c } = m, i = {}, a = (h) => { let { current: c } = m, i = {}, a = (l) => {
if (!n.parentNode || !r.parentNode) if (!n.parentNode || !r.parentNode)
return L(t, a); return L(t, a);
let v = i; let v = i;
i = {}, m.push(c); i = {}, m.push(c);
let l = e(h, function(u, f) { let h = e(l, function(u, f) {
let b; let b;
return T(v, u) ? (b = v[u], delete v[u]) : b = f(), i[u] = b, b; return T(v, u) ? (b = v[u], delete v[u]) : b = f(), i[u] = b, b;
}); });
m.pop(), Array.isArray(l) || (l = [l]); m.pop(), Array.isArray(h) || (h = [h]);
let x = document.createComment(""); let x = document.createComment("");
l.push(x), n.after(...l); h.push(x), n.after(...h);
let y; let w;
for (; (y = x.nextSibling) && y !== r; ) for (; (w = x.nextSibling) && w !== r; )
y.remove(); w.remove();
x.remove(), n.isConnected && St(c.host()); x.remove(), n.isConnected && St(c.host());
}; };
return Q(t, a), ft(t, a, n, e), a(t()), o; return Q(t, a), ft(t, a, n, e), a(t()), o;
@ -537,27 +519,26 @@ function St(t) {
t[R] = t[R].filter(([e, n]) => n.isConnected ? !0 : (L(...e), !1)); t[R] = t[R].filter(([e, n]) => n.isConnected ? !0 : (L(...e), !1));
}); });
} }
var Ct = { var Ot = {
_set(t) { _set(t) {
this.value = t; this.value = t;
} }
}; };
function Ot(t) { function Ct(t) {
return function(e, n) { return function(e, n) {
let r = (...c) => c.length ? e.setAttribute(n, ...c) : K(r), o = at(r, e.getAttribute(n), Ct); let r = (...c) => c.length ? e.setAttribute(n, ...c) : K(r), o = at(r, e.getAttribute(n), Ot);
return t[n] = o, o; return t[n] = o, o;
}; };
} }
var G = "__dde_attributes"; var G = "__dde_attributes";
E.observedAttributes = function(t) { E.observedAttributes = function(t) {
let e = t[G] = {}, n = F(t, Ot(e)); let e = t[G] = {}, n = F(t, Ct(e));
return w.attributeChanged(function({ detail: o }) { return y.attributeChanged(function({ detail: o }) {
/*! This maps attributes to signals (`S.observedAttributes`). /*! This maps attributes to signals (`S.observedAttributes`).
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
let [c, i] = o, a = this[G][c]; let [c, i] = o, a = this[G][c];
if (a) if (a) return E.action(a, "_set", i);
return E.action(a, "_set", i); })(t), y.disconnected(function() {
})(t), w.disconnected(function() {
/*! This removes all signals mapped to attributes (`S.observedAttributes`). /*! This removes all signals mapped to attributes (`S.observedAttributes`).
* Investigate `__dde_attributes` key of the element.*/ * Investigate `__dde_attributes` key of the element.*/
E.clear(...Object.values(this[G])); E.clear(...Object.values(this[G]));
@ -566,8 +547,7 @@ E.observedAttributes = function(t) {
var ut = { var ut = {
isSignal: z, isSignal: z,
processReactiveAttribute(t, e, n, r) { processReactiveAttribute(t, e, n, r) {
if (!z(n)) if (!z(n)) return n;
return n;
let o = (c) => { let o = (c) => {
if (!t.isConnected) if (!t.isConnected)
return L(n, o); return L(n, o);
@ -579,7 +559,7 @@ var ut = {
function ft(t, e, ...n) { function ft(t, e, ...n) {
let { current: r } = m; let { current: r } = m;
r.prevent || r.host(function(o) { r.prevent || r.host(function(o) {
o[R] || (o[R] = [], w.disconnected( o[R] || (o[R] = [], y.disconnected(
() => ( () => (
/*! /*!
* Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, ?). * Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, ?).
@ -631,14 +611,12 @@ function Rt() {
return H[H.length - 1]; return H[H.length - 1];
} }
function K(t) { function K(t) {
if (!t[p]) if (!t[p]) return;
return;
let { value: e, listeners: n } = t[p], r = Rt(); let { value: e, listeners: n } = t[p], r = Rt();
return r && n.add(r), g.has(r) && g.get(r).add(t), e; return r && n.add(r), g.has(r) && g.get(r).add(t), e;
} }
function dt(t, e, n) { function dt(t, e, n) {
if (!t[p]) if (!t[p]) return;
return;
let r = t[p]; let r = t[p];
if (!(!n && r.value === e)) if (!(!n && r.value === e))
return r.value = e, r.listeners.forEach((o) => o(e)), e; return r.value = e, r.listeners.forEach((o) => o(e)), e;
@ -649,15 +627,12 @@ function Q(t, e) {
} }
function L(t, e, n) { function L(t, e, n) {
let r = t[p]; let r = t[p];
if (!r) if (!r) return;
return;
let o = r.listeners.delete(e); let o = r.listeners.delete(e);
if (n && !r.listeners.size) { if (n && !r.listeners.size) {
if (E.clear(t), !g.has(r)) if (E.clear(t), !g.has(r)) return o;
return o;
let c = g.get(r); let c = g.get(r);
if (!g.has(c)) if (!g.has(c)) return o;
return o;
g.get(c).forEach((i) => L(i, c, !0)); g.get(c).forEach((i) => L(i, c, !0));
} }
return o; return o;
@ -667,23 +642,23 @@ function L(t, e, n) {
B(ut); B(ut);
export { export {
E as S, E as S,
P as assign, j as assign,
nt as assignAttribute, nt as assignAttribute,
ht as chainableAppend, ht as chainableAppend,
gt as classListDeclarative, gt as classListDeclarative,
j as createElement, P as createElement,
qt as createElementNS, qt as createElementNS,
Zt as customElementRender, Zt as customElementRender,
yt as customElementWithDDE, wt as customElementWithDDE,
Qt as dispatchEvent, Qt as dispatchEvent,
j as el, P as el,
qt as elNS, qt as elNS,
vt as elementAttribute, vt as elementAttribute,
Ft as empty, Ft as empty,
z as isSignal, z as isSignal,
yt as lifecyclesToEvents, wt as lifecyclesToEvents,
_t as observedAttributes, _t as observedAttributes,
w as on, y as on,
B as registerReactivity, B as registerReactivity,
m as scope, m as scope,
E as signal, E as signal,

21
dist/esm.d.ts vendored
View File

@ -47,7 +47,7 @@ type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagName
type textContent= string | ddeSignal<string>; type textContent= string | ddeSignal<string>;
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap, TAG extends keyof ExtendedHTMLElementTagNameMap,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : HTMLElement) EL extends ExtendedHTMLElementTagNameMap[TAG]
>( >(
tag_name: TAG, tag_name: TAG,
attrs?: ElementAttributes<EL> | textContent, attrs?: ElementAttributes<EL> | textContent,
@ -58,7 +58,7 @@ export function el(
): ddeDocumentFragment ): ddeDocumentFragment
export function el( export function el(
tag_name: string, tag_name: string,
attrs?: ElementAttributes<HTMLElement>, attrs?: ElementAttributes<HTMLElement> | textContent,
...addons: ddeElementAddon<HTMLElement>[] ...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement ): ddeHTMLElement
@ -101,7 +101,18 @@ export function elNS(
export { elNS as createElementNS } export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL /**
* Mapper function (optional). Pass for coppying attributes, this is NOT implemented by {@link simulateSlots} itself!
* */
type simulateSlotsMapper= (body: HTMLSlotElement, el: HTMLElement)=> void;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL, mapper?: simulateSlotsMapper): EL
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL, mapper?: simulateSlotsMapper): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void; (element: SupportedElement, data?: any)=> void;
@ -177,12 +188,12 @@ export const scope: {
export function customElementRender< export function customElementRender<
EL extends HTMLElement, EL extends HTMLElement,
P extends any = Record<string, any> P extends any = Record<string, string | ddeSignal<string>>
>( >(
custom_element: EL, custom_element: EL,
target: ShadowRoot | EL, target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment, render: (props: P)=> SupportedElement | DocumentFragment,
props?: P | ((...args: any[])=> P) props?: P | ((el: EL)=> P)
): EL ): EL
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL

103
dist/esm.js vendored
View File

@ -96,15 +96,14 @@ function Q(t) {
return t.append === $ || (t.appendOriginal = t.append, t.append = $), t; return t.append === $ || (t.appendOriginal = t.append, t.append = $), t;
} }
var T; var T;
function k(t, e, ...n) { function j(t, e, ...n) {
let r = L(this), o = 0, c, f; let r = L(this), o = 0, c, f;
switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) { switch ((Object(e) !== e || r.isSignal(e)) && (e = { textContent: e }), !0) {
case typeof t == "function": { case typeof t == "function": {
o = 1, S.push({ scope: t, host: (...b) => b.length ? (o === 1 ? n.unshift(...b) : b.forEach((l) => l(f)), void 0) : f }), c = t(e || void 0); o = 1, S.push({ scope: t, host: (...b) => b.length ? (o === 1 ? n.unshift(...b) : b.forEach((h) => h(f)), void 0) : f }), c = t(e || void 0);
let d = c instanceof a.F; let d = c instanceof a.F;
if (c.nodeName === "#comment") if (c.nodeName === "#comment") break;
break; let p = j.mark({
let p = k.mark({
type: "component", type: "component",
name: t.name, name: t.name,
host: d ? "this" : "parentElement" host: d ? "this" : "parentElement"
@ -126,20 +125,21 @@ function k(t, e, ...n) {
} }
return Q(c), f || (f = c), n.forEach((d) => d(f)), o && S.pop(), o = 2, c; return Q(c), f || (f = c), n.forEach((d) => d(f)), o && S.pop(), o = 2, c;
} }
function bt(t, e = t, n = void 0) { function bt(t, e, n) {
typeof e != "object" && (n = e, e = t);
let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((f, d) => Reflect.set(f, d.name || r, d) && f, {}), c = q(o, r); let r = Symbol.for("default"), o = Array.from(e.querySelectorAll("slot")).reduce((f, d) => Reflect.set(f, d.name || r, d) && f, {}), c = q(o, r);
if (t.append = new Proxy(t.append, { if (t.append = new Proxy(t.append, {
apply(f, d, p) { apply(f, d, p) {
if (!p.length) if (p[0] === e) return f.apply(t, p);
return t; if (!p.length) return t;
let b = a.D.createDocumentFragment(); let b = a.D.createDocumentFragment();
for (let l of p) { for (let h of p) {
if (!l || !l.slot) { if (!h || !h.slot) {
c && b.appendChild(l); c && b.append(h);
continue; continue;
} }
let A = l.slot, _ = o[A]; let A = h.slot, _ = o[A];
tt(l, "remove", "slot"), _ && (X(_, l, n), Reflect.deleteProperty(o, A)); tt(h, "remove", "slot"), _ && (X(_, h, n), Reflect.deleteProperty(o, A));
} }
return c && (o[r].replaceWith(b), Reflect.deleteProperty(o, r)), t.append = f, t; return c && (o[r].replaceWith(b), Reflect.deleteProperty(o, r)), t.append = f, t;
} }
@ -157,7 +157,7 @@ function X(t, e, n) {
t.replaceWith(e); t.replaceWith(e);
} }
} }
k.mark = function(t, e = !1) { j.mark = function(t, e = !1) {
t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" "); t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" ");
let n = e ? "" : "/", r = a.D.createComment(`<dde:mark ${t}${a.ssr}${n}>`); let n = e ? "" : "/", r = a.D.createComment(`<dde:mark ${t}${a.ssr}${n}>`);
return e && (r.end = a.D.createComment("</dde:mark>")), r; return e && (r.end = a.D.createComment("</dde:mark>")), r;
@ -166,14 +166,13 @@ function gt(t) {
let e = this; let e = this;
return function(...r) { return function(...r) {
T = t; T = t;
let o = k.call(e, ...r); let o = j.call(e, ...r);
return T = void 0, o; return T = void 0, o;
}; };
} }
var P = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: U } = a; var P = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: U } = a;
function O(t, ...e) { function O(t, ...e) {
if (!e.length) if (!e.length) return t;
return t;
P.set(t, B(t, this)); P.set(t, B(t, this));
for (let [n, r] of Object.entries(Object.assign({}, ...e))) for (let [n, r] of Object.entries(Object.assign({}, ...e)))
z.call(this, t, n, r); z.call(this, t, n, r);
@ -188,10 +187,8 @@ function z(t, e, n) {
(d, p) => z.call(c, t, d, p) (d, p) => z.call(c, t, d, p)
); );
let [f] = e; let [f] = e;
if (f === "=") if (f === "=") return r(e.slice(1), n);
return r(e.slice(1), n); if (f === ".") return H(t, e.slice(1), n);
if (f === ".")
return H(t, e.slice(1), n);
if (/(aria|data)([A-Z])/.test(e)) if (/(aria|data)([A-Z])/.test(e))
return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n); return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), r(e, n);
switch (e === "className" && (e = "class"), e) { switch (e === "className" && (e = "class"), e) {
@ -200,8 +197,8 @@ function z(t, e, n) {
case "textContent": case "textContent":
return U(t, e, n); return U(t, e, n);
case "style": case "style":
if (typeof n != "object") if (typeof n != "object") break;
break; /* falls through */
case "dataset": case "dataset":
return M(o, n, H.bind(null, t[e])); return M(o, n, H.bind(null, t[e]));
case "ariaset": case "ariaset":
@ -212,8 +209,7 @@ function z(t, e, n) {
return et(t, e) ? U(t, e, n) : r(e, n); return et(t, e) ? U(t, e, n) : r(e, n);
} }
function B(t, e) { function B(t, e) {
if (P.has(t)) if (P.has(t)) return P.get(t);
return P.get(t);
let r = (t instanceof a.S ? rt : nt).bind(null, t, "Attribute"), o = L(e); let r = (t instanceof a.S ? rt : nt).bind(null, t, "Attribute"), o = L(e);
return { setRemoveAttr: r, s: o }; return { setRemoveAttr: r, s: o };
} }
@ -232,14 +228,12 @@ function tt(t, e, n, r) {
return t instanceof a.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r); return t instanceof a.H ? t[e + "Attribute"](n, r) : t[e + "AttributeNS"](null, n, r);
} }
function et(t, e) { function et(t, e) {
if (!(e in t)) if (!(e in t)) return !1;
return !1;
let n = I(t, e); let n = I(t, e);
return !E(n.set); return !E(n.set);
} }
function I(t, e) { function I(t, e) {
if (t = Object.getPrototypeOf(t), !t) if (t = Object.getPrototypeOf(t), !t) return {};
return {};
let n = Object.getOwnPropertyDescriptor(t, e); let n = Object.getOwnPropertyDescriptor(t, e);
return n || I(t, e); return n || I(t, e);
} }
@ -274,7 +268,7 @@ function ot() {
let t = /* @__PURE__ */ new Map(), e = !1, n = (i) => function(u) { let t = /* @__PURE__ */ new Map(), e = !1, n = (i) => function(u) {
for (let s of u) for (let s of u)
if (s.type === "childList") { if (s.type === "childList") {
if (l(s.addedNodes, !0)) { if (h(s.addedNodes, !0)) {
i(); i();
continue; continue;
} }
@ -293,8 +287,7 @@ function ot() {
s.connected.has(u) || (s.connected.add(u), s.length_c += 1); s.connected.has(u) || (s.connected.add(u), s.length_c += 1);
}, },
offConnected(i, u) { offConnected(i, u) {
if (!t.has(i)) if (!t.has(i)) return;
return;
let s = t.get(i); let s = t.get(i);
s.connected.has(u) && (s.connected.delete(u), s.length_c -= 1, o(i, s)); s.connected.has(u) && (s.connected.delete(u), s.length_c -= 1, o(i, s));
}, },
@ -304,8 +297,7 @@ function ot() {
s.disconnected.has(u) || (s.disconnected.add(u), s.length_d += 1); s.disconnected.has(u) || (s.disconnected.add(u), s.length_d += 1);
}, },
offDisconnected(i, u) { offDisconnected(i, u) {
if (!t.has(i)) if (!t.has(i)) return;
return;
let s = t.get(i); let s = t.get(i);
s.disconnected.has(u) && (s.disconnected.delete(u), s.length_d -= 1, o(i, s)); s.disconnected.has(u) && (s.disconnected.delete(u), s.length_d -= 1, o(i, s));
} }
@ -314,8 +306,7 @@ function ot() {
u.length_c || u.length_d || (t.delete(i), d()); u.length_c || u.length_d || (t.delete(i), d());
} }
function c(i) { function c(i) {
if (t.has(i)) if (t.has(i)) return t.get(i);
return t.get(i);
let u = { let u = {
connected: /* @__PURE__ */ new WeakSet(), connected: /* @__PURE__ */ new WeakSet(),
length_c: 0, length_c: 0,
@ -338,26 +329,24 @@ function ot() {
async function b(i) { async function b(i) {
t.size > 30 && await p(); t.size > 30 && await p();
let u = []; let u = [];
if (!(i instanceof Node)) if (!(i instanceof Node)) return u;
return u;
for (let s of t.keys()) for (let s of t.keys())
s === i || !(s instanceof Node) || i.contains(s) && u.push(s); s === i || !(s instanceof Node) || i.contains(s) && u.push(s);
return u; return u;
} }
function l(i, u) { function h(i, u) {
let s = !1; let s = !1;
for (let h of i) { for (let l of i) {
if (u && b(h).then(l), !t.has(h)) if (u && b(l).then(h), !t.has(l)) continue;
continue; let m = t.get(l);
let m = t.get(h); m.length_c && (l.dispatchEvent(new Event(g)), m.connected = /* @__PURE__ */ new WeakSet(), m.length_c = 0, m.length_d || t.delete(l), s = !0);
m.length_c && (h.dispatchEvent(new Event(g)), m.connected = /* @__PURE__ */ new WeakSet(), m.length_c = 0, m.length_d || t.delete(h), s = !0);
} }
return s; return s;
} }
function A(i, u) { function A(i, u) {
let s = !1; let s = !1;
for (let h of i) for (let l of i)
u && b(h).then(A), !(!t.has(h) || !t.get(h).length_d) && ((globalThis.queueMicrotask || setTimeout)(_(h)), s = !0); u && b(l).then(A), !(!t.has(l) || !t.get(l).length_d) && ((globalThis.queueMicrotask || setTimeout)(_(l)), s = !0);
return s; return s;
} }
function _(i) { function _(i) {
@ -379,20 +368,20 @@ function Dt(t, e, n, r = it) {
return o || t.dispatchEvent(new Event(g)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(y, w.observe(e), { once: !0 }), S.pop(), e.append(c); return o || t.dispatchEvent(new Event(g)), e.nodeType === 11 && typeof e.mode == "string" && t.addEventListener(y, w.observe(e), { once: !0 }), S.pop(), e.append(c);
} }
function ct(t) { function ct(t) {
return W(t.prototype, "connectedCallback", function(e, n, r) { return k(t.prototype, "connectedCallback", function(e, n, r) {
e.apply(n, r), n.dispatchEvent(new Event(g)); e.apply(n, r), n.dispatchEvent(new Event(g));
}), W(t.prototype, "disconnectedCallback", function(e, n, r) { }), k(t.prototype, "disconnectedCallback", function(e, n, r) {
e.apply(n, r), (globalThis.queueMicrotask || setTimeout)( e.apply(n, r), (globalThis.queueMicrotask || setTimeout)(
() => !n.isConnected && n.dispatchEvent(new Event(y)) () => !n.isConnected && n.dispatchEvent(new Event(y))
); );
}), W(t.prototype, "attributeChangedCallback", function(e, n, r) { }), k(t.prototype, "attributeChangedCallback", function(e, n, r) {
let [o, , c] = r; let [o, , c] = r;
n.dispatchEvent(new CustomEvent(D, { n.dispatchEvent(new CustomEvent(D, {
detail: [o, c] detail: [o, c]
})), e.apply(n, r); })), e.apply(n, r);
}), t.prototype[x] = !0, t; }), t.prototype[x] = !0, t;
} }
function W(t, e, n) { function k(t, e, n) {
t[e] = new Proxy(t[e] || (() => { t[e] = new Proxy(t[e] || (() => {
}), { apply: n }); }), { apply: n });
} }
@ -424,18 +413,16 @@ R.disconnected = function(t, e) {
return r.addEventListener(y, t, e), r[x] || N(e.signal, () => w.offDisconnected(r, t)) && w.onDisconnected(r, t), r; return r.addEventListener(y, t, e), r[x] || N(e.signal, () => w.offDisconnected(r, t)) && w.onDisconnected(r, t), r;
}; };
}; };
var j = /* @__PURE__ */ new WeakMap(); var W = /* @__PURE__ */ new WeakMap();
R.disconnectedAsAbort = function(t) { R.disconnectedAsAbort = function(t) {
if (j.has(t)) if (W.has(t)) return W.get(t);
return j.get(t);
let e = new AbortController(); let e = new AbortController();
return j.set(t, e), t(R.disconnected(() => e.abort())), e; return W.set(t, e), t(R.disconnected(() => e.abort())), e;
}; };
var st = /* @__PURE__ */ new WeakSet(); var st = /* @__PURE__ */ new WeakSet();
R.attributeChanged = function(t, e) { R.attributeChanged = function(t, e) {
return typeof e != "object" && (e = {}), function(r) { return typeof e != "object" && (e = {}), function(r) {
if (r.addEventListener(D, t, e), r[x] || st.has(r) || !a.M) if (r.addEventListener(D, t, e), r[x] || st.has(r) || !a.M) return r;
return r;
let o = new a.M(function(f) { let o = new a.M(function(f) {
for (let { attributeName: d, target: p } of f) for (let { attributeName: d, target: p } of f)
p.dispatchEvent( p.dispatchEvent(
@ -450,12 +437,12 @@ export {
z as assignAttribute, z as assignAttribute,
Q as chainableAppend, Q as chainableAppend,
Y as classListDeclarative, Y as classListDeclarative,
k as createElement, j as createElement,
gt as createElementNS, gt as createElementNS,
Dt as customElementRender, Dt as customElementRender,
ct as customElementWithDDE, ct as customElementWithDDE,
_t as dispatchEvent, _t as dispatchEvent,
k as el, j as el,
gt as elNS, gt as elNS,
tt as elementAttribute, tt as elementAttribute,
vt as empty, vt as empty,

View File

@ -145,6 +145,7 @@ main > *{
--shiki-token-punctuation: var(--code); --shiki-token-punctuation: var(--code);
--shiki-token-link: #EE0000; --shiki-token-link: #EE0000;
white-space: pre; white-space: pre;
tab-size: 2; tab-size: 2;
overflow: scroll; overflow: scroll;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,15 +14,14 @@ ${host}{
--shiki-token-punctuation: var(--code); --shiki-token-punctuation: var(--code);
--shiki-token-link: #EE0000; --shiki-token-link: #EE0000;
white-space: pre; white-space: pre;
tab-size: 2;${""/* TODO: allow custom tab size?! */} tab-size: 2; /* TODO: allow custom tab size?! */
overflow: scroll; overflow: scroll;
} }
${host}[data-js=todo]{ ${host}[data-js=todo]{
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--standard-border-radius); border-radius: var(--standard-border-radius);
margin-bottom: 1rem; margin-bottom: 1rem;
${/* to fix shift when → dataJS=done */""} margin-top: 18.4px; /* to fix shift when → dataJS=done */
margin-top: 18.4px;
padding: 1rem 1.4rem; padding: 1rem 1.4rem;
} }
`; `;

View File

@ -0,0 +1,23 @@
import { customElementWithDDE, el, on } from "deka-dom-el";
export class HTMLCustomElement extends HTMLElement{
static tagName= "custom-element";
connectedCallback(){
this.append(
el("p", "Hello from custom element!")
);
}
}
customElementWithDDE(HTMLCustomElement);
customElements.define(HTMLCustomElement.tagName, HTMLCustomElement);
const instance= el(HTMLCustomElement.tagName);
on.connected( // preffered
e=> console.log("Element connected to the DOM (v1):", e)
)(instance);
instance.addEventListener(
"dde:connected",
e=> console.log("Element connected to the DOM (v2):", e)
);
document.body.append(
instance,
);

View File

@ -0,0 +1,33 @@
import {
customElementRender,
customElementWithDDE,
} from "deka-dom-el";
export class HTMLCustomElement extends HTMLElement{
static tagName= "custom-element";
static observedAttributes= [ "attr" ];
connectedCallback(){
customElementRender(
this,
this.attachShadow({ mode: "open" }),
ddeComponent
);
}
set attr(value){ this.setAttribute("attr", value); }
get attr(){ return this.getAttribute("attr"); }
}
import { el, on, scope } from "deka-dom-el";
function ddeComponent({ attr }){
scope.host(
on.connected(e=> console.log(e.target.outerHTML)),
);
return el().append(
el("p", `Hello from Custom Element with attribute '${attr}'`)
);
}
customElementWithDDE(HTMLCustomElement);
customElements.define(HTMLCustomElement.tagName, HTMLCustomElement);
document.body.append(
el(HTMLCustomElement.tagName, { attr: "Attribute" })
);

View File

@ -1,5 +1,5 @@
class CustomHTMLElement extends HTMLElement{ export class HTMLCustomElement extends HTMLElement{
static tagName = "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)` static tagName= "custom-element"; // just suggestion, we can use `el(HTMLCustomElement.tagName)`
static observedAttributes= [ "custom-attribute" ]; static observedAttributes= [ "custom-attribute" ];
constructor(){ constructor(){
super(); super();
@ -18,4 +18,4 @@ class CustomHTMLElement extends HTMLElement{
get customAttribute(){ return this.getAttribute("custom-attribute"); } get customAttribute(){ return this.getAttribute("custom-attribute"); }
set customAttribute(value){ this.setAttribute("custom-attribute", value); } set customAttribute(value){ this.setAttribute("custom-attribute", value); }
} }
customElements.define(CustomHTMLElement.tagName, CustomHTMLElement); customElements.define(HTMLCustomElement.tagName, HTMLCustomElement);

View File

@ -0,0 +1,42 @@
import {
customElementRender,
customElementWithDDE,
observedAttributes,
el, on, scope
} from "deka-dom-el";
import { S } from "deka-dom-el/signals";
export class HTMLCustomElement extends HTMLElement{
static tagName= "custom-element";
static observedAttributes= [ "attr" ];
connectedCallback(){
console.log(observedAttributes(this));
customElementRender(
this,
this.attachShadow({ mode: "open" }),
ddeComponent,
S.observedAttributes
);
}
set attr(value){ this.setAttribute("attr", value); }
get attr(){ return this.getAttribute("attr"); }
}
/** @param {{ attr: ddeSignal<string, {}> }} props */
function ddeComponent({ attr }){
scope.host(
on.connected(e=> console.log(e.target.outerHTML)),
);
return el().append(
el("p", S(()=> `Hello from Custom Element with attribute '${attr()}'`))
);
}
customElementWithDDE(HTMLCustomElement);
customElements.define(HTMLCustomElement.tagName, HTMLCustomElement);
document.body.append(
el(HTMLCustomElement.tagName, { attr: "Attribute" })
);
setTimeout(
()=> document.querySelector(HTMLCustomElement.tagName).setAttribute("attr", "New Value"),
3*750
);

View File

@ -0,0 +1,69 @@
import {
el,
customElementRender,
customElementWithDDE,
} from "deka-dom-el";
function ddeComponent(){
return el().append(
el("style", `
.red{ color: firebrick; }
`),
el("p", { className: "red" }).append(
"Hello from ", el("slot", "Custom Element"), "!"
)
);
}
export class A extends HTMLElement{
static tagName= "custom-element-without";
connectedCallback(){
customElementRender(
this,
this,
ddeComponent
);
}
}
customElementWithDDE(A);
customElements.define(A.tagName, A);
export class B extends HTMLElement{
static tagName= "custom-element-open";
connectedCallback(){
customElementRender(
this,
this.attachShadow({ mode: "open" }),
ddeComponent
);
}
}
customElementWithDDE(B);
customElements.define(B.tagName, B);
export class C extends HTMLElement{
static tagName= "custom-element-closed";
connectedCallback(){
customElementRender(
this,
this.attachShadow({ mode: "closed" }),
ddeComponent
);
}
}
customElementWithDDE(C);
customElements.define(C.tagName, C);
document.body.append(
el(A.tagName).append("Without shadowRoot"),
el("hr"),
el(B.tagName).append("Open shadowRoot"),
el("hr"),
el(C.tagName).append("Closed shadowRoot"),
el("style", `
.red{ color: crimson; }
`),
);
console.log(A.tagName, "expect modifications");
document.body.querySelector(A.tagName).querySelector("p").textContent+= " (editable with JS)";
console.log(B.tagName, "expect modifications");
document.body.querySelector(B.tagName).shadowRoot.querySelector("p").textContent+= " (editable with JS)";
console.log(C.tagName, "expect error ↓");
document.body.querySelector(C.tagName).querySelector("p").textContent+= " (editable with JS)";

View File

@ -0,0 +1,41 @@
import {
customElementRender,
customElementWithDDE,
el,
simulateSlots
} from "deka-dom-el";
export class HTMLCustomElement extends HTMLElement{
static tagName= "custom-slotting";
connectedCallback(){
const c= ()=> simulateSlots(this, ddeComponent());
customElementRender(this, this, c);
}
}
customElementWithDDE(HTMLCustomElement);
customElements.define(HTMLCustomElement.tagName, HTMLCustomElement);
document.body.append(
el(HTMLCustomElement.tagName),
el(HTMLCustomElement.tagName).append(
"Slot"
),
el(ddeComponentSlot),
el(ddeComponentSlot).append(
"Slot"
),
);
function ddeComponent(){
return el().append(
el("p").append(
"Hello ", el("slot", "World")
)
);
}
function ddeComponentSlot(){
return simulateSlots(el().append(
el("p").append(
"Hello ", el("slot", "World")
)
));
}

View File

@ -0,0 +1,6 @@
// pseudo code!
const onchage=
event=>
console.log("Reacting to the:", event); // A
input.addEventListener("change", onchange); // B
input.dispatchEvent(new Event("change")); // C

View File

@ -1,15 +1,15 @@
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { S } from "deka-dom-el/signals"; import { S } from "deka-dom-el/signals";
const clicks= S(0); const clicks= S(0); // A
document.body.append( document.body.append(
el().append( el().append(
el("p", S(()=> el("p", S(()=>
"Hello World "+"🎉".repeat(clicks()) "Hello World "+"🎉".repeat(clicks()) // B
)), )),
el("button", { el("button", {
type: "button", type: "button",
onclick: ()=> clicks(clicks()+1), onclick: ()=> clicks(clicks()+1), // C
textContent: "Fire" textContent: "Fire",
}) })
) )
); );

View File

@ -4,7 +4,7 @@ import { mnemonicUl } from "../mnemonicUl.html.js";
export function mnemonic(){ export function mnemonic(){
return mnemonicUl().append( return mnemonicUl().append(
el("li").append( el("li").append(
el("code", "customElementRender(<custom-element>, <render-function>[, <properties>])"), " — use function to render DOM structure for given <custom-element>", el("code", "customElementRender(<custom-element>, <connect-target>, <render-function>[, <properties>])"), " — use function to render DOM structure for given <custom-element>",
), ),
el("li").append( el("li").append(
el("code", "customElementWithDDE(<custom-element>)"), " — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator", el("code", "customElementWithDDE(<custom-element>)"), " — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator",
@ -17,6 +17,12 @@ export function mnemonic(){
), ),
el("li").append( el("li").append(
el("code", "lifecyclesToEvents(<class-declaration>)"), " — convert lifecycle methods to events, can be also used as decorator", el("code", "lifecyclesToEvents(<class-declaration>)"), " — convert lifecycle methods to events, can be also used as decorator",
) ),
el("li").append(
el("code", "simulateSlots(<class-instance>, <body>[, <mapper>])"), " — simulate slots for Custom Elements without shadow DOM",
),
el("li").append(
el("code", "simulateSlots(<dde-component>[, <mapper>])"), " — simulate slots for “dde”/functional components",
),
); );
} }

View File

@ -1,41 +1,62 @@
import { t, T } from "./utils/index.js";
export const info= { export const info= {
href: "./", href: "./",
title: "Introduction", title: t`Introduction`,
description: "Introducing a library.", description: t`Introducing a library.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js"; import { simplePage } from "./layout/simplePage.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { example } from "./components/example.html.js"; import { example } from "./components/example.html.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
const references= {
w_mvv:{
title: t`Wikipedia: Modelviewviewmodel`,
href: "https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel",
},
w_mvc: {
title: t`Wikipedia: Modelviewcontroller`,
href: "https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller",
},
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces."), el("p", t`The library tries to provide pure JavaScript tool(s) to create reactive interfaces using …`),
el("p").append(
"We start with creating and modifying a static elements and end up with UI templates.", el(h3, t`Event-driven programming (3 parts separation ≡ 3PS)`),
" ", el("p").append(t`
el("i").append( Let's introduce the basic principle on which the library is built. We'll use the JavaScript listener as
"From ", el("code", "document.createElement"), " to ", el("code", "el"), "." a starting point.
), `),
" ", el(code, { src: fileURL("./components/examples/introducing/3ps.js"), page_id }),
"Then we go through the native events system and the way to include it declaratively in UI templates.", el("p").append(...T`
" ", As we can see, in the code at location A we define ${el("em", t`how to react`)} when the function
el("i").append( is called with any event as an argument. At that moment, we ${el("em", t`don't care who/why/how`)}
"From ", el("code", "element.addEventListener"), " to ", el("code", "on"), "." the function was called. Similarly, at point B, we reference to a function to be called on the event
), ${el("em", t`without caring`)} what the function will do at that time. Finally, at point C, we tell
), the application that a change has occurred, in the input, and we ${el("em", t`don't care if/how someone`)}
el("p").append( is listening for the event.
"Next step is providing interactivity not only for our UI templates.", `),
" ", el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }),
"We introduce signals (", el("code", "S"), ") and how them incorporate to UI templates.", el("p").append(...T`
), The library introduces a new type of variable/constant called ${el("em", t`signal`)} allowing us to
el("p").append( to use introduced 3PS pattern in our applications. As you can see it in the example above.
"Now we will clarify how the signals are incorporated into our templates with regard ", `),
"to application performance. This is not the only reason the library uses ", el("p").append(...T`
el("code", "scope"), "s. We will look at how they work in components represented ", Also please notice that there is very similar 3PS pattern used for separate creation of UI and
"in JavaScript by functions." business logic.
), `),
el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id }), el("p").append(...T`
The 3PS is very simplified definition of the pattern. There are more deep/academic definitions more precisely
describe usage in specific situations, see for example ${el("a", { textContent: t`MVVM`, ...references.w_mvv })}
or ${el("a", { textContent: t`MVC`, ...references.w_mvc })}.
`),
el(h3, t`Organization of the documentation`),
); );
} }

View File

@ -1,6 +1,7 @@
import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: "Elements", title: t`Elements`,
description: "Basic concepts of elements modifications and creations.", description: t`Basic concepts of elements modifications and creations.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -11,113 +12,142 @@ import { mnemonic } from "./components/mnemonic/elements-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
const references= {
/** document.createElement() */
mdn_create: {
title: t`MDN documentation page for document.createElement()`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement",
},
/** Interface Description Language (`el.textContent`) */
mdn_idl: {
title: t`MDN page about Interface Description Language`,
href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
},
/** HTMLElement */
mdn_el: {
title: t`MDN documentation page for HTMLElement`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement"
},
/** HTMLParagraphElement */
mdn_p: {
title: t`MDN documentation page for HTMLParagraphElement (\`p\` tag)`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement"
},
/** `[a, b] = [1, 2]` */
mdn_destruct: {
title: t`MDN page about destructuring assignment syntax (e.g. \`[a, b] = [1, 2]\`)`,
href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment",
},
/** document.createElementNS() */
mdn_ns: {
title: t`MDN documentation page for document.createElementNS() (e.g. for SVG elements)`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS",
}
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", "Native JavaScript DOM elements creations"), el("h2", t`Native JavaScript DOM elements creations`),
el("p", "Lets go through all patterns we would like to use and what needs to be improved for better experience."), el("p", t`
Lets go through all patterns we would like to use and what needs to be improved for better experience.
`),
el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }),
el(h3, "Creating element(s) (with custom attributes)"), el(h3, t`Creating element(s) (with custom attributes)`),
el("p").append( el("p").append(...T`
"You can create a native DOM element by using the ", You can create a native DOM element by using the ${el("a", references.mdn_create).append(
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
el("code", "document.createElement()") using ${el("code", "Object.assign()")}. More precisely, this way you can sets some
), ". ", ${el("a", references.mdn_idl).append( el("abbr", { textContent: "IDL", title: "Interface Description Language" }))}
"It is also possible to provide a some attribute(s) declaratively using ", el("code", "Object.assign()"), ". ", also known as a JavaScript property.
"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" })
), " also known as a JavaScript property."
),
el(example, { src: fileURL("./components/examples/elements/nativeCreateElement.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/nativeCreateElement.js"), page_id }),
el("p").append( el("p").append(...T`
"To make this easier, you can use the ", el("code", "el"), " function. ", To make this easier, you can use the ${el("code", "el")} function. Internally in basic examples,
"Internally in basic examples, it is wrapper around ", el("code", "assign(document.createElement(…), { … })"), "." it is wrapper around ${el("code", "assign(document.createElement(…), { … })")}.
), `),
el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }),
el("p").append( el("p").append(...T`
"The ", el("code", "assign"), " function provides improved behaviour of ", el("code", "Object.assign()"), ". ", The ${el("code", "assign")} function provides improved behaviour of ${el("code", "Object.assign()")}.
"You can declaratively sets any IDL and attribute of the given element. ", You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback
"Function prefers IDL and fallback to the ", el("code", "element.setAttribute"), " if there is no writable property in the element prototype." to the ${el("code", "element.setAttribute")} if there is no writable property in the element prototype.
), `),
el("p").append( el("p").append(...T`
"You can study all JavaScript elements interfaces to the corresponding HTML elements. ", You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements
"All HTML elements inherits from ", el("a", { textContent: "HTMLElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" }), ". ", inherits from ${el("a", { textContent: "HTMLElement", ...references.mdn_el })}. To see
"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" }), ". ", all available IDLs for example for paragraphs, see ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}.
"Moreover, the ", el("code", "assign"), " provides a way to sets declaratively some convenient properties:" Moreover, the ${el("code", "assign")} provides a way to sets declaratively some convenient properties:
), `),
el("ul").append( el("ul").append(
el("li").append( el("li").append(...T`
"It is possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attributes using object notation." It is possible to sets ${el("code", "data-*")}/${el("code", "aria-*")} attributes using object notation.
), `),
el("li").append( el("li").append(...T`
"In opposite, it is also possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attribute using camelCase notation." 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(...T`You can use string or object as a value for ${el("code", "style")} property.`),
), el("li").append(...T`
el("li").append( ${el("code", "className")} (IDL preffered)/${el("code", "class")} are ways to add CSS classes
el("code", "className"), " (IDL preffered)/", el("code", "class"), " are ways to add CSS class to the element. ", to the element. You can use string (similarly to ${el("code", "class=\"…\"")} syntax in HTML) or
"You can use string (similarly to ", el("code", "class=\"…\"") ," syntax in HTML) or array of strings. ", array of strings. This is handy to concat conditional classes.
"This is handy to concat conditional classes." `),
), el("li").append(...T`
el("li").append( Use ${el("code", "classList")} to toggle specific classes. This will be handy later when
"Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.", the reactivity via signals is beeing introduced.
), `),
el("li").append( el("li").append(...T`
"The ", el("code", "assign"), " also accepts the ", el("code", "undefined"), " as a value for any property to remove it from the element declaratively. ", The ${el("code", "assign")} also accepts the ${el("code", "undefined")} as a value for any property
"Also for some IDL the corresponding attribute is removed as it can be confusing. ", to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed
el("em").append( as it can be confusing. ${el("em").append(...T`For example, natievly the elements ${el("code", "id")}
"For example, natievly the elements ", el("code", "id"), " is removed by setting the IDL to an empty string." is removed by setting the IDL to an empty string.`)}
) `),
), el("li").append(...T`
el("li").append( You can use ${el("code", "=")} or ${el("code", ".")} to force processing given key as attribute/property
"You can use ", el("code", "="), " or ", el("code", "."), " to force processing given key as attribute/property of the element." of the element.
) `)
),
el("p").append(
"For processing, the ", el("code", "assign"), " internally uses ", el("code", "assignAttribute"), " and ", el("code", "classListDeclarative"), "."
), ),
el("p").append(...T`
For processing, the ${el("code", "assign")} internally uses ${el("code", "assignAttribute")} and
${el("code", "classListDeclarative")}.
`),
el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }),
el(h3, "Native JavaScript templating"), el(h3, t`Native JavaScript templating`),
el("p", "By default, the native JS has no good way to define HTML template using DOM API:"), el("p", t`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(example, { src: fileURL("./components/examples/elements/nativeAppend.js"), page_id }),
el("p").append( el("p").append(...T`
"This library therefore overwrites the ", el("code", "append"), " method of created elements to always return parent element." This library therefore overwrites the ${el("code", "append")} method of created elements to always return
), parent element.
`),
el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }),
el(h3, "Basic (state-less) components"), el(h3, t`Basic (state-less) components`),
el("p").append( el("p").append(...T`
"You can use functions for encapsulation (repeating) logic. ", You can use functions for encapsulation (repeating) logic. The ${el("code", "el")} accepts function
"The ", el("code", "el"), " accepts function as first argument. ", as first argument. In that case, the function should return dom elements and the second argument for
"In that case, the function should return dom elements and the second argument for ", el("code", "el"), " is argument for given element." ${el("code", "el")} is argument for given element.
), `),
el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }),
el("p").append( el("p").append(...T`
"As you can see, in case of state-less/basic components there is no difference", As you can see, in case of state-less/basic components there is no difference between calling component
" between calling component function directly or using ", el("code", "el"), " function.", function directly or using ${el("code", "el")} function.
), `),
el("p", { className: "notice" }).append( el("p", { className: "notice" }).append(...T`
"It is nice to use similar naming convention as native DOM API. ", It is nice to use similar naming convention as native DOM API. This allows us to use
"This allows us to use ", el("a", { textContent: "the destructuring assignment syntax", href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment", title: "Destructuring assignment | MDN" }), ${el("a", { textContent: t`the destructuring assignment syntax`, ...references.mdn_destruct })} and keep
" and keep track of the native API (things are best remembered through regular use).", track of the native API (things are best remembered through regular use).
), `),
el(h3, "Creating non-HTML elements"), el(h3, t`Creating non-HTML elements`),
el("p").append( el("p").append(...T`
"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", Similarly to the native DOM API (${el("a", references.mdn_ns).append(el("code", "document.createElementNS"))})
" we need to tell JavaScript which kind of the element to create.", for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use
" We can use the ", el("code", "elNS"), " function:" the ${el("code", "elNS")} function:
), `),
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
el(mnemonic) el(mnemonic)

View File

@ -1,6 +1,7 @@
import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: "Events and Addons", title: t`Events and Addons`,
description: "Using not only events in UI declaratively.", description: t`Using not only events in UI declaratively.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -11,121 +12,136 @@ import { mnemonic } from "./components/mnemonic/events-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
const references= {
/** element.addEventListener() */
mdn_listen: {
title: t`MDN documentation page for elemetn.addEventListener`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener",
},
/** AbortSignal+element.addEventListener */
mdn_abortListener: {
title: t`MDN documentation page for using AbortSignal with element.addEventListener`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal",
},
/** comparison listening options by WebReflection */
web_events: {
href: "https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944",
},
/** Custom Element lifecycle callbacks */
mdn_customElement: {
href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks"
},
/** MutationObserver */
mdn_mutation: {
href: "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver",
},
/** Readding the element to the DOM fix by Vue */
vue_fix: {
title: t`Vue and Web Components, lifecycle implementation readding the element to the DOM`,
href: "https://vuejs.org/guide/extras/web-components.html#lifecycle",
}
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", "Listenning to the native DOM events and other Addons"), el("h2", t`Listenning to the native DOM events and other Addons`),
el("p").append( el("p").append(...T`
"We quickly introduce helper to listening to the native DOM events.", We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called
" ", ${el("em", t`Addon`)} to incorporate not only this in UI templates declaratively.
"And library syntax/pattern so-called ", el("em", "Addon"), " to", `),
" incorporate not only this in UI templates declaratively."
),
el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }),
el(h3, "Events and listenners"), el(h3, t`Events and listenners`),
el("p").append( el("p").append(...T`
"In JavaScript you can listen to the native DOM events of the given element by using ", 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( ${el("a", references.mdn_listen).append( el("code", "element.addEventListener(type, listener, options)") )}.
el("code", "element.addEventListener(type, listener, options)") The library provides an alternative (${el("code", "on")}) accepting the differen order of the arguments:
), ".", `),
" ",
"The library provides an alternative (", el("code", "on"), ") accepting the differen order",
" of the arguments:"
),
el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }),
el("p").append( el("p").append(...T`
"…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
" accepts only object as the ", el("code", "options"), " (but it is still optional)." object as the ${el("code", "options")} (but it is still optional).
), `),
el("p", { className: "notice" }).append( el("p", { className: "notice" }).append(...T`
"The other difference is that there is ", el("strong", "no"), " ", el("code", "off"), " function.", The other difference is that there is ${el("strong", "no")} ${el("code", "off")} function. You can remove
" ", listener declaratively using ${el("a", { textContent: "AbortSignal", ...references.mdn_abortListener })}:
"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(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
el("div", { className: "notice" }).append( el("div", { className: "notice" }).append(
el("p", "So, there are (typically) three ways to handle events. You can use:"), el("p", t`So, there are (typically) three ways to handle events. You can use:`),
el("ul").append( 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(event)" })`)),
el("li").append( el("code", `el("button", { textContent: "click me", onclick: console.log })`)), 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("li").append( el("code", `el("button", { textContent: "click me" }, on("click", console.log))`))
), ),
el("p").append( el("p").append(...T`
"In the first example we force to use HTML attribute (it corresponds to ", el("code", `<button onclick="console.log(event)">click me</button>`), ").", 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", t`Side note:
el("em", "Side note: this can be useful in case of SSR."), this can be useful in case of SSR.`)} To study difference, you can read a nice summary here:
" ", ${el("a", { textContent: "GIST @WebReflection/web_events.md", ...references.web_events })}.
"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, t`Addons`),
el("p").append( el("p").append(...T`
"From practical point of view, ", el("em", "Addons"), " are just functions that accept any html element", From practical point of view, ${el("em", t`Addons`)} are just functions that accept any HTML element as
" as their first parameter. You can see that the ", el("code", "on(…)"), " fullfills this requirement." their first parameter. You can see that the ${el("code", "on(…)")} fullfills this requirement.
), `),
el("p").append( el("p").append(...T`
"You can use Addons as ≥3rd argument of ", el("code", "el"), " function. This way is possible to extends", You can use Addons as 3rd argument of ${el("code", "el")} function. This way is possible to extends your
" you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:" templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:
), `),
el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }), el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }),
el("p").append( el("p").append(...T`
"As the example shows, you can also provide types in JSDoc+TypeScript by using global type ", el("code", "ddeElementAddon"), ".", As the example shows, you can also provide types in JSDoc+TypeScript by using global type
" ", ${el("code", "ddeElementAddon")}. Also notice, you can use Addons to get element reference.
"Also notice, you can use Addons to get element reference.", `),
), el(h3, t`Life-cycle events`),
el(h3, "Life-cycle events"), el("p").append(...T`
el("p").append( Addons are called immediately when the element is created, even it is not connected to live DOM yet.
"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.
" ", `),
"Therefore, you can understand the Addon to be “oncreate” event." el("p").append(...T`
), The library provide three additional live-cycle events corresponding to how they are named in a case of
el("p").append( custom elements: ${el("code", "on.connected")}, ${el("code", "on.disconnected")} and ${el("code", "on.attributeChanged")}.
"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(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
el("p").append( el("p").append(...T`
"For Custom elements, we will later introduce a way to replace ", el("code", "*Callback"), For Custom elements, we will later introduce a way to replace ${el("code", "*Callback")} syntax with
" syntax with ", el("code", "dde:*"), " events. The ", el("code", "on.*"), " functions then", ${el("code", "dde:*")} events. The ${el("code", "on.*")} functions then listen to the appropriate
" 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" }), ")." Custom Elements events (see ${el("a", { textContent: t`Custom element lifecycle callbacks | MDN`, ...references.mdn_customElement })}).
), `),
el("p").append( el("p").append(...T`
"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"), But, in case of regular elemnets the ${el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")}
" is internaly used to track these events. Therefore, there are some drawbacks:", is internaly used to track these events. Therefore, there are some drawbacks:
), `),
el("ul").append( el("ul").append(
el("li").append( el("li").append(...T`
"To proper listener registration, you need to use ", el("code", "on.*"), " not `on(\"dde:*\", …)`!" To proper listener registration, you need to use ${el("code", "on.*")} not \`on("dde:*", …)\`!
), `),
el("li").append( el("li").append(...T`
"Use sparingly! Internally, library must loop of all registered events and fires event properly.", Use sparingly! Internally, library must loop of all registered events and fires event properly.
" ", ${el("strong", t`It is good practice to use the fact that if an element is removed, its children are
el("strong", "It is good practice to use the fact that if an element is removed, its children are also removed!"), also removed!`)} In this spirit, we will introduce later the ${el("strong", t`host`)} syntax to
" ", register, clean up procedures when the component is removed from the app.
"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."
),
),
el("p").append(
"To provide intuitive behaviour, similar also to how the life-cycle events works in other",
" frameworks/libraries, deka-dom-el library ensures that ", el("code", "on.connected"),
" and ", el("code", "on.disconnected"), " are called only once and only when the element",
" is (dis)connected to live DOM. The solution is inspired by ", el("a", { textContent: "Vue", href: "https://vuejs.org/guide/extras/web-components.html#lifecycle", title: "Vue and Web Components | Lifecycle" }), ".",
" For using native behaviour re-(dis)connecting element, use:"
), ),
el("p").append(...T`
To provide intuitive behaviour, similar also to how the life-cycle events works in other
frameworks/libraries, deka-dom-el library ensures that ${el("code", "on.connected")} and
${el("code", "on.disconnected")} are called only once and only when the element, is (dis)connected to
live DOM. The solution is inspired by ${el("a", { textContent: "Vue", ...references.vue_fix })}. For using
native behaviour re-(dis)connecting element, use:
`),
el("ul").append( el("ul").append(
el("li").append("custom ", el("code", "MutationObserver"), " or logic in (dis)", el("code", "connectedCallback"), " or…"), el("li").append(...T`custom ${el("code", "MutationObserver")} or logic in (dis)${el("code", "connectedCallback")} or…`),
el("li").append("re-add ", el("code", "on.connected"), " or ", el("code", "on.disconnected"), " listeners.") el("li").append(...T`re-add ${el("code", "on.connected")} or ${el("code", "on.disconnected")} listeners.`)
), ),
el(h3, "Final notes"), el(h3, t`Final notes`),
el("p", "The library also provides a method to dispatch the events."), el("p", t`The library also provides a method to dispatch the events.`),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el(mnemonic) el(mnemonic)

View File

@ -1,6 +1,7 @@
import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: "Signals and reactivity", title: t`Signals and reactivity`,
description: "Handling reactivity in UI via signals.", description: t`Handling reactivity in UI via signals.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -11,95 +12,115 @@ import { mnemonic } from "./components/mnemonic/signals-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
const references= {
/** Event-driven programming */
wiki_event_driven: {
title: t`Wikipedia: Event-driven programming`,
href: "https://en.wikipedia.org/wiki/Event-driven_programming",
},
/** Publishsubscribe pattern */
wiki_pubsub: {
title: t`Wikipedia: Publishsubscribe pattern`,
href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern",
},
/** NPM package: fpubsub */
fpubsub: {
title: t`NPM package: fpubsub`,
href: "https://www.npmjs.com/package/fpubsub",
},
/** JS Primitives | MDN */
mdn_primitive: {
title: t`Primitive | MDN`,
href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive",
},
/** useReducer */
mdn_use_reducer: {
title: t`useReducer hook | React docs`,
href: "https://react.dev/reference/react/useReducer",
}
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", "Using signals to manage reactivity"), el("h2", t`Using signals to manage reactivity`),
el("p").append( el("p").append(...T`
"How a program responds to variable data or user", How a program responds to variable data or user interactions is one of the fundamental problems of
" interactions is one of the fundamental problems of programming.", programming. If we desire to solve the issue in a declarative manner, signals may be a viable approach.
" If we desire to solve the issue in a declarative manner,", `),
" signals may be a viable approach.",
),
el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
el(h3, "Introducing signals"), el(h3, t`Introducing signals`),
el("p").append( el("p").append(...T`
"Using signals, we split program logic into the three parts.", Lets re-introduce
" Firstly (α), we create a variable (constant) representing reactive", ${el("a", { textContent: t`3PS principle`, href: "./#h-event-driven-programming--parts-separation--ps" })}.
" value. Somewhere later, we can register (β) a logic reacting", `),
" to the signal value changes. Similarly, in a remaining part (γ), we", el("p").append(...T`
" can update the signal value." Using signals, we split program logic into the three parts. Firstly (α), we create a variable (constant)
), representing reactive value. Somewhere later, we can register (β) a logic reacting to the signal value
changes. Similarly, in a remaining part (γ), we can update the signal value.
`),
el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }),
el("p").append( el("p").append(...T`
"All this is just an example of ", All this is just an example of
el("a", { textContent: "Event-driven programming", href: "https://en.wikipedia.org/wiki/Event-driven_programming", title: "Wikipedia: Event-driven programming" }), ${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })} and
" and ", ${el("a", { textContent: t`Publishsubscribe pattern`, ...references.wiki_pubsub })} (compare for example
el("a", { textContent: "Publishsubscribe pattern", href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern", title: "Wikipedia: Publishsubscribe pattern" }), with ${el("a", { textContent: t`fpubsub library`, ...references.fpubsub })}). All three parts can be in
" (compare for example with ", el("a", { textContent: "fpubsub library", href: "https://www.npmjs.com/package/fpubsub", title: "NPM package: fpubsub" }), ").", some manner independent and still connected to the same reactive entity.
" All three parts can be in some manner independent and still connected", `),
" to the same reactive entity." el("p").append(...T`
), Signals are implemented in the library as functions. To see current value of signal, just call it without
el("p").append( any arguments ${el("code", "console.log(signal())")}. To update the signal value, pass any argument
"Signals are implemented in the library as functions. To see current value", ${el("code", `signal('${t`a new value`}')`)}. For listenning the signal value changes, use
" of signal, just call it without any arguments ", el("code", "console.log(signal())"), ".", ${el("code", "S.on(signal, console.log)")}.
" To update the signal value, pass any argument ", el("code", "signal('a new value')"), ".", `),
" For listenning the signal value changes, use ", el("code", "S.on(signal, console.log)"), "." el("p").append(...T`
), Similarly to the ${el("code", "on")} function to register DOM events listener. You can use
el("p").append( ${el("code", "AbortController")}/${el("code", "AbortSignal")} to ${el("em", "off")}/stop listenning. In
"Similarly to the ", el("code", "on"), " function to register DOM events listener.", example, you also found the way for representing live piece of code computation pattern (derived signal):
" You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to", `),
" ", el("em", "off"), "/stop listenning. In example, you also found the way for representing",
" “live” piece of code computation pattern (derived signal):"
),
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
el(h3, "Signals and actions"), el(h3, t`Signals and actions`),
el("p").append( el("p").append(...T`
el("code", "S(/* primitive */)"), " allows you to declare simple reactive variables, typically", ${el("code", `S(/* ${t`primitive`} */)`)} allows you to declare simple reactive variables, typically, around
" around ", el("em", "immutable"), " ", el("a", { textContent: "primitive types", title: "Primitive | MDN", href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive" }), ".", ${el("em", t`immutable`)} ${el("a", { textContent: t`primitive types`, ...references.mdn_primitive })}.
" ", However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures.
"However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures." `),
),
el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }),
el("p", "…but typical user-case is object/array (maps, sets and other mutable objects):"), el("p", t`…but typical user-case is object/array (maps, sets and other mutable objects):`),
el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }),
el("p").append( el("p").append(...T`
"In some way, you can compare it with ", el("a", { textContent: "useReducer", href: "https://react.dev/reference/react/useReducer", title: "useReducer hook | React docs" }), In some way, you can compare it with ${el("a", { textContent: "useReducer", ...references.mdn_use_reducer })}
" hook from React. So, the ", el("code", "S(<data>, <actions>)"), " pattern creates", hook from React. So, the ${el("code", "S(<data>, <actions>)")} pattern creates a store machine. We can
" a store “machine”. We can then invoke (dispatch) registered action by calling", then invoke (dispatch) registered action by calling ${el("code", "S.action(<signal>, <name>, ...<args>)")}
" ", el("code", "S.action(<signal>, <name>, ...<args>)"), " after the action call", after the action call the signal calls all its listeners. This can be stopped by calling
" the signal calls all its listeners. This can be stopped by calling ", el("code", "this.stopPropagation()"), ${el("code", "this.stopPropagation()")} in the method representing the given action. As it can be seen in
" in the method representing the given action. As it can be seen in examples, the “store” value is", examples, the store value is available also in the function for given action (${el("code", "this.value")}).
" available also in the function for given action (", el("code", "this.value"), ")." `),
),
el(h3, "Reactive DOM attributes and elements"), el(h3, t`Reactive DOM attributes and elements`),
el("p", "There are on basic level two distinc situation to mirror dynamic value into the DOM/UI"), el("p", t`There are on basic level two distinc situation to mirror dynamic value into the DOM/UI`),
el("ol").append( el("ol").append(
el("li", "to change some attribute(s) of existing element(s)"), el("li", t`to change some attribute(s) of existing element(s)`),
el("li", "to generate elements itself dynamically this covers conditions and loops") el("li", t`to generate elements itself dynamically this covers conditions and loops`)
), ),
el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
el("p").append( el("p").append(...T`
"To derived attribute based on value of signal variable just use the signal as", To derived attribute based on value of signal variable just use the signal as a value of the attribute
" a value of the attribute (", el("code", "assign(element, { attribute: S('value') })"), ").", (${el("code", "assign(element, { attribute: S('value') })")}). ${el("code", "assign")}/${el("code", "el")}
" ", el("code", "assign"), "/", el("code", "el"), " provides ways to glue reactive attributes/classes", provides ways to glue reactive attributes/classes more granularly into the DOM. Just use dedicated build-in
" more granularly into the DOM. Just use dedicated build-in attributes ", el("code", "dataset"), ", ", attributes ${el("code", "dataset")}, ${el("code", "ariaset")} and ${el("code", "classList")}.
el("code", "ariaset"), " and ", el("code", "classList"), "." `),
), el("p").append(...T`
el("p").append( For computation, you can use the derived signal (see above) like
"For computation, you can use the “derived signal” (see above) like ", el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })"), ".", ${el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })")}. This is read-only signal
" ", its value is computed based on given function and updated when any signal used in the function changes.
"This is read-only signal its value is computed based on given function and updated when any signal used in the function changes." `),
), el("p").append(...T`
el("p").append( To represent part of the template filled dynamically based on the signal value use
"To represent part of the template filled dynamically based on the signal value use ", el("code", "S.el(signal, DOMgenerator)"), ".", ${el("code", "S.el(signal, DOMgenerator)")}. This was already used in the todo example above or see:
" This was already used in the todo example above or see:" `),
),
el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }),
el(mnemonic) el(mnemonic)

View File

@ -1,6 +1,7 @@
import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: "Scopes and components", title: t`Scopes and components`,
description: "Organizing UI into components", description: t`Organizing UI into components`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -11,67 +12,74 @@ import { mnemonic } from "./components/mnemonic/scopes-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
const references= {
/** Garbage collection on MDN */
garbage_collection: {
title: t`MDN documentation page for Garbage collection`,
href: "https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection",
},
/** Signals */
signals: {
title: t`Signals section on this library`,
href: "./p04-signals#h-introducing-signals",
}
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", "Using functions as UI components"), el("h2", t`Using functions as UI components`),
el("p").append( el("p").append(...T`
"For state-less components we can use functions as UI components (see “Elements” page).", For state-less components we can use functions as UI components (see Elements page). But in real life,
" But in real life, we may need to handle the component live-cycle and provide", we may need to handle the component live-cycle and provide JavaScript the way to properly use
" JavaScript the way to properly use the ", el("a", { textContent: "Garbage collection", href: "https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection", title: "Garbage collection | MDN" }), "." the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}.
), `),
el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
el("p").append( el("p").append(...T`The library therefore use ${el("em", t`scopes`)} to provide these functionalities.`),
"The library therefore use ", el("em", "scopes"), " to provide these functionalities.",
),
el(h3, "Scopes and hosts"), el(h3, t`Scopes and hosts`),
el("p").append( el("p").append(...T`
"The ", el("strong", "host"), " is the name for the element representing the component.", The ${el("strong", "host")} is the name for the element representing the component. This is typically
" This is typically element returned by function. To get reference, you can use ", element returned by function. To get reference, you can use ${el("code", "scope.host()")} to applly addons
el("code", "scope.host()"), " to applly addons just use ", el("code", "scope.host(...<addons>)"), "." just use ${el("code", "scope.host(...<addons>)")}.
), `),
el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }),
el("p").append( el("p").append(...T`
"To better understanding we implement function ", el("code", "elClass"), " helping to create", To better understanding we implement function ${el("code", "elClass")} helping to create component as
" component as class instances." class instances.
), `),
el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }),
el("p").append( el("p").append(...T`
"As you can see, the ", el("code", "scope.host()"), " is stored temporarily and synchronously.", As you can see, the ${el("code", "scope.host()")} is stored temporarily and synchronously. Therefore, at
" Therefore, at least in the beginning of using library, it is the good practise to store", least in the beginning of using library, it is the good practise to store ${el("code", "host")} in the root
" ", el("code", "host"), " in the root of your component. As it may be changed, typically when", of your component. As it may be changed, typically when there is asynchronous code in the component.
" there is asynchronous code in the component." `),
),
el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),
el(h3, "Scopes, signals and cleaning magic"), el(h3, t`Scopes, signals and cleaning magic`),
el("p").append( el("p").append(...T`
"The ", el("code", "host"), " is internally used to register the cleaning procedure,", The ${el("code", "host")} is internally used to register the cleaning procedure, when the component
" when the component (", el("code", "host"), " element) is removed from the DOM." (${el("code", "host")} element) is removed from the DOM.
), `),
el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }),
el("p").append( el("p").append(...T`
"The text content of the paragraph is changing when the value of the signal ", el("code", "textContent"), The text content of the paragraph is changing when the value of the signal ${el("code", "textContent")}
" is changed. Internally, there is association between ", el("code", "textContent"), " and the paragraph", is changed. Internally, there is association between ${el("code", "textContent")} and the paragraph,
" similar to using ", el("code", "S.on(textContent, /* update the paragraph */)"), "." similar to using ${el("code", `S.on(textContent, /* ${t`update the paragraph`} */)`)}.
), `),
el("p").append( el("p").append(...T`
"This listener must be removed when the component is removed from the DOM. To do it, the library", This listener must be removed when the component is removed from the DOM. To do it, the library assign
" assign internally ", el("code", "on.disconnected(/* remove the listener */)(host())"), " to the host element." internally ${el("code", `on.disconnected(/* ${t`remove the listener`} */)(host())`)} to the host element.
), `),
el("p", { className: "notice" }).append( el("p", { className: "notice" }).append(...T`
"The library DOM API and signals works ideally when used declaratively.", The library DOM API and signals works ideally when used declaratively. It means, you split your app logic
" It means, you split your app logic into three parts as it was itroduced in ", el("a", { textContent: "Signals", href: "http://localhost:40911/docs/p04-signals#h-introducing-signals" }), "." into three parts as it was itroduced in ${el("a", { textContent: "Signals", ...references.signals })}.
), `),
el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id }),
el("p").append( el("p").append(...T`
"Strictly speaking, the imperative way of using the library is not prohibited.", Strictly speaking, the imperative way of using the library is not prohibited. Just be careful (rather avoid)
" Just be careful (rather avoid) mixing declarative approach (using signals)", mixing declarative approach (using signals) and imperative manipulation of elements.
" and imperative manipulation of elements.", `),
),
el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }),
el(mnemonic) el(mnemonic)

View File

@ -1,6 +1,7 @@
import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: "Custom elements", title: t`Web Components`,
description: "Using custom elements in combinantion with DDE", description: t`Using custom elements in combinantion with DDE`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -11,24 +12,131 @@ import { mnemonic } from "./components/mnemonic/customElement-init.js";
import { code } from "./components/code.html.js"; import { code } from "./components/code.html.js";
/** @param {string} url */ /** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url); const fileURL= url=> new URL(url, import.meta.url);
const references= {
/** Web Components on MDN */
mdn_web_components: {
title: t`MDN documentation page for Web Components`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components",
},
/** observedAttributes on MDN */
mdn_observedAttributes: {
title: t`MDN documentation page for observedAttributes`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#responding_to_attribute_changes",
},
/** Custom Elements on MDN */
mdn_custom_elements: {
title: t`MDN documentation page for Custom Elements`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements",
},
/** Custom Elements tips from WebReflection */
custom_elements_tips: {
title: t`Ideas and tips from WebReflection`,
href: "https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4",
},
/** Shallow DOM on mdn */
mdn_shadow_dom_depth: {
title: t`MDN documentation page for Shadow DOM`,
href: "https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM",
},
/** Shallow DOM on mdn */
mdn_shadow_dom_slot: {
title: t`MDN documentation page for <slot>`,
href: "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot",
},
/** Shallow DOM */
shadow_dom_depth: {
title: t`Everything you need to know about Shadow DOM (github repo praveenpuglia/shadow-dom-in-depth)`,
href: "https://github.com/praveenpuglia/shadow-dom-in-depth",
},
};
/** @param {import("./types.d.ts").PageAttrs} attrs */ /** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", "Using custom elements in combinantion with DDE"), el("h2", t`Using web components in combinantion with DDE`),
el("p").append( el("p").append(...T`
The DDE library allows for use within ${el("a", references.mdn_web_components).append( el("strong", t`Web Components`) )}
), for dom-tree generation. However, in order to be able to use signals (possibly mapping to registered
${el("a", references.mdn_observedAttributes).append( el("code", "observedAttributes") )}) and additional
functionality is (unfortunately) required to use helpers provided by the library.
`),
el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }),
el(h3, "Custom Elements Introduction"), el(h3, t`Custom Elements Introduction`),
el("p").append( el("p").append(...T`
el("a", { textContent: "Using custom elements", href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements", title: "Article about custom elements on MDN" }) Web Components, specifically Custom Elements, are a set of web platform APIs that allow you to create
), new HTML tags with custom functionality encapsulated within them. This allows for the creation of reusable
components that can be used across web applications.
`),
el("p").append(...T`
To start with, lets see how to use native Custom Elements. As starting point please read
${el("a", references.mdn_custom_elements).append( el("strong", t`Using Custom Elements`), t` on MDN` )}.
To sum up and for mnemonic see following code overview:
`),
el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }),
el("p").append( el("p").append(...T`
el("a", { textContent: "Handy Custom Elements' Patterns", href: "https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4", title: "Ideas and tips from WebReflection" }) For more advanced use of Custom Elements, the summary ${el("a", references.custom_elements_tips)
.append( el("strong", t`Handy Custom Elements Patterns`) )} may be useful. Especially pay attention to
linking HTML attributes and defining setters/getters, this is very helpful to use in combination with
the library (${el("code", `el(HTMLCustomElement.tagName, { customAttribute: "${t`new-value`}" });`)}).
`),
el("p").append(...T`
Also see the Life Cycle Events sections, very similarly we would like to use
${el("a", { textContent: t`DDE events`, href: "./p03-events.html", title: t`See events part of the library documentation` })}.
To do it, the library provides function ${el("code", "customElementWithDDE")}
`),
el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }),
el("h3", t`Custom Elements with DDE`),
el("p").append(...T`
The ${el("code", "customElementWithDDE")} function is only (small) part of the inregration of the library.
More important for coexistence is render component function as a body of the Custom Element. For that, you
can use ${el("code", "customElementRender")} with arguments instance reference, target for connection,
render function and optional properties (will be passed to the render function) see later
`),
el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }),
el("p").append(...T`
as you can see, you can use components created based on the documentation previously introduced. To unlock
full potential, use with combination ${el("code", "customElementWithDDE")} (allows to use livecycle events)
and ${el("code", "observedAttributes")} (converts attributes to render function arguments
${el("em", "default")}) or ${el("code", "S.observedAttributes")} (converts attributes to signals).
`),
el(example, { src: fileURL("./components/examples/customElement/observedAttributes.js"), page_id }),
el(h3, t`Shadow DOM`),
el("p").append(...T`
Shadow DOM is a web platform feature that allows for the encapsulation of a components internal DOM tree
from the rest of the document. This means that styles and scripts applied to the document will not affect
the components internal DOM, and vice versa.
`),
el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }),
el("p").append(...T`
Regarding to ${el("code", "this.attachShadow({ mode: 'open' })")} see quick overview
${el("a", { textContent: t`Using Shadow DOM`, ...references.mdn_shadow_dom_depth })}. An another source of
information can be ${el("a", { textContent: t`Shadow DOM in Depth`, ...references.shadow_dom_depth })}.
`),
el("p").append(...T`
Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append(
el("strong", t`<slot>`), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}:
`),
el(example, { src: fileURL("./components/examples/customElement/simulateSlots.js"), page_id }),
el("p").append(...T`
To sum up:
`),
el("ul").append(
el("li").append(...T`
The use of shadow DOM to encapsulate the internal structure of the custom element, which affects how
the custom element can be styled and modified using JavaScript and CSS.
`),
el("li").append(...T`
The ability to access and modify the internal structure of the custom element using JavaScript, which
is affected by the use of shadow DOM and the mode of the shadow DOM.
`),
el("li").append(...T`
The use of slots to allow for the insertion of content from the parent document into the custom
element, which is affected by the use of shadow DOM and the mode of the shadow DOM.
`),
), ),
el(mnemonic) el(mnemonic)

View File

@ -1,3 +1,4 @@
export { t } from "./utils/index.js";
export const path_target= { export const path_target= {
root: "docs/", root: "docs/",
css: "docs/" css: "docs/"

52
docs_src/utils/index.js Normal file
View File

@ -0,0 +1,52 @@
/**
* This is helper to write texts in code more readable
* and doesnt inpact the finally generated text in HTML.
*
* ```js
* t`
* Hello ${el("b", "world")}!
* How are you?
* ` === "Hello <b>world</b>! How are you?"
* ```
*
* In future, this can be expanded to allow translations.
*
* ```js
* t(key)`text`; // for example
* ```
*
* @param {TemplateStringsArray} strings
* @param {...(string|Node)} values
* @returns {(string|Node)[]}
* */
export function T(strings, ...values){
const out= [];
tT(s=> out.push(s), strings, ...values);
return out;
}
/**
* Similarly to {@link T}, but for only strings.
* @param {TemplateStringsArray} strings
* @param {...string} values
* @returns {string}
* */
export function t(strings, ...values){
let out= "";
tT(s=> out+= s, strings, ...values);
return out;
}
/**
* @param {(input: string|Node)=> void} callback
* @param {TemplateStringsArray} strings
* @param {...(string|Node)} values
* */
function tT(callback, strings, ...values){
const { length }= strings;
const last= length-1;
for(let i= 0; i<length; i++){
const out= strings[i].replace(/\n\s+/g, " ");
callback(!i ? out.trimStart() : i===last ? out.trimEnd() : out);
if(i<values.length) callback(values[i]);
}
}

View File

@ -1,18 +1,22 @@
import { style, el } from './exports.js'; import { style, el, S } from './exports.js';
document.head.append(style.element); document.head.append(style.element);
import { fullNameComponent } from './components/fullNameComponent.js'; import { fullNameComponent } from './components/fullNameComponent.js';
import { todosComponent } from './components/todosComponent.js'; import { todosComponent } from './components/todosComponent.js';
import { CustomHTMLTestElement, CustomSlottingHTMLElement } from "./components/webComponent.js"; import { CustomHTMLTestElement, CustomSlottingHTMLElement } from "./components/webComponent.js";
import { thirdParty } from "./components/3rd-party.js"; import { thirdParty } from "./components/3rd-party.js";
const toggle= S(false);
document.body.append( document.body.append(
el("h1", "Experiments:"), el("h1", "Experiments:"),
el(fullNameComponent), el(fullNameComponent),
el(todosComponent), el(todosComponent),
el(CustomHTMLTestElement.tagName, { name: "attr" }), el(CustomHTMLTestElement.tagName, { name: "attr" }),
el(thirdParty), el(thirdParty),
el(CustomSlottingHTMLElement.tagName).append( el(CustomSlottingHTMLElement.tagName, { onclick: ()=> toggle(!toggle()) }).append(
el("strong", { slot: "name", textContent: "Honzo" }), el("strong", { slot: "name", textContent: "Honzo" }),
el("span", "…default slot") S.el(toggle, is=> is
? el("span", "…default slot")
: el("span", "…custom slot")
)
) )
); );

21
index.d.ts vendored
View File

@ -47,7 +47,7 @@ type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagName
type textContent= string | ddeSignal<string>; type textContent= string | ddeSignal<string>;
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap, TAG extends keyof ExtendedHTMLElementTagNameMap,
EL extends (TAG extends keyof ExtendedHTMLElementTagNameMap ? ExtendedHTMLElementTagNameMap[TAG] : HTMLElement) EL extends ExtendedHTMLElementTagNameMap[TAG]
>( >(
tag_name: TAG, tag_name: TAG,
attrs?: ElementAttributes<EL> | textContent, attrs?: ElementAttributes<EL> | textContent,
@ -58,7 +58,7 @@ export function el(
): ddeDocumentFragment ): ddeDocumentFragment
export function el( export function el(
tag_name: string, tag_name: string,
attrs?: ElementAttributes<HTMLElement>, attrs?: ElementAttributes<HTMLElement> | textContent,
...addons: ddeElementAddon<HTMLElement>[] ...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement ): ddeHTMLElement
@ -101,7 +101,18 @@ export function elNS(
export { elNS as createElementNS } export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: EL): EL /**
* Mapper function (optional). Pass for coppying attributes, this is NOT implemented by {@link simulateSlots} itself!
* */
type simulateSlotsMapper= (body: HTMLSlotElement, el: HTMLElement)=> void;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL, mapper?: simulateSlotsMapper): EL
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL, mapper?: simulateSlotsMapper): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void; (element: SupportedElement, data?: any)=> void;
@ -177,12 +188,12 @@ export const scope: {
export function customElementRender< export function customElementRender<
EL extends HTMLElement, EL extends HTMLElement,
P extends any = Record<string, any> P extends any = Record<string, string | ddeSignal<string>>
>( >(
custom_element: EL, custom_element: EL,
target: ShadowRoot | EL, target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment, render: (props: P)=> SupportedElement | DocumentFragment,
props?: P | ((...args: any[])=> P) props?: P | ((el: EL)=> P)
): EL ): EL
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL

1334
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -62,14 +62,12 @@
"limit": "10.5 kB", "limit": "10.5 kB",
"gzip": false, "gzip": false,
"brotli": false "brotli": false
}, },
{ {
"path": "./signals.js", "path": "./signals.js",
"limit": "12 kB", "limit": "12 kB",
"gzip": false, "gzip": false,
"brotli": false "brotli": false
}, },
{ {
"path": "./index-with-signals.js", "path": "./index-with-signals.js",
@ -95,12 +93,12 @@
"typescript" "typescript"
], ],
"devDependencies": { "devDependencies": {
"@size-limit/preset-small-lib": "^11.0.1", "@size-limit/preset-small-lib": "~11.0",
"dts-bundler": "^0.1.0", "dts-bundler": "~0.1",
"esbuild": "^0.19.9", "esbuild": "~0.24",
"jsdom": "^23.0.1", "jsdom": "~25.0",
"jshint": "^2.13.6", "jshint": "~2.13",
"nodejsscript": "github:jaandrle/nodejsscript#dev-v1", "nodejsscript": "^1.0.2",
"size-limit-node-esbuild": "^0.3.0" "size-limit-node-esbuild": "~0.3"
} }
} }

2
signals.d.ts vendored
View File

@ -55,7 +55,7 @@ interface signal{
* */ * */
el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<any, any>>; observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
} }
export const signal: signal; export const signal: signal;
export const S: signal; export const S: signal;

View File

@ -67,18 +67,23 @@ export function createElement(tag, attributes, ...addons){
} }
import { hasOwn } from "./helpers.js"; import { hasOwn } from "./helpers.js";
/** @param {HTMLElement} element @param {HTMLElement} [root] */ /** @param {HTMLElement} element @param {HTMLElement} [root] */
export function simulateSlots(element, root= element, mapper= undefined){ export function simulateSlots(element, root, mapper){
if(typeof root!=="object"){
mapper= root;
root= element;
}
const _default= Symbol.for("default"); const _default= Symbol.for("default");
const slots= Array.from(root.querySelectorAll("slot")) const slots= Array.from(root.querySelectorAll("slot"))
.reduce((out, curr)=> Reflect.set(out, curr.name || _default, curr) && out, {}); .reduce((out, curr)=> Reflect.set(out, curr.name || _default, curr) && out, {});
const has_d= hasOwn(slots, _default); const has_d= hasOwn(slots, _default);
element.append= new Proxy(element.append, { element.append= new Proxy(element.append, {
apply(orig, _, els){ apply(orig, _, els){
if(els[0]===root) return orig.apply(element, els);
if(!els.length) return element; if(!els.length) return element;
const d= env.D.createDocumentFragment(); const d= env.D.createDocumentFragment();
for(const el of els){ for(const el of els){
if(!el || !el.slot){ if(has_d) d.appendChild(el); continue; } if(!el || !el.slot){ if(has_d) d.append(el); continue; }
const name= el.slot; const name= el.slot;
const slot= slots[name]; const slot= slots[name];
elementAttribute(el, "remove", "slot"); elementAttribute(el, "remove", "slot");