This commit is contained in:
25
dist/sigpro-ui.css
vendored
25
dist/sigpro-ui.css
vendored
@@ -4775,31 +4775,6 @@
|
|||||||
flex-direction: var(--tabs-direction);
|
flex-direction: var(--tabs-direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.footer {
|
|
||||||
@layer daisyui.l1.l2.l3 {
|
|
||||||
display: grid;
|
|
||||||
width: 100%;
|
|
||||||
grid-auto-flow: row;
|
|
||||||
place-items: start;
|
|
||||||
column-gap: calc(0.25rem * 4);
|
|
||||||
row-gap: calc(0.25rem * 10);
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
& > * {
|
|
||||||
display: grid;
|
|
||||||
place-items: start;
|
|
||||||
gap: calc(0.25rem * 2);
|
|
||||||
}
|
|
||||||
&.footer-center {
|
|
||||||
grid-auto-flow: column dense;
|
|
||||||
place-items: center;
|
|
||||||
text-align: center;
|
|
||||||
& > * {
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.stat {
|
.stat {
|
||||||
@layer daisyui.l1.l2.l3 {
|
@layer daisyui.l1.l2.l3 {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
|
|||||||
4
dist/sigpro-ui.editor.esm.js
vendored
4
dist/sigpro-ui.editor.esm.js
vendored
@@ -1,8 +1,8 @@
|
|||||||
// src/editor.js
|
// src/editor.js
|
||||||
import { $ as $2, isFunc as isFunc2, h as h2 } from "./sigpro.js";
|
import { $ as $2, isFunc as isFunc2, h as h2 } from "sigpro";
|
||||||
|
|
||||||
// src/sigpro-ui.js
|
// src/sigpro-ui.js
|
||||||
import { $, watch, h, mount, when, each, isFunc } from "./sigpro.js";
|
import { $, watch, h, mount, when, each, isFunc } from "sigpro";
|
||||||
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
||||||
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
||||||
var currentLocale = $("en");
|
var currentLocale = $("en");
|
||||||
|
|||||||
4
dist/sigpro-ui.editor.esm.min.js
vendored
4
dist/sigpro-ui.editor.esm.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/sigpro-ui.esm.js
vendored
2
dist/sigpro-ui.esm.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
// src/sigpro-ui.js
|
// src/sigpro-ui.js
|
||||||
import { $, watch, h, mount, when, each, isFunc } from "./sigpro.js";
|
import { $, watch, h, mount, when, each, isFunc } from "sigpro";
|
||||||
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
var val = (val2) => typeof val2 === "function" ? val2() : val2;
|
||||||
var getBy = (item, field = "label") => item && typeof item === "object" ? item[field] : item;
|
var getBy = (item, field = "label") => item && typeof item === "object" ? item[field] : item;
|
||||||
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
|
||||||
|
|||||||
2
dist/sigpro-ui.esm.min.js
vendored
2
dist/sigpro-ui.esm.min.js
vendored
File diff suppressed because one or more lines are too long
159
dist/sigpro-ui.js
vendored
159
dist/sigpro-ui.js
vendored
@@ -92,7 +92,7 @@ var spui = (() => {
|
|||||||
val: () => val
|
val: () => val
|
||||||
});
|
});
|
||||||
|
|
||||||
// src/sigpro.js
|
// node_modules/sigpro/dist/sigpro.esm.js
|
||||||
var isFunc = (f) => typeof f === "function";
|
var isFunc = (f) => typeof f === "function";
|
||||||
var isObj = (o) => o && typeof o === "object";
|
var isObj = (o) => o && typeof o === "object";
|
||||||
var isArr = Array.isArray;
|
var isArr = Array.isArray;
|
||||||
@@ -108,7 +108,8 @@ var spui = (() => {
|
|||||||
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
var SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","));
|
||||||
var dispose = (eff) => {
|
var dispose = (eff) => {
|
||||||
if (!eff || eff._disposed) return;
|
if (!eff || eff._disposed)
|
||||||
|
return;
|
||||||
eff._disposed = true;
|
eff._disposed = true;
|
||||||
const stack = [eff];
|
const stack = [eff];
|
||||||
while (stack.length) {
|
while (stack.length) {
|
||||||
@@ -128,7 +129,8 @@ var spui = (() => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var onUnmount = (fn) => {
|
var onUnmount = (fn) => {
|
||||||
if (activeOwner) (activeOwner._cleanups ||= /* @__PURE__ */ new Set()).add(fn);
|
if (activeOwner)
|
||||||
|
(activeOwner._cleanups ||= /* @__PURE__ */ new Set()).add(fn);
|
||||||
};
|
};
|
||||||
var untrack = (fn) => {
|
var untrack = (fn) => {
|
||||||
const p = activeEffect;
|
const p = activeEffect;
|
||||||
@@ -141,8 +143,10 @@ var spui = (() => {
|
|||||||
};
|
};
|
||||||
var createEffect = (fn, isComputed = false) => {
|
var createEffect = (fn, isComputed = false) => {
|
||||||
const effect = () => {
|
const effect = () => {
|
||||||
if (effect._disposed) return;
|
if (effect._disposed)
|
||||||
if (effect._deps) effect._deps.forEach((s) => s.delete(effect));
|
return;
|
||||||
|
if (effect._deps)
|
||||||
|
effect._deps.forEach((s) => s.delete(effect));
|
||||||
if (effect._cleanups) {
|
if (effect._cleanups) {
|
||||||
effect._cleanups.forEach((c) => c());
|
effect._cleanups.forEach((c) => c());
|
||||||
effect._cleanups.clear();
|
effect._cleanups.clear();
|
||||||
@@ -165,15 +169,19 @@ var spui = (() => {
|
|||||||
effect._depth = activeEffect ? activeEffect._depth + 1 : 0;
|
effect._depth = activeEffect ? activeEffect._depth + 1 : 0;
|
||||||
effect._mounts = [];
|
effect._mounts = [];
|
||||||
effect._parent = activeOwner;
|
effect._parent = activeOwner;
|
||||||
if (activeOwner) (activeOwner._children ||= /* @__PURE__ */ new Set()).add(effect);
|
if (activeOwner)
|
||||||
|
(activeOwner._children ||= /* @__PURE__ */ new Set()).add(effect);
|
||||||
return effect;
|
return effect;
|
||||||
};
|
};
|
||||||
var flush = () => {
|
var flush = () => {
|
||||||
if (isFlushing) return;
|
if (isFlushing)
|
||||||
|
return;
|
||||||
isFlushing = true;
|
isFlushing = true;
|
||||||
const sorted = Array.from(effectQueue).sort((a, b) => a._depth - b._depth);
|
const sorted = Array.from(effectQueue).sort((a, b) => a._depth - b._depth);
|
||||||
effectQueue.clear();
|
effectQueue.clear();
|
||||||
for (const e of sorted) if (!e._disposed) e();
|
for (const e of sorted)
|
||||||
|
if (!e._disposed)
|
||||||
|
e();
|
||||||
isFlushing = false;
|
isFlushing = false;
|
||||||
};
|
};
|
||||||
var trackUpdate = (subs, trigger = false) => {
|
var trackUpdate = (subs, trigger = false) => {
|
||||||
@@ -183,16 +191,19 @@ var spui = (() => {
|
|||||||
} else if (trigger && subs.size > 0) {
|
} else if (trigger && subs.size > 0) {
|
||||||
let hasQueue = false;
|
let hasQueue = false;
|
||||||
for (const e of subs) {
|
for (const e of subs) {
|
||||||
if (e === activeEffect || e._disposed) continue;
|
if (e === activeEffect || e._disposed)
|
||||||
|
continue;
|
||||||
if (e._isComputed) {
|
if (e._isComputed) {
|
||||||
e._dirty = true;
|
e._dirty = true;
|
||||||
if (e._subs) trackUpdate(e._subs, true);
|
if (e._subs)
|
||||||
|
trackUpdate(e._subs, true);
|
||||||
} else {
|
} else {
|
||||||
effectQueue.add(e);
|
effectQueue.add(e);
|
||||||
hasQueue = true;
|
hasQueue = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasQueue && !isFlushing && batchDepth === 0) queueMicrotask(flush);
|
if (hasQueue && !isFlushing && batchDepth === 0)
|
||||||
|
queueMicrotask(flush);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var $ = (val2, key = null) => {
|
var $ = (val2, key = null) => {
|
||||||
@@ -224,7 +235,8 @@ var spui = (() => {
|
|||||||
computed._disposed = false;
|
computed._disposed = false;
|
||||||
return computed;
|
return computed;
|
||||||
}
|
}
|
||||||
if (key) try {
|
if (key)
|
||||||
|
try {
|
||||||
val2 = JSON.parse(localStorage.getItem(key)) ?? val2;
|
val2 = JSON.parse(localStorage.getItem(key)) ?? val2;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
@@ -233,7 +245,8 @@ var spui = (() => {
|
|||||||
const next = isFunc(args[0]) ? args[0](val2) : args[0];
|
const next = isFunc(args[0]) ? args[0](val2) : args[0];
|
||||||
if (!Object.is(val2, next)) {
|
if (!Object.is(val2, next)) {
|
||||||
val2 = next;
|
val2 = next;
|
||||||
if (key) localStorage.setItem(key, JSON.stringify(val2));
|
if (key)
|
||||||
|
localStorage.setItem(key, JSON.stringify(val2));
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,22 +268,27 @@ var spui = (() => {
|
|||||||
return () => dispose(effect);
|
return () => dispose(effect);
|
||||||
};
|
};
|
||||||
var cleanupNode = (node) => {
|
var cleanupNode = (node) => {
|
||||||
if (!node) return;
|
if (!node)
|
||||||
|
return;
|
||||||
if (node._cleanups) {
|
if (node._cleanups) {
|
||||||
node._cleanups.forEach((fn) => fn());
|
node._cleanups.forEach((fn) => fn());
|
||||||
node._cleanups.clear();
|
node._cleanups.clear();
|
||||||
}
|
}
|
||||||
if (node._ownerEffect) dispose(node._ownerEffect);
|
if (node._ownerEffect)
|
||||||
if (node.childNodes) node.childNodes.forEach((n) => cleanupNode(n));
|
dispose(node._ownerEffect);
|
||||||
|
if (node.childNodes)
|
||||||
|
node.childNodes.forEach((n) => cleanupNode(n));
|
||||||
};
|
};
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
var DANGEROUS_URI_ATTRS = /* @__PURE__ */ new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
var DANGEROUS_URI_ATTRS = /* @__PURE__ */ new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
||||||
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
||||||
var validateAttr = (key, val2) => {
|
var validateAttr = (key, val2) => {
|
||||||
if (val2 == null || val2 === false) return null;
|
if (val2 == null || val2 === false)
|
||||||
|
return null;
|
||||||
if (isDangerousAttr(key)) {
|
if (isDangerousAttr(key)) {
|
||||||
const sVal = String(val2);
|
const sVal = String(val2);
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) return "#";
|
if (DANGEROUS_PROTOCOL.test(sVal))
|
||||||
|
return "#";
|
||||||
}
|
}
|
||||||
return val2;
|
return val2;
|
||||||
};
|
};
|
||||||
@@ -290,7 +308,8 @@ var spui = (() => {
|
|||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
const result = effect._result;
|
const result = effect._result;
|
||||||
if (result == null) return null;
|
if (result == null)
|
||||||
|
return null;
|
||||||
const node = result instanceof Node || isArr(result) && result.every((n) => n instanceof Node) ? result : doc.createTextNode(String(result));
|
const node = result instanceof Node || isArr(result) && result.every((n) => n instanceof Node) ? result : doc.createTextNode(String(result));
|
||||||
const attach = (n) => {
|
const attach = (n) => {
|
||||||
if (isObj(n) && !n._isRuntime) {
|
if (isObj(n) && !n._isRuntime) {
|
||||||
@@ -325,11 +344,16 @@ var spui = (() => {
|
|||||||
} else if (isFunc(v)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const val2 = validateAttr(k, v());
|
const val2 = validateAttr(k, v());
|
||||||
if (k === "class") el.className = val2 || "";
|
if (k === "class")
|
||||||
else if (val2 == null) el.removeAttribute(k);
|
el.className = val2 || "";
|
||||||
else if (k === "style" && typeof val2 === "string") el.setAttribute("style", val2);
|
else if (val2 == null)
|
||||||
else if (k in el && !isSVG) el[k] = val2;
|
el.removeAttribute(k);
|
||||||
else el.setAttribute(k, val2 === true ? "" : val2);
|
else if (k === "style" && typeof val2 === "string")
|
||||||
|
el.setAttribute("style", val2);
|
||||||
|
else if (k in el && !isSVG)
|
||||||
|
el[k] = val2;
|
||||||
|
else
|
||||||
|
el.setAttribute(k, val2 === true ? "" : val2);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
@@ -341,14 +365,18 @@ var spui = (() => {
|
|||||||
} else {
|
} else {
|
||||||
const val2 = validateAttr(k, v);
|
const val2 = validateAttr(k, v);
|
||||||
if (val2 != null) {
|
if (val2 != null) {
|
||||||
if (k === "style" && typeof val2 === "string") el.setAttribute("style", val2);
|
if (k === "style" && typeof val2 === "string")
|
||||||
else if (k in el && !isSVG) el[k] = val2;
|
el.setAttribute("style", val2);
|
||||||
else el.setAttribute(k, val2 === true ? "" : val2);
|
else if (k in el && !isSVG)
|
||||||
|
el[k] = val2;
|
||||||
|
else
|
||||||
|
el.setAttribute(k, val2 === true ? "" : val2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const append = (c) => {
|
const append = (c) => {
|
||||||
if (isArr(c)) return c.forEach(append);
|
if (isArr(c))
|
||||||
|
return c.forEach(append);
|
||||||
if (isFunc(c)) {
|
if (isFunc(c)) {
|
||||||
const anchor = doc.createTextNode("");
|
const anchor = doc.createTextNode("");
|
||||||
el.appendChild(anchor);
|
el.appendChild(anchor);
|
||||||
@@ -357,15 +385,20 @@ var spui = (() => {
|
|||||||
const res = c();
|
const res = c();
|
||||||
const next = (isArr(res) ? res : [res]).map(ensureNode);
|
const next = (isArr(res) ? res : [res]).map(ensureNode);
|
||||||
currentNodes.forEach((n) => {
|
currentNodes.forEach((n) => {
|
||||||
if (n._isRuntime) n.destroy();
|
if (n._isRuntime)
|
||||||
else cleanupNode(n);
|
n.destroy();
|
||||||
if (n.parentNode) n.remove();
|
else
|
||||||
|
cleanupNode(n);
|
||||||
|
if (n.parentNode)
|
||||||
|
n.remove();
|
||||||
});
|
});
|
||||||
let ref = anchor;
|
let ref = anchor;
|
||||||
for (let i = next.length - 1; i >= 0; i--) {
|
for (let i = next.length - 1; i >= 0; i--) {
|
||||||
const node = next[i];
|
const node = next[i];
|
||||||
if (node.parentNode !== ref.parentNode) ref.parentNode?.insertBefore(node, ref);
|
if (node.parentNode !== ref.parentNode)
|
||||||
if (node._mounts) node._mounts.forEach((fn) => fn());
|
ref.parentNode?.insertBefore(node, ref);
|
||||||
|
if (node._mounts)
|
||||||
|
node._mounts.forEach((fn) => fn());
|
||||||
ref = node;
|
ref = node;
|
||||||
}
|
}
|
||||||
currentNodes = next;
|
currentNodes = next;
|
||||||
@@ -376,7 +409,8 @@ var spui = (() => {
|
|||||||
} else {
|
} else {
|
||||||
const node = ensureNode(c);
|
const node = ensureNode(c);
|
||||||
el.appendChild(node);
|
el.appendChild(node);
|
||||||
if (node._mounts) node._mounts.forEach((fn) => fn());
|
if (node._mounts)
|
||||||
|
node._mounts.forEach((fn) => fn());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
append(children);
|
append(children);
|
||||||
@@ -392,7 +426,8 @@ var spui = (() => {
|
|||||||
activeOwner = { _cleanups: cleanups };
|
activeOwner = { _cleanups: cleanups };
|
||||||
activeEffect = null;
|
activeEffect = null;
|
||||||
const processResult = (result) => {
|
const processResult = (result) => {
|
||||||
if (!result) return;
|
if (!result)
|
||||||
|
return;
|
||||||
if (result._isRuntime) {
|
if (result._isRuntime) {
|
||||||
cleanups.add(result.destroy);
|
cleanups.add(result.destroy);
|
||||||
container.appendChild(result.container);
|
container.appendChild(result.container);
|
||||||
@@ -422,9 +457,7 @@ var spui = (() => {
|
|||||||
const anchor = doc.createTextNode("");
|
const anchor = doc.createTextNode("");
|
||||||
const root = h("div", { style: "display:contents" }, [anchor]);
|
const root = h("div", { style: "display:contents" }, [anchor]);
|
||||||
let currentView = null;
|
let currentView = null;
|
||||||
watch(
|
watch(() => !!(isFunc(cond) ? cond() : cond), (show) => {
|
||||||
() => !!(isFunc(cond) ? cond() : cond),
|
|
||||||
(show) => {
|
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
currentView.destroy();
|
currentView.destroy();
|
||||||
currentView = null;
|
currentView = null;
|
||||||
@@ -434,8 +467,7 @@ var spui = (() => {
|
|||||||
currentView = render(() => isFunc(content) ? content() : content);
|
currentView = render(() => isFunc(content) ? content() : content);
|
||||||
root.insertBefore(currentView.container, anchor);
|
root.insertBefore(currentView.container, anchor);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
onUnmount(() => currentView?.destroy());
|
onUnmount(() => currentView?.destroy());
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
@@ -451,8 +483,10 @@ var spui = (() => {
|
|||||||
const item = newItems[i];
|
const item = newItems[i];
|
||||||
const key = keyField ? item?.[keyField] ?? i : item?.id ?? i;
|
const key = keyField ? item?.[keyField] ?? i : item?.id ?? i;
|
||||||
let view = cache.get(key);
|
let view = cache.get(key);
|
||||||
if (!view) view = render(() => itemFn(item, i));
|
if (!view)
|
||||||
else cache.delete(key);
|
view = render(() => itemFn(item, i));
|
||||||
|
else
|
||||||
|
cache.delete(key);
|
||||||
nextCache.set(key, view);
|
nextCache.set(key, view);
|
||||||
nextOrder.push(view);
|
nextOrder.push(view);
|
||||||
}
|
}
|
||||||
@@ -461,49 +495,20 @@ var spui = (() => {
|
|||||||
for (let i = nextOrder.length - 1; i >= 0; i--) {
|
for (let i = nextOrder.length - 1; i >= 0; i--) {
|
||||||
const view = nextOrder[i];
|
const view = nextOrder[i];
|
||||||
const node = view.container;
|
const node = view.container;
|
||||||
if (node.nextSibling !== lastRef) root.insertBefore(node, lastRef);
|
if (node.nextSibling !== lastRef)
|
||||||
|
root.insertBefore(node, lastRef);
|
||||||
lastRef = node;
|
lastRef = node;
|
||||||
}
|
}
|
||||||
cache = nextCache;
|
cache = nextCache;
|
||||||
});
|
});
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
var router = (routes) => {
|
|
||||||
const getHash = () => window.location.hash.slice(1) || "/";
|
|
||||||
const path = $(getHash());
|
|
||||||
const handler = () => path(getHash());
|
|
||||||
window.addEventListener("hashchange", handler);
|
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler));
|
|
||||||
const hook = h("div", { class: "router-hook" });
|
|
||||||
let currentView = null;
|
|
||||||
watch([path], () => {
|
|
||||||
const cur = path();
|
|
||||||
const route = routes.find((r) => {
|
|
||||||
const p1 = r.path.split("/").filter(Boolean);
|
|
||||||
const p2 = cur.split("/").filter(Boolean);
|
|
||||||
return p1.length === p2.length && p1.every((p, i) => p[0] === ":" || p === p2[i]);
|
|
||||||
}) || routes.find((r) => r.path === "*");
|
|
||||||
if (route) {
|
|
||||||
currentView?.destroy();
|
|
||||||
const params = {};
|
|
||||||
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
|
||||||
if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
|
||||||
});
|
|
||||||
router.params(params);
|
|
||||||
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component);
|
|
||||||
hook.replaceChildren(currentView.container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return hook;
|
|
||||||
};
|
|
||||||
router.params = $({});
|
|
||||||
router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
|
||||||
router.back = () => window.history.back();
|
|
||||||
router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
|
||||||
var mount = (comp, target) => {
|
var mount = (comp, target) => {
|
||||||
const t2 = typeof target === "string" ? doc.querySelector(target) : target;
|
const t2 = typeof target === "string" ? doc.querySelector(target) : target;
|
||||||
if (!t2) return;
|
if (!t2)
|
||||||
if (MOUNTED_NODES.has(t2)) MOUNTED_NODES.get(t2).destroy();
|
return;
|
||||||
|
if (MOUNTED_NODES.has(t2))
|
||||||
|
MOUNTED_NODES.get(t2).destroy();
|
||||||
const inst = render(isFunc(comp) ? comp : () => comp);
|
const inst = render(isFunc(comp) ? comp : () => comp);
|
||||||
t2.replaceChildren(inst.container);
|
t2.replaceChildren(inst.container);
|
||||||
MOUNTED_NODES.set(t2, inst);
|
MOUNTED_NODES.set(t2, inst);
|
||||||
|
|||||||
2
dist/sigpro-ui.min.css
vendored
2
dist/sigpro-ui.min.css
vendored
File diff suppressed because one or more lines are too long
4
dist/sigpro-ui.min.js
vendored
4
dist/sigpro-ui.min.js
vendored
File diff suppressed because one or more lines are too long
2
docs/sigpro-ui.min.css
vendored
2
docs/sigpro-ui.min.css
vendored
File diff suppressed because one or more lines are too long
4
docs/sigpro-ui.min.js
vendored
4
docs/sigpro-ui.min.js
vendored
File diff suppressed because one or more lines are too long
15
package.json
15
package.json
@@ -44,12 +44,12 @@
|
|||||||
"clean": "rm -rf ./dist ./css/*.css ./docs/*.js ./docs/*.css",
|
"clean": "rm -rf ./dist ./css/*.css ./docs/*.js ./docs/*.css",
|
||||||
"build:css": "tailwindcss -i ./src/sigpro-ui.css -o ./dist/sigpro-ui.css --content './src/**/*.js' && du -h ./dist/sigpro-ui.css",
|
"build:css": "tailwindcss -i ./src/sigpro-ui.css -o ./dist/sigpro-ui.css --content './src/**/*.js' && du -h ./dist/sigpro-ui.css",
|
||||||
"build:cssmin": "tailwindcss -i ./src/sigpro-ui.css -o ./dist/sigpro-ui.min.css --content './src/**/*.js' --minify && du -h ./dist/sigpro-ui.css",
|
"build:cssmin": "tailwindcss -i ./src/sigpro-ui.css -o ./dist/sigpro-ui.min.css --content './src/**/*.js' --minify && du -h ./dist/sigpro-ui.css",
|
||||||
"build:js:iife": "esbuild ./src/build_umd.js --bundle --outfile=./dist/sigpro-ui.js --format=iife --global-name=spui --external:./src/sigpro.js=window",
|
"build:js:iife": "esbuild ./src/build_umd.js --bundle --outfile=./dist/sigpro-ui.js --format=iife --global-name=spui --external:sigpro=window",
|
||||||
"build:js:iife:min": "esbuild ./src/build_umd.js --bundle --outfile=./dist/sigpro-ui.min.js --format=iife --global-name=spui --minify --external:./src/sigpro.js=window",
|
"build:js:iife:min": "esbuild ./src/build_umd.js --bundle --outfile=./dist/sigpro-ui.min.js --format=iife --global-name=spui --minify --external:sigpro=window",
|
||||||
"build:js:esm": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.js --format=esm --external ./src/sigpro.js",
|
"build:js:esm": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.js --format=esm --external sigpro",
|
||||||
"build:js:esm:min": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.min.js --format=esm --minify --external ./src/sigpro.js",
|
"build:js:esm:min": "bun build ./src/build_esm.js --bundle --outfile=./dist/sigpro-ui.esm.min.js --format=esm --minify --external sigpro",
|
||||||
"build:js:editor:esm": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.js --format=esm --external ./src/sigpro.js",
|
"build:js:editor:esm": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.js --format=esm --external sigpro",
|
||||||
"build:js:editor:esm:min": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.min.js --format=esm --minify --external ./src/sigpro.js",
|
"build:js:editor:esm:min": "bun build ./src/build_editor.js --bundle --outfile=./dist/sigpro-ui.editor.esm.min.js --format=esm --minify --external sigpro",
|
||||||
"copy:docs": "cp dist/sigpro-ui.min.css dist/sigpro-ui.min.js docs/",
|
"copy:docs": "cp dist/sigpro-ui.min.css dist/sigpro-ui.min.js docs/",
|
||||||
"build": "bun run clean && bun run build:css && bun run build:cssmin && bun run build:js:iife && bun run build:js:iife:min && bun run build:js:esm && bun run build:js:esm:min && bun run build:js:editor:esm && bun run build:js:editor:esm:min && bun run copy:docs",
|
"build": "bun run clean && bun run build:css && bun run build:cssmin && bun run build:js:iife && bun run build:js:iife:min && bun run build:js:esm && bun run build:js:esm:min && bun run build:js:editor:esm && bun run build:js:editor:esm:min && bun run copy:docs",
|
||||||
"docs": "bun x serve docs"
|
"docs": "bun x serve docs"
|
||||||
@@ -61,5 +61,8 @@
|
|||||||
"daisyui": "^5.5.19",
|
"daisyui": "^5.5.19",
|
||||||
"esbuild": "^0.28.0",
|
"esbuild": "^0.28.0",
|
||||||
"tailwindcss": "^4.2.4"
|
"tailwindcss": "^4.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sigpro": "git+http://gitea:3000/natxocc/sigpro"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { $, isFunc, h } from "./sigpro.js"
|
import { $, isFunc, h } from "sigpro"
|
||||||
import { val, cls } from "./sigpro-ui.js"
|
import { val, cls } from "./sigpro-ui.js"
|
||||||
|
|
||||||
export const Editor = (p) => {
|
export const Editor = (p) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { $, watch, h, mount, when, each, isFunc } from "./sigpro.js"
|
import { $, watch, h, mount, when, each, isFunc } from "sigpro"
|
||||||
export const val = val => typeof val === "function" ? val() : val;
|
export const val = val => typeof val === "function" ? val() : val;
|
||||||
export const getBy = (item, field = 'label') => (item && typeof item === 'object') ? item[field] : item;
|
export const getBy = (item, field = 'label') => (item && typeof item === 'object') ? item[field] : item;
|
||||||
export const cls = (...classes) => classes.filter(Boolean).join(' ').trim();
|
export const cls = (...classes) => classes.filter(Boolean).join(' ').trim();
|
||||||
|
|||||||
513
src/sigpro.js
513
src/sigpro.js
@@ -1,513 +0,0 @@
|
|||||||
const isFunc = f => typeof f === "function"
|
|
||||||
const isObj = o => o && typeof o === "object"
|
|
||||||
const isArr = Array.isArray
|
|
||||||
const doc = typeof document !== "undefined" ? document : null
|
|
||||||
const ensureNode = n => n?._isRuntime ? n.container : (n instanceof Node ? n : doc.createTextNode(n == null ? "" : String(n)))
|
|
||||||
|
|
||||||
let activeEffect = null
|
|
||||||
let activeOwner = null
|
|
||||||
let isFlushing = false
|
|
||||||
let batchDepth = 0
|
|
||||||
const effectQueue = new Set()
|
|
||||||
const proxyCache = new WeakMap()
|
|
||||||
const ITER = Symbol('iter')
|
|
||||||
const MOUNTED_NODES = new WeakMap()
|
|
||||||
|
|
||||||
const SVG_NS = "http://www.w3.org/2000/svg"
|
|
||||||
const XLINK_NS = "http://www.w3.org/1999/xlink"
|
|
||||||
const SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","))
|
|
||||||
|
|
||||||
const dispose = eff => {
|
|
||||||
if (!eff || eff._disposed) return
|
|
||||||
eff._disposed = true
|
|
||||||
const stack = [eff]
|
|
||||||
while (stack.length) {
|
|
||||||
const e = stack.pop()
|
|
||||||
if (e._cleanups) {
|
|
||||||
e._cleanups.forEach(fn => fn())
|
|
||||||
e._cleanups.clear()
|
|
||||||
}
|
|
||||||
if (e._children) {
|
|
||||||
e._children.forEach(child => stack.push(child))
|
|
||||||
e._children.clear()
|
|
||||||
}
|
|
||||||
if (e._deps) {
|
|
||||||
e._deps.forEach(depSet => depSet.delete(e))
|
|
||||||
e._deps.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onUnmount = fn => {
|
|
||||||
if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
const untrack = fn => {
|
|
||||||
const p = activeEffect
|
|
||||||
activeEffect = null
|
|
||||||
try { return fn() } finally { activeEffect = p }
|
|
||||||
}
|
|
||||||
|
|
||||||
const createEffect = (fn, isComputed = false) => {
|
|
||||||
const effect = () => {
|
|
||||||
if (effect._disposed) return
|
|
||||||
if (effect._deps) effect._deps.forEach(s => s.delete(effect))
|
|
||||||
if (effect._cleanups) {
|
|
||||||
effect._cleanups.forEach(c => c())
|
|
||||||
effect._cleanups.clear()
|
|
||||||
}
|
|
||||||
const prevEffect = activeEffect
|
|
||||||
const prevOwner = activeOwner
|
|
||||||
activeEffect = activeOwner = effect
|
|
||||||
try {
|
|
||||||
return effect._result = fn()
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[SigPro]", e)
|
|
||||||
} finally {
|
|
||||||
activeEffect = prevEffect
|
|
||||||
activeOwner = prevOwner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
effect._deps = effect._cleanups = effect._children = null
|
|
||||||
effect._disposed = false
|
|
||||||
effect._isComputed = isComputed
|
|
||||||
effect._depth = activeEffect ? activeEffect._depth + 1 : 0
|
|
||||||
effect._mounts = []
|
|
||||||
effect._parent = activeOwner
|
|
||||||
if (activeOwner) (activeOwner._children ||= new Set()).add(effect)
|
|
||||||
return effect
|
|
||||||
}
|
|
||||||
|
|
||||||
const flush = () => {
|
|
||||||
if (isFlushing) return
|
|
||||||
isFlushing = true
|
|
||||||
const sorted = Array.from(effectQueue).sort((a, b) => a._depth - b._depth)
|
|
||||||
effectQueue.clear()
|
|
||||||
for (const e of sorted) if (!e._disposed) e()
|
|
||||||
isFlushing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const batch = fn => {
|
|
||||||
batchDepth++
|
|
||||||
try {
|
|
||||||
return fn()
|
|
||||||
} finally {
|
|
||||||
batchDepth--
|
|
||||||
if (batchDepth === 0 && effectQueue.size > 0 && !isFlushing) flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const trackUpdate = (subs, trigger = false) => {
|
|
||||||
if (!trigger && activeEffect && !activeEffect._disposed) {
|
|
||||||
subs.add(activeEffect);
|
|
||||||
(activeEffect._deps ||= new Set()).add(subs)
|
|
||||||
} else if (trigger && subs.size > 0) {
|
|
||||||
let hasQueue = false
|
|
||||||
for (const e of subs) {
|
|
||||||
if (e === activeEffect || e._disposed) continue
|
|
||||||
if (e._isComputed) {
|
|
||||||
e._dirty = true
|
|
||||||
if (e._subs) trackUpdate(e._subs, true)
|
|
||||||
} else {
|
|
||||||
effectQueue.add(e)
|
|
||||||
hasQueue = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasQueue && !isFlushing && batchDepth === 0) queueMicrotask(flush)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const $ = (val, key = null) => {
|
|
||||||
const subs = new Set()
|
|
||||||
if (isFunc(val)) {
|
|
||||||
let cache
|
|
||||||
const computed = () => {
|
|
||||||
if (computed._dirty) {
|
|
||||||
const prev = activeEffect
|
|
||||||
activeEffect = computed
|
|
||||||
try {
|
|
||||||
const next = val()
|
|
||||||
if (!Object.is(cache, next)) {
|
|
||||||
cache = next
|
|
||||||
trackUpdate(subs, true)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
activeEffect = prev
|
|
||||||
}
|
|
||||||
computed._dirty = false
|
|
||||||
}
|
|
||||||
trackUpdate(subs)
|
|
||||||
return cache
|
|
||||||
}
|
|
||||||
computed._isComputed = true
|
|
||||||
computed._subs = subs
|
|
||||||
computed._dirty = true
|
|
||||||
computed._deps = null
|
|
||||||
computed._disposed = false
|
|
||||||
return computed
|
|
||||||
}
|
|
||||||
if (key) try { val = JSON.parse(localStorage.getItem(key)) ?? val } catch (e) { }
|
|
||||||
return (...args) => {
|
|
||||||
if (args.length) {
|
|
||||||
const next = isFunc(args[0]) ? args[0](val) : args[0]
|
|
||||||
if (!Object.is(val, next)) {
|
|
||||||
val = next
|
|
||||||
if (key) localStorage.setItem(key, JSON.stringify(val))
|
|
||||||
trackUpdate(subs, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trackUpdate(subs)
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const $$ = (target) => {
|
|
||||||
if (!isObj(target)) return target
|
|
||||||
const cached = proxyCache.get(target)
|
|
||||||
if (cached) return cached
|
|
||||||
|
|
||||||
const subs = new Map()
|
|
||||||
const getSubs = (key) => {
|
|
||||||
let set = subs.get(key)
|
|
||||||
if (!set) subs.set(key, set = new Set())
|
|
||||||
return set
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxy = new Proxy(target, {
|
|
||||||
get(target, key, receiver) {
|
|
||||||
if (typeof key !== 'symbol') trackUpdate(getSubs(key))
|
|
||||||
return $$(Reflect.get(target, key, receiver))
|
|
||||||
},
|
|
||||||
set(target, key, value, receiver) {
|
|
||||||
const hadKey = Reflect.has(target, key)
|
|
||||||
const oldValue = Reflect.get(target, key, receiver)
|
|
||||||
const result = Reflect.set(target, key, value, receiver)
|
|
||||||
if (result && !Object.is(oldValue, value)) {
|
|
||||||
trackUpdate(getSubs(key), true)
|
|
||||||
if (!hadKey) trackUpdate(getSubs(ITER), true)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
deleteProperty(target, key) {
|
|
||||||
const result = Reflect.deleteProperty(target, key)
|
|
||||||
if (result) {
|
|
||||||
trackUpdate(getSubs(key), true)
|
|
||||||
trackUpdate(getSubs(ITER), true)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
ownKeys(target) {
|
|
||||||
trackUpdate(getSubs(ITER))
|
|
||||||
return Reflect.ownKeys(target)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
proxyCache.set(target, proxy)
|
|
||||||
return proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
const watch = (sources, cb) => {
|
|
||||||
if (cb === undefined) {
|
|
||||||
const effect = createEffect(sources)
|
|
||||||
effect()
|
|
||||||
return () => dispose(effect)
|
|
||||||
}
|
|
||||||
const effect = createEffect(() => {
|
|
||||||
const vals = isArr(sources) ? sources.map(s => s()) : sources()
|
|
||||||
untrack(() => cb(vals))
|
|
||||||
})
|
|
||||||
effect()
|
|
||||||
return () => dispose(effect)
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanupNode = (node) => {
|
|
||||||
if (!node) return;
|
|
||||||
if (node._cleanups) {
|
|
||||||
node._cleanups.forEach(fn => fn());
|
|
||||||
node._cleanups.clear();
|
|
||||||
}
|
|
||||||
if (node._ownerEffect) dispose(node._ownerEffect);
|
|
||||||
if (node.childNodes) node.childNodes.forEach(n => cleanupNode(n));
|
|
||||||
};
|
|
||||||
|
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
|
||||||
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
|
|
||||||
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
|
|
||||||
|
|
||||||
const validateAttr = (key, val) => {
|
|
||||||
if (val == null || val === false) return null
|
|
||||||
if (isDangerousAttr(key)) {
|
|
||||||
const sVal = String(val)
|
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) return '#'
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
const h = (tag, props = {}, children = []) => {
|
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
|
||||||
children = props
|
|
||||||
props = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFunc(tag)) {
|
|
||||||
const effect = createEffect(() => {
|
|
||||||
const result = tag(props, {
|
|
||||||
children,
|
|
||||||
emit: (ev, ...args) => props[`on${ev[0].toUpperCase()}${ev.slice(1)}`]?.(...args)
|
|
||||||
})
|
|
||||||
effect._result = result
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
effect()
|
|
||||||
|
|
||||||
const result = effect._result
|
|
||||||
if (result == null) return null
|
|
||||||
|
|
||||||
const node = (result instanceof Node || (isArr(result) && result.every(n => n instanceof Node)))
|
|
||||||
? result
|
|
||||||
: doc.createTextNode(String(result))
|
|
||||||
|
|
||||||
const attach = n => {
|
|
||||||
if (isObj(n) && !n._isRuntime) {
|
|
||||||
n._mounts = effect._mounts || []
|
|
||||||
n._cleanups = effect._cleanups || new Set()
|
|
||||||
n._ownerEffect = effect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isArr(node) ? node.forEach(attach) : attach(node)
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSVG = SVG_TAGS.has(tag)
|
|
||||||
const el = isSVG ? doc.createElementNS(SVG_NS, tag) : doc.createElement(tag)
|
|
||||||
el._cleanups = new Set()
|
|
||||||
|
|
||||||
for (const k of Object.keys(props)) {
|
|
||||||
let v = props[k]
|
|
||||||
if (k === "ref") {
|
|
||||||
isFunc(v) ? v(el) : (v.current = el)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
|
||||||
const cleanVal = validateAttr(k.slice(6), v)
|
|
||||||
cleanVal == null
|
|
||||||
? el.removeAttributeNS(XLINK_NS, k.slice(6))
|
|
||||||
: el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (k.startsWith("on")) {
|
|
||||||
const ev = k.slice(2).toLowerCase()
|
|
||||||
el.addEventListener(ev, v)
|
|
||||||
const off = () => el.removeEventListener(ev, v)
|
|
||||||
el._cleanups.add(off)
|
|
||||||
onUnmount(off)
|
|
||||||
} else if (isFunc(v)) {
|
|
||||||
const effect = createEffect(() => {
|
|
||||||
const val = validateAttr(k, v())
|
|
||||||
if (k === "class") el.className = val || ""
|
|
||||||
else if (val == null) el.removeAttribute(k)
|
|
||||||
else if (k === "style" && typeof val === "string") el.setAttribute("style", val)
|
|
||||||
else if (k in el && !isSVG) el[k] = val
|
|
||||||
else el.setAttribute(k, val === true ? "" : val)
|
|
||||||
})
|
|
||||||
effect()
|
|
||||||
el._cleanups.add(() => dispose(effect))
|
|
||||||
onUnmount(() => dispose(effect))
|
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
|
||||||
const evType = k === "checked" ? "change" : "input"
|
|
||||||
el.addEventListener(evType, ev => v(ev.target[k]))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const val = validateAttr(k, v)
|
|
||||||
if (val != null) {
|
|
||||||
if (k === "style" && typeof val === "string") el.setAttribute("style", val)
|
|
||||||
else if (k in el && !isSVG) el[k] = val
|
|
||||||
else el.setAttribute(k, val === true ? "" : val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const append = c => {
|
|
||||||
if (isArr(c)) return c.forEach(append)
|
|
||||||
if (isFunc(c)) {
|
|
||||||
const anchor = doc.createTextNode("")
|
|
||||||
el.appendChild(anchor)
|
|
||||||
let currentNodes = []
|
|
||||||
const effect = createEffect(() => {
|
|
||||||
const res = c()
|
|
||||||
const next = (isArr(res) ? res : [res]).map(ensureNode)
|
|
||||||
currentNodes.forEach(n => {
|
|
||||||
if (n._isRuntime) n.destroy()
|
|
||||||
else cleanupNode(n)
|
|
||||||
if (n.parentNode) n.remove()
|
|
||||||
})
|
|
||||||
let ref = anchor
|
|
||||||
for (let i = next.length - 1; i >= 0; i--) {
|
|
||||||
const node = next[i]
|
|
||||||
if (node.parentNode !== ref.parentNode) ref.parentNode?.insertBefore(node, ref)
|
|
||||||
if (node._mounts) node._mounts.forEach(fn => fn())
|
|
||||||
ref = node
|
|
||||||
}
|
|
||||||
currentNodes = next
|
|
||||||
})
|
|
||||||
effect()
|
|
||||||
el._cleanups.add(() => dispose(effect))
|
|
||||||
onUnmount(() => dispose(effect))
|
|
||||||
} else {
|
|
||||||
const node = ensureNode(c)
|
|
||||||
el.appendChild(node)
|
|
||||||
if (node._mounts) node._mounts.forEach(fn => fn())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
append(children)
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
|
|
||||||
const render = renderFn => {
|
|
||||||
const cleanups = new Set()
|
|
||||||
const previousOwner = activeOwner
|
|
||||||
const previousEffect = activeEffect
|
|
||||||
const container = doc.createElement("div")
|
|
||||||
container.style.display = "contents"
|
|
||||||
container.setAttribute("role", "presentation")
|
|
||||||
activeOwner = { _cleanups: cleanups }
|
|
||||||
activeEffect = null
|
|
||||||
|
|
||||||
const processResult = result => {
|
|
||||||
if (!result) return
|
|
||||||
if (result._isRuntime) {
|
|
||||||
cleanups.add(result.destroy)
|
|
||||||
container.appendChild(result.container)
|
|
||||||
} else if (isArr(result)) {
|
|
||||||
result.forEach(processResult)
|
|
||||||
} else {
|
|
||||||
container.appendChild(result instanceof Node ? result : doc.createTextNode(String(result == null ? "" : result)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
processResult(renderFn({ onCleanup: fn => cleanups.add(fn) }))
|
|
||||||
} finally {
|
|
||||||
activeOwner = previousOwner
|
|
||||||
activeEffect = previousEffect
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
_isRuntime: true,
|
|
||||||
container,
|
|
||||||
destroy: () => {
|
|
||||||
cleanups.forEach(fn => fn())
|
|
||||||
cleanupNode(container)
|
|
||||||
container.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const when = (cond, SIP, NOP = null) => {
|
|
||||||
const anchor = doc.createTextNode("")
|
|
||||||
const root = h("div", { style: "display:contents" }, [anchor])
|
|
||||||
let currentView = null
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => !!(isFunc(cond) ? cond() : cond),
|
|
||||||
show => {
|
|
||||||
if (currentView) {
|
|
||||||
currentView.destroy()
|
|
||||||
currentView = null
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = show ? SIP : NOP
|
|
||||||
if (content) {
|
|
||||||
currentView = render(() => isFunc(content) ? content() : content)
|
|
||||||
root.insertBefore(currentView.container, anchor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
onUnmount(() => currentView?.destroy())
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
const each = (src, itemFn, keyField) => {
|
|
||||||
const anchor = doc.createTextNode("")
|
|
||||||
const root = h("div", { style: "display:contents" }, [anchor])
|
|
||||||
let cache = new Map()
|
|
||||||
watch(() => (isFunc(src) ? src() : src) || [], items => {
|
|
||||||
const nextCache = new Map()
|
|
||||||
const nextOrder = []
|
|
||||||
const newItems = items || []
|
|
||||||
for (let i = 0; i < newItems.length; i++) {
|
|
||||||
const item = newItems[i]
|
|
||||||
const key = keyField ? (item?.[keyField] ?? i) : (item?.id ?? i)
|
|
||||||
let view = cache.get(key)
|
|
||||||
if (!view) view = render(() => itemFn(item, i))
|
|
||||||
else cache.delete(key)
|
|
||||||
nextCache.set(key, view)
|
|
||||||
nextOrder.push(view)
|
|
||||||
}
|
|
||||||
cache.forEach(view => view.destroy())
|
|
||||||
let lastRef = anchor
|
|
||||||
for (let i = nextOrder.length - 1; i >= 0; i--) {
|
|
||||||
const view = nextOrder[i]
|
|
||||||
const node = view.container
|
|
||||||
if (node.nextSibling !== lastRef) root.insertBefore(node, lastRef)
|
|
||||||
lastRef = node
|
|
||||||
}
|
|
||||||
cache = nextCache
|
|
||||||
})
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = routes => {
|
|
||||||
const getHash = () => window.location.hash.slice(1) || "/"
|
|
||||||
const path = $(getHash())
|
|
||||||
const handler = () => path(getHash())
|
|
||||||
window.addEventListener("hashchange", handler)
|
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler))
|
|
||||||
const hook = h("div", { class: "router-hook" })
|
|
||||||
let currentView = null
|
|
||||||
watch([path], () => {
|
|
||||||
const cur = path()
|
|
||||||
const route = routes.find(r => {
|
|
||||||
const p1 = r.path.split("/").filter(Boolean)
|
|
||||||
const p2 = cur.split("/").filter(Boolean)
|
|
||||||
return p1.length === p2.length && p1.every((p, i) => p[0] === ":" || p === p2[i])
|
|
||||||
}) || routes.find(r => r.path === "*")
|
|
||||||
if (route) {
|
|
||||||
currentView?.destroy()
|
|
||||||
const params = {}
|
|
||||||
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
|
||||||
if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]
|
|
||||||
})
|
|
||||||
router.params(params)
|
|
||||||
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component)
|
|
||||||
hook.replaceChildren(currentView.container)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return hook
|
|
||||||
}
|
|
||||||
router.params = $({})
|
|
||||||
router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/")
|
|
||||||
router.back = () => window.history.back()
|
|
||||||
router.path = () => window.location.hash.replace(/^#/, "") || "/"
|
|
||||||
|
|
||||||
const Fragment = (props) => props.children;
|
|
||||||
|
|
||||||
const mount = (comp, target) => {
|
|
||||||
const t = typeof target === "string" ? doc.querySelector(target) : target
|
|
||||||
if (!t) return
|
|
||||||
if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy()
|
|
||||||
const inst = render(isFunc(comp) ? comp : () => comp)
|
|
||||||
t.replaceChildren(inst.container)
|
|
||||||
MOUNTED_NODES.set(t, inst)
|
|
||||||
return inst
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
"a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video"
|
|
||||||
.split(" ")
|
|
||||||
.forEach(tag => { window[tag] = (props, children) => h(tag, props, children) })
|
|
||||||
}
|
|
||||||
|
|
||||||
export { $, $$, watch, batch, h, Fragment, mount, when, each, router, onUnmount, isArr, isFunc, isObj }
|
|
||||||
Reference in New Issue
Block a user