From bf3069d439a5aa94e94eeb2b467a07026a5e6f7d Mon Sep 17 00:00:00 2001 From: natxocc Date: Mon, 6 Apr 2026 18:28:07 +0200 Subject: [PATCH] Update Funcions --- Readme.md | 4 +- dist/sigpro.esm.js | 18 +- dist/sigpro.esm.min.js | 2 +- dist/sigpro.js | 18 +- dist/sigpro.min.js | 2 +- docs/_sidebar.md | 14 +- docs/api/for.md | 18 +- docs/api/html.md | 20 +- docs/api/if.md | 30 +-- docs/api/jsx.md | 24 +-- docs/api/mount.md | 30 +-- docs/api/quick.md | 43 ++-- docs/api/router.md | 26 +-- docs/api/signal.md | 16 +- docs/api/tags.md | 30 +-- docs/api/watch.md | 20 +- docs/examples.md | 32 +-- docs/index.html | 6 +- docs/install.md | 8 +- docs/sigpro.js | 472 +++++++++++++++++++++++++++++++++++++++++ docs/ui/quick.md | 4 +- docs/vite/plugin.md | 12 +- package.json | 3 +- sigpro.d.ts | 234 +++++++++++--------- 24 files changed, 793 insertions(+), 293 deletions(-) create mode 100644 docs/sigpro.js diff --git a/Readme.md b/Readme.md index f4a6469..277c852 100644 --- a/Readme.md +++ b/Readme.md @@ -81,7 +81,7 @@ const Counter = () => { ]); }; -$mount(Counter, "#app"); +Mount(Counter, "#app"); ``` ----- @@ -96,7 +96,7 @@ $mount(Counter, "#app"); | **Native Persistence** | **Included ($)** | Requires Plugins | Manual | | **Dependencies** | **Zero** | Many | Build Toolchain | | **Lifecycle Mgmt** | **Automatic (Cleanup Root)** | Manual / Hook-based | Manual / Hook-based | -| **Routing** | **Reactive Hash ($router) + File-based (Vite)** | Virtual Router (External) | File-based / External | +| **Routing** | **Reactive Hash (Router) + File-based (Vite)** | Virtual Router (External) | File-based / External | | **Learning Curve** | **Zero (Vanilla JS)** | Steep (JSX/Templates) | Medium (Directives) | ----- diff --git a/dist/sigpro.esm.js b/dist/sigpro.esm.js index 398b155..bb5f67a 100644 --- a/dist/sigpro.esm.js +++ b/dist/sigpro.esm.js @@ -337,15 +337,19 @@ var For = (source, renderFn, keyFn, tag = "div", props = { style: "display:conte for (let i = 0;i < items.length; i++) { const item = items[i]; const key = keyFn ? keyFn(item, i) : i; - let view = viewCache.get(key) || Render(() => renderFn(item, i)); + let view = viewCache.get(key); + if (!view) { + const result = renderFn(item, i); + view = result instanceof Node ? { container: result, destroy: () => { + cleanupNode(result); + result.remove(); + } } : Render(() => result); + } viewCache.delete(key); nextCache.set(key, view); order.push(key); } - viewCache.forEach((view) => { - view.destroy(); - view.container.remove(); - }); + viewCache.forEach((v) => v.destroy()); let anchor = marker; for (let i = order.length - 1;i >= 0; i--) { const view = nextCache.get(order[i]); @@ -411,8 +415,7 @@ var Mount = (component, target) => { MOUNTED_NODES.set(targetEl, instance); return instance; }; -var Fragment = ({ children }) => children; -var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount, Fragment }; +var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount }; if (typeof window !== "undefined") { 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(" "); @@ -430,7 +433,6 @@ export { Render, Mount, If, - Fragment, For, $$, $ diff --git a/dist/sigpro.esm.min.js b/dist/sigpro.esm.min.js index bc14d3e..4cc9925 100644 --- a/dist/sigpro.esm.min.js +++ b/dist/sigpro.esm.min.js @@ -1 +1 @@ -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 $}; +var w=null,m=null,b=new Set,C=!1,R=new WeakMap,O=document,S=Array.isArray,M=Object.assign,j=(t)=>O.createElement(t),v=(t)=>O.createTextNode(String(t??"")),h=(t)=>typeof t==="function",P=(t)=>typeof t==="object"&&t!==null,T=(t,s)=>{let c=w;w=t;try{return s()}finally{w=c}},A=(t)=>{if(t._cleanups)t._cleanups.forEach((s)=>s()),t._cleanups.clear();t.childNodes?.forEach(A)},U=()=>{if(C)return;C=!0;while(b.size>0){let t=Array.from(b).sort((s,c)=>(s.depth||0)-(c.depth||0));b.clear();for(let s of t)if(!s._deleted)s()}C=!1},B=(t)=>{if(w&&!w._deleted)t.add(w),w._deps.add(t)},k=(t)=>{if(t.forEach((s)=>{if(s===w||s._deleted)return;if(s._isComputed){if(s.markDirty(),s._subs)k(s._subs)}else b.add(s)}),!C)queueMicrotask(U)},N=(t)=>{let s=new Set,c=m,i=j("div");i.style.display="contents",m={cleanups:s};let n=(e)=>{if(!e)return;if(e._isRuntime)s.add(e.destroy),i.appendChild(e.container);else if(S(e))e.forEach(n);else i.appendChild(e instanceof Node?e:v(e))};try{n(t({onCleanup:(e)=>s.add(e)}))}finally{m=c}return{_isRuntime:!0,container:i,destroy:()=>{s.forEach((e)=>e()),A(i),i.remove()}}},W=(t,s=null)=>{let c=new Set;if(h(t)){let n,e=!0,r=()=>{if(r._deleted)return;r._deps.forEach((a)=>a.delete(r)),r._deps.clear(),T(r,()=>{let a=t();if(!Object.is(n,a)||e)n=a,e=!1,k(c)})};if(M(r,{_deps:new Set,_isComputed:!0,_subs:c,_deleted:!1,markDirty:()=>e=!0,stop:()=>{r._deleted=!0,r._deps.forEach((a)=>a.delete(r)),c.clear()}}),m)m.cleanups.add(r.stop);return()=>{if(e)r();return B(c),n}}let i=t;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 e=h(n[0])?n[0](i):n[0];if(!Object.is(i,e)){if(i=e,s)localStorage.setItem(s,JSON.stringify(i));k(c)}}return B(c),i}},D=(t,s=new WeakMap)=>{if(!P(t))return t;if(s.has(t))return s.get(t);let c={},i=new Proxy(t,{get(n,e){if(w)B(c[e]??=new Set);let r=Reflect.get(n,e);return P(r)?D(r,s):r},set(n,e,r){if(Object.is(n[e],r))return!0;let a=Reflect.set(n,e,r);if(c[e])k(c[e]);return a}});return s.set(t,i),i},E=(t,s)=>{let c=S(t),i=c?s:t;if(!h(i))return()=>{};let n=m,e=()=>{if(e._deleted)return;e._deps.forEach((a)=>a.delete(e)),e._deps.clear(),e._cleanups.forEach((a)=>a()),e._cleanups.clear();let r=m;e.depth=w?w.depth+1:0,T(e,()=>{if(m={cleanups:e._cleanups},c)T(null,i),t.forEach((a)=>h(a)&&a());else i();m=r})};if(M(e,{_deps:new Set,_cleanups:new Set,_deleted:!1,stop:()=>{if(e._deleted)return;if(e._deleted=!0,b.delete(e),e._deps.forEach((r)=>r.delete(e)),e._cleanups.forEach((r)=>r()),n)n.cleanups.delete(e.stop)}}),n)n.cleanups.add(e.stop);return e(),e.stop},y=(t,s={},c=[])=>{if(s instanceof Node||S(s)||!P(s))c=s,s={};let n=/^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(t)?O.createElementNS("http://www.w3.org/2000/svg",t):j(t);n._cleanups=new Set,n.onUnmount=(o)=>n._cleanups.add(o);let e=["disabled","checked","required","readonly","selected","multiple","autofocus"],r=(o,l)=>{let d=(o==="src"||o==="href")&&String(l).toLowerCase().includes("javascript:")?"#":l;if(e.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(E(()=>{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",f=(u)=>l(u.target[o]);n.addEventListener(p,f),n._cleanups.add(()=>n.removeEventListener(p,f))}}else r(o,l)}let a=(o)=>{if(S(o))return o.forEach(a);if(h(o)){let l=v("");n.appendChild(l);let d=[];n._cleanups.add(E(()=>{let p=o(),f=(S(p)?p:[p]).map((u)=>u?._isRuntime?u.container:u instanceof Node?u:v(u));d.forEach((u)=>{A(u),u.remove()}),f.forEach((u)=>l.parentNode?.insertBefore(u,l)),d=f}))}else n.appendChild(o instanceof Node?o:v(o))};return a(c),n},q=(t,s,c=null,i=null)=>{let n=v(""),e=y("div",{style:"display:contents"},[n]),r=null,a=null;return E(()=>{let o=!!(h(t)?t():t);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=N(()=>h(d)?d():d),e.insertBefore(r.container,n),o&&i?.in)i.in(r.container)}}),e},I=(t,s,c,i="div",n={style:"display:contents"})=>{let e=v(""),r=y(i,n,[e]),a=new Map;return E(()=>{let o=(h(t)?t():t)||[],l=new Map,d=[];for(let f=0;f{A(g),g.remove()}}:N(()=>g)}a.delete(x),l.set(x,L),d.push(x)}a.forEach((f)=>f.destroy());let p=e;for(let f=d.length-1;f>=0;f--){let u=l.get(d[f]);if(u.container.nextSibling!==p)r.insertBefore(u.container,p);p=u.container}a=l}),r},_=(t)=>{let s=W(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>s(window.location.hash.replace(/^#/,"")||"/"));let c=y("div",{class:"router-outlet"}),i=null;return E([s],async()=>{let n=s(),e=t.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])})||t.find((r)=>r.path==="*");if(e){let r=e.component;if(h(r)&&r.toString().includes("import"))r=(await r()).default||await r();let a={};if(e.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=N(()=>{try{return h(r)?r(a):r}catch(o){return y("div",{class:"p-4 text-error"},"Error loading view")}}),c.appendChild(i.container)}}),c};_.params=W({});_.to=(t)=>window.location.hash=t.replace(/^#?\/?/,"#/");_.back=()=>window.history.back();_.path=()=>window.location.hash.replace(/^#/,"")||"/";var $=(t,s)=>{let c=typeof s==="string"?O.querySelector(s):s;if(!c)return;if(R.has(c))R.get(c).destroy();let i=N(h(t)?t:()=>t);return c.replaceChildren(i.container),R.set(c,i),i},V={$:W,$$:D,Render:N,Watch:E,Tag:y,If:q,For:I,Router:_,Mount:$};if(typeof window<"u")M(window,V),"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)=>y(s,i,n)}),window.SigPro=Object.freeze(V);export{E as Watch,y as Tag,_ as Router,N as Render,$ as Mount,q as If,I as For,D as $$,W as $}; diff --git a/dist/sigpro.js b/dist/sigpro.js index 447976b..70f8da7 100644 --- a/dist/sigpro.js +++ b/dist/sigpro.js @@ -36,7 +36,6 @@ Render: () => Render, Mount: () => Mount, If: () => If, - Fragment: () => Fragment, For: () => For, $$: () => $$, $: () => $ @@ -381,15 +380,19 @@ for (let i = 0;i < items.length; i++) { const item = items[i]; const key = keyFn ? keyFn(item, i) : i; - let view = viewCache.get(key) || Render(() => renderFn(item, i)); + let view = viewCache.get(key); + if (!view) { + const result = renderFn(item, i); + view = result instanceof Node ? { container: result, destroy: () => { + cleanupNode(result); + result.remove(); + } } : Render(() => result); + } viewCache.delete(key); nextCache.set(key, view); order.push(key); } - viewCache.forEach((view) => { - view.destroy(); - view.container.remove(); - }); + viewCache.forEach((v) => v.destroy()); let anchor = marker; for (let i = order.length - 1;i >= 0; i--) { const view = nextCache.get(order[i]); @@ -455,8 +458,7 @@ MOUNTED_NODES.set(targetEl, instance); return instance; }; - var Fragment = ({ children }) => children; - var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount, Fragment }; + var SigPro = { $, $$, Render, Watch, Tag, If, For, Router, Mount }; if (typeof window !== "undefined") { 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(" "); diff --git a/dist/sigpro.min.js b/dist/sigpro.min.js index 7692ef0..fdee9a4 100644 --- a/dist/sigpro.min.js +++ b/dist/sigpro.min.js @@ -1 +1 @@ -(()=>{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);})(); +(()=>{var{defineProperty:P,getOwnPropertyNames:F,getOwnPropertyDescriptor:G}=Object,J=Object.prototype.hasOwnProperty;var D=new WeakMap,Q=(e)=>{var t=D.get(e),o;if(t)return t;if(t=P({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")F(e).map((c)=>!J.call(t,c)&&P(t,c,{get:()=>e[c],enumerable:!(o=G(e,c))||o.enumerable}));return D.set(e,t),t};var X=(e,t)=>{for(var o in t)P(e,o,{get:t[o],enumerable:!0,configurable:!0,set:(c)=>t[o]=()=>c})};var Y={};X(Y,{Watch:()=>v,Tag:()=>E,Router:()=>_,Render:()=>g,Mount:()=>z,If:()=>I,For:()=>$,$$:()=>j,$:()=>L});var w=null,m=null,S=new Set,C=!1,T=new WeakMap,O=document,N=Array.isArray,V=Object.assign,q=(e)=>O.createElement(e),y=(e)=>O.createTextNode(String(e??"")),h=(e)=>typeof e==="function",B=(e)=>typeof e==="object"&&e!==null,M=(e,t)=>{let o=w;w=e;try{return t()}finally{w=o}},A=(e)=>{if(e._cleanups)e._cleanups.forEach((t)=>t()),e._cleanups.clear();e.childNodes?.forEach(A)},H=()=>{if(C)return;C=!0;while(S.size>0){let e=Array.from(S).sort((t,o)=>(t.depth||0)-(o.depth||0));S.clear();for(let t of e)if(!t._deleted)t()}C=!1},W=(e)=>{if(w&&!w._deleted)e.add(w),w._deps.add(e)},k=(e)=>{if(e.forEach((t)=>{if(t===w||t._deleted)return;if(t._isComputed){if(t.markDirty(),t._subs)k(t._subs)}else S.add(t)}),!C)queueMicrotask(H)},g=(e)=>{let t=new Set,o=m,c=q("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(N(n))n.forEach(s);else c.appendChild(n instanceof Node?n:y(n))};try{s(e({onCleanup:(n)=>t.add(n)}))}finally{m=o}return{_isRuntime:!0,container:c,destroy:()=>{t.forEach((n)=>n()),A(c),c.remove()}}},L=(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(),M(r,()=>{let a=e();if(!Object.is(s,a)||n)s=a,n=!1,k(o)})};if(V(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 W(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));k(o)}}return W(o),c}},j=(e,t=new WeakMap)=>{if(!B(e))return e;if(t.has(e))return t.get(e);let o={},c=new Proxy(e,{get(s,n){if(w)W(o[n]??=new Set);let r=Reflect.get(s,n);return B(r)?j(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])k(o[n]);return a}});return t.set(e,c),c},v=(e,t)=>{let o=N(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,M(n,()=>{if(m={cleanups:n._cleanups},o)M(null,c),e.forEach((a)=>h(a)&&a());else c();m=r})};if(V(n,{_deps:new Set,_cleanups:new Set,_deleted:!1,stop:()=>{if(n._deleted)return;if(n._deleted=!0,S.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},E=(e,t={},o=[])=>{if(t instanceof Node||N(t)||!B(t))o=t,t={};let s=/^(svg|path|circle|rect|line|polyline|polygon|g|defs|text|tspan|use)$/.test(e)?O.createElementNS("http://www.w3.org/2000/svg",e):q(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(v(()=>{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",f=(u)=>l(u.target[i]);s.addEventListener(p,f),s._cleanups.add(()=>s.removeEventListener(p,f))}}else r(i,l)}let a=(i)=>{if(N(i))return i.forEach(a);if(h(i)){let l=y("");s.appendChild(l);let d=[];s._cleanups.add(v(()=>{let p=i(),f=(N(p)?p:[p]).map((u)=>u?._isRuntime?u.container:u instanceof Node?u:y(u));d.forEach((u)=>{A(u),u.remove()}),f.forEach((u)=>l.parentNode?.insertBefore(u,l)),d=f}))}else s.appendChild(i instanceof Node?i:y(i))};return a(o),s},I=(e,t,o=null,c=null)=>{let s=y(""),n=E("div",{style:"display:contents"},[s]),r=null,a=null;return v(()=>{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=g(()=>h(d)?d():d),n.insertBefore(r.container,s),i&&c?.in)c.in(r.container)}}),n},$=(e,t,o,c="div",s={style:"display:contents"})=>{let n=y(""),r=E(c,s,[n]),a=new Map;return v(()=>{let i=(h(e)?e():e)||[],l=new Map,d=[];for(let f=0;f{A(b),b.remove()}}:g(()=>b)}a.delete(x),l.set(x,R),d.push(x)}a.forEach((f)=>f.destroy());let p=n;for(let f=d.length-1;f>=0;f--){let u=l.get(d[f]);if(u.container.nextSibling!==p)r.insertBefore(u.container,p);p=u.container}a=l}),r},_=(e)=>{let t=L(window.location.hash.replace(/^#/,"")||"/");window.addEventListener("hashchange",()=>t(window.location.hash.replace(/^#/,"")||"/"));let o=E("div",{class:"router-outlet"}),c=null;return v([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=g(()=>{try{return h(r)?r(a):r}catch(i){return E("div",{class:"p-4 text-error"},"Error loading view")}}),o.appendChild(c.container)}}),o};_.params=L({});_.to=(e)=>window.location.hash=e.replace(/^#?\/?/,"#/");_.back=()=>window.history.back();_.path=()=>window.location.hash.replace(/^#/,"")||"/";var z=(e,t)=>{let o=typeof t==="string"?O.querySelector(t):t;if(!o)return;if(T.has(o))T.get(o).destroy();let c=g(h(e)?e:()=>e);return o.replaceChildren(c.container),T.set(o,c),c},U={$:L,$$:j,Render:g,Watch:v,Tag:E,If:I,For:$,Router:_,Mount:z};if(typeof window<"u")V(window,U),"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)=>E(t,c,s)}),window.SigPro=Object.freeze(U);})(); diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 8c9b3b9..7bfee7e 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -7,13 +7,13 @@ * **API Reference** * [Quick Start](api/quick.md) - * [$ signals](api/signal.md) - * [$watch](api/watch.md) - * [$if](api/if.md) - * [$for](api/for.md) - * [$router](api/router.md) - * [$mount](api/mount.md) - * [$html](api/html.md) + * [Signals & Proxies](api/signal.md) + * [Watch](api/watch.md) + * [If](api/if.md) + * [For](api/for.md) + * [Router](api/router.md) + * [Mount](api/mount.md) + * [Tag](api/html.md) * [Tags](api/tags.md) * [Global Store](api/global.md) * [JSX Style](api/jsx.md) diff --git a/docs/api/for.md b/docs/api/for.md index 6661b22..069f43e 100644 --- a/docs/api/for.md +++ b/docs/api/for.md @@ -1,11 +1,11 @@ -# Reactive Lists: `$for( )` +# Reactive Lists: `For( )` -The `$for` function is a high-performance list renderer. It maps an array (or a Signal containing an array) to DOM nodes. Unlike a simple `.map()`, `$for` is **keyed**, meaning it only updates, moves, or deletes the specific items that changed. +The `For` function is a high-performance list renderer. It maps an array (or a Signal containing an array) to DOM nodes. Unlike a simple `.map()`, `For` is **keyed**, meaning it only updates, moves, or deletes the specific items that changed. ## Function Signature ```typescript -$for( +For( source: Signal | Function | any[], render: (item: any, index: number) => HTMLElement, keyFn?: (item: any, index: number) => string | number @@ -34,7 +34,7 @@ const users = $([ ]); Ul({ class: "list" }, [ - $for(users, + For(users, (user) => Li({ class: "p-2" }, user.name), (user) => user.id // Stable and unique key ) @@ -42,14 +42,14 @@ Ul({ class: "list" }, [ ``` ### 2. Simplified Usage (Automatic Key) -If you omit the third parameter, `$for` will automatically use the array index as the key. This is ideal for simple lists that don't change order frequently. +If you omit the third parameter, `For` will automatically use the array index as the key. This is ideal for simple lists that don't change order frequently. ```javascript const tags = $(["Tech", "JS", "Web"]); // No need to pass keyFn if the index is sufficient Div({ class: "flex gap-1" }, [ - $for(tags, (tag) => Badge(tag)) + For(tags, (tag) => Badge(tag)) ]); ``` @@ -57,7 +57,7 @@ Div({ class: "flex gap-1" }, [ ## How it Works (The Reconciliation) -When the `source` signal changes, `$for` performs the following steps: +When the `source` signal changes, `For` performs the following steps: 1. **Key Diffing**: It compares the new keys with the previous ones stored in an internal `Map`. 2. **Node Reuse**: If a key already exists, the DOM node is **reused** and moved to its new position. No new elements are created. @@ -68,13 +68,13 @@ When the `source` signal changes, `$for` performs the following steps: ## Performance Tips * **Stable Keys**: Never use `Math.random()` as a key. This will force SigPro to destroy and recreate the entire list on every update, killing performance. -* **State Preservation**: If your list items have internal state (like an input with text), `$for` ensures that state is preserved even if the list is reordered, as long as the key (`id`) remains the same. +* **State Preservation**: If your list items have internal state (like an input with text), `For` ensures that state is preserved even if the list is reordered, as long as the key (`id`) remains the same. --- ## Summary Comparison -| Feature | Standard `Array.map` | SigPro `$for` | +| Feature | Standard `Array.map` | SigPro `For` | | :--- | :--- | :--- | | **Re-render** | Re-renders everything | Only updates changes | | **DOM Nodes** | Re-created every time | **Reused via Keys** | diff --git a/docs/api/html.md b/docs/api/html.md index 5744a5a..418493e 100644 --- a/docs/api/html.md +++ b/docs/api/html.md @@ -1,11 +1,11 @@ -# The DOM Factory: `$html( )` +# The DOM Factory: `Tag( )` -`$html` is the internal engine that creates, attributes, and attaches reactivity to DOM elements. It uses `$watch` to maintain a live, high-performance link between your Signals and the Document Object Model. +`Tag` is the internal engine that creates, attributes, and attaches reactivity to DOM elements. It uses `Watch` to maintain a live, high-performance link between your Signals and the Document Object Model. ## Function Signature ```typescript -$html(tagName: string, props?: Object, children?: any[] | any): HTMLElement +Tag(tagName: string, props?: Object, children?: any[] | any): HTMLElement ``` | Parameter | Type | Required | Description | @@ -50,7 +50,7 @@ Button({ ``` ### 4. Reactive Attributes (One-Way) -If an attribute value is a **function** (like a Signal), `$html` creates an internal **`$watch`** to keep the DOM in sync with the state. +If an attribute value is a **function** (like a Signal), `Tag` creates an internal **`Watch`** to keep the DOM in sync with the state. ```javascript Div({ @@ -72,7 +72,7 @@ Input({ > **Note:** To use a Signal as **read-only** in an input, wrap it in an anonymous function: `value: () => username()`. ### 6. Reactive Children -Children can be static or dynamic. When a child is a function, SigPro creates a reactive boundary using `$watch` for that specific part of the DOM. +Children can be static or dynamic. When a child is a function, SigPro creates a reactive boundary using `Watch` for that specific part of the DOM. ```javascript Div({}, [ @@ -85,20 +85,20 @@ Div({}, [ --- ## Memory Management (Internal) -Every element created with `$html` is "self-aware" regarding its reactive dependencies. -* **`._cleanups`**: A hidden `Set` attached to the element that stores all `stop()` functions from its internal `$watch` calls and event listeners. -* **Lifecycle**: When an element is removed by a Controller (`$if`, `$for`, or `$router`), SigPro performs a recursive **"sweep"** to execute these cleanups, ensuring **zero memory leaks**. +Every element created with `Tag` is "self-aware" regarding its reactive dependencies. +* **`._cleanups`**: A hidden `Set` attached to the element that stores all `stop()` functions from its internal `Watch` calls and event listeners. +* **Lifecycle**: When an element is removed by a Controller (`If`, `For`, or `Router`), SigPro performs a recursive **"sweep"** to execute these cleanups, ensuring **zero memory leaks**. --- ## Tag Constructors (The Shortcuts) -Instead of writing `$html("div", ...)` every time, SigPro provides PascalCase global functions for all standard HTML tags. These are direct mappings to the `$html` factory. +Instead of writing `Tag("div", ...)` every time, SigPro provides PascalCase global functions for all standard HTML tags. These are direct mappings to the `Tag` factory. ```javascript // This: Div({ class: "wrapper" }, [ Span("Hello") ]) // Is exactly equivalent to: -$html("div", { class: "wrapper" }, [ $html("span", {}, "Hello") ]) +Tag("div", { class: "wrapper" }, [ Tag("span", {}, "Hello") ]) ``` diff --git a/docs/api/if.md b/docs/api/if.md index fecb907..8415d82 100644 --- a/docs/api/if.md +++ b/docs/api/if.md @@ -1,11 +1,11 @@ -# Reactive Branching: `$if( )` +# Reactive Branching: `If( )` -The `$if` function is a reactive control flow operator. It manages the conditional rendering of components with optional smooth transitions, ensuring that only the active branch exists in the DOM and in memory. +The `If` function is a reactive control flow operator. It manages the conditional rendering of components with optional smooth transitions, ensuring that only the active branch exists in the DOM and in memory. ## Function Signature ```typescript -$if( +If( condition: Signal | Function, thenVal: Component | Node, otherwiseVal?: Component | Node, @@ -53,7 +53,7 @@ const fade = { } }; -$if(show, Modal, null, fade); +If(show, Modal, null, fade); ``` --- @@ -68,7 +68,7 @@ const isVisible = $(false); Div([ Button({ onclick: () => isVisible(!isVisible()) }, "Toggle Message"), - $if(isVisible, + If(isVisible, P("Now you see me!"), P("Now you don't...") ) @@ -83,7 +83,7 @@ const showModal = $(false); Div([ Button({ onclick: () => showModal(true) }, "Open Modal"), - $if(showModal, + If(showModal, () => Modal({ onClose: () => showModal(false) }), null, fade // ← Smooth enter/exit animation @@ -93,10 +93,10 @@ Div([ ### 3. Lazy Component Loading -Unlike CSS `display: none`, `$if` is **lazy**. The inactive branch is never created, saving memory. +Unlike CSS `display: none`, `If` is **lazy**. The inactive branch is never created, saving memory. ```javascript -$if(() => user.isLogged(), +If(() => user.isLogged(), () => Dashboard(), // Only executed if logged in () => LoginGate() // Only executed if guest ) @@ -105,15 +105,15 @@ $if(() => user.isLogged(), ### 4. Complex Conditions ```javascript -$if(() => count() > 10 && status() === 'ready', +If(() => count() > 10 && status() === 'ready', Span("Threshold reached!") ) ``` -### 5. $if.not Helper +### 5. If.not Helper ```javascript -$if.not(loading, +If.not(loading, () => Content(), // Shows when loading is FALSE () => Spinner() // Shows when loading is TRUE ) @@ -123,10 +123,10 @@ $if.not(loading, ## Automatic Cleanup -One of the core strengths of `$if` is its integrated **Cleanup** logic. SigPro ensures that when a branch is swapped out, it is completely purged. +One of the core strengths of `If` is its integrated **Cleanup** logic. SigPro ensures that when a branch is swapped out, it is completely purged. -1. **Stop Watchers**: All `$watch` calls inside the inactive branch are permanently stopped. -2. **Unbind Events**: Event listeners attached via `$html` are removed. +1. **Stop Watchers**: All `Watch` calls inside the inactive branch are permanently stopped. +2. **Unbind Events**: Event listeners attached via `Tag` are removed. 3. **Recursive Sweep**: SigPro performs a deep "sweep" of the removed branch. 4. **Transition Respect**: When using transitions, destruction only happens AFTER the `out` animation completes. @@ -142,7 +142,7 @@ One of the core strengths of `$if` is its integrated **Cleanup** logic. SigPro e ## Technical Comparison -| Feature | Standard CSS `hidden` | SigPro `$if` | +| Feature | Standard CSS `hidden` | SigPro `If` | | :--- | :--- | :--- | | **DOM Presence** | Always present | Only if active | | **Reactivity** | Still processing | **Paused/Destroyed** | diff --git a/docs/api/jsx.md b/docs/api/jsx.md index 05ea8b5..dbb1f25 100644 --- a/docs/api/jsx.md +++ b/docs/api/jsx.md @@ -11,7 +11,7 @@ SigPro works seamlessly with JSX. { "compilerOptions": { "jsx": "react", - "jsxFactory": "$html", + "jsxFactory": "Tag", "jsxFragmentFactory": "Fragment" } } @@ -25,7 +25,7 @@ import { defineConfig } from 'vite' export default defineConfig({ esbuild: { - jsxFactory: '$html', + jsxFactory: 'Tag', jsxFragmentFactory: 'Fragment' } }) @@ -38,7 +38,7 @@ export default defineConfig({ export default { plugins: [ ['@babel/plugin-transform-react-jsx', { - pragma: '$html', + pragma: 'Tag', pragmaFrag: 'Fragment' }] ] @@ -49,7 +49,7 @@ export default { ```jsx // App.jsx -import { $, $mount, Fragment } from 'sigpro'; +import { $, Mount, Fragment } from 'sigpro'; const Button = ({ onClick, children }) => (