From 9e64161aa20c9841d6d77d49f95ef16e38de0f35 Mon Sep 17 00:00:00 2001 From: natxocc Date: Sun, 5 Apr 2026 23:19:39 +0200 Subject: [PATCH] Reorder --- dist/sigpro.esm.js | 616 +++++++++++++++++------------------ dist/sigpro.esm.min.js | 2 +- dist/sigpro.js | 616 +++++++++++++++++------------------ dist/sigpro.min.js | 2 +- index.js | 2 +- package.json | 3 +- sigpro/index.js => sigpro.js | 2 +- 7 files changed, 621 insertions(+), 622 deletions(-) rename sigpro/index.js => sigpro.js (99%) diff --git a/dist/sigpro.esm.js b/dist/sigpro.esm.js index 6f3a67d..398b155 100644 --- a/dist/sigpro.esm.js +++ b/dist/sigpro.esm.js @@ -1,437 +1,437 @@ -// sigpro/index.js +// sigpro.js var activeEffect = null; var currentOwner = null; var effectQueue = new Set; var isFlushing = false; var MOUNTED_NODES = new WeakMap; -var flush = () => { +var doc = document; +var isArr = Array.isArray; +var assign = Object.assign; +var createEl = (t) => doc.createElement(t); +var createText = (t) => doc.createTextNode(String(t ?? "")); +var isFunc = (f) => typeof f === "function"; +var isObj = (o) => typeof o === "object" && o !== null; +var runWithContext = (effect, callback) => { + const previousEffect = activeEffect; + activeEffect = effect; + try { + return callback(); + } finally { + activeEffect = previousEffect; + } +}; +var cleanupNode = (node) => { + if (node._cleanups) { + node._cleanups.forEach((dispose) => dispose()); + node._cleanups.clear(); + } + node.childNodes?.forEach(cleanupNode); +}; +var flushEffects = () => { if (isFlushing) return; isFlushing = true; while (effectQueue.size > 0) { - const sorted = Array.from(effectQueue).sort((a, b) => (a.depth || 0) - (b.depth || 0)); + const sortedEffects = Array.from(effectQueue).sort((a, b) => (a.depth || 0) - (b.depth || 0)); effectQueue.clear(); - for (const eff of sorted) - if (!eff._deleted) - eff(); + for (const effect of sortedEffects) { + if (!effect._deleted) + effect(); + } } isFlushing = false; }; -var track = (subs) => { +var trackSubscription = (subscribers) => { if (activeEffect && !activeEffect._deleted) { - subs.add(activeEffect); - activeEffect._deps.add(subs); + subscribers.add(activeEffect); + activeEffect._deps.add(subscribers); } }; -var trigger = (subs) => { - for (const eff of subs) { - if (eff === activeEffect || eff._deleted) - continue; - if (eff._isComputed) { - eff.markDirty(); - if (eff._subs) - trigger(eff._subs); +var triggerUpdate = (subscribers) => { + subscribers.forEach((effect) => { + if (effect === activeEffect || effect._deleted) + return; + if (effect._isComputed) { + effect.markDirty(); + if (effect._subs) + triggerUpdate(effect._subs); } else { - effectQueue.add(eff); + effectQueue.add(effect); } - } + }); if (!isFlushing) - queueMicrotask(flush); + queueMicrotask(flushEffects); }; -var sweep = (node) => { - if (node._cleanups) { - node._cleanups.forEach((f) => f()); - node._cleanups.clear(); - } - node.childNodes?.forEach(sweep); -}; -var _view = (fn) => { +var Render = (renderFn) => { const cleanups = new Set; - const prev = currentOwner; - const container = document.createElement("div"); + const previousOwner = currentOwner; + const container = createEl("div"); container.style.display = "contents"; currentOwner = { cleanups }; + 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 : createText(result)); + } + }; try { - const res = fn({ onCleanup: (f) => cleanups.add(f) }); - const process = (n) => { - if (!n) - return; - if (n._isRuntime) { - cleanups.add(n.destroy); - container.appendChild(n.container); - } else if (Array.isArray(n)) - n.forEach(process); - else - container.appendChild(n instanceof Node ? n : document.createTextNode(String(n))); - }; - process(res); + processResult(renderFn({ onCleanup: (fn) => cleanups.add(fn) })); } finally { - currentOwner = prev; + currentOwner = previousOwner; } return { _isRuntime: true, container, destroy: () => { - cleanups.forEach((f) => f()); - sweep(container); + cleanups.forEach((fn) => fn()); + cleanupNode(container); container.remove(); } }; }; -var $ = (initial, key = null) => { - if (typeof initial === "function") { - const subs2 = new Set; - let cached, dirty = true; +var $ = (initialValue, storageKey = null) => { + const subscribers = new Set; + if (isFunc(initialValue)) { + let cachedValue, isDirty = true; const effect = () => { if (effect._deleted) return; - effect._deps.forEach((s) => s.delete(effect)); + effect._deps.forEach((dep) => dep.delete(effect)); effect._deps.clear(); - const prev = activeEffect; - activeEffect = effect; - try { - const val = initial(); - if (!Object.is(cached, val) || dirty) { - cached = val; - dirty = false; - trigger(subs2); + runWithContext(effect, () => { + const newValue = initialValue(); + if (!Object.is(cachedValue, newValue) || isDirty) { + cachedValue = newValue; + isDirty = false; + triggerUpdate(subscribers); } - } finally { - activeEffect = prev; + }); + }; + assign(effect, { + _deps: new Set, + _isComputed: true, + _subs: subscribers, + _deleted: false, + markDirty: () => isDirty = true, + stop: () => { + effect._deleted = true; + effect._deps.forEach((dep) => dep.delete(effect)); + subscribers.clear(); } - }; - effect._deps = new Set; - effect._isComputed = true; - effect._subs = subs2; - effect._deleted = false; - effect.markDirty = () => dirty = true; - effect.stop = () => { - effect._deleted = true; - effect._deps.forEach((s) => s.delete(effect)); - subs2.clear(); - }; + }); if (currentOwner) currentOwner.cleanups.add(effect.stop); return () => { - if (dirty) + if (isDirty) effect(); - track(subs2); - return cached; + trackSubscription(subscribers); + return cachedValue; }; } - let value = initial; - if (key) { + let value = initialValue; + if (storageKey) { try { - const saved = localStorage.getItem(key); + const saved = localStorage.getItem(storageKey); if (saved !== null) value = JSON.parse(saved); } catch (e) { - console.warn("SigPro: LocalStorage locked", e); + console.warn("SigPro Storage Lock", e); } } - const subs = new Set; return (...args) => { if (args.length) { - const next = typeof args[0] === "function" ? args[0](value) : args[0]; - if (!Object.is(value, next)) { - value = next; - if (key) - localStorage.setItem(key, JSON.stringify(value)); - trigger(subs); + const nextValue = isFunc(args[0]) ? args[0](value) : args[0]; + if (!Object.is(value, nextValue)) { + value = nextValue; + if (storageKey) + localStorage.setItem(storageKey, JSON.stringify(value)); + triggerUpdate(subscribers); } } - track(subs); + trackSubscription(subscribers); return value; }; }; -var $watch = (target, fn) => { - const isExplicit = Array.isArray(target); - const callback = isExplicit ? fn : target; - const depsInput = isExplicit ? target : null; - if (typeof callback !== "function") +var $$ = (object, cache = new WeakMap) => { + if (!isObj(object)) + return object; + if (cache.has(object)) + return cache.get(object); + const keySubscribers = {}; + const proxy = new Proxy(object, { + get(target, key) { + if (activeEffect) + trackSubscription(keySubscribers[key] ??= new Set); + const value = Reflect.get(target, key); + return isObj(value) ? $$(value, cache) : value; + }, + set(target, key, value) { + if (Object.is(target[key], value)) + return true; + const success = Reflect.set(target, key, value); + if (keySubscribers[key]) + triggerUpdate(keySubscribers[key]); + return success; + } + }); + cache.set(object, proxy); + return proxy; +}; +var Watch = (target, callbackFn) => { + const isExplicit = isArr(target); + const callback = isExplicit ? callbackFn : target; + if (!isFunc(callback)) return () => {}; const owner = currentOwner; const runner = () => { if (runner._deleted) return; - runner._deps.forEach((s) => s.delete(runner)); + runner._deps.forEach((dep) => dep.delete(runner)); runner._deps.clear(); - runner._cleanups.forEach((c) => c()); + runner._cleanups.forEach((cleanup) => cleanup()); runner._cleanups.clear(); - const prevEffect = activeEffect; - const prevOwner = currentOwner; - activeEffect = runner; - currentOwner = { cleanups: runner._cleanups }; - runner.depth = prevEffect ? prevEffect.depth + 1 : 0; - try { + const previousOwner = currentOwner; + runner.depth = activeEffect ? activeEffect.depth + 1 : 0; + runWithContext(runner, () => { + currentOwner = { cleanups: runner._cleanups }; if (isExplicit) { - activeEffect = null; - callback(); - activeEffect = runner; - depsInput.forEach((d) => typeof d === "function" && d()); + runWithContext(null, callback); + target.forEach((dep) => isFunc(dep) && dep()); } else { callback(); } - } finally { - activeEffect = prevEffect; - currentOwner = prevOwner; + currentOwner = previousOwner; + }); + }; + assign(runner, { + _deps: new Set, + _cleanups: new Set, + _deleted: false, + stop: () => { + if (runner._deleted) + return; + runner._deleted = true; + effectQueue.delete(runner); + runner._deps.forEach((dep) => dep.delete(runner)); + runner._cleanups.forEach((cleanup) => cleanup()); + if (owner) + owner.cleanups.delete(runner.stop); } - }; - runner._deps = new Set; - runner._cleanups = new Set; - runner._deleted = false; - runner.stop = () => { - if (runner._deleted) - return; - runner._deleted = true; - effectQueue.delete(runner); - runner._deps.forEach((s) => s.delete(runner)); - runner._cleanups.forEach((c) => c()); - if (owner) - owner.cleanups.delete(runner.stop); - }; + }); if (owner) owner.cleanups.add(runner.stop); runner(); return runner.stop; }; -var $html = (tag, props = {}, content = []) => { - if (props instanceof Node || Array.isArray(props) || typeof props !== "object") { - content = props; +var Tag = (tag, props = {}, children = []) => { + if (props instanceof Node || isArr(props) || !isObj(props)) { + children = props; props = {}; } - const svgTags = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "g", "defs", "text", "tspan", "use"]; - const isSVG = svgTags.includes(tag); - const el = isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag); - const _sanitize = (key, val) => (key === "src" || key === "href") && String(val).toLowerCase().includes("javascript:") ? "#" : val; - el._cleanups = new Set; - const boolAttrs = ["disabled", "checked", "required", "readonly", "selected", "multiple", "autofocus"]; - for (let [key, val] of Object.entries(props)) { + const isSVG = /^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(tag); + const element = isSVG ? doc.createElementNS("http://www.w3.org/2000/svg", tag) : createEl(tag); + element._cleanups = new Set; + element.onUnmount = (fn) => element._cleanups.add(fn); + const booleanAttributes = ["disabled", "checked", "required", "readonly", "selected", "multiple", "autofocus"]; + const updateAttribute = (name, value) => { + const sanitized = (name === "src" || name === "href") && String(value).toLowerCase().includes("javascript:") ? "#" : value; + if (booleanAttributes.includes(name)) { + element[name] = !!sanitized; + sanitized ? element.setAttribute(name, "") : element.removeAttribute(name); + } else { + sanitized == null ? element.removeAttribute(name) : element.setAttribute(name, sanitized); + } + }; + for (let [key, value] of Object.entries(props)) { if (key === "ref") { - typeof val === "function" ? val(el) : val.current = el; + isFunc(value) ? value(element) : value.current = element; continue; } - const isSignal = typeof val === "function", isInput = ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName), isBindAttr = key === "value" || key === "checked"; - if (isInput && isBindAttr && isSignal) { - el._cleanups.add($watch(() => { - const currentVal = val(); - if (el[key] !== currentVal) - el[key] = currentVal; - })); - const eventName = key === "checked" ? "change" : "input", handler = (event) => val(event.target[key]); - el.addEventListener(eventName, handler); - el._cleanups.add(() => el.removeEventListener(eventName, handler)); - } else if (key.startsWith("on")) { - const eventName = key.slice(2).toLowerCase().split(".")[0], handler = (event) => val(event); - el.addEventListener(eventName, handler); - el._cleanups.add(() => el.removeEventListener(eventName, handler)); + const isSignal = isFunc(value); + if (key.startsWith("on")) { + const eventName = key.slice(2).toLowerCase().split(".")[0]; + element.addEventListener(eventName, value); + element._cleanups.add(() => element.removeEventListener(eventName, value)); } else if (isSignal) { - el._cleanups.add($watch(() => { - const currentVal = _sanitize(key, val()); - if (key === "class") { - el.className = currentVal || ""; - } else if (boolAttrs.includes(key)) { - if (currentVal) { - el.setAttribute(key, ""); - el[key] = true; - } else { - el.removeAttribute(key); - el[key] = false; - } - } else { - if (currentVal == null) { - el.removeAttribute(key); - } else if (isSVG && typeof currentVal === "number") { - el.setAttribute(key, currentVal); - } else { - el.setAttribute(key, currentVal); - } - } + element._cleanups.add(Watch(() => { + const currentVal = value(); + key === "class" ? element.className = currentVal || "" : updateAttribute(key, currentVal); })); - } else { - if (boolAttrs.includes(key)) { - if (val) { - el.setAttribute(key, ""); - el[key] = true; - } else { - el.removeAttribute(key); - el[key] = false; - } - } else { - el.setAttribute(key, _sanitize(key, val)); + if (["INPUT", "TEXTAREA", "SELECT"].includes(element.tagName) && (key === "value" || key === "checked")) { + const event = key === "checked" ? "change" : "input"; + const handler = (e) => value(e.target[key]); + element.addEventListener(event, handler); + element._cleanups.add(() => element.removeEventListener(event, handler)); } + } else { + updateAttribute(key, value); } } - const append = (child) => { - if (Array.isArray(child)) - return child.forEach(append); - if (child instanceof Node) { - el.appendChild(child); - } else if (typeof child === "function") { - const marker = document.createTextNode(""); - el.appendChild(marker); - let nodes = []; - el._cleanups.add($watch(() => { - const res = child(), next = (Array.isArray(res) ? res : [res]).map((i) => i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? "")); - nodes.forEach((n) => { - sweep?.(n); - n.remove(); + const appendChildNode = (child) => { + if (isArr(child)) + return child.forEach(appendChildNode); + if (isFunc(child)) { + const marker = createText(""); + element.appendChild(marker); + let currentNodes = []; + element._cleanups.add(Watch(() => { + const result = child(); + const nextNodes = (isArr(result) ? result : [result]).map((node) => node?._isRuntime ? node.container : node instanceof Node ? node : createText(node)); + currentNodes.forEach((node) => { + cleanupNode(node); + node.remove(); }); - next.forEach((n) => marker.parentNode?.insertBefore(n, marker)); - nodes = next; + nextNodes.forEach((node) => marker.parentNode?.insertBefore(node, marker)); + currentNodes = nextNodes; })); - } else - el.appendChild(document.createTextNode(child ?? "")); - }; - append(content); - return el; -}; -var $if = (condition, thenVal, otherwiseVal = null, transition = null) => { - const marker = document.createTextNode(""); - const container = $html("div", { style: "display:contents" }, [marker]); - let current = null, last = null; - $watch(() => { - const state = !!(typeof condition === "function" ? condition() : condition); - if (state === last) - return; - last = state; - if (current && !state && transition?.out) { - transition.out(current.container, () => { - current.destroy(); - current = null; - }); } else { - if (current) - current.destroy(); - current = null; + element.appendChild(child instanceof Node ? child : createText(child)); } - if (state || !state && otherwiseVal) { - const branch = state ? thenVal : otherwiseVal; - if (branch) { - current = _view(() => typeof branch === "function" ? branch() : branch); - container.insertBefore(current.container, marker); - if (state && transition?.in) - transition.in(current.container); - } + }; + appendChildNode(children); + return element; +}; +var If = (condition, thenVal, otherwiseVal = null, transition = null) => { + const marker = createText(""); + const container = Tag("div", { style: "display:contents" }, [marker]); + let currentView = null, lastState = null; + Watch(() => { + const state = !!(isFunc(condition) ? condition() : condition); + if (state === lastState) + return; + lastState = state; + const dispose = () => { + if (currentView) + currentView.destroy(); + currentView = null; + }; + if (currentView && !state && transition?.out) { + transition.out(currentView.container, dispose); + } else { + dispose(); + } + const branch = state ? thenVal : otherwiseVal; + if (branch) { + currentView = Render(() => isFunc(branch) ? branch() : branch); + container.insertBefore(currentView.container, marker); + if (state && transition?.in) + transition.in(currentView.container); } }); return container; }; -$if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal); -var $for = (source, render, keyFn, tag = "div", props = { style: "display:contents" }) => { - const marker = document.createTextNode(""); - const container = $html(tag, props, [marker]); - let cache = new Map; - $watch(() => { - const items = (typeof source === "function" ? source() : source) || []; - const newCache = new Map; - const newOrder = []; +var For = (source, renderFn, keyFn, tag = "div", props = { style: "display:contents" }) => { + const marker = createText(""); + const container = Tag(tag, props, [marker]); + let viewCache = new Map; + Watch(() => { + const items = (isFunc(source) ? source() : source) || []; + const nextCache = new Map; + const order = []; for (let i = 0;i < items.length; i++) { const item = items[i]; const key = keyFn ? keyFn(item, i) : i; - let run = cache.get(key); - if (!run) { - run = _view(() => render(item, i)); - } else { - cache.delete(key); - } - newCache.set(key, run); - newOrder.push(key); + let view = viewCache.get(key) || Render(() => renderFn(item, i)); + viewCache.delete(key); + nextCache.set(key, view); + order.push(key); } - cache.forEach((run) => { - run.destroy(); - run.container.remove(); + viewCache.forEach((view) => { + view.destroy(); + view.container.remove(); }); let anchor = marker; - for (let i = newOrder.length - 1;i >= 0; i--) { - const run = newCache.get(newOrder[i]); - if (run.container.nextSibling !== anchor) { - container.insertBefore(run.container, anchor); + for (let i = order.length - 1;i >= 0; i--) { + const view = nextCache.get(order[i]); + if (view.container.nextSibling !== anchor) { + container.insertBefore(view.container, anchor); } - anchor = run.container; + anchor = view.container; } - cache = newCache; + viewCache = nextCache; }); return container; }; -var $router = (routes) => { - const sPath = $(window.location.hash.replace(/^#/, "") || "/"); - window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/")); - const outlet = $html("div", { class: "router-outlet" }); - let current = null; - $watch([sPath], async () => { - const path = sPath(); +var Router = (routes) => { + const currentPath = $(window.location.hash.replace(/^#/, "") || "/"); + window.addEventListener("hashchange", () => currentPath(window.location.hash.replace(/^#/, "") || "/")); + const outlet = Tag("div", { class: "router-outlet" }); + let currentView = null; + Watch([currentPath], async () => { + const path = currentPath(); const route = routes.find((r) => { - const rp = r.path.split("/").filter(Boolean), pp = path.split("/").filter(Boolean); - return rp.length === pp.length && rp.every((p, i) => p.startsWith(":") || p === pp[i]); + const routeParts = r.path.split("/").filter(Boolean); + const pathParts = path.split("/").filter(Boolean); + return routeParts.length === pathParts.length && routeParts.every((part, i) => part.startsWith(":") || part === pathParts[i]); }) || routes.find((r) => r.path === "*"); if (route) { - let comp = route.component; - if (typeof comp === "function" && comp.toString().includes("import")) { - comp = (await comp()).default || await comp(); + let component = route.component; + if (isFunc(component) && component.toString().includes("import")) { + component = (await component()).default || await component(); } const params = {}; - route.path.split("/").filter(Boolean).forEach((p, i) => { - if (p.startsWith(":")) - params[p.slice(1)] = path.split("/").filter(Boolean)[i]; + route.path.split("/").filter(Boolean).forEach((part, i) => { + if (part.startsWith(":")) + params[part.slice(1)] = path.split("/").filter(Boolean)[i]; }); - if (current) - current.destroy(); - if ($router.params) - $router.params(params); - current = _view(() => { + if (currentView) + currentView.destroy(); + if (Router.params) + Router.params(params); + currentView = Render(() => { try { - return typeof comp === "function" ? comp(params) : comp; + return isFunc(component) ? component(params) : component; } catch (e) { - return $html("div", { class: "p-4 text-error" }, "Error loading view"); + return Tag("div", { class: "p-4 text-error" }, "Error loading view"); } }); - outlet.appendChild(current.container); + outlet.appendChild(currentView.container); } }); return outlet; }; -$router.params = $({}); -$router.to = (path) => window.location.hash = path.replace(/^#?\/?/, "#/"); -$router.back = () => window.history.back(); -$router.path = () => window.location.hash.replace(/^#/, "") || "/"; -var $mount = (component, target) => { - const el = typeof target === "string" ? document.querySelector(target) : target; - if (!el) +Router.params = $({}); +Router.to = (path) => window.location.hash = path.replace(/^#?\/?/, "#/"); +Router.back = () => window.history.back(); +Router.path = () => window.location.hash.replace(/^#/, "") || "/"; +var Mount = (component, target) => { + const targetEl = typeof target === "string" ? doc.querySelector(target) : target; + if (!targetEl) return; - if (MOUNTED_NODES.has(el)) - MOUNTED_NODES.get(el).destroy(); - const instance = _view(typeof component === "function" ? component : () => component); - el.replaceChildren(instance.container); - MOUNTED_NODES.set(el, instance); + if (MOUNTED_NODES.has(targetEl)) + MOUNTED_NODES.get(targetEl).destroy(); + const instance = Render(isFunc(component) ? component : () => component); + targetEl.replaceChildren(instance.container); + MOUNTED_NODES.set(targetEl, instance); return instance; }; var Fragment = ({ children }) => children; -var SigProCore = { $, $watch, $html, $if, $for, $router, $mount, Fragment }; +var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount, Fragment }; if (typeof window !== "undefined") { - const install = (registry) => { - Object.keys(registry).forEach((key) => { - window[key] = registry[key]; - }); - const tags = `div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter`.split(/\s+/); - tags.forEach((tagName) => { - const helperName = tagName.charAt(0).toUpperCase() + tagName.slice(1); - if (!(helperName in window)) { - window[helperName] = (props, content) => $html(tagName, props, content); - } - }); - window.Fragment = Fragment; - window.SigPro = Object.freeze(registry); - }; - install(SigProCore); + assign(window, SigPro); + const tags = `div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter`.split(" "); + tags.forEach((tag) => { + const helper = tag[0].toUpperCase() + tag.slice(1); + if (!(helper in window)) + window[helper] = (p, c) => Tag(tag, p, c); + }); + window.SigPro = Object.freeze(SigPro); } export { + Watch, + Tag, + Router, + Render, + Mount, + If, Fragment, - $watch, - $router, - $mount, - $if, - $html, - $for, + For, + $$, $ }; diff --git a/dist/sigpro.esm.min.js b/dist/sigpro.esm.min.js index c7b92dd..bc14d3e 100644 --- a/dist/sigpro.esm.min.js +++ b/dist/sigpro.esm.min.js @@ -1 +1 @@ -var p=null,w=null,b=new Set,S=!1,N=new WeakMap,L=()=>{if(S)return;S=!0;while(b.size>0){let s=Array.from(b).sort((r,a)=>(r.depth||0)-(a.depth||0));b.clear();for(let r of s)if(!r._deleted)r()}S=!1},k=(s)=>{if(p&&!p._deleted)s.add(p),p._deps.add(s)},x=(s)=>{for(let r of s){if(r===p||r._deleted)continue;if(r._isComputed){if(r.markDirty(),r._subs)x(r._subs)}else b.add(r)}if(!S)queueMicrotask(L)},O=(s)=>{if(s._cleanups)s._cleanups.forEach((r)=>r()),s._cleanups.clear();s.childNodes?.forEach(O)},A=(s)=>{let r=new Set,a=w,c=document.createElement("div");c.style.display="contents",w={cleanups:r};try{let i=s({onCleanup:(e)=>r.add(e)}),n=(e)=>{if(!e)return;if(e._isRuntime)r.add(e.destroy),c.appendChild(e.container);else if(Array.isArray(e))e.forEach(n);else c.appendChild(e instanceof Node?e:document.createTextNode(String(e)))};n(i)}finally{w=a}return{_isRuntime:!0,container:c,destroy:()=>{r.forEach((i)=>i()),O(c),c.remove()}}},T=(s,r=null)=>{if(typeof s==="function"){let i=new Set,n,e=!0,o=()=>{if(o._deleted)return;o._deps.forEach((t)=>t.delete(o)),o._deps.clear();let f=p;p=o;try{let t=s();if(!Object.is(n,t)||e)n=t,e=!1,x(i)}finally{p=f}};if(o._deps=new Set,o._isComputed=!0,o._subs=i,o._deleted=!1,o.markDirty=()=>e=!0,o.stop=()=>{o._deleted=!0,o._deps.forEach((f)=>f.delete(o)),i.clear()},w)w.cleanups.add(o.stop);return()=>{if(e)o();return k(i),n}}let a=s;if(r)try{let i=localStorage.getItem(r);if(i!==null)a=JSON.parse(i)}catch(i){console.warn("SigPro: LocalStorage locked",i)}let c=new Set;return(...i)=>{if(i.length){let n=typeof i[0]==="function"?i[0](a):i[0];if(!Object.is(a,n)){if(a=n,r)localStorage.setItem(r,JSON.stringify(a));x(c)}}return k(c),a}};var _=(s,r)=>{let a=Array.isArray(s),c=a?r:s,i=a?s:null;if(typeof c!=="function")return()=>{};let n=w,e=()=>{if(e._deleted)return;e._deps.forEach((t)=>t.delete(e)),e._deps.clear(),e._cleanups.forEach((t)=>t()),e._cleanups.clear();let o=p,f=w;p=e,w={cleanups:e._cleanups},e.depth=o?o.depth+1:0;try{if(a)p=null,c(),p=e,i.forEach((t)=>typeof t==="function"&&t());else c()}finally{p=o,w=f}};if(e._deps=new Set,e._cleanups=new Set,e._deleted=!1,e.stop=()=>{if(e._deleted)return;if(e._deleted=!0,b.delete(e),e._deps.forEach((o)=>o.delete(e)),e._cleanups.forEach((o)=>o()),n)n.cleanups.delete(e.stop)},n)n.cleanups.add(e.stop);return e(),e.stop},E=(s,r={},a=[])=>{if(r instanceof Node||Array.isArray(r)||typeof r!=="object")a=r,r={};let i=["svg","path","circle","rect","line","polyline","polygon","g","defs","text","tspan","use"].includes(s),n=i?document.createElementNS("http://www.w3.org/2000/svg",s):document.createElement(s),e=(t,d)=>(t==="src"||t==="href")&&String(d).toLowerCase().includes("javascript:")?"#":d;n._cleanups=new Set;let o=["disabled","checked","required","readonly","selected","multiple","autofocus"];for(let[t,d]of Object.entries(r)){if(t==="ref"){typeof d==="function"?d(n):d.current=n;continue}let m=typeof d==="function";if(["INPUT","TEXTAREA","SELECT"].includes(n.tagName)&&(t==="value"||t==="checked")&&m){n._cleanups.add(_(()=>{let g=d();if(n[t]!==g)n[t]=g}));let l=t==="checked"?"change":"input",y=(g)=>d(g.target[t]);n.addEventListener(l,y),n._cleanups.add(()=>n.removeEventListener(l,y))}else if(t.startsWith("on")){let l=t.slice(2).toLowerCase().split(".")[0],y=(g)=>d(g);n.addEventListener(l,y),n._cleanups.add(()=>n.removeEventListener(l,y))}else if(m)n._cleanups.add(_(()=>{let l=e(t,d());if(t==="class")n.className=l||"";else if(o.includes(t))if(l)n.setAttribute(t,""),n[t]=!0;else n.removeAttribute(t),n[t]=!1;else if(l==null)n.removeAttribute(t);else if(i&&typeof l==="number")n.setAttribute(t,l);else n.setAttribute(t,l)}));else if(o.includes(t))if(d)n.setAttribute(t,""),n[t]=!0;else n.removeAttribute(t),n[t]=!1;else n.setAttribute(t,e(t,d))}let f=(t)=>{if(Array.isArray(t))return t.forEach(f);if(t instanceof Node)n.appendChild(t);else if(typeof t==="function"){let d=document.createTextNode("");n.appendChild(d);let m=[];n._cleanups.add(_(()=>{let u=t(),h=(Array.isArray(u)?u:[u]).map((l)=>l?._isRuntime?l.container:l instanceof Node?l:document.createTextNode(l??""));m.forEach((l)=>{O?.(l),l.remove()}),h.forEach((l)=>d.parentNode?.insertBefore(l,d)),m=h}))}else n.appendChild(document.createTextNode(t??""))};return f(a),n},C=(s,r,a=null,c=null)=>{let i=document.createTextNode(""),n=E("div",{style:"display:contents"},[i]),e=null,o=null;return _(()=>{let f=!!(typeof s==="function"?s():s);if(f===o)return;if(o=f,e&&!f&&c?.out)c.out(e.container,()=>{e.destroy(),e=null});else{if(e)e.destroy();e=null}if(f||!f&&a){let t=f?r:a;if(t){if(e=A(()=>typeof t==="function"?t():t),n.insertBefore(e.container,i),f&&c?.in)c.in(e.container)}}}),n};C.not=(s,r,a)=>C(()=>!(typeof s==="function"?s():s),r,a);var $=(s,r,a,c="div",i={style:"display:contents"})=>{let n=document.createTextNode(""),e=E(c,i,[n]),o=new Map;return _(()=>{let f=(typeof s==="function"?s():s)||[],t=new Map,d=[];for(let u=0;ur(h,u));else o.delete(l);t.set(l,y),d.push(l)}o.forEach((u)=>{u.destroy(),u.container.remove()});let m=n;for(let u=d.length-1;u>=0;u--){let h=t.get(d[u]);if(h.container.nextSibling!==m)e.insertBefore(h.container,m);m=h.container}o=t}),e},v=(s)=>{let r=T(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>r(window.location.hash.replace(/^#/,"")||"/"));let a=E("div",{class:"router-outlet"}),c=null;return _([r],async()=>{let i=r(),n=s.find((e)=>{let o=e.path.split("/").filter(Boolean),f=i.split("/").filter(Boolean);return o.length===f.length&&o.every((t,d)=>t.startsWith(":")||t===f[d])})||s.find((e)=>e.path==="*");if(n){let e=n.component;if(typeof e==="function"&&e.toString().includes("import"))e=(await e()).default||await e();let o={};if(n.path.split("/").filter(Boolean).forEach((f,t)=>{if(f.startsWith(":"))o[f.slice(1)]=i.split("/").filter(Boolean)[t]}),c)c.destroy();if(v.params)v.params(o);c=A(()=>{try{return typeof e==="function"?e(o):e}catch(f){return E("div",{class:"p-4 text-error"},"Error loading view")}}),a.appendChild(c.container)}}),a};v.params=T({});v.to=(s)=>window.location.hash=s.replace(/^#?\/?/,"#/");v.back=()=>window.history.back();v.path=()=>window.location.hash.replace(/^#/,"")||"/";var P=(s,r)=>{let a=typeof r==="string"?document.querySelector(r):r;if(!a)return;if(N.has(a))N.get(a).destroy();let c=A(typeof s==="function"?s:()=>s);return a.replaceChildren(c.container),N.set(a,c),c},B=({children:s})=>s,I={$:T,$watch:_,$html:E,$if:C,$for:$,$router:v,$mount:P,Fragment:B};if(typeof window<"u")((r)=>{Object.keys(r).forEach((c)=>{window[c]=r[c]}),"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter".split(/\s+/).forEach((c)=>{let i=c.charAt(0).toUpperCase()+c.slice(1);if(!(i in window))window[i]=(n,e)=>E(c,n,e)}),window.Fragment=B,window.SigPro=Object.freeze(r)})(I);export{B as Fragment,_ as $watch,v as $router,P as $mount,C as $if,E as $html,$ as $for,T as $}; +var w=null,m=null,y=new Set,x=!1,O=new WeakMap,k=document,b=Array.isArray,P=Object.assign,W=(e)=>k.createElement(e),E=(e)=>k.createTextNode(String(e??"")),h=(e)=>typeof e==="function",A=(e)=>typeof e==="object"&&e!==null,L=(e,s)=>{let c=w;w=e;try{return s()}finally{w=c}},T=(e)=>{if(e._cleanups)e._cleanups.forEach((s)=>s()),e._cleanups.clear();e.childNodes?.forEach(T)},D=()=>{if(x)return;x=!0;while(y.size>0){let e=Array.from(y).sort((s,c)=>(s.depth||0)-(c.depth||0));y.clear();for(let s of e)if(!s._deleted)s()}x=!1},R=(e)=>{if(w&&!w._deleted)e.add(w),w._deps.add(e)},C=(e)=>{if(e.forEach((s)=>{if(s===w||s._deleted)return;if(s._isComputed){if(s.markDirty(),s._subs)C(s._subs)}else y.add(s)}),!x)queueMicrotask(D)},S=(e)=>{let s=new Set,c=m,i=W("div");i.style.display="contents",m={cleanups:s};let n=(t)=>{if(!t)return;if(t._isRuntime)s.add(t.destroy),i.appendChild(t.container);else if(b(t))t.forEach(n);else i.appendChild(t instanceof Node?t:E(t))};try{n(e({onCleanup:(t)=>s.add(t)}))}finally{m=c}return{_isRuntime:!0,container:i,destroy:()=>{s.forEach((t)=>t()),T(i),i.remove()}}},B=(e,s=null)=>{let c=new Set;if(h(e)){let n,t=!0,r=()=>{if(r._deleted)return;r._deps.forEach((a)=>a.delete(r)),r._deps.clear(),L(r,()=>{let a=e();if(!Object.is(n,a)||t)n=a,t=!1,C(c)})};if(P(r,{_deps:new Set,_isComputed:!0,_subs:c,_deleted:!1,markDirty:()=>t=!0,stop:()=>{r._deleted=!0,r._deps.forEach((a)=>a.delete(r)),c.clear()}}),m)m.cleanups.add(r.stop);return()=>{if(t)r();return R(c),n}}let i=e;if(s)try{let n=localStorage.getItem(s);if(n!==null)i=JSON.parse(n)}catch(n){console.warn("SigPro Storage Lock",n)}return(...n)=>{if(n.length){let t=h(n[0])?n[0](i):n[0];if(!Object.is(i,t)){if(i=t,s)localStorage.setItem(s,JSON.stringify(i));C(c)}}return R(c),i}},V=(e,s=new WeakMap)=>{if(!A(e))return e;if(s.has(e))return s.get(e);let c={},i=new Proxy(e,{get(n,t){if(w)R(c[t]??=new Set);let r=Reflect.get(n,t);return A(r)?V(r,s):r},set(n,t,r){if(Object.is(n[t],r))return!0;let a=Reflect.set(n,t,r);if(c[t])C(c[t]);return a}});return s.set(e,i),i},v=(e,s)=>{let c=b(e),i=c?s:e;if(!h(i))return()=>{};let n=m,t=()=>{if(t._deleted)return;t._deps.forEach((a)=>a.delete(t)),t._deps.clear(),t._cleanups.forEach((a)=>a()),t._cleanups.clear();let r=m;t.depth=w?w.depth+1:0,L(t,()=>{if(m={cleanups:t._cleanups},c)L(null,i),e.forEach((a)=>h(a)&&a());else i();m=r})};if(P(t,{_deps:new Set,_cleanups:new Set,_deleted:!1,stop:()=>{if(t._deleted)return;if(t._deleted=!0,y.delete(t),t._deps.forEach((r)=>r.delete(t)),t._cleanups.forEach((r)=>r()),n)n.cleanups.delete(t.stop)}}),n)n.cleanups.add(t.stop);return t(),t.stop},g=(e,s={},c=[])=>{if(s instanceof Node||b(s)||!A(s))c=s,s={};let n=/^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(e)?k.createElementNS("http://www.w3.org/2000/svg",e):W(e);n._cleanups=new Set,n.onUnmount=(o)=>n._cleanups.add(o);let t=["disabled","checked","required","readonly","selected","multiple","autofocus"],r=(o,l)=>{let d=(o==="src"||o==="href")&&String(l).toLowerCase().includes("javascript:")?"#":l;if(t.includes(o))n[o]=!!d,d?n.setAttribute(o,""):n.removeAttribute(o);else d==null?n.removeAttribute(o):n.setAttribute(o,d)};for(let[o,l]of Object.entries(s)){if(o==="ref"){h(l)?l(n):l.current=n;continue}let d=h(l);if(o.startsWith("on")){let p=o.slice(2).toLowerCase().split(".")[0];n.addEventListener(p,l),n._cleanups.add(()=>n.removeEventListener(p,l))}else if(d){if(n._cleanups.add(v(()=>{let p=l();o==="class"?n.className=p||"":r(o,p)})),["INPUT","TEXTAREA","SELECT"].includes(n.tagName)&&(o==="value"||o==="checked")){let p=o==="checked"?"change":"input",u=(f)=>l(f.target[o]);n.addEventListener(p,u),n._cleanups.add(()=>n.removeEventListener(p,u))}}else r(o,l)}let a=(o)=>{if(b(o))return o.forEach(a);if(h(o)){let l=E("");n.appendChild(l);let d=[];n._cleanups.add(v(()=>{let p=o(),u=(b(p)?p:[p]).map((f)=>f?._isRuntime?f.container:f instanceof Node?f:E(f));d.forEach((f)=>{T(f),f.remove()}),u.forEach((f)=>l.parentNode?.insertBefore(f,l)),d=u}))}else n.appendChild(o instanceof Node?o:E(o))};return a(c),n},U=(e,s,c=null,i=null)=>{let n=E(""),t=g("div",{style:"display:contents"},[n]),r=null,a=null;return v(()=>{let o=!!(h(e)?e():e);if(o===a)return;a=o;let l=()=>{if(r)r.destroy();r=null};if(r&&!o&&i?.out)i.out(r.container,l);else l();let d=o?s:c;if(d){if(r=S(()=>h(d)?d():d),t.insertBefore(r.container,n),o&&i?.in)i.in(r.container)}}),t},q=(e,s,c,i="div",n={style:"display:contents"})=>{let t=E(""),r=g(i,n,[t]),a=new Map;return v(()=>{let o=(h(e)?e():e)||[],l=new Map,d=[];for(let u=0;us(f,u));a.delete(N),l.set(N,j),d.push(N)}a.forEach((u)=>{u.destroy(),u.container.remove()});let p=t;for(let u=d.length-1;u>=0;u--){let f=l.get(d[u]);if(f.container.nextSibling!==p)r.insertBefore(f.container,p);p=f.container}a=l}),r},_=(e)=>{let s=B(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>s(window.location.hash.replace(/^#/,"")||"/"));let c=g("div",{class:"router-outlet"}),i=null;return v([s],async()=>{let n=s(),t=e.find((r)=>{let a=r.path.split("/").filter(Boolean),o=n.split("/").filter(Boolean);return a.length===o.length&&a.every((l,d)=>l.startsWith(":")||l===o[d])})||e.find((r)=>r.path==="*");if(t){let r=t.component;if(h(r)&&r.toString().includes("import"))r=(await r()).default||await r();let a={};if(t.path.split("/").filter(Boolean).forEach((o,l)=>{if(o.startsWith(":"))a[o.slice(1)]=n.split("/").filter(Boolean)[l]}),i)i.destroy();if(_.params)_.params(a);i=S(()=>{try{return h(r)?r(a):r}catch(o){return g("div",{class:"p-4 text-error"},"Error loading view")}}),c.appendChild(i.container)}}),c};_.params=B({});_.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");_.back=()=>window.history.back();_.path=()=>window.location.hash.replace(/^#/,"")||"/";var I=(e,s)=>{let c=typeof s==="string"?k.querySelector(s):s;if(!c)return;if(O.has(c))O.get(c).destroy();let i=S(h(e)?e:()=>e);return c.replaceChildren(i.container),O.set(c,i),i},$=({children:e})=>e,M={$:B,$$:V,Render:S,Watch:v,Tag:g,If:U,For:q,Router:_,Mount:I,Fragment:$};if(typeof window<"u")P(window,M),"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter".split(" ").forEach((s)=>{let c=s[0].toUpperCase()+s.slice(1);if(!(c in window))window[c]=(i,n)=>g(s,i,n)}),window.SigPro=Object.freeze(M);export{v as Watch,g as Tag,_ as Router,S as Render,I as Mount,U as If,$ as Fragment,q as For,V as $$,B as $}; diff --git a/dist/sigpro.js b/dist/sigpro.js index 2d6fa4f..447976b 100644 --- a/dist/sigpro.js +++ b/dist/sigpro.js @@ -30,441 +30,441 @@ // index.js var exports_sigpro = {}; __export(exports_sigpro, { + Watch: () => Watch, + Tag: () => Tag, + Router: () => Router, + Render: () => Render, + Mount: () => Mount, + If: () => If, Fragment: () => Fragment, - $watch: () => $watch, - $router: () => $router, - $mount: () => $mount, - $if: () => $if, - $html: () => $html, - $for: () => $for, + For: () => For, + $$: () => $$, $: () => $ }); - // sigpro/index.js + // sigpro.js var activeEffect = null; var currentOwner = null; var effectQueue = new Set; var isFlushing = false; var MOUNTED_NODES = new WeakMap; - var flush = () => { + var doc = document; + var isArr = Array.isArray; + var assign = Object.assign; + var createEl = (t) => doc.createElement(t); + var createText = (t) => doc.createTextNode(String(t ?? "")); + var isFunc = (f) => typeof f === "function"; + var isObj = (o) => typeof o === "object" && o !== null; + var runWithContext = (effect, callback) => { + const previousEffect = activeEffect; + activeEffect = effect; + try { + return callback(); + } finally { + activeEffect = previousEffect; + } + }; + var cleanupNode = (node) => { + if (node._cleanups) { + node._cleanups.forEach((dispose) => dispose()); + node._cleanups.clear(); + } + node.childNodes?.forEach(cleanupNode); + }; + var flushEffects = () => { if (isFlushing) return; isFlushing = true; while (effectQueue.size > 0) { - const sorted = Array.from(effectQueue).sort((a, b) => (a.depth || 0) - (b.depth || 0)); + const sortedEffects = Array.from(effectQueue).sort((a, b) => (a.depth || 0) - (b.depth || 0)); effectQueue.clear(); - for (const eff of sorted) - if (!eff._deleted) - eff(); + for (const effect of sortedEffects) { + if (!effect._deleted) + effect(); + } } isFlushing = false; }; - var track = (subs) => { + var trackSubscription = (subscribers) => { if (activeEffect && !activeEffect._deleted) { - subs.add(activeEffect); - activeEffect._deps.add(subs); + subscribers.add(activeEffect); + activeEffect._deps.add(subscribers); } }; - var trigger = (subs) => { - for (const eff of subs) { - if (eff === activeEffect || eff._deleted) - continue; - if (eff._isComputed) { - eff.markDirty(); - if (eff._subs) - trigger(eff._subs); + var triggerUpdate = (subscribers) => { + subscribers.forEach((effect) => { + if (effect === activeEffect || effect._deleted) + return; + if (effect._isComputed) { + effect.markDirty(); + if (effect._subs) + triggerUpdate(effect._subs); } else { - effectQueue.add(eff); + effectQueue.add(effect); } - } + }); if (!isFlushing) - queueMicrotask(flush); + queueMicrotask(flushEffects); }; - var sweep = (node) => { - if (node._cleanups) { - node._cleanups.forEach((f) => f()); - node._cleanups.clear(); - } - node.childNodes?.forEach(sweep); - }; - var _view = (fn) => { + var Render = (renderFn) => { const cleanups = new Set; - const prev = currentOwner; - const container = document.createElement("div"); + const previousOwner = currentOwner; + const container = createEl("div"); container.style.display = "contents"; currentOwner = { cleanups }; + 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 : createText(result)); + } + }; try { - const res = fn({ onCleanup: (f) => cleanups.add(f) }); - const process = (n) => { - if (!n) - return; - if (n._isRuntime) { - cleanups.add(n.destroy); - container.appendChild(n.container); - } else if (Array.isArray(n)) - n.forEach(process); - else - container.appendChild(n instanceof Node ? n : document.createTextNode(String(n))); - }; - process(res); + processResult(renderFn({ onCleanup: (fn) => cleanups.add(fn) })); } finally { - currentOwner = prev; + currentOwner = previousOwner; } return { _isRuntime: true, container, destroy: () => { - cleanups.forEach((f) => f()); - sweep(container); + cleanups.forEach((fn) => fn()); + cleanupNode(container); container.remove(); } }; }; - var $ = (initial, key = null) => { - if (typeof initial === "function") { - const subs2 = new Set; - let cached, dirty = true; + var $ = (initialValue, storageKey = null) => { + const subscribers = new Set; + if (isFunc(initialValue)) { + let cachedValue, isDirty = true; const effect = () => { if (effect._deleted) return; - effect._deps.forEach((s) => s.delete(effect)); + effect._deps.forEach((dep) => dep.delete(effect)); effect._deps.clear(); - const prev = activeEffect; - activeEffect = effect; - try { - const val = initial(); - if (!Object.is(cached, val) || dirty) { - cached = val; - dirty = false; - trigger(subs2); + runWithContext(effect, () => { + const newValue = initialValue(); + if (!Object.is(cachedValue, newValue) || isDirty) { + cachedValue = newValue; + isDirty = false; + triggerUpdate(subscribers); } - } finally { - activeEffect = prev; + }); + }; + assign(effect, { + _deps: new Set, + _isComputed: true, + _subs: subscribers, + _deleted: false, + markDirty: () => isDirty = true, + stop: () => { + effect._deleted = true; + effect._deps.forEach((dep) => dep.delete(effect)); + subscribers.clear(); } - }; - effect._deps = new Set; - effect._isComputed = true; - effect._subs = subs2; - effect._deleted = false; - effect.markDirty = () => dirty = true; - effect.stop = () => { - effect._deleted = true; - effect._deps.forEach((s) => s.delete(effect)); - subs2.clear(); - }; + }); if (currentOwner) currentOwner.cleanups.add(effect.stop); return () => { - if (dirty) + if (isDirty) effect(); - track(subs2); - return cached; + trackSubscription(subscribers); + return cachedValue; }; } - let value = initial; - if (key) { + let value = initialValue; + if (storageKey) { try { - const saved = localStorage.getItem(key); + const saved = localStorage.getItem(storageKey); if (saved !== null) value = JSON.parse(saved); } catch (e) { - console.warn("SigPro: LocalStorage locked", e); + console.warn("SigPro Storage Lock", e); } } - const subs = new Set; return (...args) => { if (args.length) { - const next = typeof args[0] === "function" ? args[0](value) : args[0]; - if (!Object.is(value, next)) { - value = next; - if (key) - localStorage.setItem(key, JSON.stringify(value)); - trigger(subs); + const nextValue = isFunc(args[0]) ? args[0](value) : args[0]; + if (!Object.is(value, nextValue)) { + value = nextValue; + if (storageKey) + localStorage.setItem(storageKey, JSON.stringify(value)); + triggerUpdate(subscribers); } } - track(subs); + trackSubscription(subscribers); return value; }; }; - var $watch = (target, fn) => { - const isExplicit = Array.isArray(target); - const callback = isExplicit ? fn : target; - const depsInput = isExplicit ? target : null; - if (typeof callback !== "function") + var $$ = (object, cache = new WeakMap) => { + if (!isObj(object)) + return object; + if (cache.has(object)) + return cache.get(object); + const keySubscribers = {}; + const proxy = new Proxy(object, { + get(target, key) { + if (activeEffect) + trackSubscription(keySubscribers[key] ??= new Set); + const value = Reflect.get(target, key); + return isObj(value) ? $$(value, cache) : value; + }, + set(target, key, value) { + if (Object.is(target[key], value)) + return true; + const success = Reflect.set(target, key, value); + if (keySubscribers[key]) + triggerUpdate(keySubscribers[key]); + return success; + } + }); + cache.set(object, proxy); + return proxy; + }; + var Watch = (target, callbackFn) => { + const isExplicit = isArr(target); + const callback = isExplicit ? callbackFn : target; + if (!isFunc(callback)) return () => {}; const owner = currentOwner; const runner = () => { if (runner._deleted) return; - runner._deps.forEach((s) => s.delete(runner)); + runner._deps.forEach((dep) => dep.delete(runner)); runner._deps.clear(); - runner._cleanups.forEach((c) => c()); + runner._cleanups.forEach((cleanup) => cleanup()); runner._cleanups.clear(); - const prevEffect = activeEffect; - const prevOwner = currentOwner; - activeEffect = runner; - currentOwner = { cleanups: runner._cleanups }; - runner.depth = prevEffect ? prevEffect.depth + 1 : 0; - try { + const previousOwner = currentOwner; + runner.depth = activeEffect ? activeEffect.depth + 1 : 0; + runWithContext(runner, () => { + currentOwner = { cleanups: runner._cleanups }; if (isExplicit) { - activeEffect = null; - callback(); - activeEffect = runner; - depsInput.forEach((d) => typeof d === "function" && d()); + runWithContext(null, callback); + target.forEach((dep) => isFunc(dep) && dep()); } else { callback(); } - } finally { - activeEffect = prevEffect; - currentOwner = prevOwner; + currentOwner = previousOwner; + }); + }; + assign(runner, { + _deps: new Set, + _cleanups: new Set, + _deleted: false, + stop: () => { + if (runner._deleted) + return; + runner._deleted = true; + effectQueue.delete(runner); + runner._deps.forEach((dep) => dep.delete(runner)); + runner._cleanups.forEach((cleanup) => cleanup()); + if (owner) + owner.cleanups.delete(runner.stop); } - }; - runner._deps = new Set; - runner._cleanups = new Set; - runner._deleted = false; - runner.stop = () => { - if (runner._deleted) - return; - runner._deleted = true; - effectQueue.delete(runner); - runner._deps.forEach((s) => s.delete(runner)); - runner._cleanups.forEach((c) => c()); - if (owner) - owner.cleanups.delete(runner.stop); - }; + }); if (owner) owner.cleanups.add(runner.stop); runner(); return runner.stop; }; - var $html = (tag, props = {}, content = []) => { - if (props instanceof Node || Array.isArray(props) || typeof props !== "object") { - content = props; + var Tag = (tag, props = {}, children = []) => { + if (props instanceof Node || isArr(props) || !isObj(props)) { + children = props; props = {}; } - const svgTags = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "g", "defs", "text", "tspan", "use"]; - const isSVG = svgTags.includes(tag); - const el = isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag); - const _sanitize = (key, val) => (key === "src" || key === "href") && String(val).toLowerCase().includes("javascript:") ? "#" : val; - el._cleanups = new Set; - const boolAttrs = ["disabled", "checked", "required", "readonly", "selected", "multiple", "autofocus"]; - for (let [key, val] of Object.entries(props)) { + const isSVG = /^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(tag); + const element = isSVG ? doc.createElementNS("http://www.w3.org/2000/svg", tag) : createEl(tag); + element._cleanups = new Set; + element.onUnmount = (fn) => element._cleanups.add(fn); + const booleanAttributes = ["disabled", "checked", "required", "readonly", "selected", "multiple", "autofocus"]; + const updateAttribute = (name, value) => { + const sanitized = (name === "src" || name === "href") && String(value).toLowerCase().includes("javascript:") ? "#" : value; + if (booleanAttributes.includes(name)) { + element[name] = !!sanitized; + sanitized ? element.setAttribute(name, "") : element.removeAttribute(name); + } else { + sanitized == null ? element.removeAttribute(name) : element.setAttribute(name, sanitized); + } + }; + for (let [key, value] of Object.entries(props)) { if (key === "ref") { - typeof val === "function" ? val(el) : val.current = el; + isFunc(value) ? value(element) : value.current = element; continue; } - const isSignal = typeof val === "function", isInput = ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName), isBindAttr = key === "value" || key === "checked"; - if (isInput && isBindAttr && isSignal) { - el._cleanups.add($watch(() => { - const currentVal = val(); - if (el[key] !== currentVal) - el[key] = currentVal; - })); - const eventName = key === "checked" ? "change" : "input", handler = (event) => val(event.target[key]); - el.addEventListener(eventName, handler); - el._cleanups.add(() => el.removeEventListener(eventName, handler)); - } else if (key.startsWith("on")) { - const eventName = key.slice(2).toLowerCase().split(".")[0], handler = (event) => val(event); - el.addEventListener(eventName, handler); - el._cleanups.add(() => el.removeEventListener(eventName, handler)); + const isSignal = isFunc(value); + if (key.startsWith("on")) { + const eventName = key.slice(2).toLowerCase().split(".")[0]; + element.addEventListener(eventName, value); + element._cleanups.add(() => element.removeEventListener(eventName, value)); } else if (isSignal) { - el._cleanups.add($watch(() => { - const currentVal = _sanitize(key, val()); - if (key === "class") { - el.className = currentVal || ""; - } else if (boolAttrs.includes(key)) { - if (currentVal) { - el.setAttribute(key, ""); - el[key] = true; - } else { - el.removeAttribute(key); - el[key] = false; - } - } else { - if (currentVal == null) { - el.removeAttribute(key); - } else if (isSVG && typeof currentVal === "number") { - el.setAttribute(key, currentVal); - } else { - el.setAttribute(key, currentVal); - } - } + element._cleanups.add(Watch(() => { + const currentVal = value(); + key === "class" ? element.className = currentVal || "" : updateAttribute(key, currentVal); })); - } else { - if (boolAttrs.includes(key)) { - if (val) { - el.setAttribute(key, ""); - el[key] = true; - } else { - el.removeAttribute(key); - el[key] = false; - } - } else { - el.setAttribute(key, _sanitize(key, val)); + if (["INPUT", "TEXTAREA", "SELECT"].includes(element.tagName) && (key === "value" || key === "checked")) { + const event = key === "checked" ? "change" : "input"; + const handler = (e) => value(e.target[key]); + element.addEventListener(event, handler); + element._cleanups.add(() => element.removeEventListener(event, handler)); } + } else { + updateAttribute(key, value); } } - const append = (child) => { - if (Array.isArray(child)) - return child.forEach(append); - if (child instanceof Node) { - el.appendChild(child); - } else if (typeof child === "function") { - const marker = document.createTextNode(""); - el.appendChild(marker); - let nodes = []; - el._cleanups.add($watch(() => { - const res = child(), next = (Array.isArray(res) ? res : [res]).map((i) => i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? "")); - nodes.forEach((n) => { - sweep?.(n); - n.remove(); + const appendChildNode = (child) => { + if (isArr(child)) + return child.forEach(appendChildNode); + if (isFunc(child)) { + const marker = createText(""); + element.appendChild(marker); + let currentNodes = []; + element._cleanups.add(Watch(() => { + const result = child(); + const nextNodes = (isArr(result) ? result : [result]).map((node) => node?._isRuntime ? node.container : node instanceof Node ? node : createText(node)); + currentNodes.forEach((node) => { + cleanupNode(node); + node.remove(); }); - next.forEach((n) => marker.parentNode?.insertBefore(n, marker)); - nodes = next; + nextNodes.forEach((node) => marker.parentNode?.insertBefore(node, marker)); + currentNodes = nextNodes; })); - } else - el.appendChild(document.createTextNode(child ?? "")); - }; - append(content); - return el; - }; - var $if = (condition, thenVal, otherwiseVal = null, transition = null) => { - const marker = document.createTextNode(""); - const container = $html("div", { style: "display:contents" }, [marker]); - let current = null, last = null; - $watch(() => { - const state = !!(typeof condition === "function" ? condition() : condition); - if (state === last) - return; - last = state; - if (current && !state && transition?.out) { - transition.out(current.container, () => { - current.destroy(); - current = null; - }); } else { - if (current) - current.destroy(); - current = null; + element.appendChild(child instanceof Node ? child : createText(child)); } - if (state || !state && otherwiseVal) { - const branch = state ? thenVal : otherwiseVal; - if (branch) { - current = _view(() => typeof branch === "function" ? branch() : branch); - container.insertBefore(current.container, marker); - if (state && transition?.in) - transition.in(current.container); - } + }; + appendChildNode(children); + return element; + }; + var If = (condition, thenVal, otherwiseVal = null, transition = null) => { + const marker = createText(""); + const container = Tag("div", { style: "display:contents" }, [marker]); + let currentView = null, lastState = null; + Watch(() => { + const state = !!(isFunc(condition) ? condition() : condition); + if (state === lastState) + return; + lastState = state; + const dispose = () => { + if (currentView) + currentView.destroy(); + currentView = null; + }; + if (currentView && !state && transition?.out) { + transition.out(currentView.container, dispose); + } else { + dispose(); + } + const branch = state ? thenVal : otherwiseVal; + if (branch) { + currentView = Render(() => isFunc(branch) ? branch() : branch); + container.insertBefore(currentView.container, marker); + if (state && transition?.in) + transition.in(currentView.container); } }); return container; }; - $if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal); - var $for = (source, render, keyFn, tag = "div", props = { style: "display:contents" }) => { - const marker = document.createTextNode(""); - const container = $html(tag, props, [marker]); - let cache = new Map; - $watch(() => { - const items = (typeof source === "function" ? source() : source) || []; - const newCache = new Map; - const newOrder = []; + var For = (source, renderFn, keyFn, tag = "div", props = { style: "display:contents" }) => { + const marker = createText(""); + const container = Tag(tag, props, [marker]); + let viewCache = new Map; + Watch(() => { + const items = (isFunc(source) ? source() : source) || []; + const nextCache = new Map; + const order = []; for (let i = 0;i < items.length; i++) { const item = items[i]; const key = keyFn ? keyFn(item, i) : i; - let run = cache.get(key); - if (!run) { - run = _view(() => render(item, i)); - } else { - cache.delete(key); - } - newCache.set(key, run); - newOrder.push(key); + let view = viewCache.get(key) || Render(() => renderFn(item, i)); + viewCache.delete(key); + nextCache.set(key, view); + order.push(key); } - cache.forEach((run) => { - run.destroy(); - run.container.remove(); + viewCache.forEach((view) => { + view.destroy(); + view.container.remove(); }); let anchor = marker; - for (let i = newOrder.length - 1;i >= 0; i--) { - const run = newCache.get(newOrder[i]); - if (run.container.nextSibling !== anchor) { - container.insertBefore(run.container, anchor); + for (let i = order.length - 1;i >= 0; i--) { + const view = nextCache.get(order[i]); + if (view.container.nextSibling !== anchor) { + container.insertBefore(view.container, anchor); } - anchor = run.container; + anchor = view.container; } - cache = newCache; + viewCache = nextCache; }); return container; }; - var $router = (routes) => { - const sPath = $(window.location.hash.replace(/^#/, "") || "/"); - window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/")); - const outlet = $html("div", { class: "router-outlet" }); - let current = null; - $watch([sPath], async () => { - const path = sPath(); + var Router = (routes) => { + const currentPath = $(window.location.hash.replace(/^#/, "") || "/"); + window.addEventListener("hashchange", () => currentPath(window.location.hash.replace(/^#/, "") || "/")); + const outlet = Tag("div", { class: "router-outlet" }); + let currentView = null; + Watch([currentPath], async () => { + const path = currentPath(); const route = routes.find((r) => { - const rp = r.path.split("/").filter(Boolean), pp = path.split("/").filter(Boolean); - return rp.length === pp.length && rp.every((p, i) => p.startsWith(":") || p === pp[i]); + const routeParts = r.path.split("/").filter(Boolean); + const pathParts = path.split("/").filter(Boolean); + return routeParts.length === pathParts.length && routeParts.every((part, i) => part.startsWith(":") || part === pathParts[i]); }) || routes.find((r) => r.path === "*"); if (route) { - let comp = route.component; - if (typeof comp === "function" && comp.toString().includes("import")) { - comp = (await comp()).default || await comp(); + let component = route.component; + if (isFunc(component) && component.toString().includes("import")) { + component = (await component()).default || await component(); } const params = {}; - route.path.split("/").filter(Boolean).forEach((p, i) => { - if (p.startsWith(":")) - params[p.slice(1)] = path.split("/").filter(Boolean)[i]; + route.path.split("/").filter(Boolean).forEach((part, i) => { + if (part.startsWith(":")) + params[part.slice(1)] = path.split("/").filter(Boolean)[i]; }); - if (current) - current.destroy(); - if ($router.params) - $router.params(params); - current = _view(() => { + if (currentView) + currentView.destroy(); + if (Router.params) + Router.params(params); + currentView = Render(() => { try { - return typeof comp === "function" ? comp(params) : comp; + return isFunc(component) ? component(params) : component; } catch (e) { - return $html("div", { class: "p-4 text-error" }, "Error loading view"); + return Tag("div", { class: "p-4 text-error" }, "Error loading view"); } }); - outlet.appendChild(current.container); + outlet.appendChild(currentView.container); } }); return outlet; }; - $router.params = $({}); - $router.to = (path) => window.location.hash = path.replace(/^#?\/?/, "#/"); - $router.back = () => window.history.back(); - $router.path = () => window.location.hash.replace(/^#/, "") || "/"; - var $mount = (component, target) => { - const el = typeof target === "string" ? document.querySelector(target) : target; - if (!el) + Router.params = $({}); + Router.to = (path) => window.location.hash = path.replace(/^#?\/?/, "#/"); + Router.back = () => window.history.back(); + Router.path = () => window.location.hash.replace(/^#/, "") || "/"; + var Mount = (component, target) => { + const targetEl = typeof target === "string" ? doc.querySelector(target) : target; + if (!targetEl) return; - if (MOUNTED_NODES.has(el)) - MOUNTED_NODES.get(el).destroy(); - const instance = _view(typeof component === "function" ? component : () => component); - el.replaceChildren(instance.container); - MOUNTED_NODES.set(el, instance); + if (MOUNTED_NODES.has(targetEl)) + MOUNTED_NODES.get(targetEl).destroy(); + const instance = Render(isFunc(component) ? component : () => component); + targetEl.replaceChildren(instance.container); + MOUNTED_NODES.set(targetEl, instance); return instance; }; var Fragment = ({ children }) => children; - var SigProCore = { $, $watch, $html, $if, $for, $router, $mount, Fragment }; + var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount, Fragment }; if (typeof window !== "undefined") { - const install = (registry) => { - Object.keys(registry).forEach((key) => { - window[key] = registry[key]; - }); - const tags = `div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter`.split(/\s+/); - tags.forEach((tagName) => { - const helperName = tagName.charAt(0).toUpperCase() + tagName.slice(1); - if (!(helperName in window)) { - window[helperName] = (props, content) => $html(tagName, props, content); - } - }); - window.Fragment = Fragment; - window.SigPro = Object.freeze(registry); - }; - install(SigProCore); + assign(window, SigPro); + const tags = `div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter`.split(" "); + tags.forEach((tag) => { + const helper = tag[0].toUpperCase() + tag.slice(1); + if (!(helper in window)) + window[helper] = (p, c) => Tag(tag, p, c); + }); + window.SigPro = Object.freeze(SigPro); } })(); diff --git a/dist/sigpro.min.js b/dist/sigpro.min.js index a478228..7692ef0 100644 --- a/dist/sigpro.min.js +++ b/dist/sigpro.min.js @@ -1 +1 @@ -(()=>{var{defineProperty:C,getOwnPropertyNames:M,getOwnPropertyDescriptor:R}=Object,j=Object.prototype.hasOwnProperty;var L=new WeakMap,W=(r)=>{var t=L.get(r),c;if(t)return t;if(t=C({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function")M(r).map((o)=>!j.call(t,o)&&C(t,o,{get:()=>r[o],enumerable:!(c=R(r,o))||c.enumerable}));return L.set(r,t),t};var q=(r,t)=>{for(var c in t)C(r,c,{get:t[c],enumerable:!0,configurable:!0,set:(o)=>t[c]=()=>o})};var U={};q(U,{Fragment:()=>B,$watch:()=>_,$router:()=>v,$mount:()=>I,$if:()=>A,$html:()=>g,$for:()=>P,$:()=>x});var p=null,w=null,b=new Set,S=!1,O=new WeakMap,D=()=>{if(S)return;S=!0;while(b.size>0){let r=Array.from(b).sort((t,c)=>(t.depth||0)-(c.depth||0));b.clear();for(let t of r)if(!t._deleted)t()}S=!1},$=(r)=>{if(p&&!p._deleted)r.add(p),p._deps.add(r)},T=(r)=>{for(let t of r){if(t===p||t._deleted)continue;if(t._isComputed){if(t.markDirty(),t._subs)T(t._subs)}else b.add(t)}if(!S)queueMicrotask(D)},k=(r)=>{if(r._cleanups)r._cleanups.forEach((t)=>t()),r._cleanups.clear();r.childNodes?.forEach(k)},N=(r)=>{let t=new Set,c=w,o=document.createElement("div");o.style.display="contents",w={cleanups:t};try{let i=r({onCleanup:(e)=>t.add(e)}),s=(e)=>{if(!e)return;if(e._isRuntime)t.add(e.destroy),o.appendChild(e.container);else if(Array.isArray(e))e.forEach(s);else o.appendChild(e instanceof Node?e:document.createTextNode(String(e)))};s(i)}finally{w=c}return{_isRuntime:!0,container:o,destroy:()=>{t.forEach((i)=>i()),k(o),o.remove()}}},x=(r,t=null)=>{if(typeof r==="function"){let i=new Set,s,e=!0,a=()=>{if(a._deleted)return;a._deps.forEach((n)=>n.delete(a)),a._deps.clear();let f=p;p=a;try{let n=r();if(!Object.is(s,n)||e)s=n,e=!1,T(i)}finally{p=f}};if(a._deps=new Set,a._isComputed=!0,a._subs=i,a._deleted=!1,a.markDirty=()=>e=!0,a.stop=()=>{a._deleted=!0,a._deps.forEach((f)=>f.delete(a)),i.clear()},w)w.cleanups.add(a.stop);return()=>{if(e)a();return $(i),s}}let c=r;if(t)try{let i=localStorage.getItem(t);if(i!==null)c=JSON.parse(i)}catch(i){console.warn("SigPro: LocalStorage locked",i)}let o=new Set;return(...i)=>{if(i.length){let s=typeof i[0]==="function"?i[0](c):i[0];if(!Object.is(c,s)){if(c=s,t)localStorage.setItem(t,JSON.stringify(c));T(o)}}return $(o),c}};var _=(r,t)=>{let c=Array.isArray(r),o=c?t:r,i=c?r:null;if(typeof o!=="function")return()=>{};let s=w,e=()=>{if(e._deleted)return;e._deps.forEach((n)=>n.delete(e)),e._deps.clear(),e._cleanups.forEach((n)=>n()),e._cleanups.clear();let a=p,f=w;p=e,w={cleanups:e._cleanups},e.depth=a?a.depth+1:0;try{if(c)p=null,o(),p=e,i.forEach((n)=>typeof n==="function"&&n());else o()}finally{p=a,w=f}};if(e._deps=new Set,e._cleanups=new Set,e._deleted=!1,e.stop=()=>{if(e._deleted)return;if(e._deleted=!0,b.delete(e),e._deps.forEach((a)=>a.delete(e)),e._cleanups.forEach((a)=>a()),s)s.cleanups.delete(e.stop)},s)s.cleanups.add(e.stop);return e(),e.stop},g=(r,t={},c=[])=>{if(t instanceof Node||Array.isArray(t)||typeof t!=="object")c=t,t={};let i=["svg","path","circle","rect","line","polyline","polygon","g","defs","text","tspan","use"].includes(r),s=i?document.createElementNS("http://www.w3.org/2000/svg",r):document.createElement(r),e=(n,d)=>(n==="src"||n==="href")&&String(d).toLowerCase().includes("javascript:")?"#":d;s._cleanups=new Set;let a=["disabled","checked","required","readonly","selected","multiple","autofocus"];for(let[n,d]of Object.entries(t)){if(n==="ref"){typeof d==="function"?d(s):d.current=s;continue}let m=typeof d==="function";if(["INPUT","TEXTAREA","SELECT"].includes(s.tagName)&&(n==="value"||n==="checked")&&m){s._cleanups.add(_(()=>{let E=d();if(s[n]!==E)s[n]=E}));let l=n==="checked"?"change":"input",y=(E)=>d(E.target[n]);s.addEventListener(l,y),s._cleanups.add(()=>s.removeEventListener(l,y))}else if(n.startsWith("on")){let l=n.slice(2).toLowerCase().split(".")[0],y=(E)=>d(E);s.addEventListener(l,y),s._cleanups.add(()=>s.removeEventListener(l,y))}else if(m)s._cleanups.add(_(()=>{let l=e(n,d());if(n==="class")s.className=l||"";else if(a.includes(n))if(l)s.setAttribute(n,""),s[n]=!0;else s.removeAttribute(n),s[n]=!1;else if(l==null)s.removeAttribute(n);else if(i&&typeof l==="number")s.setAttribute(n,l);else s.setAttribute(n,l)}));else if(a.includes(n))if(d)s.setAttribute(n,""),s[n]=!0;else s.removeAttribute(n),s[n]=!1;else s.setAttribute(n,e(n,d))}let f=(n)=>{if(Array.isArray(n))return n.forEach(f);if(n instanceof Node)s.appendChild(n);else if(typeof n==="function"){let d=document.createTextNode("");s.appendChild(d);let m=[];s._cleanups.add(_(()=>{let u=n(),h=(Array.isArray(u)?u:[u]).map((l)=>l?._isRuntime?l.container:l instanceof Node?l:document.createTextNode(l??""));m.forEach((l)=>{k?.(l),l.remove()}),h.forEach((l)=>d.parentNode?.insertBefore(l,d)),m=h}))}else s.appendChild(document.createTextNode(n??""))};return f(c),s},A=(r,t,c=null,o=null)=>{let i=document.createTextNode(""),s=g("div",{style:"display:contents"},[i]),e=null,a=null;return _(()=>{let f=!!(typeof r==="function"?r():r);if(f===a)return;if(a=f,e&&!f&&o?.out)o.out(e.container,()=>{e.destroy(),e=null});else{if(e)e.destroy();e=null}if(f||!f&&c){let n=f?t:c;if(n){if(e=N(()=>typeof n==="function"?n():n),s.insertBefore(e.container,i),f&&o?.in)o.in(e.container)}}}),s};A.not=(r,t,c)=>A(()=>!(typeof r==="function"?r():r),t,c);var P=(r,t,c,o="div",i={style:"display:contents"})=>{let s=document.createTextNode(""),e=g(o,i,[s]),a=new Map;return _(()=>{let f=(typeof r==="function"?r():r)||[],n=new Map,d=[];for(let u=0;ut(h,u));else a.delete(l);n.set(l,y),d.push(l)}a.forEach((u)=>{u.destroy(),u.container.remove()});let m=s;for(let u=d.length-1;u>=0;u--){let h=n.get(d[u]);if(h.container.nextSibling!==m)e.insertBefore(h.container,m);m=h.container}a=n}),e},v=(r)=>{let t=x(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>t(window.location.hash.replace(/^#/,"")||"/"));let c=g("div",{class:"router-outlet"}),o=null;return _([t],async()=>{let i=t(),s=r.find((e)=>{let a=e.path.split("/").filter(Boolean),f=i.split("/").filter(Boolean);return a.length===f.length&&a.every((n,d)=>n.startsWith(":")||n===f[d])})||r.find((e)=>e.path==="*");if(s){let e=s.component;if(typeof e==="function"&&e.toString().includes("import"))e=(await e()).default||await e();let a={};if(s.path.split("/").filter(Boolean).forEach((f,n)=>{if(f.startsWith(":"))a[f.slice(1)]=i.split("/").filter(Boolean)[n]}),o)o.destroy();if(v.params)v.params(a);o=N(()=>{try{return typeof e==="function"?e(a):e}catch(f){return g("div",{class:"p-4 text-error"},"Error loading view")}}),c.appendChild(o.container)}}),c};v.params=x({});v.to=(r)=>window.location.hash=r.replace(/^#?\/?/,"#/");v.back=()=>window.history.back();v.path=()=>window.location.hash.replace(/^#/,"")||"/";var I=(r,t)=>{let c=typeof t==="string"?document.querySelector(t):t;if(!c)return;if(O.has(c))O.get(c).destroy();let o=N(typeof r==="function"?r:()=>r);return c.replaceChildren(o.container),O.set(c,o),o},B=({children:r})=>r,z={$:x,$watch:_,$html:g,$if:A,$for:P,$router:v,$mount:I,Fragment:B};if(typeof window<"u")((t)=>{Object.keys(t).forEach((o)=>{window[o]=t[o]}),"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter".split(/\s+/).forEach((o)=>{let i=o.charAt(0).toUpperCase()+o.slice(1);if(!(i in window))window[i]=(s,e)=>g(o,s,e)}),window.Fragment=B,window.SigPro=Object.freeze(t)})(z);})(); +(()=>{var{defineProperty:A,getOwnPropertyNames:F,getOwnPropertyDescriptor:G}=Object,J=Object.prototype.hasOwnProperty;var V=new WeakMap,Q=(e)=>{var t=V.get(e),o;if(t)return t;if(t=A({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")F(e).map((c)=>!J.call(t,c)&&A(t,c,{get:()=>e[c],enumerable:!(o=G(e,c))||o.enumerable}));return V.set(e,t),t};var X=(e,t)=>{for(var o in t)A(e,o,{get:t[o],enumerable:!0,configurable:!0,set:(c)=>t[o]=()=>c})};var Y={};X(Y,{Watch:()=>E,Tag:()=>v,Router:()=>_,Render:()=>y,Mount:()=>I,If:()=>U,Fragment:()=>$,For:()=>q,$$:()=>W,$:()=>O});var w=null,m=null,b=new Set,x=!1,L=new WeakMap,k=document,S=Array.isArray,B=Object.assign,D=(e)=>k.createElement(e),g=(e)=>k.createTextNode(String(e??"")),h=(e)=>typeof e==="function",R=(e)=>typeof e==="object"&&e!==null,P=(e,t)=>{let o=w;w=e;try{return t()}finally{w=o}},M=(e)=>{if(e._cleanups)e._cleanups.forEach((t)=>t()),e._cleanups.clear();e.childNodes?.forEach(M)},H=()=>{if(x)return;x=!0;while(b.size>0){let e=Array.from(b).sort((t,o)=>(t.depth||0)-(o.depth||0));b.clear();for(let t of e)if(!t._deleted)t()}x=!1},T=(e)=>{if(w&&!w._deleted)e.add(w),w._deps.add(e)},C=(e)=>{if(e.forEach((t)=>{if(t===w||t._deleted)return;if(t._isComputed){if(t.markDirty(),t._subs)C(t._subs)}else b.add(t)}),!x)queueMicrotask(H)},y=(e)=>{let t=new Set,o=m,c=D("div");c.style.display="contents",m={cleanups:t};let s=(n)=>{if(!n)return;if(n._isRuntime)t.add(n.destroy),c.appendChild(n.container);else if(S(n))n.forEach(s);else c.appendChild(n instanceof Node?n:g(n))};try{s(e({onCleanup:(n)=>t.add(n)}))}finally{m=o}return{_isRuntime:!0,container:c,destroy:()=>{t.forEach((n)=>n()),M(c),c.remove()}}},O=(e,t=null)=>{let o=new Set;if(h(e)){let s,n=!0,r=()=>{if(r._deleted)return;r._deps.forEach((a)=>a.delete(r)),r._deps.clear(),P(r,()=>{let a=e();if(!Object.is(s,a)||n)s=a,n=!1,C(o)})};if(B(r,{_deps:new Set,_isComputed:!0,_subs:o,_deleted:!1,markDirty:()=>n=!0,stop:()=>{r._deleted=!0,r._deps.forEach((a)=>a.delete(r)),o.clear()}}),m)m.cleanups.add(r.stop);return()=>{if(n)r();return T(o),s}}let c=e;if(t)try{let s=localStorage.getItem(t);if(s!==null)c=JSON.parse(s)}catch(s){console.warn("SigPro Storage Lock",s)}return(...s)=>{if(s.length){let n=h(s[0])?s[0](c):s[0];if(!Object.is(c,n)){if(c=n,t)localStorage.setItem(t,JSON.stringify(c));C(o)}}return T(o),c}},W=(e,t=new WeakMap)=>{if(!R(e))return e;if(t.has(e))return t.get(e);let o={},c=new Proxy(e,{get(s,n){if(w)T(o[n]??=new Set);let r=Reflect.get(s,n);return R(r)?W(r,t):r},set(s,n,r){if(Object.is(s[n],r))return!0;let a=Reflect.set(s,n,r);if(o[n])C(o[n]);return a}});return t.set(e,c),c},E=(e,t)=>{let o=S(e),c=o?t:e;if(!h(c))return()=>{};let s=m,n=()=>{if(n._deleted)return;n._deps.forEach((a)=>a.delete(n)),n._deps.clear(),n._cleanups.forEach((a)=>a()),n._cleanups.clear();let r=m;n.depth=w?w.depth+1:0,P(n,()=>{if(m={cleanups:n._cleanups},o)P(null,c),e.forEach((a)=>h(a)&&a());else c();m=r})};if(B(n,{_deps:new Set,_cleanups:new Set,_deleted:!1,stop:()=>{if(n._deleted)return;if(n._deleted=!0,b.delete(n),n._deps.forEach((r)=>r.delete(n)),n._cleanups.forEach((r)=>r()),s)s.cleanups.delete(n.stop)}}),s)s.cleanups.add(n.stop);return n(),n.stop},v=(e,t={},o=[])=>{if(t instanceof Node||S(t)||!R(t))o=t,t={};let s=/^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(e)?k.createElementNS("http://www.w3.org/2000/svg",e):D(e);s._cleanups=new Set,s.onUnmount=(i)=>s._cleanups.add(i);let n=["disabled","checked","required","readonly","selected","multiple","autofocus"],r=(i,l)=>{let d=(i==="src"||i==="href")&&String(l).toLowerCase().includes("javascript:")?"#":l;if(n.includes(i))s[i]=!!d,d?s.setAttribute(i,""):s.removeAttribute(i);else d==null?s.removeAttribute(i):s.setAttribute(i,d)};for(let[i,l]of Object.entries(t)){if(i==="ref"){h(l)?l(s):l.current=s;continue}let d=h(l);if(i.startsWith("on")){let p=i.slice(2).toLowerCase().split(".")[0];s.addEventListener(p,l),s._cleanups.add(()=>s.removeEventListener(p,l))}else if(d){if(s._cleanups.add(E(()=>{let p=l();i==="class"?s.className=p||"":r(i,p)})),["INPUT","TEXTAREA","SELECT"].includes(s.tagName)&&(i==="value"||i==="checked")){let p=i==="checked"?"change":"input",u=(f)=>l(f.target[i]);s.addEventListener(p,u),s._cleanups.add(()=>s.removeEventListener(p,u))}}else r(i,l)}let a=(i)=>{if(S(i))return i.forEach(a);if(h(i)){let l=g("");s.appendChild(l);let d=[];s._cleanups.add(E(()=>{let p=i(),u=(S(p)?p:[p]).map((f)=>f?._isRuntime?f.container:f instanceof Node?f:g(f));d.forEach((f)=>{M(f),f.remove()}),u.forEach((f)=>l.parentNode?.insertBefore(f,l)),d=u}))}else s.appendChild(i instanceof Node?i:g(i))};return a(o),s},U=(e,t,o=null,c=null)=>{let s=g(""),n=v("div",{style:"display:contents"},[s]),r=null,a=null;return E(()=>{let i=!!(h(e)?e():e);if(i===a)return;a=i;let l=()=>{if(r)r.destroy();r=null};if(r&&!i&&c?.out)c.out(r.container,l);else l();let d=i?t:o;if(d){if(r=y(()=>h(d)?d():d),n.insertBefore(r.container,s),i&&c?.in)c.in(r.container)}}),n},q=(e,t,o,c="div",s={style:"display:contents"})=>{let n=g(""),r=v(c,s,[n]),a=new Map;return E(()=>{let i=(h(e)?e():e)||[],l=new Map,d=[];for(let u=0;ut(f,u));a.delete(N),l.set(N,z),d.push(N)}a.forEach((u)=>{u.destroy(),u.container.remove()});let p=n;for(let u=d.length-1;u>=0;u--){let f=l.get(d[u]);if(f.container.nextSibling!==p)r.insertBefore(f.container,p);p=f.container}a=l}),r},_=(e)=>{let t=O(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>t(window.location.hash.replace(/^#/,"")||"/"));let o=v("div",{class:"router-outlet"}),c=null;return E([t],async()=>{let s=t(),n=e.find((r)=>{let a=r.path.split("/").filter(Boolean),i=s.split("/").filter(Boolean);return a.length===i.length&&a.every((l,d)=>l.startsWith(":")||l===i[d])})||e.find((r)=>r.path==="*");if(n){let r=n.component;if(h(r)&&r.toString().includes("import"))r=(await r()).default||await r();let a={};if(n.path.split("/").filter(Boolean).forEach((i,l)=>{if(i.startsWith(":"))a[i.slice(1)]=s.split("/").filter(Boolean)[l]}),c)c.destroy();if(_.params)_.params(a);c=y(()=>{try{return h(r)?r(a):r}catch(i){return v("div",{class:"p-4 text-error"},"Error loading view")}}),o.appendChild(c.container)}}),o};_.params=O({});_.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");_.back=()=>window.history.back();_.path=()=>window.location.hash.replace(/^#/,"")||"/";var I=(e,t)=>{let o=typeof t==="string"?k.querySelector(t):t;if(!o)return;if(L.has(o))L.get(o).destroy();let c=y(h(e)?e:()=>e);return o.replaceChildren(c.container),L.set(o,c),c},$=({children:e})=>e,j={$:O,$$:W,Render:y,Watch:E,Tag:v,If:U,For:q,Router:_,Mount:I,Fragment:$};if(typeof window<"u")B(window,j),"div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter".split(" ").forEach((t)=>{let o=t[0].toUpperCase()+t.slice(1);if(!(o in window))window[o]=(c,s)=>v(t,c,s)}),window.SigPro=Object.freeze(j);})(); diff --git a/index.js b/index.js index 7c1a028..122c639 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,2 @@ // index.js -export * from './sigpro/index.js'; \ No newline at end of file +export * from './sigpro.js'; \ No newline at end of file diff --git a/package.json b/package.json index 9c8589b..34d557a 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,9 @@ "types": "./sigpro.d.ts", "exports": { ".": { - "development": "./index.js", "import": "./dist/sigpro.esm.min.js", "script": "./dist/sigpro.js", - "types": "./sigpro/sigpro.d.ts" + "types": "./sigpro.d.ts" }, "./vite": "./vite/index.js", "./vite/*": "./vite/*.js" diff --git a/sigpro/index.js b/sigpro.js similarity index 99% rename from sigpro/index.js rename to sigpro.js index 8f70844..b364ba3 100644 --- a/sigpro/index.js +++ b/sigpro.js @@ -429,5 +429,5 @@ if (typeof window !== "undefined") { window.SigPro = Object.freeze(SigPro); } -export { $, $$, Render, Watch, Tag, If, For, Router, Mount, Fragment }; +export { $, $$, Render, Watch, Tag, If, For, Router, Mount }; export default SigPro;