diff --git a/dist/sigpro.esm.js b/dist/sigpro.esm.js index b2412c0..2bf4841 100644 --- a/dist/sigpro.esm.js +++ b/dist/sigpro.esm.js @@ -33,11 +33,7 @@ var dispose = (eff) => { } } }; -var onMount = (fn) => { - if (activeOwner) - (activeOwner._mounts ||= []).push(fn); -}; -var onUnmount = (fn) => { +var _onUnmount = (fn) => { if (activeOwner) (activeOwner._cleanups ||= new Set).add(fn); }; @@ -93,7 +89,7 @@ var flush = () => { e(); isFlushing = false; }; -var Batch = (fn) => { +var batch = (fn) => { batchDepth++; try { return fn(); @@ -126,16 +122,16 @@ var trackUpdate = (subs, trigger = false) => { queueMicrotask(flush); } }; -var $ = (val2, key = null) => { +var $ = (val, key = null) => { const subs = new Set; - if (isFunc(val2)) { + if (isFunc(val)) { let cache; const computed = () => { if (computed._dirty) { const prev = activeEffect; activeEffect = computed; try { - const next = val2(); + const next = val(); if (!Object.is(cache, next)) { cache = next; trackUpdate(subs, true); @@ -155,25 +151,25 @@ var $ = (val2, key = null) => { computed._disposed = false; computed.stop = () => {}; if (activeOwner) - onUnmount(computed.stop); + _onUnmount(computed.stop); return computed; } if (key) try { - val2 = JSON.parse(localStorage.getItem(key)) ?? val2; + val = JSON.parse(localStorage.getItem(key)) ?? val; } catch (e) {} return (...args) => { if (args.length) { - const next = isFunc(args[0]) ? args[0](val2) : args[0]; - if (!Object.is(val2, next)) { - val2 = next; + const next = isFunc(args[0]) ? args[0](val) : args[0]; + if (!Object.is(val, next)) { + val = next; if (key) - localStorage.setItem(key, JSON.stringify(val2)); + localStorage.setItem(key, JSON.stringify(val)); trackUpdate(subs, true); } } trackUpdate(subs); - return val2; + return val; }; }; var $$ = (target) => { @@ -222,7 +218,7 @@ var $$ = (target) => { proxyCache.set(target, proxy); return proxy; }; -var Watch = (sources, cb) => { +var watch = (sources, cb) => { if (cb === undefined) { const effect2 = createEffect(sources); effect2(); @@ -247,25 +243,24 @@ var cleanupNode = (node) => { }; var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i; var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on"); -var validateAttr = (key, val2) => { - if (val2 == null || val2 === false) +var validateAttr = (key, val) => { + if (val == null || val === false) return null; if (isDangerousAttr(key)) { - const sVal = String(val2); + const sVal = String(val); if (DANGEROUS_PROTOCOL.test(sVal)) { console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`); return "#"; } } - return val2; + return val; }; -var Tag = (tag, props = {}, children = []) => { +var h = (tag, props = {}, children = []) => { if (props instanceof Node || isArr(props) || !isObj(props)) { children = props; props = {}; } if (isFunc(tag)) { - const ctx = { _mounts: [], _cleanups: new Set }; const effect = createEffect(() => { const result2 = tag(props, { children, @@ -302,7 +297,7 @@ var Tag = (tag, props = {}, children = []) => { } if (isSVG && k.startsWith("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; } if (k.startsWith("on")) { @@ -310,33 +305,33 @@ var Tag = (tag, props = {}, children = []) => { el.addEventListener(ev, v); const off = () => el.removeEventListener(ev, v); el._cleanups.add(off); - onUnmount(off); + _onUnmount(off); } else if (isFunc(v)) { const effect = createEffect(() => { - const val2 = validateAttr(k, v()); + const val = validateAttr(k, v()); if (k === "class") - el.className = val2 || ""; - else if (val2 == null) + el.className = val || ""; + else if (val == null) el.removeAttribute(k); else if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) { const evType = k === "checked" ? "change" : "input"; el.addEventListener(evType, (ev) => v(ev.target[k])); } } else { - const val2 = validateAttr(k, v); - if (val2 != null) { + const val = validateAttr(k, v); + if (val != null) { if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); } } } @@ -371,7 +366,7 @@ var Tag = (tag, props = {}, children = []) => { }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); } else { const node = ensureNode(c); el.appendChild(node); @@ -382,7 +377,7 @@ var Tag = (tag, props = {}, children = []) => { append(children); return el; }; -var Render = (renderFn) => { +var render = (renderFn) => { const cleanups = new Set; const mounts = []; const previousOwner = activeOwner; @@ -421,29 +416,46 @@ var Render = (renderFn) => { } }; }; -var If = (cond, ifYes, ifNot = null) => { - const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); - let currentView = null; - Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => { - if (currentView) { - currentView.destroy(); - currentView = null; - } - const content = show ? ifYes : ifNot; - if (content) { - currentView = Render(() => isFunc(content) ? content() : content); - root.insertBefore(currentView.container, anchor); +var when = (cond, render2, { enter, leave } = {}) => { + const wrap = h("div", { style: "display:contents" }); + let view = null; + const wait = (el, cb) => { + if (!el) + return cb(); + let done = false; + 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(); + } } }); - onUnmount(() => currentView?.destroy()); - return root; + return _onUnmount(() => view?.destroy()), wrap; }; -var For = (src, itemFn, keyFn) => { +var each = (src, itemFn, keyFn) => { const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); + const root = h("div", { style: "display:contents" }, [anchor]); let cache = new Map; - Watch(() => (isFunc(src) ? src() : src) || [], (items) => { + watch(() => (isFunc(src) ? src() : src) || [], (items) => { const nextCache = new Map; const nextOrder = []; const newItems = items || []; @@ -452,7 +464,7 @@ var For = (src, itemFn, keyFn) => { const key = keyFn ? keyFn(item, i) : item?.id ?? i; let view = cache.get(key); if (!view) - view = Render(() => itemFn(item, i)); + view = render(() => itemFn(item, i)); else cache.delete(key); nextCache.set(key, view); @@ -471,15 +483,15 @@ var For = (src, itemFn, keyFn) => { }); return root; }; -var Router = (routes) => { +var router = (routes) => { const getHash = () => window.location.hash.slice(1) || "/"; const path = $(getHash()); const handler = () => path(getHash()); window.addEventListener("hashchange", handler); - onUnmount(() => window.removeEventListener("hashchange", handler)); - const hook = Tag("div", { class: "router-hook" }); + _onUnmount(() => window.removeEventListener("hashchange", handler)); + const hook = h("div", { class: "router-hook" }); let currentView = null; - Watch([path], () => { + watch([path], () => { const cur = path(); const route = routes.find((r) => { const p1 = r.path.split("/").filter(Boolean); @@ -493,91 +505,43 @@ var Router = (routes) => { if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]; }); - Router.params(params); - currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component); + router.params(params); + currentView = render(() => isFunc(route.component) ? route.component(params) : route.component); hook.replaceChildren(currentView.container); } }); return hook; }; -Router.params = $({}); -Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); -Router.back = () => window.history.back(); -Router.path = () => window.location.hash.replace(/^#/, "") || "/"; -var Anim = (show, render, { enter, leave } = {}) => { - 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) => { +router.params = $({}); +router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); +router.back = () => window.history.back(); +router.path = () => window.location.hash.replace(/^#/, "") || "/"; +var mount = (comp, target) => { const t = typeof target === "string" ? doc.querySelector(target) : target; if (!t) return; if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy(); - const inst = Render(isFunc(comp) ? comp : () => comp); + const inst = render(isFunc(comp) ? comp : () => comp); t.replaceChildren(inst.container); MOUNTED_NODES.set(t, inst); return inst; }; -var SigPro = Object.freeze({ - $, - $$, - Watch, - Tag, - Render, - If, - For, - Router, - Mount, - onMount, - onUnmount, - Anim, - Batch -}); +var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch }); if (typeof window !== "undefined") { 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) => { - const name = t[0].toUpperCase() + t.slice(1); - window[name] = (p, c) => Tag(t, p, c); + "a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video".split(" ").forEach((tag) => { + window[tag] = (props, children) => h(tag, props, children); }); } export { - onUnmount, - onMount, - Watch, - Tag, - Router, - Render, - Mount, - If, - For, - Batch, - Anim, + when, + watch, + router, + mount, + h, + each, + batch, $$, $ }; diff --git a/dist/sigpro.esm.min.js b/dist/sigpro.esm.min.js index 641f803..bcac585 100644 --- a/dist/sigpro.esm.min.js +++ b/dist/sigpro.esm.min.js @@ -1 +1 @@ -var m=(e)=>typeof e==="function",j=(e)=>e&&typeof e==="object",N=Array.isArray,E=typeof document<"u"?document:null,$=(e)=>e?._isRuntime?e.container:e instanceof Node?e:E.createTextNode(e==null?"":String(e)),p=null,_=null,C=!1,A=0,T=new Set,U=new WeakMap,L=Symbol("iter"),M=new WeakMap,v=(e)=>{if(!e||e._disposed)return;e._disposed=!0;let s=[e];while(s.length){let t=s.pop();if(t._cleanups)t._cleanups.forEach((r)=>r()),t._cleanups.clear();if(t._children)t._children.forEach((r)=>s.push(r)),t._children.clear();if(t._deps)t._deps.forEach((r)=>r.delete(t)),t._deps.clear()}},k=(e)=>{if(_)(_._mounts||=[]).push(e)},g=(e)=>{if(_)(_._cleanups||=new Set).add(e)},q=(e)=>{let s=p;p=null;try{return e()}finally{p=s}},O=(e,s=!1)=>{let t=()=>{if(t._disposed)return;if(t._deps)t._deps.forEach((c)=>c.delete(t));if(t._cleanups)t._cleanups.forEach((c)=>c()),t._cleanups.clear();let r=p,n=_;p=_=t;try{return t._result=e()}catch(c){console.error("[SigPro]",c)}finally{p=r,_=n}};if(t._deps=t._cleanups=t._children=null,t._disposed=!1,t._isComputed=s,t._depth=p?p._depth+1:0,t._mounts=[],t._parent=_,_)(_._children||=new Set).add(t);return t},W=()=>{if(C)return;C=!0;let e=Array.from(T).sort((s,t)=>s._depth-t._depth);T.clear();for(let s of e)if(!s._disposed)s();C=!1},z=(e)=>{A++;try{return e()}finally{if(A--,A===0&&T.size>0&&!C)W()}},w=(e,s=!1)=>{if(!s&&p&&!p._disposed)e.add(p),(p._deps||=new Set).add(e);else if(s&&e.size>0){let t=!1;for(let r of e){if(r===p||r._disposed)continue;if(r._isComputed){if(r._dirty=!0,r._subs)w(r._subs,!0)}else T.add(r),t=!0}if(t&&!C&&A===0)queueMicrotask(W)}},B=(e,s=null)=>{let t=new Set;if(m(e)){let r,n=()=>{if(n._dirty){let c=p;p=n;try{let i=e();if(!Object.is(r,i))r=i,w(t,!0)}finally{p=c}n._dirty=!1}return w(t),r};if(n._isComputed=!0,n._subs=t,n._dirty=!0,n._deps=null,n._disposed=!1,n.stop=()=>{},_)g(n.stop);return n}if(s)try{e=JSON.parse(localStorage.getItem(s))??e}catch(r){}return(...r)=>{if(r.length){let n=m(r[0])?r[0](e):r[0];if(!Object.is(e,n)){if(e=n,s)localStorage.setItem(s,JSON.stringify(e));w(t,!0)}}return w(t),e}},D=(e)=>{if(!j(e))return e;let s=U.get(e);if(s)return s;let t=new Map,r=(n)=>{let c=t.get(n);if(!c)t.set(n,c=new Set);return c};return s=new Proxy(e,{get(n,c,i){if(typeof c!=="symbol")w(r(c));return D(Reflect.get(n,c,i))},set(n,c,i,o){let l=!Reflect.has(n,c),a=Reflect.get(n,c,o),d=Reflect.set(n,c,i,o);if(d&&!Object.is(a,i)){if(w(r(c),!0),l)w(r(L),!0)}return d},deleteProperty(n,c){let i=Reflect.deleteProperty(n,c);if(i)w(r(c),!0),w(r(L),!0);return i},ownKeys(n){return w(r(L)),Reflect.ownKeys(n)}}),U.set(e,s),s},R=(e,s)=>{if(s===void 0){let r=O(e);return r(),()=>v(r)}let t=O(()=>{let r=Array.isArray(e)?e.map((n)=>n()):e();q(()=>s(r))});return t(),()=>v(t)},P=(e)=>{if(e._cleanups)e._cleanups.forEach((s)=>s()),e._cleanups.clear();if(e._ownerEffect)v(e._ownerEffect);if(e.childNodes)e.childNodes.forEach(P)},F=/^\s*(javascript|data|vbscript):/i,G=(e)=>e==="src"||e==="href"||e.startsWith("on"),I=(e,s)=>{if(s==null||s===!1)return null;if(G(e)){let t=String(s);if(F.test(t))return console.warn(`[SigPro] Bloqueado protocolo peligroso en ${e}`),"#"}return s},S=(e,s={},t=[])=>{if(s instanceof Node||N(s)||!j(s))t=s,s={};if(m(e)){let i={_mounts:[],_cleanups:new Set},o=O(()=>{let f=e(s,{children:t,emit:(h,...u)=>s[`on${h[0].toUpperCase()}${h.slice(1)}`]?.(...u)});return o._result=f,f});o();let l=o._result;if(l==null)return null;let a=l instanceof Node||N(l)&&l.every((f)=>f instanceof Node)?l:E.createTextNode(String(l)),d=(f)=>{if(j(f)&&!f._isRuntime)f._mounts=o._mounts||[],f._cleanups=o._cleanups||new Set,f._ownerEffect=o};return N(a)?a.forEach(d):d(a),a}let r=/^(svg|path|circle|rect|line|poly(line|gon)|g|defs|text(path)?|tspan|use|symbol|image|marker|ellipse)$/i.test(e),n=r?E.createElementNS("http://www.w3.org/2000/svg",e):E.createElement(e);n._cleanups=new Set;for(let i in s){if(!s.hasOwnProperty(i))continue;let o=s[i];if(i==="ref"){m(o)?o(n):o.current=n;continue}if(r&&i.startsWith("xlink:")){val==null?n.removeAttributeNS("http://www.w3.org/1999/xlink",i.slice(6)):n.setAttributeNS("http://www.w3.org/1999/xlink",i.slice(6),val);continue}if(i.startsWith("on")){let l=i.slice(2).toLowerCase();n.addEventListener(l,o);let a=()=>n.removeEventListener(l,o);n._cleanups.add(a),g(a)}else if(m(o)){let l=O(()=>{let a=I(i,o());if(i==="class")n.className=a||"";else if(a==null)n.removeAttribute(i);else if(i in n&&!r)n[i]=a;else n.setAttribute(i,a===!0?"":a)});if(l(),n._cleanups.add(()=>v(l)),g(()=>v(l)),/^(INPUT|TEXTAREA|SELECT)$/.test(n.tagName)&&(i==="value"||i==="checked")){let a=i==="checked"?"change":"input";n.addEventListener(a,(d)=>o(d.target[i]))}}else{let l=I(i,o);if(l!=null)if(i in n&&!r)n[i]=l;else n.setAttribute(i,l===!0?"":l)}}let c=(i)=>{if(N(i))return i.forEach(c);if(m(i)){let o=E.createTextNode("");n.appendChild(o);let l=[],a=O(()=>{let d=i(),f=(N(d)?d:[d]).map($);l.forEach((u)=>{if(u._isRuntime)u.destroy();else P(u);if(u.parentNode)u.remove()});let h=o;for(let u=f.length-1;u>=0;u--){let y=f[u];if(y.parentNode!==h.parentNode)h.parentNode?.insertBefore(y,h);if(y._mounts)y._mounts.forEach((V)=>V());h=y}l=f});a(),n._cleanups.add(()=>v(a)),g(()=>v(a))}else{let o=$(i);if(n.appendChild(o),o._mounts)o._mounts.forEach((l)=>l())}};return c(t),n},b=(e)=>{let s=new Set,t=[],r=_,n=p,c=E.createElement("div");c.style.display="contents",c.setAttribute("role","presentation"),_={_cleanups:s,_mounts:t},p=null;let i=(o)=>{if(!o)return;if(o._isRuntime)s.add(o.destroy),c.appendChild(o.container);else if(N(o))o.forEach(i);else c.appendChild(o instanceof Node?o:E.createTextNode(String(o==null?"":o)))};try{i(e({onCleanup:(o)=>s.add(o)}))}finally{_=r,p=n}return t.forEach((o)=>o()),{_isRuntime:!0,container:c,destroy:()=>{s.forEach((o)=>o()),P(c),c.remove()}}},J=(e,s,t=null)=>{let r=E.createTextNode(""),n=S("div",{style:"display:contents"},[r]),c=null;return R(()=>!!(m(e)?e():e),(i)=>{if(c)c.destroy(),c=null;let o=i?s:t;if(o)c=b(()=>m(o)?o():o),n.insertBefore(c.container,r)}),g(()=>c?.destroy()),n},K=(e,s,t)=>{let r=E.createTextNode(""),n=S("div",{style:"display:contents"},[r]),c=new Map;return R(()=>(m(e)?e():e)||[],(i)=>{let o=new Map,l=[],a=i||[];for(let f=0;fs(h,f));else c.delete(u);o.set(u,y),l.push(y)}c.forEach((f)=>f.destroy());let d=r;for(let f=l.length-1;f>=0;f--){let u=l[f].container;if(u.nextSibling!==d)n.insertBefore(u,d);d=u}c=o}),n},x=(e)=>{let s=()=>window.location.hash.slice(1)||"/",t=B(s()),r=()=>t(s());window.addEventListener("hashchange",r),g(()=>window.removeEventListener("hashchange",r));let n=S("div",{class:"router-hook"}),c=null;return R([t],()=>{let i=t(),o=e.find((l)=>{let a=l.path.split("/").filter(Boolean),d=i.split("/").filter(Boolean);return a.length===d.length&&a.every((f,h)=>f[0]===":"||f===d[h])})||e.find((l)=>l.path==="*");if(o){c?.destroy();let l={};o.path.split("/").filter(Boolean).forEach((a,d)=>{if(a[0]===":")l[a.slice(1)]=i.split("/").filter(Boolean)[d]}),x.params(l),c=b(()=>m(o.component)?o.component(l):o.component),n.replaceChildren(c.container)}}),n};x.params=B({});x.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");x.back=()=>window.history.back();x.path=()=>window.location.hash.replace(/^#/,"")||"/";var Q=(e,s,{enter:t,leave:r}={})=>{let n=S("div",{style:"display:contents"}),c=null,i=(o,l)=>{let a=!1,d=()=>!a&&(a=!0,l());if(!o)return d();"transitionend animationend".split(" ").map((f)=>o.addEventListener(f,d,{once:!0})),setTimeout(d,500)};return R(e,(o)=>{if(o&&!c){let l=(c=b(s)).container.firstChild;if(n.appendChild(c.container),t&&l)l.classList.add(t),l.clientTop,l.classList.add(t+"-active"),i(l,()=>l.classList.remove(t,t+"-active"))}else if(!o&&c){let l=c.container.firstChild,a=()=>(c?.destroy(),c=null);r&&l?(l.classList.add(r),i(l,a)):a()}}),g(()=>c?.destroy()),n},H=(e,s)=>{let t=typeof s==="string"?E.querySelector(s):s;if(!t)return;if(M.has(t))M.get(t).destroy();let r=b(m(e)?e:()=>e);return t.replaceChildren(r.container),M.set(t,r),r},X=Object.freeze({$:B,$$:D,Watch:R,Tag:S,Render:b,If:J,For:K,Router:x,Mount:H,onMount:k,onUnmount:g,Anim:Q,Batch:z});if(typeof window<"u")Object.assign(window,X),"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((e)=>{let s=e[0].toUpperCase()+e.slice(1);window[s]=(t,r)=>S(e,t,r)});export{g as onUnmount,k as onMount,R as Watch,S as Tag,x as Router,b as Render,H as Mount,J as If,K as For,z as Batch,Q as Anim,D as $$,B as $}; +var y=(e)=>typeof e==="function",j=(e)=>e&&typeof e==="object",b=Array.isArray,E=typeof document<"u"?document:null,B=(e)=>e?._isRuntime?e.container:e instanceof Node?e:E.createTextNode(e==null?"":String(e)),u=null,_=null,S=!1,O=0,A=new Set,k=new WeakMap,T=Symbol("iter"),L=new WeakMap,g=(e)=>{if(!e||e._disposed)return;e._disposed=!0;let n=[e];while(n.length){let t=n.pop();if(t._cleanups)t._cleanups.forEach((r)=>r()),t._cleanups.clear();if(t._children)t._children.forEach((r)=>n.push(r)),t._children.clear();if(t._deps)t._deps.forEach((r)=>r.delete(t)),t._deps.clear()}},v=(e)=>{if(_)(_._cleanups||=new Set).add(e)},W=(e)=>{let n=u;u=null;try{return e()}finally{u=n}},x=(e,n=!1)=>{let t=()=>{if(t._disposed)return;if(t._deps)t._deps.forEach((c)=>c.delete(t));if(t._cleanups)t._cleanups.forEach((c)=>c()),t._cleanups.clear();let r=u,s=_;u=_=t;try{return t._result=e()}catch(c){console.error("[SigPro]",c)}finally{u=r,_=s}};if(t._deps=t._cleanups=t._children=null,t._disposed=!1,t._isComputed=n,t._depth=u?u._depth+1:0,t._mounts=[],t._parent=_,_)(_._children||=new Set).add(t);return t},D=()=>{if(S)return;S=!0;let e=Array.from(A).sort((n,t)=>n._depth-t._depth);A.clear();for(let n of e)if(!n._disposed)n();S=!1},q=(e)=>{O++;try{return e()}finally{if(O--,O===0&&A.size>0&&!S)D()}},m=(e,n=!1)=>{if(!n&&u&&!u._disposed)e.add(u),(u._deps||=new Set).add(e);else if(n&&e.size>0){let t=!1;for(let r of e){if(r===u||r._disposed)continue;if(r._isComputed){if(r._dirty=!0,r._subs)m(r._subs,!0)}else A.add(r),t=!0}if(t&&!S&&O===0)queueMicrotask(D)}},P=(e,n=null)=>{let t=new Set;if(y(e)){let r,s=()=>{if(s._dirty){let c=u;u=s;try{let i=e();if(!Object.is(r,i))r=i,m(t,!0)}finally{u=c}s._dirty=!1}return m(t),r};if(s._isComputed=!0,s._subs=t,s._dirty=!0,s._deps=null,s._disposed=!1,s.stop=()=>{},_)v(s.stop);return s}if(n)try{e=JSON.parse(localStorage.getItem(n))??e}catch(r){}return(...r)=>{if(r.length){let s=y(r[0])?r[0](e):r[0];if(!Object.is(e,s)){if(e=s,n)localStorage.setItem(n,JSON.stringify(e));m(t,!0)}}return m(t),e}},I=(e)=>{if(!j(e))return e;let n=k.get(e);if(n)return n;let t=new Map,r=(s)=>{let c=t.get(s);if(!c)t.set(s,c=new Set);return c};return n=new Proxy(e,{get(s,c,i){if(typeof c!=="symbol")m(r(c));return I(Reflect.get(s,c,i))},set(s,c,i,o){let l=!Reflect.has(s,c),a=Reflect.get(s,c,o),f=Reflect.set(s,c,i,o);if(f&&!Object.is(a,i)){if(m(r(c),!0),l)m(r(T),!0)}return f},deleteProperty(s,c){let i=Reflect.deleteProperty(s,c);if(i)m(r(c),!0),m(r(T),!0);return i},ownKeys(s){return m(r(T)),Reflect.ownKeys(s)}}),k.set(e,n),n},R=(e,n)=>{if(n===void 0){let r=x(e);return r(),()=>g(r)}let t=x(()=>{let r=Array.isArray(e)?e.map((s)=>s()):e();W(()=>n(r))});return t(),()=>g(t)},M=(e)=>{if(e._cleanups)e._cleanups.forEach((n)=>n()),e._cleanups.clear();if(e._ownerEffect)g(e._ownerEffect);if(e.childNodes)e.childNodes.forEach(M)},z=/^\s*(javascript|data|vbscript):/i,G=(e)=>e==="src"||e==="href"||e.startsWith("on"),U=(e,n)=>{if(n==null||n===!1)return null;if(G(e)){let t=String(n);if(z.test(t))return console.warn(`[SigPro] Bloqueado protocolo peligroso en ${e}`),"#"}return n},C=(e,n={},t=[])=>{if(n instanceof Node||b(n)||!j(n))t=n,n={};if(y(e)){let i=x(()=>{let f=e(n,{children:t,emit:(d,...h)=>n[`on${d[0].toUpperCase()}${d.slice(1)}`]?.(...h)});return i._result=f,f});i();let o=i._result;if(o==null)return null;let l=o instanceof Node||b(o)&&o.every((f)=>f instanceof Node)?o:E.createTextNode(String(o)),a=(f)=>{if(j(f)&&!f._isRuntime)f._mounts=i._mounts||[],f._cleanups=i._cleanups||new Set,f._ownerEffect=i};return b(l)?l.forEach(a):a(l),l}let r=/^(svg|path|circle|rect|line|poly(line|gon)|g|defs|text(path)?|tspan|use|symbol|image|marker|ellipse)$/i.test(e),s=r?E.createElementNS("http://www.w3.org/2000/svg",e):E.createElement(e);s._cleanups=new Set;for(let i in n){if(!n.hasOwnProperty(i))continue;let o=n[i];if(i==="ref"){y(o)?o(s):o.current=s;continue}if(r&&i.startsWith("xlink:")){o==null?s.removeAttributeNS("http://www.w3.org/1999/xlink",i.slice(6)):s.setAttributeNS("http://www.w3.org/1999/xlink",i.slice(6),o);continue}if(i.startsWith("on")){let l=i.slice(2).toLowerCase();s.addEventListener(l,o);let a=()=>s.removeEventListener(l,o);s._cleanups.add(a),v(a)}else if(y(o)){let l=x(()=>{let a=U(i,o());if(i==="class")s.className=a||"";else if(a==null)s.removeAttribute(i);else if(i in s&&!r)s[i]=a;else s.setAttribute(i,a===!0?"":a)});if(l(),s._cleanups.add(()=>g(l)),v(()=>g(l)),/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName)&&(i==="value"||i==="checked")){let a=i==="checked"?"change":"input";s.addEventListener(a,(f)=>o(f.target[i]))}}else{let l=U(i,o);if(l!=null)if(i in s&&!r)s[i]=l;else s.setAttribute(i,l===!0?"":l)}}let c=(i)=>{if(b(i))return i.forEach(c);if(y(i)){let o=E.createTextNode("");s.appendChild(o);let l=[],a=x(()=>{let f=i(),d=(b(f)?f:[f]).map(B);l.forEach((p)=>{if(p._isRuntime)p.destroy();else M(p);if(p.parentNode)p.remove()});let h=o;for(let p=d.length-1;p>=0;p--){let w=d[p];if(w.parentNode!==h.parentNode)h.parentNode?.insertBefore(w,h);if(w._mounts)w._mounts.forEach((V)=>V());h=w}l=d});a(),s._cleanups.add(()=>g(a)),v(()=>g(a))}else{let o=B(i);if(s.appendChild(o),o._mounts)o._mounts.forEach((l)=>l())}};return c(t),s},$=(e)=>{let n=new Set,t=[],r=_,s=u,c=E.createElement("div");c.style.display="contents",c.setAttribute("role","presentation"),_={_cleanups:n,_mounts:t},u=null;let i=(o)=>{if(!o)return;if(o._isRuntime)n.add(o.destroy),c.appendChild(o.container);else if(b(o))o.forEach(i);else c.appendChild(o instanceof Node?o:E.createTextNode(String(o==null?"":o)))};try{i(e({onCleanup:(o)=>n.add(o)}))}finally{_=r,u=s}return t.forEach((o)=>o()),{_isRuntime:!0,container:c,destroy:()=>{n.forEach((o)=>o()),M(c),c.remove()}}},J=(e,n,{enter:t,leave:r}={})=>{let s=C("div",{style:"display:contents"}),c=null,i=(o,l)=>{if(!o)return l();let a=!1,f=()=>!a&&(a=!0,l());o.addEventListener("transitionend",f,{once:!0}),o.addEventListener("animationend",f,{once:!0}),setTimeout(f,500)};return R(e,(o)=>{if(o&&!c){let l=(c=n(n)).container.firstChild;if(s.appendChild(c.container),t&&l)l.classList.add(t),l.clientTop,l.classList.add(t+"-active"),i(l,()=>l.classList.remove(t,t+"-active"))}else if(!o&&c){let l=c.container.firstChild,a=()=>(c.destroy(),c=null);if(r&&l)l.classList.add(r),i(l,a);else a()}}),v(()=>c?.destroy()),s},K=(e,n,t)=>{let r=E.createTextNode(""),s=C("div",{style:"display:contents"},[r]),c=new Map;return R(()=>(y(e)?e():e)||[],(i)=>{let o=new Map,l=[],a=i||[];for(let d=0;dn(h,d));else c.delete(p);o.set(p,w),l.push(w)}c.forEach((d)=>d.destroy());let f=r;for(let d=l.length-1;d>=0;d--){let p=l[d].container;if(p.nextSibling!==f)s.insertBefore(p,f);f=p}c=o}),s},N=(e)=>{let n=()=>window.location.hash.slice(1)||"/",t=P(n()),r=()=>t(n());window.addEventListener("hashchange",r),v(()=>window.removeEventListener("hashchange",r));let s=C("div",{class:"router-hook"}),c=null;return R([t],()=>{let i=t(),o=e.find((l)=>{let a=l.path.split("/").filter(Boolean),f=i.split("/").filter(Boolean);return a.length===f.length&&a.every((d,h)=>d[0]===":"||d===f[h])})||e.find((l)=>l.path==="*");if(o){c?.destroy();let l={};o.path.split("/").filter(Boolean).forEach((a,f)=>{if(a[0]===":")l[a.slice(1)]=i.split("/").filter(Boolean)[f]}),N.params(l),c=$(()=>y(o.component)?o.component(l):o.component),s.replaceChildren(c.container)}}),s};N.params=P({});N.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");N.back=()=>window.history.back();N.path=()=>window.location.hash.replace(/^#/,"")||"/";var Q=(e,n)=>{let t=typeof n==="string"?E.querySelector(n):n;if(!t)return;if(L.has(t))L.get(t).destroy();let r=$(y(e)?e:()=>e);return t.replaceChildren(r.container),L.set(t,r),r},F=Object.freeze({$:P,$$:I,watch:R,h:C,when:J,each:K,router:N,mount:Q,batch:q});if(typeof window<"u")Object.assign(window,F),"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((e)=>{window[e]=(n,t)=>C(e,n,t)});export{J as when,R as watch,N as router,Q as mount,C as h,K as each,q as batch,I as $$,P as $}; diff --git a/dist/sigpro.js b/dist/sigpro.js index a37f90f..571e9fb 100644 --- a/dist/sigpro.js +++ b/dist/sigpro.js @@ -40,17 +40,13 @@ // index.js var exports_sigpro = {}; __export(exports_sigpro, { - onUnmount: () => onUnmount, - onMount: () => onMount, - Watch: () => Watch, - Tag: () => Tag, - Router: () => Router, - Render: () => Render, - Mount: () => Mount, - If: () => If, - For: () => For, - Batch: () => Batch, - Anim: () => Anim, + when: () => when, + watch: () => watch, + router: () => router, + mount: () => mount, + h: () => h, + each: () => each, + batch: () => batch, $$: () => $$, $: () => $ }); @@ -90,11 +86,7 @@ } } }; - var onMount = (fn) => { - if (activeOwner) - (activeOwner._mounts ||= []).push(fn); - }; - var onUnmount = (fn) => { + var _onUnmount = (fn) => { if (activeOwner) (activeOwner._cleanups ||= new Set).add(fn); }; @@ -150,7 +142,7 @@ e(); isFlushing = false; }; - var Batch = (fn) => { + var batch = (fn) => { batchDepth++; try { return fn(); @@ -183,16 +175,16 @@ queueMicrotask(flush); } }; - var $ = (val2, key = null) => { + var $ = (val, key = null) => { const subs = new Set; - if (isFunc(val2)) { + if (isFunc(val)) { let cache; const computed = () => { if (computed._dirty) { const prev = activeEffect; activeEffect = computed; try { - const next = val2(); + const next = val(); if (!Object.is(cache, next)) { cache = next; trackUpdate(subs, true); @@ -212,25 +204,25 @@ computed._disposed = false; computed.stop = () => {}; if (activeOwner) - onUnmount(computed.stop); + _onUnmount(computed.stop); return computed; } if (key) try { - val2 = JSON.parse(localStorage.getItem(key)) ?? val2; + val = JSON.parse(localStorage.getItem(key)) ?? val; } catch (e) {} return (...args) => { if (args.length) { - const next = isFunc(args[0]) ? args[0](val2) : args[0]; - if (!Object.is(val2, next)) { - val2 = next; + const next = isFunc(args[0]) ? args[0](val) : args[0]; + if (!Object.is(val, next)) { + val = next; if (key) - localStorage.setItem(key, JSON.stringify(val2)); + localStorage.setItem(key, JSON.stringify(val)); trackUpdate(subs, true); } } trackUpdate(subs); - return val2; + return val; }; }; var $$ = (target) => { @@ -279,7 +271,7 @@ proxyCache.set(target, proxy); return proxy; }; - var Watch = (sources, cb) => { + var watch = (sources, cb) => { if (cb === undefined) { const effect2 = createEffect(sources); effect2(); @@ -304,25 +296,24 @@ }; var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i; var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on"); - var validateAttr = (key, val2) => { - if (val2 == null || val2 === false) + var validateAttr = (key, val) => { + if (val == null || val === false) return null; if (isDangerousAttr(key)) { - const sVal = String(val2); + const sVal = String(val); if (DANGEROUS_PROTOCOL.test(sVal)) { console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`); return "#"; } } - return val2; + return val; }; - var Tag = (tag, props = {}, children = []) => { + var h = (tag, props = {}, children = []) => { if (props instanceof Node || isArr(props) || !isObj(props)) { children = props; props = {}; } if (isFunc(tag)) { - const ctx = { _mounts: [], _cleanups: new Set }; const effect = createEffect(() => { const result2 = tag(props, { children, @@ -359,7 +350,7 @@ } if (isSVG && k.startsWith("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; } if (k.startsWith("on")) { @@ -367,33 +358,33 @@ el.addEventListener(ev, v); const off = () => el.removeEventListener(ev, v); el._cleanups.add(off); - onUnmount(off); + _onUnmount(off); } else if (isFunc(v)) { const effect = createEffect(() => { - const val2 = validateAttr(k, v()); + const val = validateAttr(k, v()); if (k === "class") - el.className = val2 || ""; - else if (val2 == null) + el.className = val || ""; + else if (val == null) el.removeAttribute(k); else if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) { const evType = k === "checked" ? "change" : "input"; el.addEventListener(evType, (ev) => v(ev.target[k])); } } else { - const val2 = validateAttr(k, v); - if (val2 != null) { + const val = validateAttr(k, v); + if (val != null) { if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); } } } @@ -428,7 +419,7 @@ }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); } else { const node = ensureNode(c); el.appendChild(node); @@ -439,7 +430,7 @@ append(children); return el; }; - var Render = (renderFn) => { + var render = (renderFn) => { const cleanups = new Set; const mounts = []; const previousOwner = activeOwner; @@ -478,29 +469,46 @@ } }; }; - var If = (cond, ifYes, ifNot = null) => { - const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); - let currentView = null; - Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => { - if (currentView) { - currentView.destroy(); - currentView = null; - } - const content = show ? ifYes : ifNot; - if (content) { - currentView = Render(() => isFunc(content) ? content() : content); - root.insertBefore(currentView.container, anchor); + var when = (cond, render2, { enter, leave } = {}) => { + const wrap = h("div", { style: "display:contents" }); + let view = null; + const wait = (el, cb) => { + if (!el) + return cb(); + let done = false; + 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(); + } } }); - onUnmount(() => currentView?.destroy()); - return root; + return _onUnmount(() => view?.destroy()), wrap; }; - var For = (src, itemFn, keyFn) => { + var each = (src, itemFn, keyFn) => { const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); + const root = h("div", { style: "display:contents" }, [anchor]); let cache = new Map; - Watch(() => (isFunc(src) ? src() : src) || [], (items) => { + watch(() => (isFunc(src) ? src() : src) || [], (items) => { const nextCache = new Map; const nextOrder = []; const newItems = items || []; @@ -509,7 +517,7 @@ const key = keyFn ? keyFn(item, i) : item?.id ?? i; let view = cache.get(key); if (!view) - view = Render(() => itemFn(item, i)); + view = render(() => itemFn(item, i)); else cache.delete(key); nextCache.set(key, view); @@ -528,15 +536,15 @@ }); return root; }; - var Router = (routes) => { + var router = (routes) => { const getHash = () => window.location.hash.slice(1) || "/"; const path = $(getHash()); const handler = () => path(getHash()); window.addEventListener("hashchange", handler); - onUnmount(() => window.removeEventListener("hashchange", handler)); - const hook = Tag("div", { class: "router-hook" }); + _onUnmount(() => window.removeEventListener("hashchange", handler)); + const hook = h("div", { class: "router-hook" }); let currentView = null; - Watch([path], () => { + watch([path], () => { const cur = path(); const route = routes.find((r) => { const p1 = r.path.split("/").filter(Boolean); @@ -550,77 +558,33 @@ if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]; }); - Router.params(params); - currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component); + router.params(params); + currentView = render(() => isFunc(route.component) ? route.component(params) : route.component); hook.replaceChildren(currentView.container); } }); return hook; }; - Router.params = $({}); - Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); - Router.back = () => window.history.back(); - Router.path = () => window.location.hash.replace(/^#/, "") || "/"; - var Anim = (show, render, { enter, leave } = {}) => { - 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) => { + router.params = $({}); + router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); + router.back = () => window.history.back(); + router.path = () => window.location.hash.replace(/^#/, "") || "/"; + var mount = (comp, target) => { const t = typeof target === "string" ? doc.querySelector(target) : target; if (!t) return; if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy(); - const inst = Render(isFunc(comp) ? comp : () => comp); + const inst = render(isFunc(comp) ? comp : () => comp); t.replaceChildren(inst.container); MOUNTED_NODES.set(t, inst); return inst; }; - var SigPro = Object.freeze({ - $, - $$, - Watch, - Tag, - Render, - If, - For, - Router, - Mount, - onMount, - onUnmount, - Anim, - Batch - }); + var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch }); if (typeof window !== "undefined") { 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) => { - const name = t[0].toUpperCase() + t.slice(1); - window[name] = (p, c) => Tag(t, p, c); + "a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video".split(" ").forEach((tag) => { + window[tag] = (props, children) => h(tag, props, children); }); } })(); diff --git a/dist/sigpro.min.js b/dist/sigpro.min.js index cc6b328..7c57d64 100644 --- a/dist/sigpro.min.js +++ b/dist/sigpro.min.js @@ -1 +1 @@ -(()=>{var{defineProperty:M,getOwnPropertyNames:H,getOwnPropertyDescriptor:X}=Object,Y=Object.prototype.hasOwnProperty;function Z(e){return this[e]}var ee=(e)=>{var n=(I??=new WeakMap).get(e),t;if(n)return n;if(n=M({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function"){for(var o of H(e))if(!Y.call(n,o))M(n,o,{get:Z.bind(e,o),enumerable:!(t=X(e,o))||t.enumerable})}return I.set(e,n),n},I;var te=(e)=>e;function ne(e,n){this[e]=te.bind(null,n)}var se=(e,n)=>{for(var t in n)M(e,t,{get:n[t],enumerable:!0,configurable:!0,set:ne.bind(n,t)})};var le={};se(le,{onUnmount:()=>g,onMount:()=>k,Watch:()=>C,Tag:()=>N,Router:()=>b,Render:()=>S,Mount:()=>K,If:()=>F,For:()=>G,Batch:()=>z,Anim:()=>J,$$:()=>$,$:()=>L});var m=(e)=>typeof e==="function",P=(e)=>e&&typeof e==="object",x=Array.isArray,E=typeof document<"u"?document:null,W=(e)=>e?._isRuntime?e.container:e instanceof Node?e:E.createTextNode(e==null?"":String(e)),p=null,_=null,O=!1,A=0,T=new Set,D=new WeakMap,j=Symbol("iter"),B=new WeakMap,v=(e)=>{if(!e||e._disposed)return;e._disposed=!0;let n=[e];while(n.length){let t=n.pop();if(t._cleanups)t._cleanups.forEach((o)=>o()),t._cleanups.clear();if(t._children)t._children.forEach((o)=>n.push(o)),t._children.clear();if(t._deps)t._deps.forEach((o)=>o.delete(t)),t._deps.clear()}},k=(e)=>{if(_)(_._mounts||=[]).push(e)},g=(e)=>{if(_)(_._cleanups||=new Set).add(e)},oe=(e)=>{let n=p;p=null;try{return e()}finally{p=n}},R=(e,n=!1)=>{let t=()=>{if(t._disposed)return;if(t._deps)t._deps.forEach((c)=>c.delete(t));if(t._cleanups)t._cleanups.forEach((c)=>c()),t._cleanups.clear();let o=p,s=_;p=_=t;try{return t._result=e()}catch(c){console.error("[SigPro]",c)}finally{p=o,_=s}};if(t._deps=t._cleanups=t._children=null,t._disposed=!1,t._isComputed=n,t._depth=p?p._depth+1:0,t._mounts=[],t._parent=_,_)(_._children||=new Set).add(t);return t},q=()=>{if(O)return;O=!0;let e=Array.from(T).sort((n,t)=>n._depth-t._depth);T.clear();for(let n of e)if(!n._disposed)n();O=!1},z=(e)=>{A++;try{return e()}finally{if(A--,A===0&&T.size>0&&!O)q()}},w=(e,n=!1)=>{if(!n&&p&&!p._disposed)e.add(p),(p._deps||=new Set).add(e);else if(n&&e.size>0){let t=!1;for(let o of e){if(o===p||o._disposed)continue;if(o._isComputed){if(o._dirty=!0,o._subs)w(o._subs,!0)}else T.add(o),t=!0}if(t&&!O&&A===0)queueMicrotask(q)}},L=(e,n=null)=>{let t=new Set;if(m(e)){let o,s=()=>{if(s._dirty){let c=p;p=s;try{let i=e();if(!Object.is(o,i))o=i,w(t,!0)}finally{p=c}s._dirty=!1}return w(t),o};if(s._isComputed=!0,s._subs=t,s._dirty=!0,s._deps=null,s._disposed=!1,s.stop=()=>{},_)g(s.stop);return s}if(n)try{e=JSON.parse(localStorage.getItem(n))??e}catch(o){}return(...o)=>{if(o.length){let s=m(o[0])?o[0](e):o[0];if(!Object.is(e,s)){if(e=s,n)localStorage.setItem(n,JSON.stringify(e));w(t,!0)}}return w(t),e}},$=(e)=>{if(!P(e))return e;let n=D.get(e);if(n)return n;let t=new Map,o=(s)=>{let c=t.get(s);if(!c)t.set(s,c=new Set);return c};return n=new Proxy(e,{get(s,c,i){if(typeof c!=="symbol")w(o(c));return $(Reflect.get(s,c,i))},set(s,c,i,r){let l=!Reflect.has(s,c),a=Reflect.get(s,c,r),d=Reflect.set(s,c,i,r);if(d&&!Object.is(a,i)){if(w(o(c),!0),l)w(o(j),!0)}return d},deleteProperty(s,c){let i=Reflect.deleteProperty(s,c);if(i)w(o(c),!0),w(o(j),!0);return i},ownKeys(s){return w(o(j)),Reflect.ownKeys(s)}}),D.set(e,n),n},C=(e,n)=>{if(n===void 0){let o=R(e);return o(),()=>v(o)}let t=R(()=>{let o=Array.isArray(e)?e.map((s)=>s()):e();oe(()=>n(o))});return t(),()=>v(t)},U=(e)=>{if(e._cleanups)e._cleanups.forEach((n)=>n()),e._cleanups.clear();if(e._ownerEffect)v(e._ownerEffect);if(e.childNodes)e.childNodes.forEach(U)},re=/^\s*(javascript|data|vbscript):/i,ce=(e)=>e==="src"||e==="href"||e.startsWith("on"),V=(e,n)=>{if(n==null||n===!1)return null;if(ce(e)){let t=String(n);if(re.test(t))return console.warn(`[SigPro] Bloqueado protocolo peligroso en ${e}`),"#"}return n},N=(e,n={},t=[])=>{if(n instanceof Node||x(n)||!P(n))t=n,n={};if(m(e)){let i={_mounts:[],_cleanups:new Set},r=R(()=>{let f=e(n,{children:t,emit:(h,...u)=>n[`on${h[0].toUpperCase()}${h.slice(1)}`]?.(...u)});return r._result=f,f});r();let l=r._result;if(l==null)return null;let a=l instanceof Node||x(l)&&l.every((f)=>f instanceof Node)?l:E.createTextNode(String(l)),d=(f)=>{if(P(f)&&!f._isRuntime)f._mounts=r._mounts||[],f._cleanups=r._cleanups||new Set,f._ownerEffect=r};return x(a)?a.forEach(d):d(a),a}let o=/^(svg|path|circle|rect|line|poly(line|gon)|g|defs|text(path)?|tspan|use|symbol|image|marker|ellipse)$/i.test(e),s=o?E.createElementNS("http://www.w3.org/2000/svg",e):E.createElement(e);s._cleanups=new Set;for(let i in n){if(!n.hasOwnProperty(i))continue;let r=n[i];if(i==="ref"){m(r)?r(s):r.current=s;continue}if(o&&i.startsWith("xlink:")){val==null?s.removeAttributeNS("http://www.w3.org/1999/xlink",i.slice(6)):s.setAttributeNS("http://www.w3.org/1999/xlink",i.slice(6),val);continue}if(i.startsWith("on")){let l=i.slice(2).toLowerCase();s.addEventListener(l,r);let a=()=>s.removeEventListener(l,r);s._cleanups.add(a),g(a)}else if(m(r)){let l=R(()=>{let a=V(i,r());if(i==="class")s.className=a||"";else if(a==null)s.removeAttribute(i);else if(i in s&&!o)s[i]=a;else s.setAttribute(i,a===!0?"":a)});if(l(),s._cleanups.add(()=>v(l)),g(()=>v(l)),/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName)&&(i==="value"||i==="checked")){let a=i==="checked"?"change":"input";s.addEventListener(a,(d)=>r(d.target[i]))}}else{let l=V(i,r);if(l!=null)if(i in s&&!o)s[i]=l;else s.setAttribute(i,l===!0?"":l)}}let c=(i)=>{if(x(i))return i.forEach(c);if(m(i)){let r=E.createTextNode("");s.appendChild(r);let l=[],a=R(()=>{let d=i(),f=(x(d)?d:[d]).map(W);l.forEach((u)=>{if(u._isRuntime)u.destroy();else U(u);if(u.parentNode)u.remove()});let h=r;for(let u=f.length-1;u>=0;u--){let y=f[u];if(y.parentNode!==h.parentNode)h.parentNode?.insertBefore(y,h);if(y._mounts)y._mounts.forEach((Q)=>Q());h=y}l=f});a(),s._cleanups.add(()=>v(a)),g(()=>v(a))}else{let r=W(i);if(s.appendChild(r),r._mounts)r._mounts.forEach((l)=>l())}};return c(t),s},S=(e)=>{let n=new Set,t=[],o=_,s=p,c=E.createElement("div");c.style.display="contents",c.setAttribute("role","presentation"),_={_cleanups:n,_mounts:t},p=null;let i=(r)=>{if(!r)return;if(r._isRuntime)n.add(r.destroy),c.appendChild(r.container);else if(x(r))r.forEach(i);else c.appendChild(r instanceof Node?r:E.createTextNode(String(r==null?"":r)))};try{i(e({onCleanup:(r)=>n.add(r)}))}finally{_=o,p=s}return t.forEach((r)=>r()),{_isRuntime:!0,container:c,destroy:()=>{n.forEach((r)=>r()),U(c),c.remove()}}},F=(e,n,t=null)=>{let o=E.createTextNode(""),s=N("div",{style:"display:contents"},[o]),c=null;return C(()=>!!(m(e)?e():e),(i)=>{if(c)c.destroy(),c=null;let r=i?n:t;if(r)c=S(()=>m(r)?r():r),s.insertBefore(c.container,o)}),g(()=>c?.destroy()),s},G=(e,n,t)=>{let o=E.createTextNode(""),s=N("div",{style:"display:contents"},[o]),c=new Map;return C(()=>(m(e)?e():e)||[],(i)=>{let r=new Map,l=[],a=i||[];for(let f=0;fn(h,f));else c.delete(u);r.set(u,y),l.push(y)}c.forEach((f)=>f.destroy());let d=o;for(let f=l.length-1;f>=0;f--){let u=l[f].container;if(u.nextSibling!==d)s.insertBefore(u,d);d=u}c=r}),s},b=(e)=>{let n=()=>window.location.hash.slice(1)||"/",t=L(n()),o=()=>t(n());window.addEventListener("hashchange",o),g(()=>window.removeEventListener("hashchange",o));let s=N("div",{class:"router-hook"}),c=null;return C([t],()=>{let i=t(),r=e.find((l)=>{let a=l.path.split("/").filter(Boolean),d=i.split("/").filter(Boolean);return a.length===d.length&&a.every((f,h)=>f[0]===":"||f===d[h])})||e.find((l)=>l.path==="*");if(r){c?.destroy();let l={};r.path.split("/").filter(Boolean).forEach((a,d)=>{if(a[0]===":")l[a.slice(1)]=i.split("/").filter(Boolean)[d]}),b.params(l),c=S(()=>m(r.component)?r.component(l):r.component),s.replaceChildren(c.container)}}),s};b.params=L({});b.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");b.back=()=>window.history.back();b.path=()=>window.location.hash.replace(/^#/,"")||"/";var J=(e,n,{enter:t,leave:o}={})=>{let s=N("div",{style:"display:contents"}),c=null,i=(r,l)=>{let a=!1,d=()=>!a&&(a=!0,l());if(!r)return d();"transitionend animationend".split(" ").map((f)=>r.addEventListener(f,d,{once:!0})),setTimeout(d,500)};return C(e,(r)=>{if(r&&!c){let l=(c=S(n)).container.firstChild;if(s.appendChild(c.container),t&&l)l.classList.add(t),l.clientTop,l.classList.add(t+"-active"),i(l,()=>l.classList.remove(t,t+"-active"))}else if(!r&&c){let l=c.container.firstChild,a=()=>(c?.destroy(),c=null);o&&l?(l.classList.add(o),i(l,a)):a()}}),g(()=>c?.destroy()),s},K=(e,n)=>{let t=typeof n==="string"?E.querySelector(n):n;if(!t)return;if(B.has(t))B.get(t).destroy();let o=S(m(e)?e:()=>e);return t.replaceChildren(o.container),B.set(t,o),o},ie=Object.freeze({$:L,$$:$,Watch:C,Tag:N,Render:S,If:F,For:G,Router:b,Mount:K,onMount:k,onUnmount:g,Anim:J,Batch:z});if(typeof window<"u")Object.assign(window,ie),"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((e)=>{let n=e[0].toUpperCase()+e.slice(1);window[n]=(t,o)=>N(e,t,o)});})(); +(()=>{var{defineProperty:L,getOwnPropertyNames:Q,getOwnPropertyDescriptor:F}=Object,H=Object.prototype.hasOwnProperty;function X(e){return this[e]}var Y=(e)=>{var n=(U??=new WeakMap).get(e),t;if(n)return n;if(n=L({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function"){for(var o of Q(e))if(!H.call(n,o))L(n,o,{get:X.bind(e,o),enumerable:!(t=F(e,o))||t.enumerable})}return U.set(e,n),n},U;var Z=(e)=>e;function ee(e,n){this[e]=Z.bind(null,n)}var te=(e,n)=>{for(var t in n)L(e,t,{get:n[t],enumerable:!0,configurable:!0,set:ee.bind(n,t)})};var ie={};te(ie,{when:()=>z,watch:()=>O,router:()=>b,mount:()=>J,h:()=>S,each:()=>G,batch:()=>q,$$:()=>$,$:()=>T});var y=(e)=>typeof e==="function",M=(e)=>e&&typeof e==="object",v=Array.isArray,E=typeof document<"u"?document:null,D=(e)=>e?._isRuntime?e.container:e instanceof Node?e:E.createTextNode(e==null?"":String(e)),u=null,_=null,x=!1,A=0,R=new Set,I=new WeakMap,j=Symbol("iter"),P=new WeakMap,g=(e)=>{if(!e||e._disposed)return;e._disposed=!0;let n=[e];while(n.length){let t=n.pop();if(t._cleanups)t._cleanups.forEach((o)=>o()),t._cleanups.clear();if(t._children)t._children.forEach((o)=>n.push(o)),t._children.clear();if(t._deps)t._deps.forEach((o)=>o.delete(t)),t._deps.clear()}},N=(e)=>{if(_)(_._cleanups||=new Set).add(e)},ne=(e)=>{let n=u;u=null;try{return e()}finally{u=n}},C=(e,n=!1)=>{let t=()=>{if(t._disposed)return;if(t._deps)t._deps.forEach((c)=>c.delete(t));if(t._cleanups)t._cleanups.forEach((c)=>c()),t._cleanups.clear();let o=u,s=_;u=_=t;try{return t._result=e()}catch(c){console.error("[SigPro]",c)}finally{u=o,_=s}};if(t._deps=t._cleanups=t._children=null,t._disposed=!1,t._isComputed=n,t._depth=u?u._depth+1:0,t._mounts=[],t._parent=_,_)(_._children||=new Set).add(t);return t},W=()=>{if(x)return;x=!0;let e=Array.from(R).sort((n,t)=>n._depth-t._depth);R.clear();for(let n of e)if(!n._disposed)n();x=!1},q=(e)=>{A++;try{return e()}finally{if(A--,A===0&&R.size>0&&!x)W()}},m=(e,n=!1)=>{if(!n&&u&&!u._disposed)e.add(u),(u._deps||=new Set).add(e);else if(n&&e.size>0){let t=!1;for(let o of e){if(o===u||o._disposed)continue;if(o._isComputed){if(o._dirty=!0,o._subs)m(o._subs,!0)}else R.add(o),t=!0}if(t&&!x&&A===0)queueMicrotask(W)}},T=(e,n=null)=>{let t=new Set;if(y(e)){let o,s=()=>{if(s._dirty){let c=u;u=s;try{let i=e();if(!Object.is(o,i))o=i,m(t,!0)}finally{u=c}s._dirty=!1}return m(t),o};if(s._isComputed=!0,s._subs=t,s._dirty=!0,s._deps=null,s._disposed=!1,s.stop=()=>{},_)N(s.stop);return s}if(n)try{e=JSON.parse(localStorage.getItem(n))??e}catch(o){}return(...o)=>{if(o.length){let s=y(o[0])?o[0](e):o[0];if(!Object.is(e,s)){if(e=s,n)localStorage.setItem(n,JSON.stringify(e));m(t,!0)}}return m(t),e}},$=(e)=>{if(!M(e))return e;let n=I.get(e);if(n)return n;let t=new Map,o=(s)=>{let c=t.get(s);if(!c)t.set(s,c=new Set);return c};return n=new Proxy(e,{get(s,c,i){if(typeof c!=="symbol")m(o(c));return $(Reflect.get(s,c,i))},set(s,c,i,r){let l=!Reflect.has(s,c),a=Reflect.get(s,c,r),f=Reflect.set(s,c,i,r);if(f&&!Object.is(a,i)){if(m(o(c),!0),l)m(o(j),!0)}return f},deleteProperty(s,c){let i=Reflect.deleteProperty(s,c);if(i)m(o(c),!0),m(o(j),!0);return i},ownKeys(s){return m(o(j)),Reflect.ownKeys(s)}}),I.set(e,n),n},O=(e,n)=>{if(n===void 0){let o=C(e);return o(),()=>g(o)}let t=C(()=>{let o=Array.isArray(e)?e.map((s)=>s()):e();ne(()=>n(o))});return t(),()=>g(t)},B=(e)=>{if(e._cleanups)e._cleanups.forEach((n)=>n()),e._cleanups.clear();if(e._ownerEffect)g(e._ownerEffect);if(e.childNodes)e.childNodes.forEach(B)},se=/^\s*(javascript|data|vbscript):/i,oe=(e)=>e==="src"||e==="href"||e.startsWith("on"),V=(e,n)=>{if(n==null||n===!1)return null;if(oe(e)){let t=String(n);if(se.test(t))return console.warn(`[SigPro] Bloqueado protocolo peligroso en ${e}`),"#"}return n},S=(e,n={},t=[])=>{if(n instanceof Node||v(n)||!M(n))t=n,n={};if(y(e)){let i=C(()=>{let f=e(n,{children:t,emit:(d,...h)=>n[`on${d[0].toUpperCase()}${d.slice(1)}`]?.(...h)});return i._result=f,f});i();let r=i._result;if(r==null)return null;let l=r instanceof Node||v(r)&&r.every((f)=>f instanceof Node)?r:E.createTextNode(String(r)),a=(f)=>{if(M(f)&&!f._isRuntime)f._mounts=i._mounts||[],f._cleanups=i._cleanups||new Set,f._ownerEffect=i};return v(l)?l.forEach(a):a(l),l}let o=/^(svg|path|circle|rect|line|poly(line|gon)|g|defs|text(path)?|tspan|use|symbol|image|marker|ellipse)$/i.test(e),s=o?E.createElementNS("http://www.w3.org/2000/svg",e):E.createElement(e);s._cleanups=new Set;for(let i in n){if(!n.hasOwnProperty(i))continue;let r=n[i];if(i==="ref"){y(r)?r(s):r.current=s;continue}if(o&&i.startsWith("xlink:")){r==null?s.removeAttributeNS("http://www.w3.org/1999/xlink",i.slice(6)):s.setAttributeNS("http://www.w3.org/1999/xlink",i.slice(6),r);continue}if(i.startsWith("on")){let l=i.slice(2).toLowerCase();s.addEventListener(l,r);let a=()=>s.removeEventListener(l,r);s._cleanups.add(a),N(a)}else if(y(r)){let l=C(()=>{let a=V(i,r());if(i==="class")s.className=a||"";else if(a==null)s.removeAttribute(i);else if(i in s&&!o)s[i]=a;else s.setAttribute(i,a===!0?"":a)});if(l(),s._cleanups.add(()=>g(l)),N(()=>g(l)),/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName)&&(i==="value"||i==="checked")){let a=i==="checked"?"change":"input";s.addEventListener(a,(f)=>r(f.target[i]))}}else{let l=V(i,r);if(l!=null)if(i in s&&!o)s[i]=l;else s.setAttribute(i,l===!0?"":l)}}let c=(i)=>{if(v(i))return i.forEach(c);if(y(i)){let r=E.createTextNode("");s.appendChild(r);let l=[],a=C(()=>{let f=i(),d=(v(f)?f:[f]).map(D);l.forEach((p)=>{if(p._isRuntime)p.destroy();else B(p);if(p.parentNode)p.remove()});let h=r;for(let p=d.length-1;p>=0;p--){let w=d[p];if(w.parentNode!==h.parentNode)h.parentNode?.insertBefore(w,h);if(w._mounts)w._mounts.forEach((K)=>K());h=w}l=d});a(),s._cleanups.add(()=>g(a)),N(()=>g(a))}else{let r=D(i);if(s.appendChild(r),r._mounts)r._mounts.forEach((l)=>l())}};return c(t),s},k=(e)=>{let n=new Set,t=[],o=_,s=u,c=E.createElement("div");c.style.display="contents",c.setAttribute("role","presentation"),_={_cleanups:n,_mounts:t},u=null;let i=(r)=>{if(!r)return;if(r._isRuntime)n.add(r.destroy),c.appendChild(r.container);else if(v(r))r.forEach(i);else c.appendChild(r instanceof Node?r:E.createTextNode(String(r==null?"":r)))};try{i(e({onCleanup:(r)=>n.add(r)}))}finally{_=o,u=s}return t.forEach((r)=>r()),{_isRuntime:!0,container:c,destroy:()=>{n.forEach((r)=>r()),B(c),c.remove()}}},z=(e,n,{enter:t,leave:o}={})=>{let s=S("div",{style:"display:contents"}),c=null,i=(r,l)=>{if(!r)return l();let a=!1,f=()=>!a&&(a=!0,l());r.addEventListener("transitionend",f,{once:!0}),r.addEventListener("animationend",f,{once:!0}),setTimeout(f,500)};return O(e,(r)=>{if(r&&!c){let l=(c=n(n)).container.firstChild;if(s.appendChild(c.container),t&&l)l.classList.add(t),l.clientTop,l.classList.add(t+"-active"),i(l,()=>l.classList.remove(t,t+"-active"))}else if(!r&&c){let l=c.container.firstChild,a=()=>(c.destroy(),c=null);if(o&&l)l.classList.add(o),i(l,a);else a()}}),N(()=>c?.destroy()),s},G=(e,n,t)=>{let o=E.createTextNode(""),s=S("div",{style:"display:contents"},[o]),c=new Map;return O(()=>(y(e)?e():e)||[],(i)=>{let r=new Map,l=[],a=i||[];for(let d=0;dn(h,d));else c.delete(p);r.set(p,w),l.push(w)}c.forEach((d)=>d.destroy());let f=o;for(let d=l.length-1;d>=0;d--){let p=l[d].container;if(p.nextSibling!==f)s.insertBefore(p,f);f=p}c=r}),s},b=(e)=>{let n=()=>window.location.hash.slice(1)||"/",t=T(n()),o=()=>t(n());window.addEventListener("hashchange",o),N(()=>window.removeEventListener("hashchange",o));let s=S("div",{class:"router-hook"}),c=null;return O([t],()=>{let i=t(),r=e.find((l)=>{let a=l.path.split("/").filter(Boolean),f=i.split("/").filter(Boolean);return a.length===f.length&&a.every((d,h)=>d[0]===":"||d===f[h])})||e.find((l)=>l.path==="*");if(r){c?.destroy();let l={};r.path.split("/").filter(Boolean).forEach((a,f)=>{if(a[0]===":")l[a.slice(1)]=i.split("/").filter(Boolean)[f]}),b.params(l),c=k(()=>y(r.component)?r.component(l):r.component),s.replaceChildren(c.container)}}),s};b.params=T({});b.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");b.back=()=>window.history.back();b.path=()=>window.location.hash.replace(/^#/,"")||"/";var J=(e,n)=>{let t=typeof n==="string"?E.querySelector(n):n;if(!t)return;if(P.has(t))P.get(t).destroy();let o=k(y(e)?e:()=>e);return t.replaceChildren(o.container),P.set(t,o),o},re=Object.freeze({$:T,$$:$,watch:O,h:S,when:z,each:G,router:b,mount:J,batch:q});if(typeof window<"u")Object.assign(window,re),"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((e)=>{window[e]=(n,t)=>S(e,n,t)});})(); diff --git a/docs/sigpro.js b/docs/sigpro.js index a37f90f..571e9fb 100644 --- a/docs/sigpro.js +++ b/docs/sigpro.js @@ -40,17 +40,13 @@ // index.js var exports_sigpro = {}; __export(exports_sigpro, { - onUnmount: () => onUnmount, - onMount: () => onMount, - Watch: () => Watch, - Tag: () => Tag, - Router: () => Router, - Render: () => Render, - Mount: () => Mount, - If: () => If, - For: () => For, - Batch: () => Batch, - Anim: () => Anim, + when: () => when, + watch: () => watch, + router: () => router, + mount: () => mount, + h: () => h, + each: () => each, + batch: () => batch, $$: () => $$, $: () => $ }); @@ -90,11 +86,7 @@ } } }; - var onMount = (fn) => { - if (activeOwner) - (activeOwner._mounts ||= []).push(fn); - }; - var onUnmount = (fn) => { + var _onUnmount = (fn) => { if (activeOwner) (activeOwner._cleanups ||= new Set).add(fn); }; @@ -150,7 +142,7 @@ e(); isFlushing = false; }; - var Batch = (fn) => { + var batch = (fn) => { batchDepth++; try { return fn(); @@ -183,16 +175,16 @@ queueMicrotask(flush); } }; - var $ = (val2, key = null) => { + var $ = (val, key = null) => { const subs = new Set; - if (isFunc(val2)) { + if (isFunc(val)) { let cache; const computed = () => { if (computed._dirty) { const prev = activeEffect; activeEffect = computed; try { - const next = val2(); + const next = val(); if (!Object.is(cache, next)) { cache = next; trackUpdate(subs, true); @@ -212,25 +204,25 @@ computed._disposed = false; computed.stop = () => {}; if (activeOwner) - onUnmount(computed.stop); + _onUnmount(computed.stop); return computed; } if (key) try { - val2 = JSON.parse(localStorage.getItem(key)) ?? val2; + val = JSON.parse(localStorage.getItem(key)) ?? val; } catch (e) {} return (...args) => { if (args.length) { - const next = isFunc(args[0]) ? args[0](val2) : args[0]; - if (!Object.is(val2, next)) { - val2 = next; + const next = isFunc(args[0]) ? args[0](val) : args[0]; + if (!Object.is(val, next)) { + val = next; if (key) - localStorage.setItem(key, JSON.stringify(val2)); + localStorage.setItem(key, JSON.stringify(val)); trackUpdate(subs, true); } } trackUpdate(subs); - return val2; + return val; }; }; var $$ = (target) => { @@ -279,7 +271,7 @@ proxyCache.set(target, proxy); return proxy; }; - var Watch = (sources, cb) => { + var watch = (sources, cb) => { if (cb === undefined) { const effect2 = createEffect(sources); effect2(); @@ -304,25 +296,24 @@ }; var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i; var isDangerousAttr = (key) => key === "src" || key === "href" || key.startsWith("on"); - var validateAttr = (key, val2) => { - if (val2 == null || val2 === false) + var validateAttr = (key, val) => { + if (val == null || val === false) return null; if (isDangerousAttr(key)) { - const sVal = String(val2); + const sVal = String(val); if (DANGEROUS_PROTOCOL.test(sVal)) { console.warn(`[SigPro] Bloqueado protocolo peligroso en ${key}`); return "#"; } } - return val2; + return val; }; - var Tag = (tag, props = {}, children = []) => { + var h = (tag, props = {}, children = []) => { if (props instanceof Node || isArr(props) || !isObj(props)) { children = props; props = {}; } if (isFunc(tag)) { - const ctx = { _mounts: [], _cleanups: new Set }; const effect = createEffect(() => { const result2 = tag(props, { children, @@ -359,7 +350,7 @@ } if (isSVG && k.startsWith("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; } if (k.startsWith("on")) { @@ -367,33 +358,33 @@ el.addEventListener(ev, v); const off = () => el.removeEventListener(ev, v); el._cleanups.add(off); - onUnmount(off); + _onUnmount(off); } else if (isFunc(v)) { const effect = createEffect(() => { - const val2 = validateAttr(k, v()); + const val = validateAttr(k, v()); if (k === "class") - el.className = val2 || ""; - else if (val2 == null) + el.className = val || ""; + else if (val == null) el.removeAttribute(k); else if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) { const evType = k === "checked" ? "change" : "input"; el.addEventListener(evType, (ev) => v(ev.target[k])); } } else { - const val2 = validateAttr(k, v); - if (val2 != null) { + const val = validateAttr(k, v); + if (val != null) { if (k in el && !isSVG) - el[k] = val2; + el[k] = val; else - el.setAttribute(k, val2 === true ? "" : val2); + el.setAttribute(k, val === true ? "" : val); } } } @@ -428,7 +419,7 @@ }); effect(); el._cleanups.add(() => dispose(effect)); - onUnmount(() => dispose(effect)); + _onUnmount(() => dispose(effect)); } else { const node = ensureNode(c); el.appendChild(node); @@ -439,7 +430,7 @@ append(children); return el; }; - var Render = (renderFn) => { + var render = (renderFn) => { const cleanups = new Set; const mounts = []; const previousOwner = activeOwner; @@ -478,29 +469,46 @@ } }; }; - var If = (cond, ifYes, ifNot = null) => { - const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); - let currentView = null; - Watch(() => !!(isFunc(cond) ? cond() : cond), (show) => { - if (currentView) { - currentView.destroy(); - currentView = null; - } - const content = show ? ifYes : ifNot; - if (content) { - currentView = Render(() => isFunc(content) ? content() : content); - root.insertBefore(currentView.container, anchor); + var when = (cond, render2, { enter, leave } = {}) => { + const wrap = h("div", { style: "display:contents" }); + let view = null; + const wait = (el, cb) => { + if (!el) + return cb(); + let done = false; + 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(); + } } }); - onUnmount(() => currentView?.destroy()); - return root; + return _onUnmount(() => view?.destroy()), wrap; }; - var For = (src, itemFn, keyFn) => { + var each = (src, itemFn, keyFn) => { const anchor = doc.createTextNode(""); - const root = Tag("div", { style: "display:contents" }, [anchor]); + const root = h("div", { style: "display:contents" }, [anchor]); let cache = new Map; - Watch(() => (isFunc(src) ? src() : src) || [], (items) => { + watch(() => (isFunc(src) ? src() : src) || [], (items) => { const nextCache = new Map; const nextOrder = []; const newItems = items || []; @@ -509,7 +517,7 @@ const key = keyFn ? keyFn(item, i) : item?.id ?? i; let view = cache.get(key); if (!view) - view = Render(() => itemFn(item, i)); + view = render(() => itemFn(item, i)); else cache.delete(key); nextCache.set(key, view); @@ -528,15 +536,15 @@ }); return root; }; - var Router = (routes) => { + var router = (routes) => { const getHash = () => window.location.hash.slice(1) || "/"; const path = $(getHash()); const handler = () => path(getHash()); window.addEventListener("hashchange", handler); - onUnmount(() => window.removeEventListener("hashchange", handler)); - const hook = Tag("div", { class: "router-hook" }); + _onUnmount(() => window.removeEventListener("hashchange", handler)); + const hook = h("div", { class: "router-hook" }); let currentView = null; - Watch([path], () => { + watch([path], () => { const cur = path(); const route = routes.find((r) => { const p1 = r.path.split("/").filter(Boolean); @@ -550,77 +558,33 @@ if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i]; }); - Router.params(params); - currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component); + router.params(params); + currentView = render(() => isFunc(route.component) ? route.component(params) : route.component); hook.replaceChildren(currentView.container); } }); return hook; }; - Router.params = $({}); - Router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); - Router.back = () => window.history.back(); - Router.path = () => window.location.hash.replace(/^#/, "") || "/"; - var Anim = (show, render, { enter, leave } = {}) => { - 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) => { + router.params = $({}); + router.to = (p) => window.location.hash = p.replace(/^#?\/?/, "#/"); + router.back = () => window.history.back(); + router.path = () => window.location.hash.replace(/^#/, "") || "/"; + var mount = (comp, target) => { const t = typeof target === "string" ? doc.querySelector(target) : target; if (!t) return; if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy(); - const inst = Render(isFunc(comp) ? comp : () => comp); + const inst = render(isFunc(comp) ? comp : () => comp); t.replaceChildren(inst.container); MOUNTED_NODES.set(t, inst); return inst; }; - var SigPro = Object.freeze({ - $, - $$, - Watch, - Tag, - Render, - If, - For, - Router, - Mount, - onMount, - onUnmount, - Anim, - Batch - }); + var SigPro = Object.freeze({ $, $$, watch, h, when, each, router, mount, batch }); if (typeof window !== "undefined") { 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) => { - const name = t[0].toUpperCase() + t.slice(1); - window[name] = (p, c) => Tag(t, p, c); + "a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video".split(" ").forEach((tag) => { + window[tag] = (props, children) => h(tag, props, children); }); } })(); diff --git a/package.json b/package.json index ddc9dfb..21249e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sigpro", - "version": "1.2.13", + "version": "1.2.14", "type": "module", "license": "MIT", "main": "./dist/sigpro.esm.min.js", diff --git a/sigpro.js b/sigpro.js index 49fae26..ab53e35 100644 --- a/sigpro.js +++ b/sigpro.js @@ -1,4 +1,4 @@ -// sigpro 1.2.13 +// sigpro 1.2.14 const isFunc = f => typeof f === "function" const isObj = o => o && typeof o === "object" const isArr = Array.isArray @@ -35,11 +35,7 @@ const dispose = eff => { } } -const onMount = fn => { - if (activeOwner) (activeOwner._mounts ||= []).push(fn) -} - -const onUnmount = fn => { +const _onUnmount = fn => { if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn) } @@ -88,7 +84,7 @@ const flush = () => { isFlushing = false } -const Batch = fn => { +const batch = fn => { batchDepth++ try { return fn() @@ -148,7 +144,7 @@ const $ = (val, key = null) => { computed._deps = null computed._disposed = false computed.stop = () => { } - if (activeOwner) onUnmount(computed.stop) + if (activeOwner) _onUnmount(computed.stop) return computed } if (key) try { val = JSON.parse(localStorage.getItem(key)) ?? val } catch (e) { } @@ -213,7 +209,7 @@ const $$ = (target) => { return proxy } -const Watch = (sources, cb) => { +const watch = (sources, cb) => { if (cb === undefined) { const effect = createEffect(sources) effect() @@ -251,13 +247,12 @@ const validateAttr = (key, val) => { return val } -const Tag = (tag, props = {}, children = []) => { +const h = (tag, props = {}, children = []) => { if (props instanceof Node || isArr(props) || !isObj(props)) { children = props props = {} } if (isFunc(tag)) { - const ctx = { _mounts: [], _cleanups: new Set() } const effect = createEffect(() => { const result = tag(props, { children, @@ -299,7 +294,7 @@ const Tag = (tag, props = {}, children = []) => { } if (isSVG && k.startsWith("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 } if (k.startsWith("on")) { @@ -307,7 +302,7 @@ const Tag = (tag, props = {}, children = []) => { el.addEventListener(ev, v) const off = () => el.removeEventListener(ev, v) el._cleanups.add(off) - onUnmount(off) + _onUnmount(off) } else if (isFunc(v)) { const effect = createEffect(() => { const val = validateAttr(k, v()) @@ -318,7 +313,7 @@ const Tag = (tag, props = {}, children = []) => { }) effect() el._cleanups.add(() => dispose(effect)) - onUnmount(() => dispose(effect)) + _onUnmount(() => dispose(effect)) if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) { const evType = k === "checked" ? "change" : "input" el.addEventListener(evType, ev => v(ev.target[k])) @@ -357,7 +352,7 @@ const Tag = (tag, props = {}, children = []) => { }) effect() el._cleanups.add(() => dispose(effect)) - onUnmount(() => dispose(effect)) + _onUnmount(() => dispose(effect)) } else { const node = ensureNode(c) el.appendChild(node) @@ -368,7 +363,7 @@ const Tag = (tag, props = {}, children = []) => { return el } -const Render = renderFn => { +const render = renderFn => { const cleanups = new Set() const mounts = [] const previousOwner = activeOwner @@ -410,36 +405,48 @@ const Render = renderFn => { } } -const If = (cond, ifYes, ifNot = null) => { - const anchor = doc.createTextNode("") - const root = Tag("div", { style: "display:contents" }, [anchor]) - let currentView = null +const when = (cond, render, { enter, leave } = {}) => { + const wrap = h('div', { style: 'display:contents' }) + let view = null - Watch( - () => !!(isFunc(cond) ? cond() : cond), - show => { - if (currentView) { - currentView.destroy() - currentView = null + const wait = (el, cb) => { + if (!el) return cb() + let done = false + 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 = 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')) } - - const content = show ? ifYes : ifNot - if (content) { - currentView = Render(() => isFunc(content) ? content() : content) - root.insertBefore(currentView.container, anchor) + } 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 root + return _onUnmount(() => view?.destroy()), wrap } -const For = (src, itemFn, keyFn) => { +const each = (src, itemFn, keyFn) => { const anchor = doc.createTextNode("") - const root = Tag("div", { style: "display:contents" }, [anchor]) + const root = h("div", { style: "display:contents" }, [anchor]) let cache = new Map() - Watch(() => (isFunc(src) ? src() : src) || [], items => { + watch(() => (isFunc(src) ? src() : src) || [], items => { const nextCache = new Map() const nextOrder = [] const newItems = items || [] @@ -447,7 +454,7 @@ const For = (src, itemFn, keyFn) => { const item = newItems[i] const key = keyFn ? keyFn(item, i) : (item?.id ?? i) let view = cache.get(key) - if (!view) view = Render(() => itemFn(item, i)) + if (!view) view = render(() => itemFn(item, i)) else cache.delete(key) nextCache.set(key, view) nextOrder.push(view) @@ -465,15 +472,15 @@ const For = (src, itemFn, keyFn) => { return root } -const Router = routes => { +const router = routes => { const getHash = () => window.location.hash.slice(1) || "/" const path = $(getHash()) const handler = () => path(getHash()) window.addEventListener("hashchange", handler) - onUnmount(() => window.removeEventListener("hashchange", handler)) - const hook = Tag("div", { class: "router-hook" }) + _onUnmount(() => window.removeEventListener("hashchange", handler)) + const hook = h("div", { class: "router-hook" }) let currentView = null - Watch([path], () => { + watch([path], () => { const cur = path() const route = routes.find(r => { const p1 = r.path.split("/").filter(Boolean) @@ -486,68 +493,36 @@ const Router = routes => { route.path.split("/").filter(Boolean).forEach((p, i) => { if (p[0] === ":") params[p.slice(1)] = cur.split("/").filter(Boolean)[i] }) - Router.params(params) - currentView = Render(() => isFunc(route.component) ? route.component(params) : route.component) + router.params(params) + currentView = render(() => isFunc(route.component) ? route.component(params) : route.component) hook.replaceChildren(currentView.container) } }) return hook } -Router.params = $({}) -Router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/") -Router.back = () => window.history.back() -Router.path = () => window.location.hash.replace(/^#/, "") || "/" +router.params = $({}) +router.to = p => window.location.hash = p.replace(/^#?\/?/, "#/") +router.back = () => window.history.back() +router.path = () => window.location.hash.replace(/^#/, "") || "/" -const Anim = (show, render, { enter, leave } = {}) => { - 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 mount = (comp, target) => { const t = typeof target === "string" ? doc.querySelector(target) : target if (!t) return if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy() - const inst = Render(isFunc(comp) ? comp : () => comp) + const inst = render(isFunc(comp) ? comp : () => comp) t.replaceChildren(inst.container) MOUNTED_NODES.set(t, 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") { 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" - .split(" ").forEach(t => { - const name = t[0].toUpperCase() + t.slice(1) - window[name] = (p, c) => Tag(t, p, c) + "a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video" + .split(" ").forEach(tag => { + window[tag] = (props, children) => h(tag, props, children) }) } -export { $, $$, Watch, Tag, If, For, Router, Mount, onMount, onUnmount, Anim, Batch } \ No newline at end of file +export { $, $$, watch, h, when, each, router, mount, batch } \ No newline at end of file