named functions to underscore
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
This commit is contained in:
214
dist/sigpro.esm.js
vendored
214
dist/sigpro.esm.js
vendored
@@ -33,11 +33,7 @@ var dispose = (eff) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var onMount = (fn) => {
|
var _onUnmount = (fn) => {
|
||||||
if (activeOwner)
|
|
||||||
(activeOwner._mounts ||= []).push(fn);
|
|
||||||
};
|
|
||||||
var onUnmount = (fn) => {
|
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
(activeOwner._cleanups ||= new Set).add(fn);
|
(activeOwner._cleanups ||= new Set).add(fn);
|
||||||
};
|
};
|
||||||
@@ -93,7 +89,7 @@ var flush = () => {
|
|||||||
e();
|
e();
|
||||||
isFlushing = false;
|
isFlushing = false;
|
||||||
};
|
};
|
||||||
var Batch = (fn) => {
|
var batch = (fn) => {
|
||||||
batchDepth++;
|
batchDepth++;
|
||||||
try {
|
try {
|
||||||
return fn();
|
return fn();
|
||||||
@@ -126,16 +122,16 @@ var trackUpdate = (subs, trigger = false) => {
|
|||||||
queueMicrotask(flush);
|
queueMicrotask(flush);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var $ = (val2, key = null) => {
|
var $ = (val, key = null) => {
|
||||||
const subs = new Set;
|
const subs = new Set;
|
||||||
if (isFunc(val2)) {
|
if (isFunc(val)) {
|
||||||
let cache;
|
let cache;
|
||||||
const computed = () => {
|
const computed = () => {
|
||||||
if (computed._dirty) {
|
if (computed._dirty) {
|
||||||
const prev = activeEffect;
|
const prev = activeEffect;
|
||||||
activeEffect = computed;
|
activeEffect = computed;
|
||||||
try {
|
try {
|
||||||
const next = val2();
|
const next = val();
|
||||||
if (!Object.is(cache, next)) {
|
if (!Object.is(cache, next)) {
|
||||||
cache = next;
|
cache = next;
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
@@ -155,25 +151,25 @@ var $ = (val2, key = null) => {
|
|||||||
computed._disposed = false;
|
computed._disposed = false;
|
||||||
computed.stop = () => {};
|
computed.stop = () => {};
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
onUnmount(computed.stop);
|
_onUnmount(computed.stop);
|
||||||
return computed;
|
return computed;
|
||||||
}
|
}
|
||||||
if (key)
|
if (key)
|
||||||
try {
|
try {
|
||||||
val2 = JSON.parse(localStorage.getItem(key)) ?? val2;
|
val = JSON.parse(localStorage.getItem(key)) ?? val;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
if (args.length) {
|
if (args.length) {
|
||||||
const next = isFunc(args[0]) ? args[0](val2) : args[0];
|
const next = isFunc(args[0]) ? args[0](val) : args[0];
|
||||||
if (!Object.is(val2, next)) {
|
if (!Object.is(val, next)) {
|
||||||
val2 = next;
|
val = next;
|
||||||
if (key)
|
if (key)
|
||||||
localStorage.setItem(key, JSON.stringify(val2));
|
localStorage.setItem(key, JSON.stringify(val));
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackUpdate(subs);
|
trackUpdate(subs);
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var $$ = (target) => {
|
var $$ = (target) => {
|
||||||
@@ -222,7 +218,7 @@ var $$ = (target) => {
|
|||||||
proxyCache.set(target, proxy);
|
proxyCache.set(target, proxy);
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
var Watch = (sources, cb) => {
|
var watch = (sources, cb) => {
|
||||||
if (cb === undefined) {
|
if (cb === undefined) {
|
||||||
const effect2 = createEffect(sources);
|
const effect2 = createEffect(sources);
|
||||||
effect2();
|
effect2();
|
||||||
@@ -247,25 +243,24 @@ var cleanupNode = (node) => {
|
|||||||
};
|
};
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
||||||
var validateAttr = (key, val2) => {
|
var validateAttr = (key, val) => {
|
||||||
if (val2 == null || val2 === false)
|
if (val == null || val === false)
|
||||||
return null;
|
return null;
|
||||||
if (isDangerousAttr(key)) {
|
if (isDangerousAttr(key)) {
|
||||||
const sVal = String(val2);
|
const sVal = String(val);
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
return "#";
|
return "#";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
var Tag = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
props = {};
|
props = {};
|
||||||
}
|
}
|
||||||
if (isFunc(tag)) {
|
if (isFunc(tag)) {
|
||||||
const ctx = { _mounts: [], _cleanups: new Set };
|
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const result2 = tag(props, {
|
const result2 = tag(props, {
|
||||||
children,
|
children,
|
||||||
@@ -302,7 +297,7 @@ var Tag = (tag, props = {}, children = []) => {
|
|||||||
}
|
}
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
const ns = "http://www.w3.org/1999/xlink";
|
const ns = "http://www.w3.org/1999/xlink";
|
||||||
val == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), val);
|
v == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), v);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
@@ -310,33 +305,33 @@ var Tag = (tag, props = {}, children = []) => {
|
|||||||
el.addEventListener(ev, v);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, v);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
_onUnmount(off);
|
||||||
} else if (isFunc(v)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const val2 = validateAttr(k, v());
|
const val = validateAttr(k, v());
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = val2 || "";
|
el.className = val || "";
|
||||||
else if (val2 == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const val2 = validateAttr(k, v);
|
const val = validateAttr(k, v);
|
||||||
if (val2 != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,7 +366,7 @@ var Tag = (tag, props = {}, children = []) => {
|
|||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
} else {
|
} else {
|
||||||
const node = ensureNode(c);
|
const node = ensureNode(c);
|
||||||
el.appendChild(node);
|
el.appendChild(node);
|
||||||
@@ -382,7 +377,7 @@ var Tag = (tag, props = {}, children = []) => {
|
|||||||
append(children);
|
append(children);
|
||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
var Render = (renderFn) => {
|
var render = (renderFn) => {
|
||||||
const cleanups = new Set;
|
const cleanups = new Set;
|
||||||
const mounts = [];
|
const mounts = [];
|
||||||
const previousOwner = activeOwner;
|
const previousOwner = activeOwner;
|
||||||
@@ -421,29 +416,46 @@ var Render = (renderFn) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var If = (cond, ifYes, ifNot = null) => {
|
var when = (cond, render2, { enter, leave } = {}) => {
|
||||||
const anchor = doc.createTextNode("");
|
const wrap = h("div", { style: "display:contents" });
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
let view = null;
|
||||||
let currentView = null;
|
const wait = (el, cb) => {
|
||||||
Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => {
|
if (!el)
|
||||||
if (currentView) {
|
return cb();
|
||||||
currentView.destroy();
|
let done = false;
|
||||||
currentView = null;
|
const finish = () => !done && (done = true, cb());
|
||||||
|
el.addEventListener("transitionend", finish, { once: true });
|
||||||
|
el.addEventListener("animationend", finish, { once: true });
|
||||||
|
setTimeout(finish, 500);
|
||||||
|
};
|
||||||
|
watch(cond, (on) => {
|
||||||
|
if (on && !view) {
|
||||||
|
const el = (view = render2(render2)).container.firstChild;
|
||||||
|
wrap.appendChild(view.container);
|
||||||
|
if (enter && el) {
|
||||||
|
el.classList.add(enter);
|
||||||
|
el.clientTop;
|
||||||
|
el.classList.add(enter + "-active");
|
||||||
|
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
||||||
|
}
|
||||||
|
} else if (!on && view) {
|
||||||
|
const el = view.container.firstChild;
|
||||||
|
const destroyView = () => (view.destroy(), view = null);
|
||||||
|
if (leave && el) {
|
||||||
|
el.classList.add(leave);
|
||||||
|
wait(el, destroyView);
|
||||||
|
} else {
|
||||||
|
destroyView();
|
||||||
}
|
}
|
||||||
const content = show ? ifYes : ifNot;
|
|
||||||
if (content) {
|
|
||||||
currentView = Render(() => isFunc(content) ? content() : content);
|
|
||||||
root.insertBefore(currentView.container, anchor);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onUnmount(() => currentView?.destroy());
|
return _onUnmount(() => view?.destroy()), wrap;
|
||||||
return root;
|
|
||||||
};
|
};
|
||||||
var For = (src, itemFn, keyFn) => {
|
var each = (src, itemFn, keyFn) => {
|
||||||
const anchor = doc.createTextNode("");
|
const anchor = doc.createTextNode("");
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
const root = h("div", { style: "display:contents" }, [anchor]);
|
||||||
let cache = new Map;
|
let cache = new Map;
|
||||||
Watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
||||||
const nextCache = new Map;
|
const nextCache = new Map;
|
||||||
const nextOrder = [];
|
const nextOrder = [];
|
||||||
const newItems = items || [];
|
const newItems = items || [];
|
||||||
@@ -452,7 +464,7 @@ var For = (src, itemFn, keyFn) => {
|
|||||||
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
||||||
let view = cache.get(key);
|
let view = cache.get(key);
|
||||||
if (!view)
|
if (!view)
|
||||||
view = Render(() => itemFn(item, i));
|
view = render(() => itemFn(item, i));
|
||||||
else
|
else
|
||||||
cache.delete(key);
|
cache.delete(key);
|
||||||
nextCache.set(key, view);
|
nextCache.set(key, view);
|
||||||
@@ -471,15 +483,15 @@ var For = (src, itemFn, keyFn) => {
|
|||||||
});
|
});
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
var Router = (routes) => {
|
var router = (routes) => {
|
||||||
const getHash = () => window.location.hash.slice(1) || "/";
|
const getHash = () => window.location.hash.slice(1) || "/";
|
||||||
const path = $(getHash());
|
const path = $(getHash());
|
||||||
const handler = () => path(getHash());
|
const handler = () => path(getHash());
|
||||||
window.addEventListener("hashchange", handler);
|
window.addEventListener("hashchange", handler);
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler));
|
_onUnmount(() => window.removeEventListener("hashchange", handler));
|
||||||
const hook = Tag("div", { class: "router-hook" });
|
const hook = h("div", { class: "router-hook" });
|
||||||
let currentView = null;
|
let currentView = null;
|
||||||
Watch([path], () => {
|
watch([path], () => {
|
||||||
const cur = path();
|
const cur = path();
|
||||||
const route = routes.find((r) => {
|
const route = routes.find((r) => {
|
||||||
const p1 = r.path.split("/").filter(Boolean);
|
const p1 = r.path.split("/").filter(Boolean);
|
||||||
@@ -493,91 +505,43 @@ var Router = (routes) => {
|
|||||||
if (p[0] === ":")
|
if (p[0] === ":")
|
||||||
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
||||||
});
|
});
|
||||||
Router.params(params);
|
router.params(params);
|
||||||
currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component);
|
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component);
|
||||||
hook.replaceChildren(currentView.container);
|
hook.replaceChildren(currentView.container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return hook;
|
return hook;
|
||||||
};
|
};
|
||||||
Router.params = $({});
|
router.params = $({});
|
||||||
Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
||||||
Router.back = () => window.history.back();
|
router.back = () => window.history.back();
|
||||||
Router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
||||||
var Anim = (show, render, { enter, leave } = {}) => {
|
var mount = (comp, target) => {
|
||||||
const wrap = Tag("div", { style: "display:contents" });
|
|
||||||
let view = null;
|
|
||||||
const wait = (el, cb) => {
|
|
||||||
let done = false;
|
|
||||||
const finish = () => !done && (done = true, cb());
|
|
||||||
if (!el)
|
|
||||||
return finish();
|
|
||||||
"transitionend animationend".split(" ").map((e) => el.addEventListener(e, finish, { once: true }));
|
|
||||||
setTimeout(finish, 500);
|
|
||||||
};
|
|
||||||
Watch(show, (on) => {
|
|
||||||
if (on && !view) {
|
|
||||||
const el = (view = Render(render)).container.firstChild;
|
|
||||||
wrap.appendChild(view.container);
|
|
||||||
if (enter && el) {
|
|
||||||
el.classList.add(enter);
|
|
||||||
el.clientTop;
|
|
||||||
el.classList.add(enter + "-active");
|
|
||||||
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
|
||||||
}
|
|
||||||
} else if (!on && view) {
|
|
||||||
const el = view.container.firstChild;
|
|
||||||
const del = () => (view?.destroy(), view = null);
|
|
||||||
leave && el ? (el.classList.add(leave), wait(el, del)) : del();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return onUnmount(() => view?.destroy()), wrap;
|
|
||||||
};
|
|
||||||
var Mount = (comp, target) => {
|
|
||||||
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
||||||
if (!t)
|
if (!t)
|
||||||
return;
|
return;
|
||||||
if (MOUNTED_NODES.has(t))
|
if (MOUNTED_NODES.has(t))
|
||||||
MOUNTED_NODES.get(t).destroy();
|
MOUNTED_NODES.get(t).destroy();
|
||||||
const inst = Render(isFunc(comp) ? comp : () => comp);
|
const inst = render(isFunc(comp) ? comp : () => comp);
|
||||||
t.replaceChildren(inst.container);
|
t.replaceChildren(inst.container);
|
||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
var SigPro = Object.freeze({
|
var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch });
|
||||||
$,
|
|
||||||
$$,
|
|
||||||
Watch,
|
|
||||||
Tag,
|
|
||||||
Render,
|
|
||||||
If,
|
|
||||||
For,
|
|
||||||
Router,
|
|
||||||
Mount,
|
|
||||||
onMount,
|
|
||||||
onUnmount,
|
|
||||||
Anim,
|
|
||||||
Batch
|
|
||||||
});
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
Object.assign(window, SigPro);
|
Object.assign(window, SigPro);
|
||||||
"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer ul ol li a em strong pre code form label input textarea select button img svg".split(" ").forEach((t) => {
|
"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) => {
|
||||||
const name = t[0].toUpperCase() + t.slice(1);
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
window[name] = (p, c) => Tag(t, p, c);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
onUnmount,
|
when,
|
||||||
onMount,
|
watch,
|
||||||
Watch,
|
router,
|
||||||
Tag,
|
mount,
|
||||||
Router,
|
h,
|
||||||
Render,
|
each,
|
||||||
Mount,
|
batch,
|
||||||
If,
|
|
||||||
For,
|
|
||||||
Batch,
|
|
||||||
Anim,
|
|
||||||
$$,
|
$$,
|
||||||
$
|
$
|
||||||
};
|
};
|
||||||
|
|||||||
2
dist/sigpro.esm.min.js
vendored
2
dist/sigpro.esm.min.js
vendored
File diff suppressed because one or more lines are too long
214
dist/sigpro.js
vendored
214
dist/sigpro.js
vendored
@@ -40,17 +40,13 @@
|
|||||||
// index.js
|
// index.js
|
||||||
var exports_sigpro = {};
|
var exports_sigpro = {};
|
||||||
__export(exports_sigpro, {
|
__export(exports_sigpro, {
|
||||||
onUnmount: () => onUnmount,
|
when: () => when,
|
||||||
onMount: () => onMount,
|
watch: () => watch,
|
||||||
Watch: () => Watch,
|
router: () => router,
|
||||||
Tag: () => Tag,
|
mount: () => mount,
|
||||||
Router: () => Router,
|
h: () => h,
|
||||||
Render: () => Render,
|
each: () => each,
|
||||||
Mount: () => Mount,
|
batch: () => batch,
|
||||||
If: () => If,
|
|
||||||
For: () => For,
|
|
||||||
Batch: () => Batch,
|
|
||||||
Anim: () => Anim,
|
|
||||||
$$: () => $$,
|
$$: () => $$,
|
||||||
$: () => $
|
$: () => $
|
||||||
});
|
});
|
||||||
@@ -90,11 +86,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var onMount = (fn) => {
|
var _onUnmount = (fn) => {
|
||||||
if (activeOwner)
|
|
||||||
(activeOwner._mounts ||= []).push(fn);
|
|
||||||
};
|
|
||||||
var onUnmount = (fn) => {
|
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
(activeOwner._cleanups ||= new Set).add(fn);
|
(activeOwner._cleanups ||= new Set).add(fn);
|
||||||
};
|
};
|
||||||
@@ -150,7 +142,7 @@
|
|||||||
e();
|
e();
|
||||||
isFlushing = false;
|
isFlushing = false;
|
||||||
};
|
};
|
||||||
var Batch = (fn) => {
|
var batch = (fn) => {
|
||||||
batchDepth++;
|
batchDepth++;
|
||||||
try {
|
try {
|
||||||
return fn();
|
return fn();
|
||||||
@@ -183,16 +175,16 @@
|
|||||||
queueMicrotask(flush);
|
queueMicrotask(flush);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var $ = (val2, key = null) => {
|
var $ = (val, key = null) => {
|
||||||
const subs = new Set;
|
const subs = new Set;
|
||||||
if (isFunc(val2)) {
|
if (isFunc(val)) {
|
||||||
let cache;
|
let cache;
|
||||||
const computed = () => {
|
const computed = () => {
|
||||||
if (computed._dirty) {
|
if (computed._dirty) {
|
||||||
const prev = activeEffect;
|
const prev = activeEffect;
|
||||||
activeEffect = computed;
|
activeEffect = computed;
|
||||||
try {
|
try {
|
||||||
const next = val2();
|
const next = val();
|
||||||
if (!Object.is(cache, next)) {
|
if (!Object.is(cache, next)) {
|
||||||
cache = next;
|
cache = next;
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
@@ -212,25 +204,25 @@
|
|||||||
computed._disposed = false;
|
computed._disposed = false;
|
||||||
computed.stop = () => {};
|
computed.stop = () => {};
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
onUnmount(computed.stop);
|
_onUnmount(computed.stop);
|
||||||
return computed;
|
return computed;
|
||||||
}
|
}
|
||||||
if (key)
|
if (key)
|
||||||
try {
|
try {
|
||||||
val2 = JSON.parse(localStorage.getItem(key)) ?? val2;
|
val = JSON.parse(localStorage.getItem(key)) ?? val;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
if (args.length) {
|
if (args.length) {
|
||||||
const next = isFunc(args[0]) ? args[0](val2) : args[0];
|
const next = isFunc(args[0]) ? args[0](val) : args[0];
|
||||||
if (!Object.is(val2, next)) {
|
if (!Object.is(val, next)) {
|
||||||
val2 = next;
|
val = next;
|
||||||
if (key)
|
if (key)
|
||||||
localStorage.setItem(key, JSON.stringify(val2));
|
localStorage.setItem(key, JSON.stringify(val));
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackUpdate(subs);
|
trackUpdate(subs);
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var $$ = (target) => {
|
var $$ = (target) => {
|
||||||
@@ -279,7 +271,7 @@
|
|||||||
proxyCache.set(target, proxy);
|
proxyCache.set(target, proxy);
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
var Watch = (sources, cb) => {
|
var watch = (sources, cb) => {
|
||||||
if (cb === undefined) {
|
if (cb === undefined) {
|
||||||
const effect2 = createEffect(sources);
|
const effect2 = createEffect(sources);
|
||||||
effect2();
|
effect2();
|
||||||
@@ -304,25 +296,24 @@
|
|||||||
};
|
};
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
||||||
var validateAttr = (key, val2) => {
|
var validateAttr = (key, val) => {
|
||||||
if (val2 == null || val2 === false)
|
if (val == null || val === false)
|
||||||
return null;
|
return null;
|
||||||
if (isDangerousAttr(key)) {
|
if (isDangerousAttr(key)) {
|
||||||
const sVal = String(val2);
|
const sVal = String(val);
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
return "#";
|
return "#";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
var Tag = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
props = {};
|
props = {};
|
||||||
}
|
}
|
||||||
if (isFunc(tag)) {
|
if (isFunc(tag)) {
|
||||||
const ctx = { _mounts: [], _cleanups: new Set };
|
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const result2 = tag(props, {
|
const result2 = tag(props, {
|
||||||
children,
|
children,
|
||||||
@@ -359,7 +350,7 @@
|
|||||||
}
|
}
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
const ns = "http://www.w3.org/1999/xlink";
|
const ns = "http://www.w3.org/1999/xlink";
|
||||||
val == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), val);
|
v == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), v);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
@@ -367,33 +358,33 @@
|
|||||||
el.addEventListener(ev, v);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, v);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
_onUnmount(off);
|
||||||
} else if (isFunc(v)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const val2 = validateAttr(k, v());
|
const val = validateAttr(k, v());
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = val2 || "";
|
el.className = val || "";
|
||||||
else if (val2 == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const val2 = validateAttr(k, v);
|
const val = validateAttr(k, v);
|
||||||
if (val2 != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,7 +419,7 @@
|
|||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
} else {
|
} else {
|
||||||
const node = ensureNode(c);
|
const node = ensureNode(c);
|
||||||
el.appendChild(node);
|
el.appendChild(node);
|
||||||
@@ -439,7 +430,7 @@
|
|||||||
append(children);
|
append(children);
|
||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
var Render = (renderFn) => {
|
var render = (renderFn) => {
|
||||||
const cleanups = new Set;
|
const cleanups = new Set;
|
||||||
const mounts = [];
|
const mounts = [];
|
||||||
const previousOwner = activeOwner;
|
const previousOwner = activeOwner;
|
||||||
@@ -478,29 +469,46 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var If = (cond, ifYes, ifNot = null) => {
|
var when = (cond, render2, { enter, leave } = {}) => {
|
||||||
const anchor = doc.createTextNode("");
|
const wrap = h("div", { style: "display:contents" });
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
let view = null;
|
||||||
let currentView = null;
|
const wait = (el, cb) => {
|
||||||
Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => {
|
if (!el)
|
||||||
if (currentView) {
|
return cb();
|
||||||
currentView.destroy();
|
let done = false;
|
||||||
currentView = null;
|
const finish = () => !done && (done = true, cb());
|
||||||
|
el.addEventListener("transitionend", finish, { once: true });
|
||||||
|
el.addEventListener("animationend", finish, { once: true });
|
||||||
|
setTimeout(finish, 500);
|
||||||
|
};
|
||||||
|
watch(cond, (on) => {
|
||||||
|
if (on && !view) {
|
||||||
|
const el = (view = render2(render2)).container.firstChild;
|
||||||
|
wrap.appendChild(view.container);
|
||||||
|
if (enter && el) {
|
||||||
|
el.classList.add(enter);
|
||||||
|
el.clientTop;
|
||||||
|
el.classList.add(enter + "-active");
|
||||||
|
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
||||||
|
}
|
||||||
|
} else if (!on && view) {
|
||||||
|
const el = view.container.firstChild;
|
||||||
|
const destroyView = () => (view.destroy(), view = null);
|
||||||
|
if (leave && el) {
|
||||||
|
el.classList.add(leave);
|
||||||
|
wait(el, destroyView);
|
||||||
|
} else {
|
||||||
|
destroyView();
|
||||||
}
|
}
|
||||||
const content = show ? ifYes : ifNot;
|
|
||||||
if (content) {
|
|
||||||
currentView = Render(() => isFunc(content) ? content() : content);
|
|
||||||
root.insertBefore(currentView.container, anchor);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onUnmount(() => currentView?.destroy());
|
return _onUnmount(() => view?.destroy()), wrap;
|
||||||
return root;
|
|
||||||
};
|
};
|
||||||
var For = (src, itemFn, keyFn) => {
|
var each = (src, itemFn, keyFn) => {
|
||||||
const anchor = doc.createTextNode("");
|
const anchor = doc.createTextNode("");
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
const root = h("div", { style: "display:contents" }, [anchor]);
|
||||||
let cache = new Map;
|
let cache = new Map;
|
||||||
Watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
||||||
const nextCache = new Map;
|
const nextCache = new Map;
|
||||||
const nextOrder = [];
|
const nextOrder = [];
|
||||||
const newItems = items || [];
|
const newItems = items || [];
|
||||||
@@ -509,7 +517,7 @@
|
|||||||
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
||||||
let view = cache.get(key);
|
let view = cache.get(key);
|
||||||
if (!view)
|
if (!view)
|
||||||
view = Render(() => itemFn(item, i));
|
view = render(() => itemFn(item, i));
|
||||||
else
|
else
|
||||||
cache.delete(key);
|
cache.delete(key);
|
||||||
nextCache.set(key, view);
|
nextCache.set(key, view);
|
||||||
@@ -528,15 +536,15 @@
|
|||||||
});
|
});
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
var Router = (routes) => {
|
var router = (routes) => {
|
||||||
const getHash = () => window.location.hash.slice(1) || "/";
|
const getHash = () => window.location.hash.slice(1) || "/";
|
||||||
const path = $(getHash());
|
const path = $(getHash());
|
||||||
const handler = () => path(getHash());
|
const handler = () => path(getHash());
|
||||||
window.addEventListener("hashchange", handler);
|
window.addEventListener("hashchange", handler);
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler));
|
_onUnmount(() => window.removeEventListener("hashchange", handler));
|
||||||
const hook = Tag("div", { class: "router-hook" });
|
const hook = h("div", { class: "router-hook" });
|
||||||
let currentView = null;
|
let currentView = null;
|
||||||
Watch([path], () => {
|
watch([path], () => {
|
||||||
const cur = path();
|
const cur = path();
|
||||||
const route = routes.find((r) => {
|
const route = routes.find((r) => {
|
||||||
const p1 = r.path.split("/").filter(Boolean);
|
const p1 = r.path.split("/").filter(Boolean);
|
||||||
@@ -550,77 +558,33 @@
|
|||||||
if (p[0] === ":")
|
if (p[0] === ":")
|
||||||
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
||||||
});
|
});
|
||||||
Router.params(params);
|
router.params(params);
|
||||||
currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component);
|
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component);
|
||||||
hook.replaceChildren(currentView.container);
|
hook.replaceChildren(currentView.container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return hook;
|
return hook;
|
||||||
};
|
};
|
||||||
Router.params = $({});
|
router.params = $({});
|
||||||
Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
||||||
Router.back = () => window.history.back();
|
router.back = () => window.history.back();
|
||||||
Router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
||||||
var Anim = (show, render, { enter, leave } = {}) => {
|
var mount = (comp, target) => {
|
||||||
const wrap = Tag("div", { style: "display:contents" });
|
|
||||||
let view = null;
|
|
||||||
const wait = (el, cb) => {
|
|
||||||
let done = false;
|
|
||||||
const finish = () => !done && (done = true, cb());
|
|
||||||
if (!el)
|
|
||||||
return finish();
|
|
||||||
"transitionend animationend".split(" ").map((e) => el.addEventListener(e, finish, { once: true }));
|
|
||||||
setTimeout(finish, 500);
|
|
||||||
};
|
|
||||||
Watch(show, (on) => {
|
|
||||||
if (on && !view) {
|
|
||||||
const el = (view = Render(render)).container.firstChild;
|
|
||||||
wrap.appendChild(view.container);
|
|
||||||
if (enter && el) {
|
|
||||||
el.classList.add(enter);
|
|
||||||
el.clientTop;
|
|
||||||
el.classList.add(enter + "-active");
|
|
||||||
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
|
||||||
}
|
|
||||||
} else if (!on && view) {
|
|
||||||
const el = view.container.firstChild;
|
|
||||||
const del = () => (view?.destroy(), view = null);
|
|
||||||
leave && el ? (el.classList.add(leave), wait(el, del)) : del();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return onUnmount(() => view?.destroy()), wrap;
|
|
||||||
};
|
|
||||||
var Mount = (comp, target) => {
|
|
||||||
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
||||||
if (!t)
|
if (!t)
|
||||||
return;
|
return;
|
||||||
if (MOUNTED_NODES.has(t))
|
if (MOUNTED_NODES.has(t))
|
||||||
MOUNTED_NODES.get(t).destroy();
|
MOUNTED_NODES.get(t).destroy();
|
||||||
const inst = Render(isFunc(comp) ? comp : () => comp);
|
const inst = render(isFunc(comp) ? comp : () => comp);
|
||||||
t.replaceChildren(inst.container);
|
t.replaceChildren(inst.container);
|
||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
var SigPro = Object.freeze({
|
var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch });
|
||||||
$,
|
|
||||||
$$,
|
|
||||||
Watch,
|
|
||||||
Tag,
|
|
||||||
Render,
|
|
||||||
If,
|
|
||||||
For,
|
|
||||||
Router,
|
|
||||||
Mount,
|
|
||||||
onMount,
|
|
||||||
onUnmount,
|
|
||||||
Anim,
|
|
||||||
Batch
|
|
||||||
});
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
Object.assign(window, SigPro);
|
Object.assign(window, SigPro);
|
||||||
"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer ul ol li a em strong pre code form label input textarea select button img svg".split(" ").forEach((t) => {
|
"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) => {
|
||||||
const name = t[0].toUpperCase() + t.slice(1);
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
window[name] = (p, c) => Tag(t, p, c);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
2
dist/sigpro.min.js
vendored
2
dist/sigpro.min.js
vendored
File diff suppressed because one or more lines are too long
214
docs/sigpro.js
214
docs/sigpro.js
@@ -40,17 +40,13 @@
|
|||||||
// index.js
|
// index.js
|
||||||
var exports_sigpro = {};
|
var exports_sigpro = {};
|
||||||
__export(exports_sigpro, {
|
__export(exports_sigpro, {
|
||||||
onUnmount: () => onUnmount,
|
when: () => when,
|
||||||
onMount: () => onMount,
|
watch: () => watch,
|
||||||
Watch: () => Watch,
|
router: () => router,
|
||||||
Tag: () => Tag,
|
mount: () => mount,
|
||||||
Router: () => Router,
|
h: () => h,
|
||||||
Render: () => Render,
|
each: () => each,
|
||||||
Mount: () => Mount,
|
batch: () => batch,
|
||||||
If: () => If,
|
|
||||||
For: () => For,
|
|
||||||
Batch: () => Batch,
|
|
||||||
Anim: () => Anim,
|
|
||||||
$$: () => $$,
|
$$: () => $$,
|
||||||
$: () => $
|
$: () => $
|
||||||
});
|
});
|
||||||
@@ -90,11 +86,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var onMount = (fn) => {
|
var _onUnmount = (fn) => {
|
||||||
if (activeOwner)
|
|
||||||
(activeOwner._mounts ||= []).push(fn);
|
|
||||||
};
|
|
||||||
var onUnmount = (fn) => {
|
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
(activeOwner._cleanups ||= new Set).add(fn);
|
(activeOwner._cleanups ||= new Set).add(fn);
|
||||||
};
|
};
|
||||||
@@ -150,7 +142,7 @@
|
|||||||
e();
|
e();
|
||||||
isFlushing = false;
|
isFlushing = false;
|
||||||
};
|
};
|
||||||
var Batch = (fn) => {
|
var batch = (fn) => {
|
||||||
batchDepth++;
|
batchDepth++;
|
||||||
try {
|
try {
|
||||||
return fn();
|
return fn();
|
||||||
@@ -183,16 +175,16 @@
|
|||||||
queueMicrotask(flush);
|
queueMicrotask(flush);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var $ = (val2, key = null) => {
|
var $ = (val, key = null) => {
|
||||||
const subs = new Set;
|
const subs = new Set;
|
||||||
if (isFunc(val2)) {
|
if (isFunc(val)) {
|
||||||
let cache;
|
let cache;
|
||||||
const computed = () => {
|
const computed = () => {
|
||||||
if (computed._dirty) {
|
if (computed._dirty) {
|
||||||
const prev = activeEffect;
|
const prev = activeEffect;
|
||||||
activeEffect = computed;
|
activeEffect = computed;
|
||||||
try {
|
try {
|
||||||
const next = val2();
|
const next = val();
|
||||||
if (!Object.is(cache, next)) {
|
if (!Object.is(cache, next)) {
|
||||||
cache = next;
|
cache = next;
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
@@ -212,25 +204,25 @@
|
|||||||
computed._disposed = false;
|
computed._disposed = false;
|
||||||
computed.stop = () => {};
|
computed.stop = () => {};
|
||||||
if (activeOwner)
|
if (activeOwner)
|
||||||
onUnmount(computed.stop);
|
_onUnmount(computed.stop);
|
||||||
return computed;
|
return computed;
|
||||||
}
|
}
|
||||||
if (key)
|
if (key)
|
||||||
try {
|
try {
|
||||||
val2 = JSON.parse(localStorage.getItem(key)) ?? val2;
|
val = JSON.parse(localStorage.getItem(key)) ?? val;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
if (args.length) {
|
if (args.length) {
|
||||||
const next = isFunc(args[0]) ? args[0](val2) : args[0];
|
const next = isFunc(args[0]) ? args[0](val) : args[0];
|
||||||
if (!Object.is(val2, next)) {
|
if (!Object.is(val, next)) {
|
||||||
val2 = next;
|
val = next;
|
||||||
if (key)
|
if (key)
|
||||||
localStorage.setItem(key, JSON.stringify(val2));
|
localStorage.setItem(key, JSON.stringify(val));
|
||||||
trackUpdate(subs, true);
|
trackUpdate(subs, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackUpdate(subs);
|
trackUpdate(subs);
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var $$ = (target) => {
|
var $$ = (target) => {
|
||||||
@@ -279,7 +271,7 @@
|
|||||||
proxyCache.set(target, proxy);
|
proxyCache.set(target, proxy);
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
var Watch = (sources, cb) => {
|
var watch = (sources, cb) => {
|
||||||
if (cb === undefined) {
|
if (cb === undefined) {
|
||||||
const effect2 = createEffect(sources);
|
const effect2 = createEffect(sources);
|
||||||
effect2();
|
effect2();
|
||||||
@@ -304,25 +296,24 @@
|
|||||||
};
|
};
|
||||||
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
|
||||||
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on");
|
||||||
var validateAttr = (key, val2) => {
|
var validateAttr = (key, val) => {
|
||||||
if (val2 == null || val2 === false)
|
if (val == null || val === false)
|
||||||
return null;
|
return null;
|
||||||
if (isDangerousAttr(key)) {
|
if (isDangerousAttr(key)) {
|
||||||
const sVal = String(val2);
|
const sVal = String(val);
|
||||||
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
if (DANGEROUS_PROTOCOL.test(sVal)) {
|
||||||
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`);
|
||||||
return "#";
|
return "#";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val2;
|
return val;
|
||||||
};
|
};
|
||||||
var Tag = (tag, props = {}, children = []) => {
|
var h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props;
|
children = props;
|
||||||
props = {};
|
props = {};
|
||||||
}
|
}
|
||||||
if (isFunc(tag)) {
|
if (isFunc(tag)) {
|
||||||
const ctx = { _mounts: [], _cleanups: new Set };
|
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const result2 = tag(props, {
|
const result2 = tag(props, {
|
||||||
children,
|
children,
|
||||||
@@ -359,7 +350,7 @@
|
|||||||
}
|
}
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
const ns = "http://www.w3.org/1999/xlink";
|
const ns = "http://www.w3.org/1999/xlink";
|
||||||
val == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), val);
|
v == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), v);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
@@ -367,33 +358,33 @@
|
|||||||
el.addEventListener(ev, v);
|
el.addEventListener(ev, v);
|
||||||
const off = () => el.removeEventListener(ev, v);
|
const off = () => el.removeEventListener(ev, v);
|
||||||
el._cleanups.add(off);
|
el._cleanups.add(off);
|
||||||
onUnmount(off);
|
_onUnmount(off);
|
||||||
} else if (isFunc(v)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const val2 = validateAttr(k, v());
|
const val = validateAttr(k, v());
|
||||||
if (k === "class")
|
if (k === "class")
|
||||||
el.className = val2 || "";
|
el.className = val || "";
|
||||||
else if (val2 == null)
|
else if (val == null)
|
||||||
el.removeAttribute(k);
|
el.removeAttribute(k);
|
||||||
else if (k in el && !isSVG)
|
else if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input";
|
const evType = k === "checked" ? "change" : "input";
|
||||||
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
el.addEventListener(evType, (ev) => v(ev.target[k]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const val2 = validateAttr(k, v);
|
const val = validateAttr(k, v);
|
||||||
if (val2 != null) {
|
if (val != null) {
|
||||||
if (k in el && !isSVG)
|
if (k in el && !isSVG)
|
||||||
el[k] = val2;
|
el[k] = val;
|
||||||
else
|
else
|
||||||
el.setAttribute(k, val2 === true ? "" : val2);
|
el.setAttribute(k, val === true ? "" : val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,7 +419,7 @@
|
|||||||
});
|
});
|
||||||
effect();
|
effect();
|
||||||
el._cleanups.add(() => dispose(effect));
|
el._cleanups.add(() => dispose(effect));
|
||||||
onUnmount(() => dispose(effect));
|
_onUnmount(() => dispose(effect));
|
||||||
} else {
|
} else {
|
||||||
const node = ensureNode(c);
|
const node = ensureNode(c);
|
||||||
el.appendChild(node);
|
el.appendChild(node);
|
||||||
@@ -439,7 +430,7 @@
|
|||||||
append(children);
|
append(children);
|
||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
var Render = (renderFn) => {
|
var render = (renderFn) => {
|
||||||
const cleanups = new Set;
|
const cleanups = new Set;
|
||||||
const mounts = [];
|
const mounts = [];
|
||||||
const previousOwner = activeOwner;
|
const previousOwner = activeOwner;
|
||||||
@@ -478,29 +469,46 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var If = (cond, ifYes, ifNot = null) => {
|
var when = (cond, render2, { enter, leave } = {}) => {
|
||||||
const anchor = doc.createTextNode("");
|
const wrap = h("div", { style: "display:contents" });
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
let view = null;
|
||||||
let currentView = null;
|
const wait = (el, cb) => {
|
||||||
Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => {
|
if (!el)
|
||||||
if (currentView) {
|
return cb();
|
||||||
currentView.destroy();
|
let done = false;
|
||||||
currentView = null;
|
const finish = () => !done && (done = true, cb());
|
||||||
|
el.addEventListener("transitionend", finish, { once: true });
|
||||||
|
el.addEventListener("animationend", finish, { once: true });
|
||||||
|
setTimeout(finish, 500);
|
||||||
|
};
|
||||||
|
watch(cond, (on) => {
|
||||||
|
if (on && !view) {
|
||||||
|
const el = (view = render2(render2)).container.firstChild;
|
||||||
|
wrap.appendChild(view.container);
|
||||||
|
if (enter && el) {
|
||||||
|
el.classList.add(enter);
|
||||||
|
el.clientTop;
|
||||||
|
el.classList.add(enter + "-active");
|
||||||
|
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
||||||
|
}
|
||||||
|
} else if (!on && view) {
|
||||||
|
const el = view.container.firstChild;
|
||||||
|
const destroyView = () => (view.destroy(), view = null);
|
||||||
|
if (leave && el) {
|
||||||
|
el.classList.add(leave);
|
||||||
|
wait(el, destroyView);
|
||||||
|
} else {
|
||||||
|
destroyView();
|
||||||
}
|
}
|
||||||
const content = show ? ifYes : ifNot;
|
|
||||||
if (content) {
|
|
||||||
currentView = Render(() => isFunc(content) ? content() : content);
|
|
||||||
root.insertBefore(currentView.container, anchor);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onUnmount(() => currentView?.destroy());
|
return _onUnmount(() => view?.destroy()), wrap;
|
||||||
return root;
|
|
||||||
};
|
};
|
||||||
var For = (src, itemFn, keyFn) => {
|
var each = (src, itemFn, keyFn) => {
|
||||||
const anchor = doc.createTextNode("");
|
const anchor = doc.createTextNode("");
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor]);
|
const root = h("div", { style: "display:contents" }, [anchor]);
|
||||||
let cache = new Map;
|
let cache = new Map;
|
||||||
Watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
watch(() => (isFunc(src) ? src() : src) || [], (items) => {
|
||||||
const nextCache = new Map;
|
const nextCache = new Map;
|
||||||
const nextOrder = [];
|
const nextOrder = [];
|
||||||
const newItems = items || [];
|
const newItems = items || [];
|
||||||
@@ -509,7 +517,7 @@
|
|||||||
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
const key = keyFn ? keyFn(item, i) : item?.id ?? i;
|
||||||
let view = cache.get(key);
|
let view = cache.get(key);
|
||||||
if (!view)
|
if (!view)
|
||||||
view = Render(() => itemFn(item, i));
|
view = render(() => itemFn(item, i));
|
||||||
else
|
else
|
||||||
cache.delete(key);
|
cache.delete(key);
|
||||||
nextCache.set(key, view);
|
nextCache.set(key, view);
|
||||||
@@ -528,15 +536,15 @@
|
|||||||
});
|
});
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
var Router = (routes) => {
|
var router = (routes) => {
|
||||||
const getHash = () => window.location.hash.slice(1) || "/";
|
const getHash = () => window.location.hash.slice(1) || "/";
|
||||||
const path = $(getHash());
|
const path = $(getHash());
|
||||||
const handler = () => path(getHash());
|
const handler = () => path(getHash());
|
||||||
window.addEventListener("hashchange", handler);
|
window.addEventListener("hashchange", handler);
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler));
|
_onUnmount(() => window.removeEventListener("hashchange", handler));
|
||||||
const hook = Tag("div", { class: "router-hook" });
|
const hook = h("div", { class: "router-hook" });
|
||||||
let currentView = null;
|
let currentView = null;
|
||||||
Watch([path], () => {
|
watch([path], () => {
|
||||||
const cur = path();
|
const cur = path();
|
||||||
const route = routes.find((r) => {
|
const route = routes.find((r) => {
|
||||||
const p1 = r.path.split("/").filter(Boolean);
|
const p1 = r.path.split("/").filter(Boolean);
|
||||||
@@ -550,77 +558,33 @@
|
|||||||
if (p[0] === ":")
|
if (p[0] === ":")
|
||||||
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
params[p.slice(1)] = cur.split("/").filter(Boolean)[i];
|
||||||
});
|
});
|
||||||
Router.params(params);
|
router.params(params);
|
||||||
currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component);
|
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component);
|
||||||
hook.replaceChildren(currentView.container);
|
hook.replaceChildren(currentView.container);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return hook;
|
return hook;
|
||||||
};
|
};
|
||||||
Router.params = $({});
|
router.params = $({});
|
||||||
Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/");
|
||||||
Router.back = () => window.history.back();
|
router.back = () => window.history.back();
|
||||||
Router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
||||||
var Anim = (show, render, { enter, leave } = {}) => {
|
var mount = (comp, target) => {
|
||||||
const wrap = Tag("div", { style: "display:contents" });
|
|
||||||
let view = null;
|
|
||||||
const wait = (el, cb) => {
|
|
||||||
let done = false;
|
|
||||||
const finish = () => !done && (done = true, cb());
|
|
||||||
if (!el)
|
|
||||||
return finish();
|
|
||||||
"transitionend animationend".split(" ").map((e) => el.addEventListener(e, finish, { once: true }));
|
|
||||||
setTimeout(finish, 500);
|
|
||||||
};
|
|
||||||
Watch(show, (on) => {
|
|
||||||
if (on && !view) {
|
|
||||||
const el = (view = Render(render)).container.firstChild;
|
|
||||||
wrap.appendChild(view.container);
|
|
||||||
if (enter && el) {
|
|
||||||
el.classList.add(enter);
|
|
||||||
el.clientTop;
|
|
||||||
el.classList.add(enter + "-active");
|
|
||||||
wait(el, () => el.classList.remove(enter, enter + "-active"));
|
|
||||||
}
|
|
||||||
} else if (!on && view) {
|
|
||||||
const el = view.container.firstChild;
|
|
||||||
const del = () => (view?.destroy(), view = null);
|
|
||||||
leave && el ? (el.classList.add(leave), wait(el, del)) : del();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return onUnmount(() => view?.destroy()), wrap;
|
|
||||||
};
|
|
||||||
var Mount = (comp, target) => {
|
|
||||||
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
const t = typeof target === "string" ? doc.querySelector(target) : target;
|
||||||
if (!t)
|
if (!t)
|
||||||
return;
|
return;
|
||||||
if (MOUNTED_NODES.has(t))
|
if (MOUNTED_NODES.has(t))
|
||||||
MOUNTED_NODES.get(t).destroy();
|
MOUNTED_NODES.get(t).destroy();
|
||||||
const inst = Render(isFunc(comp) ? comp : () => comp);
|
const inst = render(isFunc(comp) ? comp : () => comp);
|
||||||
t.replaceChildren(inst.container);
|
t.replaceChildren(inst.container);
|
||||||
MOUNTED_NODES.set(t, inst);
|
MOUNTED_NODES.set(t, inst);
|
||||||
return inst;
|
return inst;
|
||||||
};
|
};
|
||||||
var SigPro = Object.freeze({
|
var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch });
|
||||||
$,
|
|
||||||
$$,
|
|
||||||
Watch,
|
|
||||||
Tag,
|
|
||||||
Render,
|
|
||||||
If,
|
|
||||||
For,
|
|
||||||
Router,
|
|
||||||
Mount,
|
|
||||||
onMount,
|
|
||||||
onUnmount,
|
|
||||||
Anim,
|
|
||||||
Batch
|
|
||||||
});
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
Object.assign(window, SigPro);
|
Object.assign(window, SigPro);
|
||||||
"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer ul ol li a em strong pre code form label input textarea select button img svg".split(" ").forEach((t) => {
|
"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) => {
|
||||||
const name = t[0].toUpperCase() + t.slice(1);
|
window[tag] = (props, children) => h(tag, props, children);
|
||||||
window[name] = (p, c) => Tag(t, p, c);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sigpro",
|
"name": "sigpro",
|
||||||
"version": "1.2.13",
|
"version": "1.2.14",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/sigpro.esm.min.js",
|
"main": "./dist/sigpro.esm.min.js",
|
||||||
|
|||||||
147
sigpro.js
147
sigpro.js
@@ -1,4 +1,4 @@
|
|||||||
// sigpro 1.2.13
|
// sigpro 1.2.14
|
||||||
const isFunc = f => typeof f === "function"
|
const isFunc = f => typeof f === "function"
|
||||||
const isObj = o => o && typeof o === "object"
|
const isObj = o => o && typeof o === "object"
|
||||||
const isArr = Array.isArray
|
const isArr = Array.isArray
|
||||||
@@ -35,11 +35,7 @@ const dispose = eff => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMount = fn => {
|
const _onUnmount = fn => {
|
||||||
if (activeOwner) (activeOwner._mounts ||= []).push(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onUnmount = fn => {
|
|
||||||
if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn)
|
if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +84,7 @@ const flush = () => {
|
|||||||
isFlushing = false
|
isFlushing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const Batch = fn => {
|
const batch = fn => {
|
||||||
batchDepth++
|
batchDepth++
|
||||||
try {
|
try {
|
||||||
return fn()
|
return fn()
|
||||||
@@ -148,7 +144,7 @@ const $ = (val, key = null) => {
|
|||||||
computed._deps = null
|
computed._deps = null
|
||||||
computed._disposed = false
|
computed._disposed = false
|
||||||
computed.stop = () => { }
|
computed.stop = () => { }
|
||||||
if (activeOwner) onUnmount(computed.stop)
|
if (activeOwner) _onUnmount(computed.stop)
|
||||||
return computed
|
return computed
|
||||||
}
|
}
|
||||||
if (key) try { val = JSON.parse(localStorage.getItem(key)) ?? val } catch (e) { }
|
if (key) try { val = JSON.parse(localStorage.getItem(key)) ?? val } catch (e) { }
|
||||||
@@ -213,7 +209,7 @@ const $$ = (target) => {
|
|||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
const Watch = (sources, cb) => {
|
const watch = (sources, cb) => {
|
||||||
if (cb === undefined) {
|
if (cb === undefined) {
|
||||||
const effect = createEffect(sources)
|
const effect = createEffect(sources)
|
||||||
effect()
|
effect()
|
||||||
@@ -251,13 +247,12 @@ const validateAttr = (key, val) => {
|
|||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tag = (tag, props = {}, children = []) => {
|
const h = (tag, props = {}, children = []) => {
|
||||||
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
if (props instanceof Node || isArr(props) || !isObj(props)) {
|
||||||
children = props
|
children = props
|
||||||
props = {}
|
props = {}
|
||||||
}
|
}
|
||||||
if (isFunc(tag)) {
|
if (isFunc(tag)) {
|
||||||
const ctx = { _mounts: [], _cleanups: new Set() }
|
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const result = tag(props, {
|
const result = tag(props, {
|
||||||
children,
|
children,
|
||||||
@@ -299,7 +294,7 @@ const Tag = (tag, props = {}, children = []) => {
|
|||||||
}
|
}
|
||||||
if (isSVG && k.startsWith("xlink:")) {
|
if (isSVG && k.startsWith("xlink:")) {
|
||||||
const ns = "http://www.w3.org/1999/xlink"
|
const ns = "http://www.w3.org/1999/xlink"
|
||||||
val == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), val)
|
v == null ? el.removeAttributeNS(ns, k.slice(6)) : el.setAttributeNS(ns, k.slice(6), v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (k.startsWith("on")) {
|
if (k.startsWith("on")) {
|
||||||
@@ -307,7 +302,7 @@ const Tag = (tag, props = {}, children = []) => {
|
|||||||
el.addEventListener(ev, v)
|
el.addEventListener(ev, v)
|
||||||
const off = () => el.removeEventListener(ev, v)
|
const off = () => el.removeEventListener(ev, v)
|
||||||
el._cleanups.add(off)
|
el._cleanups.add(off)
|
||||||
onUnmount(off)
|
_onUnmount(off)
|
||||||
} else if (isFunc(v)) {
|
} else if (isFunc(v)) {
|
||||||
const effect = createEffect(() => {
|
const effect = createEffect(() => {
|
||||||
const val = validateAttr(k, v())
|
const val = validateAttr(k, v())
|
||||||
@@ -318,7 +313,7 @@ const Tag = (tag, props = {}, children = []) => {
|
|||||||
})
|
})
|
||||||
effect()
|
effect()
|
||||||
el._cleanups.add(() => dispose(effect))
|
el._cleanups.add(() => dispose(effect))
|
||||||
onUnmount(() => dispose(effect))
|
_onUnmount(() => dispose(effect))
|
||||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
|
||||||
const evType = k === "checked" ? "change" : "input"
|
const evType = k === "checked" ? "change" : "input"
|
||||||
el.addEventListener(evType, ev => v(ev.target[k]))
|
el.addEventListener(evType, ev => v(ev.target[k]))
|
||||||
@@ -357,7 +352,7 @@ const Tag = (tag, props = {}, children = []) => {
|
|||||||
})
|
})
|
||||||
effect()
|
effect()
|
||||||
el._cleanups.add(() => dispose(effect))
|
el._cleanups.add(() => dispose(effect))
|
||||||
onUnmount(() => dispose(effect))
|
_onUnmount(() => dispose(effect))
|
||||||
} else {
|
} else {
|
||||||
const node = ensureNode(c)
|
const node = ensureNode(c)
|
||||||
el.appendChild(node)
|
el.appendChild(node)
|
||||||
@@ -368,7 +363,7 @@ const Tag = (tag, props = {}, children = []) => {
|
|||||||
return el
|
return el
|
||||||
}
|
}
|
||||||
|
|
||||||
const Render = renderFn => {
|
const render = renderFn => {
|
||||||
const cleanups = new Set()
|
const cleanups = new Set()
|
||||||
const mounts = []
|
const mounts = []
|
||||||
const previousOwner = activeOwner
|
const previousOwner = activeOwner
|
||||||
@@ -410,36 +405,48 @@ const Render = renderFn => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const If = (cond, ifYes, ifNot = null) => {
|
const when = (cond, render, { enter, leave } = {}) => {
|
||||||
const anchor = doc.createTextNode("")
|
const wrap = h('div', { style: 'display:contents' })
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor])
|
let view = null
|
||||||
let currentView = null
|
|
||||||
|
|
||||||
Watch(
|
const wait = (el, cb) => {
|
||||||
() => !!(isFunc(cond) ? cond() : cond),
|
if (!el) return cb()
|
||||||
show => {
|
let done = false
|
||||||
if (currentView) {
|
const finish = () => !done && (done = true, cb())
|
||||||
currentView.destroy()
|
el.addEventListener('transitionend', finish, { once: true })
|
||||||
currentView = null
|
el.addEventListener('animationend', finish, { once: true })
|
||||||
|
setTimeout(finish, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = show ? ifYes : ifNot
|
watch(cond, on => {
|
||||||
if (content) {
|
if (on && !view) {
|
||||||
currentView = Render(() => isFunc(content) ? content() : content)
|
const el = (view = render(render)).container.firstChild
|
||||||
root.insertBefore(currentView.container, anchor)
|
wrap.appendChild(view.container)
|
||||||
|
if (enter && el) {
|
||||||
|
el.classList.add(enter); el.clientTop
|
||||||
|
el.classList.add(enter + '-active')
|
||||||
|
wait(el, () => el.classList.remove(enter, enter + '-active'))
|
||||||
|
}
|
||||||
|
} else if (!on && view) {
|
||||||
|
const el = view.container.firstChild
|
||||||
|
const destroyView = () => (view.destroy(), view = null)
|
||||||
|
if (leave && el) {
|
||||||
|
el.classList.add(leave)
|
||||||
|
wait(el, destroyView)
|
||||||
|
} else {
|
||||||
|
destroyView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
onUnmount(() => currentView?.destroy())
|
return _onUnmount(() => view?.destroy()), wrap
|
||||||
return root
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const For = (src, itemFn, keyFn) => {
|
const each = (src, itemFn, keyFn) => {
|
||||||
const anchor = doc.createTextNode("")
|
const anchor = doc.createTextNode("")
|
||||||
const root = Tag("div", { style: "display:contents" }, [anchor])
|
const root = h("div", { style: "display:contents" }, [anchor])
|
||||||
let cache = new Map()
|
let cache = new Map()
|
||||||
Watch(() => (isFunc(src) ? src() : src) || [], items => {
|
watch(() => (isFunc(src) ? src() : src) || [], items => {
|
||||||
const nextCache = new Map()
|
const nextCache = new Map()
|
||||||
const nextOrder = []
|
const nextOrder = []
|
||||||
const newItems = items || []
|
const newItems = items || []
|
||||||
@@ -447,7 +454,7 @@ const For = (src, itemFn, keyFn) => {
|
|||||||
const item = newItems[i]
|
const item = newItems[i]
|
||||||
const key = keyFn ? keyFn(item, i) : (item?.id ?? i)
|
const key = keyFn ? keyFn(item, i) : (item?.id ?? i)
|
||||||
let view = cache.get(key)
|
let view = cache.get(key)
|
||||||
if (!view) view = Render(() => itemFn(item, i))
|
if (!view) view = render(() => itemFn(item, i))
|
||||||
else cache.delete(key)
|
else cache.delete(key)
|
||||||
nextCache.set(key, view)
|
nextCache.set(key, view)
|
||||||
nextOrder.push(view)
|
nextOrder.push(view)
|
||||||
@@ -465,15 +472,15 @@ const For = (src, itemFn, keyFn) => {
|
|||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
const Router = routes => {
|
const router = routes => {
|
||||||
const getHash = () => window.location.hash.slice(1) || "/"
|
const getHash = () => window.location.hash.slice(1) || "/"
|
||||||
const path = $(getHash())
|
const path = $(getHash())
|
||||||
const handler = () => path(getHash())
|
const handler = () => path(getHash())
|
||||||
window.addEventListener("hashchange", handler)
|
window.addEventListener("hashchange", handler)
|
||||||
onUnmount(() => window.removeEventListener("hashchange", handler))
|
_onUnmount(() => window.removeEventListener("hashchange", handler))
|
||||||
const hook = Tag("div", { class: "router-hook" })
|
const hook = h("div", { class: "router-hook" })
|
||||||
let currentView = null
|
let currentView = null
|
||||||
Watch([path], () => {
|
watch([path], () => {
|
||||||
const cur = path()
|
const cur = path()
|
||||||
const route = routes.find(r => {
|
const route = routes.find(r => {
|
||||||
const p1 = r.path.split("/").filter(Boolean)
|
const p1 = r.path.split("/").filter(Boolean)
|
||||||
@@ -486,68 +493,36 @@ const Router = routes => {
|
|||||||
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
||||||
if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]
|
if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]
|
||||||
})
|
})
|
||||||
Router.params(params)
|
router.params(params)
|
||||||
currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component)
|
currentView = render(() => isFunc(route.component) ? route.component(params) : route.component)
|
||||||
hook.replaceChildren(currentView.container)
|
hook.replaceChildren(currentView.container)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return hook
|
return hook
|
||||||
}
|
}
|
||||||
Router.params = $({})
|
router.params = $({})
|
||||||
Router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/")
|
router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/")
|
||||||
Router.back = () => window.history.back()
|
router.back = () => window.history.back()
|
||||||
Router.path = () => window.location.hash.replace(/^#/, "") || "/"
|
router.path = () => window.location.hash.replace(/^#/, "") || "/"
|
||||||
|
|
||||||
const Anim = (show, render, { enter, leave } = {}) => {
|
const mount = (comp, target) => {
|
||||||
const wrap = Tag('div', { style: 'display:contents' })
|
|
||||||
let view = null
|
|
||||||
|
|
||||||
const wait = (el, cb) => {
|
|
||||||
let done = false
|
|
||||||
const finish = () => !done && (done = true, cb())
|
|
||||||
if (!el) return finish()
|
|
||||||
'transitionend animationend'.split(' ').map(e => el.addEventListener(e, finish, { once: true }))
|
|
||||||
setTimeout(finish, 500)
|
|
||||||
}
|
|
||||||
|
|
||||||
Watch(show, on => {
|
|
||||||
if (on && !view) {
|
|
||||||
const el = (view = Render(render)).container.firstChild
|
|
||||||
wrap.appendChild(view.container)
|
|
||||||
if (enter && el) {
|
|
||||||
el.classList.add(enter); el.clientTop
|
|
||||||
el.classList.add(enter + '-active')
|
|
||||||
wait(el, () => el.classList.remove(enter, enter + '-active'))
|
|
||||||
}
|
|
||||||
} else if (!on && view) {
|
|
||||||
const el = view.container.firstChild
|
|
||||||
const del = () => (view?.destroy(), view = null)
|
|
||||||
leave && el ? (el.classList.add(leave), wait(el, del)) : del()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return onUnmount(() => view?.destroy()), wrap
|
|
||||||
}
|
|
||||||
|
|
||||||
const Mount = (comp, target) => {
|
|
||||||
const t = typeof target === "string" ? doc.querySelector(target) : target
|
const t = typeof target === "string" ? doc.querySelector(target) : target
|
||||||
if (!t) return
|
if (!t) return
|
||||||
if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy()
|
if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy()
|
||||||
const inst = Render(isFunc(comp) ? comp : () => comp)
|
const inst = render(isFunc(comp) ? comp : () => comp)
|
||||||
t.replaceChildren(inst.container)
|
t.replaceChildren(inst.container)
|
||||||
MOUNTED_NODES.set(t, inst)
|
MOUNTED_NODES.set(t, inst)
|
||||||
return inst
|
return inst
|
||||||
}
|
}
|
||||||
|
|
||||||
const SigPro = Object.freeze({ $, $$, Watch, Tag, If, For, Router, Mount, onMount, onUnmount, Anim, Batch })
|
const SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch })
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
Object.assign(window, SigPro)
|
Object.assign(window, SigPro)
|
||||||
"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer ul ol li dl dt dd a em strong pre code small sub sup b i u mark blockquote cite abbr time del ins kbd var form label input textarea select button option optgroup fieldset legend datalist output progress meter details summary dialog img svg video audio canvas figure figcaption picture source table thead tbody tfoot tr th td caption colgroup col iframe object embed template slot"
|
"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(t => {
|
.split(" ").forEach(tag => {
|
||||||
const name = t[0].toUpperCase() + t.slice(1)
|
window[tag] = (props, children) => h(tag, props, children)
|
||||||
window[name] = (p, c) => Tag(t, p, c)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { $, $$, Watch, Tag, If, For, Router, Mount, onMount, onUnmount, Anim, Batch }
|
export { $, $$, watch, h, when, each, router, mount, batch }
|
||||||
Reference in New Issue
Block a user