Reparado para sigpro ui

This commit is contained in:
2026-04-10 23:11:27 +02:00
parent 9588bcbce8
commit 9b9b345e48

View File

@@ -20,7 +20,7 @@ const dispose = eff => {
} }
}; };
export const onUnmount = fn => { const onUnmount = fn => {
if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn); if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn);
}; };
@@ -81,14 +81,14 @@ const trackUpdate = (subs, trigger = false) => {
} }
}; };
export const untrack = fn => { const p = activeEffect; activeEffect = null; try { return fn(); } finally { activeEffect = p; } }; const untrack = fn => { const p = activeEffect; activeEffect = null; try { return fn(); } finally { activeEffect = p; } };
export const onMount = fn => { const onMount = fn => {
if (activeOwner) (activeOwner._mounts ||= []).push(fn); if (activeOwner) (activeOwner._mounts ||= []).push(fn);
}; };
// Reactive state // Reactive state
export const $ = (val, key = null) => { const $ = (val, key = null) => {
const subs = new Set(); const subs = new Set();
if (isFunc(val)) { if (isFunc(val)) {
let cache, dirty = true; let cache, dirty = true;
@@ -129,7 +129,7 @@ export const $ = (val, key = null) => {
}; };
}; };
export const $$ = (obj, cache = new WeakMap()) => { const $$ = (obj, cache = new WeakMap()) => {
if (!isObj(obj)) return obj; if (!isObj(obj)) return obj;
if (cache.has(obj)) return cache.get(obj); if (cache.has(obj)) return cache.get(obj);
const subs = {}; const subs = {};
@@ -142,23 +142,15 @@ export const $$ = (obj, cache = new WeakMap()) => {
}; };
// Watchers // Watchers
export const Watch = (sources, cb) => { const Watch = (sources, cb) => {
const isArr = Array.isArray(sources); if (cb === undefined) {
const effect = createEffect(() => { const effect = createEffect(sources);
const vals = isArr ? sources.map(s => s()) : sources();
untrack(() => cb(vals));
});
effect(); effect();
return () => dispose(effect); return () => dispose(effect);
}; }
export const watch = (source, callback) => {
let oldValue, first = true;
const effect = createEffect(() => { const effect = createEffect(() => {
const newValue = isFunc(source) ? source() : source; const vals = Array.isArray(sources) ? sources.map(s => s()) : sources();
if (!first) untrack(() => callback(newValue, oldValue)); untrack(() => cb(vals));
else first = false;
oldValue = newValue;
}); });
effect(); effect();
return () => dispose(effect); return () => dispose(effect);
@@ -171,11 +163,11 @@ const cleanupNode = node => {
}; };
// provide/inject // provide/inject
export const provide = (key, value) => { const provide = (key, value) => {
if (activeOwner) activeOwner._provisions[key] = value; if (activeOwner) activeOwner._provisions[key] = value;
}; };
export const inject = (key, defaultValue) => { const inject = (key, defaultValue) => {
let ctx = activeOwner; let ctx = activeOwner;
while (ctx) { while (ctx) {
if (key in ctx._provisions) return ctx._provisions[key]; if (key in ctx._provisions) return ctx._provisions[key];
@@ -201,7 +193,7 @@ const validateAttr = (key, val) => {
}; };
// CreateElement // CreateElement
export const Tag = (tag, props = {}, children = []) => { const Tag = (tag, props = {}, children = []) => {
if (props instanceof Node || isArr(props) || !isObj(props)) { children = props; props = {}; } if (props instanceof Node || isArr(props) || !isObj(props)) { children = props; props = {}; }
if (isFunc(tag)) { if (isFunc(tag)) {
const ctx = { const ctx = {
@@ -274,7 +266,11 @@ export const Tag = (tag, props = {}, children = []) => {
const effect = createEffect(() => { const effect = createEffect(() => {
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 => { if (n._isRuntime) n.destroy(); else cleanupNode(n); }); currentNodes.forEach(n => {
if (n._isRuntime) n.destroy();
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];
@@ -298,25 +294,50 @@ export const Tag = (tag, props = {}, children = []) => {
}; };
// Render // Render
export const Render = fn => { const Render = (renderFn) => {
const cleanups = new Set();
const mounts = [];
const previousOwner = activeOwner;
const container = doc.createElement("div"); const container = doc.createElement("div");
container.style.display = "contents"; container.style.display = "contents";
const rootEffect = createEffect(() => { activeOwner = { _cleanups: cleanups, _mounts: mounts };
const res = fn({ onCleanup: onUnmount });
(isArr(res) ? res : [res]).forEach(r => container.appendChild(ensureNode(r))); const processResult = (result) => {
}); if (!result) return;
rootEffect(); if (result._isRuntime) {
rootEffect._mounts?.forEach(fn => fn()); cleanups.add(result.destroy);
return { _isRuntime: true, container, destroy: () => { dispose(rootEffect); container.remove(); } }; 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; }
mounts.forEach(fn => fn());
return {
_isRuntime: true,
container,
destroy: () => {
cleanups.forEach((fn) => fn());
cleanupNode(container);
container.remove();
},
};
}; };
// If // If
export const If = (cond, ifYes, ifNot = null, trans = null) => { const If = (cond, ifYes, ifNot = null, trans = null) => {
const anchor = doc.createTextNode(""); const anchor = doc.createTextNode("");
const root = Tag("div", { style: "display:contents" }, [anchor]); const root = Tag("div", { style: "display:contents" }, [anchor]);
let currentView = null, last = null; let currentView = null, last = null;
Watch(() => { Watch(
const show = !!(isFunc(cond) ? cond() : cond); () => !!(isFunc(cond) ? cond() : cond),
(show) => {
if (show === last) return; if (show === last) return;
last = show; last = show;
const disposeView = () => { if (currentView) { currentView.destroy(); currentView = null; } }; const disposeView = () => { if (currentView) { currentView.destroy(); currentView = null; } };
@@ -328,17 +349,19 @@ export const If = (cond, ifYes, ifNot = null, trans = null) => {
root.insertBefore(currentView.container, anchor); root.insertBefore(currentView.container, anchor);
if (trans?.in) trans.in(currentView.container); if (trans?.in) trans.in(currentView.container);
} }
}); }
);
return root; return root;
}; };
// For // For
export const For = (src, itemFn, keyFn) => { const For = (src, itemFn, keyFn) => {
const anchor = doc.createTextNode(""); const anchor = doc.createTextNode("");
const root = Tag("div", { style: "display:contents" }, [anchor]); const root = Tag("div", { style: "display:contents" }, [anchor]);
let cache = new Map(); let cache = new Map();
Watch(() => { Watch(
const items = (isFunc(src) ? src() : src) || []; () => (isFunc(src) ? src() : src) || [],
(items) => {
const next = new Map(), order = []; const next = new Map(), order = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const item = items[i]; const item = items[i];
@@ -357,12 +380,13 @@ export const For = (src, itemFn, keyFn) => {
if (view.container.nextSibling !== ref) root.insertBefore(view.container, ref); if (view.container.nextSibling !== ref) root.insertBefore(view.container, ref);
ref = view.container; ref = view.container;
} }
}); }
);
return root; return root;
}; };
// Router // Router
export 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());
@@ -394,7 +418,7 @@ Router.back = () => window.history.back();
Router.path = () => window.location.hash.replace(/^#/, "") || "/"; Router.path = () => window.location.hash.replace(/^#/, "") || "/";
// Mount // Mount
export const Mount = (comp, target) => { 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();
@@ -404,11 +428,12 @@ export const Mount = (comp, target) => {
return inst; return inst;
}; };
const SigPro = Object.freeze({ $, $$, Watch, watch, Tag, Render, If, For, Router, Mount, untrack, onMount, onUnmount, provide, inject }); const SigPro = Object.freeze({ $, $$, Watch, Tag, Render, If, For, Router, Mount, onMount, onUnmount, provide, inject });
export const initDX = () => { if (typeof window !== "undefined") {
if (typeof window === "undefined") return;
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" "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 => window[t[0].toUpperCase() + t.slice(1)] = (p, c) => SigPro.Tag(t, p, c)); .split(" ").forEach(t => window[t[0].toUpperCase() + t.slice(1)] = (p, c) => SigPro.Tag(t, p, c));
}; }
export { $, $$, Watch, Tag, Render, If, For, Router, Mount, onMount, onUnmount, provide, inject };
export default SigPro;