sprae 9.1.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sprae.min.js CHANGED
@@ -1 +1 @@
1
- var e,t,r,l,a,s=Object.defineProperty,n=Symbol.dispose||=Symbol("dispose"),o={},c=new WeakMap;function i(e,r){if(!e.children)return;if(c.has(e)){const[t,l]=c.get(e);for(let e in r)t[e]=r[e];a((()=>{for(let e of l)e()}))}const l=r||{},s=[],i=(e,r=e.parentNode)=>{if(e.attributes)for(let a=0;a<e.attributes.length;){let i=e.attributes[a];if(":"===i.name[0]){e.removeAttribute(i.name);let a=i.name.slice(1).split(":");for(let r of a){let a=o[r]||o.default,c=a(e,(a.parse||d)(i.value,d),l,r);c&&(c[n]=t(c),s.push(c))}if(c.has(e))return;if(e.parentNode!==r)return!1}else a++}for(let t,r=0;t=e.children[r];r++)!1===i(t,e)&&r--};return i(e),c.has(e)||(c.set(e,[l,s]),e.classList?.add("∴"),e[n]=()=>{for(;s.length;)s.pop()[n]();e.classList.remove("∴"),c.delete(e);let t=e.getElementsByClassName("∴");for(;t.length;)t[0][n]?.()}),l}var u,p,f={},d=(e,t,r)=>{if(r=f[e=e.trim()])return r;try{r=u(e)}catch(r){throw Object.assign(r,{message:`∴ ${r.message}\n\n${t}${e?`="${e}"\n\n`:""}`,expr:e})}return r.expr=e,f[e]=r};i.use=s=>{s.signal&&(e=s.signal,t=s.effect,l=s.computed,r=s.batch||(e=>e()),a=s.untracked||r),s.swap&&(p=s.swap),s.compile&&(u=s.compile)};var v,y={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(y,{batch:()=>g,computed:()=>b,effect:()=>h,signal:()=>m,untracked:()=>k});var m=(e,t,r=new Set)=>((t={get value(){return v?.deps.push(r.add(v)),e},set value(t){if(t!==e){e=t;for(let e of r)e(t)}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),h=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=v,v=r;try{t=e()}finally{v=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),b=(e,t=m(),r,l)=>((r={get value(){return l||=h((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),g=e=>e(),k=(e,t,r)=>(t=v,v=null,r=e(),v=t,r),w=(e,t,r,l=null,{remove:a,insert:s}=w)=>{let n,o,c,i=0,u=new Set(r);for(;c=t[i++];)u.has(c)?n=n||c:a(c,e);for(n=n||l,i=0;c=r[i++];)o=n?n.nextSibling:l,n===c?n=o:(r[i]===o&&(n=o),s(c,n,e));return r};w.insert=(e,t,r)=>r.insertBefore(e,t),w.remove=(e,t)=>t.removeChild(e);var O=w,A=Symbol(":each"),S={},N=Symbol("key");(o.each=(e,[t,r,l],a)=>{const s=e[A]=document.createTextNode(""),n=e.parentNode;e.replaceWith(s);const o=new WeakMap,c=new WeakMap;let u=[];const{insert:f,replace:d}=p,v={remove:e=>{e.remove(),e[Symbol.dispose]?.(),e[N]&&(o.delete(e[N]),c.delete(e[N]))},insert:f,replace:d};return()=>{let f=l(a)?.valueOf(),d=[];"number"==typeof f&&(f=Array.from({length:f},((e,t)=>t)));const y=new WeakMap;for(let l in f){let s,n=f[l],u=n?.key??n?.id??n??l;u=Object(u)!==u?S[u]||=Object(u):n,null==u||y.has(u)||e.content?s=(e.content||e).cloneNode(!0):(y.set(u,1),(s=o.get(u)||(o.set(u,e.cloneNode(!0)),o.get(u)))[N]=u);let p=c.get(u)||(c.set(u,Object.create(a,{[r]:{value:l}})),c.get(u));p[t]=n,i(s,p),11===s.nodeType?d.push(...s.childNodes):d.push(s)}p(n,u,u=d,s,v)}}).parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[a,s="$"]=r.split(/\s*,\s*/);return[a,s,t(l)]};var x=Symbol("if");o.if=(e,t,r)=>{let l,a,s,n=e.parentNode,o=e.nextElementSibling,c=document.createTextNode(""),u=[];return e.after(c),e.content?(l=u,e.remove(),a=[...e.content.childNodes]):a=l=[e],o?.hasAttribute(":else")?(o.removeAttribute(":else"),o.hasAttribute(":if")?s=u:(o.remove(),s=o.content?[...o.content.childNodes]:[o])):s=u,()=>{const f=t(r)?.valueOf()?a:e[x]?u:s;if(o&&(o[x]=f===a),l!=f){l[0]?.[A]&&(l=[l[0][A]]),p(n,l,l=f,c);for(let e of l)i(e,r)}}},o.default=(e,t,r,l)=>{let a=l.startsWith("on")&&l.slice(2);if(a){let l;return()=>(l?.(),l=W(e,a,t(r)?.valueOf()))}return()=>{let a=t(r)?.valueOf();if(l)T(e,l,D(a,r));else for(let t in a)T(e,j(t),D(a[t],r))}};var W=(e,t,r=(()=>{}))=>{const l={evt:"",target:e,test:()=>!0};l.evt=t.replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(l.test=C[t]?.(l,...r.split("-"))||l.test,"")));const{evt:a,target:s,test:n,defer:o,stop:c,prevent:i,...u}=l;o&&(r=o(r));const p=e=>n(e)&&(c&&e.stopPropagation(),i&&e.preventDefault(),r.call(s,e));return s.addEventListener(a,p,u),()=>s.removeEventListener(a,p,u)},C={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>$(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>L(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>E.ctrl(e)&&t.every((t=>E[t]?E[t](e):e.key===t)),shift:(e,...t)=>e=>E.shift(e)&&t.every((t=>E[t]?E[t](e):e.key===t)),alt:(e,...t)=>e=>E.alt(e)&&t.every((t=>E[t]?E[t](e):e.key===t)),meta:(e,...t)=>e=>E.meta(e)&&t.every((t=>E[t]?E[t](e):e.key===t)),arrow:()=>E.arrow,enter:()=>E.enter,escape:()=>E.escape,tab:()=>E.tab,space:()=>E.space,backspace:()=>E.backspace,delete:()=>E.delete,digit:()=>E.digit,letter:()=>E.letter,character:()=>E.character},E={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},T=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},$=(e,t)=>{let r,l,a=s=>{r=!0,setTimeout((()=>{if(r=!1,l)return l=!1,a(s),e(s)}),t)};return t=>r?l=!0:(a(t),e(t))},L=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},j=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),D=(e,t)=>e?.replace?e.replace(/\$<([^>]+)>/g,((e,r)=>t[r]?.valueOf?.()??"")):e;(o.ref=(e,t,r)=>{let l;return()=>{l&&delete r[l],r[l=D(t,r)]=e}}).parse=e=>e,o.scope=(e,t,r)=>()=>{i(e,{...r,...t(r)?.valueOf?.()||{}})},o.html=(e,t,r)=>{let l=t(r);if(!l)return;let a=(l.content||l).cloneNode(!0);e.replaceChildren(a),i(e,r)},o.text=(e,t,r)=>(e.content&&e.replaceWith(e=document.createTextNode("")),()=>{let l=t(r)?.valueOf();e.textContent=null==l?"":l}),o.class=(e,t,r)=>{let l=new Set;return()=>{let a=t(r),s=new Set;a&&("string"==typeof a?D(a?.valueOf?.(),r).split(" ").map((e=>s.add(e))):Array.isArray(a)?a.map((e=>(e=D(e?.valueOf?.(),r))&&s.add(e))):Object.entries(a).map((([e,t])=>t?.valueOf?.()&&s.add(e))));for(let t of l)s.has(t)?s.delete(t):e.classList.remove(t);for(let t of l=s)e.classList.add(t)}},o.style=(e,t,r)=>{let l=e.getAttribute("style")||"";return l.endsWith(";")||(l+="; "),()=>{let a=t(r)?.valueOf();if("string"==typeof a)e.setAttribute("style",l+D(a,r));else{e.setAttribute("style",l);for(let t in a)e.style.setProperty(t,D(a[t],r))}}},o.value=(e,t,r)=>{let l,a,s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(l=e.selectionStart,a=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),l&&e.setSelectionRange(l,a)):"checkbox"===e.type?t=>(e.checked=t,T(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return()=>s(t(r)?.valueOf?.())},o.fx=(e,t,r)=>()=>t(r),i.use(y),i.use({compile:e=>i.constructor("__scope",`with (__scope) { return ${e} };`)}),i.use({swap:O});var M=i;export{r as batch,u as compile,l as computed,M as default,o as directive,t as effect,e as signal,p as swap,a as untracked};
1
+ var e,t,r,l,n,s=Object.defineProperty,a=Symbol("signals"),o=Symbol("length");function i(t,r){if(!t)return t;if(t[a]&&!r)return t;if(Array.isArray(t))return function(t){let r;if(t[a])return t;let l=e(t.length),n=Array(t.length).fill(null);const s=new Proxy(n,{get:(s,c)=>c===o?l:c===a?n:"length"===c?Array.prototype[r]?l.peek():l.value:(r=c,n[c]?n[c].valueOf():c<n.length?(n[c]=e(i(t[c]))).value:void 0),set(e,t,r){if("length"===t){for(let e=r,t=n.length;e<t;e++)delete s[e];return l.value=n.length=r,!0}return c(n,t,r),t>=l.peek()&&(l.value=n.length=Number(t)+1),!0},deleteProperty:(e,t)=>(u(n,t),!0)});return s}(t);if(t.constructor!==Object)return t;let l=e(Object.values(t).length);r||={};const s=new Proxy(r,{get:(e,t)=>t===o?l:t===a?r:r[t]?.valueOf(),set:(e,t,n,s)=>(s=r[t],c(r,t,n),s||++l.value),deleteProperty:(e,t)=>u(r,t)&&l.value--,ownKeys:()=>(l.value,Reflect.ownKeys(r))});if(t[a])for(let e in t)r[e]=t[a][e];else for(let e in t){const l=Object.getOwnPropertyDescriptor(t,e);l?.get?(r[e]=n(l.get.bind(s)))._set=l.set?.bind(s):(r[e]=null,c(r,e,t[e]))}return s}function c(t,n,s){let a=t[n];if(a)if(s===a.peek());else if(a._set)a._set(s);else if(Array.isArray(s)&&Array.isArray(a.peek())){const e=a.peek();e[o]?r((()=>{l((()=>{let t=0,r=s.length;for(;t<r;t++)e[t]=s[t];e.length=r}))})):a.value=s}else a.value=i(s);else t[n]=a=s?.peek?s:e(i(s))}function u(e,t){const r=e[t];if(r){const l=r[Symbol.dispose];return l&&delete r[Symbol.dispose],delete e[t],l?.(),!0}}var f=Symbol.dispose||=Symbol("dispose"),p={},d=new WeakMap;function y(e,t){let r;e?.[Symbol.iterator]||(e=[e]);for(let l of e)l?.children&&(d.has(l)?Object.assign(d.get(l),t):(r||=i(t||{}),v(l,r),d.has(l)||d.set(l,r)));return r}function v(e,t,r=e.parentNode,l=[]){if(e.attributes)for(let n=0;n<e.attributes.length;){let s=e.attributes[n];if(":"===s.name[0]){e.removeAttribute(s.name);let n=s.name.slice(1).split(":");for(let r of n){let n=p[r]||p.default,a=(n.parse||g)(s.value,g),o=n(e,a,t,r);o&&l.push(o)}if(d.has(e))return;if(e.parentNode!==r)return}else n++}for(let r of[...e.children])v(r,t,e);e.classList?.add("∴"),e[f]=()=>{for(;l.length;)l.pop()();e.classList.remove("∴"),d.delete(e);let t=e.getElementsByClassName("∴");for(;t.length;)t[0][f]?.()}}var h,m={},g=(e,t,r)=>{if(r=m[e=e.trim()])return r;try{r=h(e)}catch(r){throw Object.assign(r,{message:`∴ ${r.message}\n\n${t}${e?`="${e}"\n\n`:""}`,expr:e})}return m[e]=r};y.use=s=>{s.signal&&function(s){e=s.signal,t=s.effect,n=s.computed,l=s.batch||(e=>e()),r=s.untracked||l}(s),s.compile&&(h=s.compile)};var b,k,A={};((e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})})(A,{batch:()=>N,computed:()=>O,effect:()=>w,signal:()=>S,untracked:()=>x});var S=(e,t,r=new Set)=>((t={get value(){return b?.deps.push(r.add(b)),e},set value(t){if(t!==e){e=t;for(let e of r)k?k.add(e):e()}},peek:()=>e}).toJSON=t.then=t.toString=t.valueOf=()=>t.value,t),w=(e,t,r,l)=>(l=(r=l=>{t?.call?.(),l=b,b=r;try{t=e()}finally{b=l}}).deps=[],r(),e=>{for(t?.call?.();e=l.pop();)e.delete(r)}),O=(e,t=S(),r,l)=>((r={get value(){return l||=w((()=>t.value=e())),t.value},peek:t.peek}).toJSON=r.then=r.toString=r.valueOf=()=>r.value,r),N=e=>{let t=k;t||(k=new Set);try{e()}finally{if(!t){t=k,k=null;for(const e of t)e()}}},x=(e,t,r)=>(t=b,b=null,r=e(),b=t,r),j=(e,t,r,l=null,{remove:n,insert:s}=j)=>{let a,o,i,c=0,u=new Set(r);for(;i=t[c++];)u.has(i)?a=a||i:n(i,e);for(a=a||l,c=0;i=r[c++];)o=a?a.nextSibling:l,a===i?a=o:(r[c]===o&&(a=o),s(i,a,e));return r};j.insert=(e,t,r)=>r.insertBefore(e,t),j.remove=(e,t)=>t.removeChild(e);var C=j,E=Symbol(":each");p.each=(e,[l,s,i],c)=>{const u=e[E]=document.createTextNode("");e.replaceWith(u);let f,p,d=0;const v=n((()=>{p=null;let e=i(c);return"number"==typeof e&&(e=Array.from({length:e},((e,t)=>t+1))),e?.constructor===Object&&(p=Object.keys(e),e=Object.values(e)),e||[]})),h=()=>{r((()=>{let t=0,r=v.value,n=r.length;if(f&&!f[o]){for(let e of f[a]||[])e[Symbol.dispose]();f=null,d=0}if(n<d)f.length=n;else{if(f)for(;t<d;t++)f[t]=r[t];else f=r;for(;t<n;t++){f[t]=r[t];let n=t,o=Object.create(c,{[l]:{get:()=>f[n]},[s]:{value:p?p[n]:n}}),i=(e.content||e).cloneNode(!0),d=e.content?[...i.childNodes]:[i];u.before(i),y(d,o),((f[a]||=[])[t]||={})[Symbol.dispose]=()=>{for(let e of d)e[Symbol.dispose](),e.remove()}}}d=n}))};let m=0;return t((()=>{f||v.value[o]?.value,m?m++:(h(),queueMicrotask((()=>(m&&h(),m=0))))}))},p.each.parse=(e,t)=>{let[r,l]=e.split(/\s+in\s+/),[n,s="$"]=r.split(/\s*,\s*/);return[n,s,t(l)]};var $=Symbol("if");p.if=(e,r,l)=>{let n,s,a,o=e.parentNode,i=e.nextElementSibling,c=document.createTextNode(""),u=[];return e.after(c),e.content?(n=u,e.remove(),s=[...e.content.childNodes]):s=n=[e],i?.hasAttribute(":else")?(i.removeAttribute(":else"),i.hasAttribute(":if")?a=u:(i.remove(),a=i.content?[...i.content.childNodes]:[i])):a=u,t((()=>{const t=r(l)?s:e[$]?u:a;if(i&&(i[$]=t===s),n!=t){n[0]?.[E]&&(n=[n[0][E]]);for(let e of n)e.remove();n=t;for(let e of n)o.insertBefore(e,c),y(e,l)}}))},p.default=(e,r,l,n)=>{let s,a=n.startsWith("on")&&n.slice(2);return t(a?()=>(s?.(),s=P(e,a,r(l))):()=>{let t=r(l);if(n)L(e,n,B(t,l));else for(let r in t)L(e,K(r),B(t[r],l))})};var P=(e,t,r=(()=>{}))=>{const l={evt:"",target:e,test:()=>!0};l.evt=t.replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(l.test=T[t]?.(l,...r.split("-"))||l.test,"")));const{evt:n,target:s,test:a,defer:o,stop:i,prevent:c,...u}=l;o&&(r=o(r));const f=e=>a(e)&&(i&&e.stopPropagation(),c&&e.preventDefault(),r.call(s,e));return s.addEventListener(n,f,u),()=>s.removeEventListener(n,f,u)},T={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>_(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>D(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>W.ctrl(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),shift:(e,...t)=>e=>W.shift(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),alt:(e,...t)=>e=>W.alt(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),meta:(e,...t)=>e=>W.meta(e)&&t.every((t=>W[t]?W[t](e):e.key===t)),arrow:()=>W.arrow,enter:()=>W.enter,escape:()=>W.escape,tab:()=>W.tab,space:()=>W.space,backspace:()=>W.backspace,delete:()=>W.delete,digit:()=>W.digit,letter:()=>W.letter,character:()=>W.character},W={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},L=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},_=(e,t)=>{let r,l,n=s=>{r=!0,setTimeout((()=>{if(r=!1,l)return l=!1,n(s),e(s)}),t)};return t=>r?l=!0:(n(t),e(t))},D=(e,t)=>{let r;return l=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(l)}),t)}},K=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),B=(e,t)=>e?.replace?e.replace(/\$<([^>]+)>/g,((e,r)=>t[r]??"")):e;p.ref=(e,t,r)=>{Object.defineProperty(r,B(t,r),{value:e})},p.ref.parse=e=>e,p.with=(e,r,l)=>{let n,s;return t((()=>{s=r(l),Object.assign(n||=y(e,i(s,Object.create(l[a]))),s)}))},p.html=(e,t,r)=>{let l=t(r);if(!l)return;let n=(l.content||l).cloneNode(!0);e.replaceChildren(n),y(e,r)},p.text=(e,r,l)=>(e.content&&e.replaceWith(e=document.createTextNode("")),t((()=>{let t=r(l);e.textContent=null==t?"":t}))),p.class=(e,r,l)=>{let n=new Set;return t((()=>{let t=r(l),s=new Set;t&&("string"==typeof t?B(t,l).split(" ").map((e=>s.add(e))):Array.isArray(t)?t.map((e=>(e=B(e,l))&&s.add(e))):Object.entries(t).map((([e,t])=>t&&s.add(e))));for(let t of n)s.has(t)?s.delete(t):e.classList.remove(t);for(let t of n=s)e.classList.add(t)}))},p.style=(e,r,l)=>{let n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t((()=>{let t=r(l);if("string"==typeof t)e.setAttribute("style",n+B(t,l));else{e.setAttribute("style",n);for(let r in t)e.style.setProperty(r,B(t[r],l))}}))},p.value=(e,r,l)=>{let n,s,a="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(n=e.selectionStart,s=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),n&&e.setSelectionRange(n,s)):"checkbox"===e.type?t=>(e.checked=t,L(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return t((()=>a(r(l))))},p.fx=(e,r,l)=>t((()=>r(l))),y.use(A),y.use({compile:e=>y.constructor("__scope",`with (__scope) { return ${e} };`)}),y.use({swap:C});var M=y;export{M as default};
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "9.1.1",
4
+ "version": "10.0.0",
5
5
  "main": "./sprae.js",
6
6
  "module": "./sprae.js",
7
7
  "type": "module",
8
8
  "files": [
9
9
  "core.js",
10
10
  "sprae.js",
11
+ "store.js",
11
12
  "signal.js",
12
13
  "directive",
13
14
  "dist"
14
15
  ],
15
16
  "dependencies": {
16
- "swapdom": "^1.2.1"
17
+ "ulive": "^1.0.2"
17
18
  },
18
19
  "devDependencies": {
19
20
  "@preact/signals": "^1.1.3",
@@ -22,10 +23,10 @@
22
23
  "esbuild": "^0.15.14",
23
24
  "hyperf": "^1.6.2",
24
25
  "jsdom": "^21.1.0",
25
- "subscript": "^8.3.4",
26
+ "signal-polyfill": "^0.1.1",
27
+ "subscript": "^8.3.5",
26
28
  "terser": "^5.15.1",
27
29
  "tst": "^7.1.1",
28
- "ulive": "^1.0.1",
29
30
  "usignal": "^0.9.0",
30
31
  "wait-please": "^3.1.0"
31
32
  },
package/readme.md CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  > DOM tree microhydration
4
4
 
5
- _Sprae_ is a compact & ergonomic progressive enhancement framework.<br/>
6
- It provides `:`-attributes for inline markup logic with signals reactivity.<br/>
5
+ _Sprae_ is open & minimalistic progressive enhancement framework.<br/>
7
6
  Perfect for small-scale websites, static pages, landings, prototypes, or lightweight UI.<br/>
8
7
 
9
8
 
@@ -15,17 +14,17 @@ Perfect for small-scale websites, static pages, landings, prototypes, or lightwe
15
14
  </div>
16
15
 
17
16
  <script type="module">
18
- import sprae, { signal } from 'sprae'
17
+ import sprae from 'sprae'
19
18
 
20
- const name = signal('Kitty')
21
- sprae(container, { user: { name } }) // init
19
+ // init
20
+ const state = sprae(container, { user: { name: 'Kitty' } })
22
21
 
23
- name.value = 'Dolly' // update
22
+ // update
23
+ state.user.name = 'Dolly'
24
24
  </script>
25
25
  ```
26
26
 
27
- Sprae evaluates `:`-directives and evaporates them, attaching state to html.
28
-
27
+ Sprae evaluates `:`-directives and evaporates them, returning reactive state.
29
28
 
30
29
  ## Directives
31
30
 
@@ -43,21 +42,17 @@ Control flow of elements.
43
42
  ```
44
43
 
45
44
 
46
- #### `:each="item, index in items"`
45
+ #### `:each="item, index? in items"`
47
46
 
48
- Multiply element. Item is identified either by `item.id`, `item.key` or `item` itself.
47
+ Multiply element.
49
48
 
50
49
  ```html
51
50
  <ul><li :each="item in items" :text="item"/></ul>
52
51
 
53
52
  <!-- cases -->
54
- <li :each="item, idx in list" />
55
- <li :each="val, key in obj" />
56
- <li :each="idx in number" />
57
-
58
- <!-- by condition -->
59
- <li :if="items" :each="item in items" :text="item" />
60
- <li :else>Empty list</li>
53
+ <li :each="item, idx in array" />
54
+ <li :each="value, key in object" />
55
+ <li :each="count, idx in number" />
61
56
 
62
57
  <!-- fragment -->
63
58
  <template :each="item in items">
@@ -82,22 +77,28 @@ Welcome, <template :text="user.name" />.
82
77
 
83
78
  #### `:class="value"`
84
79
 
85
- Set class value, extends existing `class`.
80
+ Set class value.
86
81
 
87
82
  ```html
88
- <!-- string with interpolation -->
83
+ <!-- appends class -->
84
+ <div class="foo" :class="bar"></div>
85
+
86
+ <!-- interpolation -->
89
87
  <div :class="'foo $<bar>'"></div>
90
88
 
91
- <!-- array/object a-la clsx -->
89
+ <!-- array/object, a-la clsx -->
92
90
  <div :class="[foo && 'foo', {bar: bar}]"></div>
93
91
  ```
94
92
 
95
93
  #### `:style="value"`
96
94
 
97
- Set style value, extends existing `style`.
95
+ Set style value.
98
96
 
99
97
  ```html
100
- <!-- string with interpolation -->
98
+ <!-- extends style -->
99
+ <div style="foo: bar" :style="'baz: qux'">
100
+
101
+ <!-- interpolation -->
101
102
  <div :style="'foo: $<bar>'"></div>
102
103
 
103
104
  <!-- object -->
@@ -109,16 +110,19 @@ Set style value, extends existing `style`.
109
110
 
110
111
  #### `:value="value"`
111
112
 
112
- Set value of an input, textarea or select. Takes handle of `checked` and `selected` attributes.
113
+ Set value of an input, textarea or select.
113
114
 
114
115
  ```html
115
116
  <input :value="value" />
116
117
  <textarea :value="value" />
117
118
 
118
- <!-- selects right option -->
119
+ <!-- selects right option & handles selected attr -->
119
120
  <select :value="selected">
120
121
  <option :each="i in 5" :value="i" :text="i"></option>
121
122
  </select>
123
+
124
+ <!-- handles checked attr -->
125
+ <input type="checkbox" :value="checked" />
122
126
  ```
123
127
 
124
128
  #### `:[prop]="value"`, `:="values"`
@@ -135,33 +139,32 @@ Set any attribute(s).
135
139
  <input :="{ id: name, name, type: 'text', value }" />
136
140
  ```
137
141
 
138
- #### `:scope="data"`
142
+ #### `:with="values"`
139
143
 
140
- Define or extend data scope for a subtree.
144
+ Define values for a subtree.
141
145
 
142
146
  ```html
143
- <x :scope="{ foo: signal('bar') }">
144
- <!-- extends parent scope -->
145
- <y :scope="{ baz: 'qux' }" :text="foo + baz"></y>
147
+ <x :with="{ foo: signal('bar') }">
148
+ <y :with="{ baz: 'qux' }" :text="foo + baz"></y>
146
149
  </x>
147
150
  ```
148
151
 
149
152
  #### `:ref="name"`
150
153
 
151
- Expose element to current scope with `name`.
154
+ Expose element with `name`.
152
155
 
153
156
  ```html
154
157
  <textarea :ref="text" placeholder="Enter text..."></textarea>
155
158
 
156
159
  <!-- iterable items -->
157
160
  <li :each="item in items" :ref="item">
158
- <input :onfocus..onblur=="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"/>
161
+ <input :onfocus..onblur="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"/>
159
162
  </li>
160
163
  ```
161
164
 
162
165
  #### `:fx="code"`
163
166
 
164
- Run effect, not changing any attribute.<br/>Optional cleanup is called in-between effect calls or on disposal.
167
+ Run effect, not changing any attribute.
165
168
 
166
169
  ```html
167
170
  <div :fx="a.value ? foo() : bar()" />
@@ -172,7 +175,7 @@ Run effect, not changing any attribute.<br/>Optional cleanup is called in-betwee
172
175
 
173
176
  #### `:on[event]="handler"`
174
177
 
175
- Attach event(s) listener with possible modifiers.
178
+ Attach event(s) listener with optional modifiers.
176
179
 
177
180
  ```html
178
181
  <input type="checkbox" :onchange="e => isChecked = e.target.value">
@@ -183,7 +186,7 @@ Attach event(s) listener with possible modifiers.
183
186
  <!-- events sequence -->
184
187
  <button :onfocus..onblur="e => ( handleFocus(), e => handleBlur())">
185
188
 
186
- <!-- event modifiers -->
189
+ <!-- modifiers -->
187
190
  <button :onclick.throttle-500="handler">Not too often</button>
188
191
  ```
189
192
 
@@ -211,7 +214,7 @@ Hello, <template :html="user.name">Guest</template>.
211
214
 
212
215
  <!-- instantiate template -->
213
216
  <template :ref="tpl"><span :text="foo"></span></template>
214
- <div :html="tpl" :scope="{foo:'bar'}">...inserted here...</div>
217
+ <div :html="tpl" :with="{foo:'bar'}">...inserted here...</div>
215
218
  ```
216
219
 
217
220
  #### `:data="values"` 🔌
@@ -267,29 +270,37 @@ Trigger when element is connected / disconnected from DOM.
267
270
 
268
271
  ## Signals
269
272
 
270
- Sprae uses signals for reactivity (see [_sprae/signal.js_](./signal.js)). It can be switched to any alternative preact-flavored signals for compatibility or performance:
273
+ Sprae can take signal values. Signals provider can be switched to any preact-flavored implementation:
271
274
 
272
275
  ```js
273
- import sprae, { signal, computed, effect, batch, untracked } from 'sprae';
276
+ import sprae from 'sprae';
277
+ import { signal, computed, effect, batch, untracked } from 'sprae/signal';
274
278
  import * as signals from '@preact/signals-core';
275
279
 
280
+ // switch provider to @preact/signals-core
276
281
  sprae.use(signals);
277
282
 
278
- sprae(el, { name: signal('Kitty') });
283
+ // use signal as state value
284
+ const name = signal('Kitty')
285
+ sprae(el, { name });
286
+
287
+ // update state
288
+ name.value = 'Dolly';
279
289
  ```
280
290
 
281
291
  Provider | Size | Feature
282
292
  :---|:---|:---
283
- [`ulive`](https://ghub.io/ulive) | 350b | Minimal implementation, basic performance, good for small states
284
- [`@webreflection/signal`](https://ghib.io/@webreflection/signal) | 531b | Class-based, better performance, good for small-medium states
285
- [`usignal`](https://ghib.io/usignal) | 850b | Class-based with optimizations, good for medium states
286
- [`@preact/signals-core`](https://ghub.io/@preact/signals-core) | 1.47kb | Best performance, good for any states
287
- [`signal-polyfill`](https://github.com/tc39/proposal-signals) | 2.5kb | Standard signals, slowest performance. Use via [adapter](https://gist.github.com/dy/bbac687464ccf5322ab0e2fd0680dc4d).
293
+ [`ulive`](https://ghub.io/ulive) (default) | 350b | Minimal implementation, basic performance, good for small states.
294
+ [`@webreflection/signal`](https://ghib.io/@webreflection/signal) | 531b | Class-based, better performance, good for small-medium states.
295
+ [`usignal`](https://ghib.io/usignal) | 850b | Class-based with optimizations, good for medium states.
296
+ [`@preact/signals-core`](https://ghub.io/@preact/signals-core) | 1.47kb | Best performance, good for any states, industry standard.
297
+ [`signal-polyfill`](https://github.com/tc39/proposal-signals) | 2.5kb | Proposal signals. Use via [adapter](https://gist.github.com/dy/bbac687464ccf5322ab0e2fd0680dc4d).
288
298
 
289
299
 
290
300
  ## Evaluator
291
301
 
292
- Expressions use _new Function_ as default evaluator, which is fast & compact way, but violates "unsafe-eval" CSP. To make eval stricter & safer, as well as sandbox expressions, an alternative evaluator can be configured, eg. _justin_:
302
+ Expressions use _new Function_ as default evaluator, which is fast & compact way, but violates "unsafe-eval" CSP.
303
+ To make eval stricter & safer, as well as sandbox expressions, an alternative evaluator can be used, eg. _justin_:
293
304
 
294
305
  ```js
295
306
  import sprae from 'sprae'
@@ -298,7 +309,7 @@ import justin from 'subscript/justin'
298
309
  sprae.use({compile: justin}) // set up justin as default compiler
299
310
  ```
300
311
 
301
- [_Justin_](https://github.com/dy/subscript?tab=readme-ov-file#justin) is minimal JS subset. It avoids "unsafe-eval" CSP and provides sandboxing.
312
+ [_Justin_](https://github.com/dy/subscript?tab=readme-ov-file#justin) is minimal JS subset that avoids "unsafe-eval" CSP and provides sandboxing.
302
313
 
303
314
  ###### Operators:
304
315
 
@@ -313,84 +324,43 @@ sprae.use({compile: justin}) // set up justin as default compiler
313
324
  `true false null undefined NaN`
314
325
 
315
326
 
316
- ## Directives
327
+ ## Custom Build
317
328
 
318
- Custom directives can be added as:
319
-
320
- ```js
321
- import sprae, { directive } from 'sprae/core.js'
322
-
323
- // define custom directive
324
- directive.id = (el, evaluate, state) => {
325
- return () => el.id = evaluate(state) // return update function
326
- }
327
- ```
328
-
329
- ## Custom build
330
-
331
- _Sprae_ can be tailored to project needs via `sprae/core` for performance, size or compatibility purposes:
329
+ _Sprae_ can be tailored to project needs via `sprae/core`:
332
330
 
333
331
  ```js
334
332
  // sprae.custom.js
335
- import sprae, { directive } from 'sprae/core.js'
333
+ import sprae, { directive } from 'sprae/core'
334
+ import { effect } from 'sprae/signal'
336
335
  import * as signals from '@preact/signals'
337
336
  import compile from 'subscript'
338
- import diff from 'udomdiff
339
337
 
340
338
  // include directives
341
339
  import 'sprae/directive/if.js'
342
340
  import 'sprae/directive/text.js'
343
341
 
342
+ // custom directive :id="expression"
343
+ directive.id = (el, evaluate, state) => {
344
+ effect(() => el.id = evaluate(state))
345
+ }
346
+
344
347
  // configure signals
345
348
  sprae.use(signals)
346
349
 
347
350
  // configure compiler
348
351
  sprae.use({ compile })
349
-
350
- // configure dom differ
351
- sprae.use({ swap: (parent, from, to, before) => udomdiff(parent, from, to, node=>node, before) })
352
- ```
353
-
354
- <!--
355
- ### DOM diffing
356
-
357
- DOM diffing uses [swapdom](https://github.com/dy/swapdom), but can be reconfigured to [list-difference](https://github.com/paldepind/list-difference/), [udomdiff](https://github.com/WebReflection/udomdiff), [domdiff](https://github.com/WebReflection/domdiff), or any other ([benchmark](https://github.com/luwes/js-diff-benchmark)):
358
-
359
- ```js
360
- import sprae from 'sprae';
361
- import domdiff from 'list-difference';
362
-
363
- // swap(parentNode, prevEls, newEls, endNode?)
364
- sprae.use({ swap: domdiff });
365
352
  ```
366
- -->
367
-
368
353
 
369
354
  <!-- ## Dispose
370
355
 
371
356
  To destroy state and detach sprae handlers, call `element[Symbol.dispose]()`. -->
372
357
 
373
358
 
374
- <!--
375
- ## v9 changes
376
-
377
- * No autoinit → use manual init via `import sprae from 'sprae'; sprae(document.body, state)`.
378
- * No default globals (`console`, `setTimeout` etc) - pass to state if required.
379
- * ``:class="`abc ${def}`"`` → `:class="'abc $<def>'"` (_justin_)
380
- * `:with={x:'x'}` -> `:scope={x:'x'}`
381
- * No reactive store → use signals for reactive values.
382
- * `:render="tpl"` → `:html="tpl"`
383
- * `@click="event.target"` → `:onclick="event => event.target"`
384
- * Async props / events are not supported, pass async functions via state.
385
- * Directives order matters, eg. `<a :if :each :scope />` !== `<a :scope :each :if />`
386
- * Only one directive per `<template>`, eg. `<template :each />`, not `<template :if :each/>`
387
- -->
388
-
389
359
  ## Justification
390
360
 
391
- [Template-parts](https://github.com/dy/template-parts) / [templize](https://github.com/dy/templize) is progressive, but is stuck with native HTML quirks ([parsing table](https://github.com/github/template-parts/issues/24), [SVG attributes](https://github.com/github/template-parts/issues/25), [liquid syntax](https://shopify.github.io/liquid/tags/template/#raw) conflict etc). [Alpine](https://github.com/alpinejs/alpine) / [petite-vue](https://github.com/vuejs/petite-vue) / [lucia](https://github.com/aidenyabi/lucia) escape native HTML quirks, but have excessive API (`:`, `x-`, `{}`, `@`, `$`) and tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223).
361
+ [Template-parts](https://github.com/dy/template-parts) is stuck with native HTML quirks ([parsing table](https://github.com/github/template-parts/issues/24), [SVG attributes](https://github.com/github/template-parts/issues/25), [liquid syntax](https://shopify.github.io/liquid/tags/template/#raw) conflict etc). [Alpine](https://github.com/alpinejs/alpine) / [petite-vue](https://github.com/vuejs/petite-vue) / [lucia](https://github.com/aidenyabi/lucia) escape native HTML quirks, but have excessive API (`:`, `x-`, `{}`, `@`, `$`) and tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223).
392
362
 
393
- _Sprae_ holds open & minimalistic philosophy, combining _`:`-directives_ with _signals_.
363
+ _Sprae_ holds open & minimalistic philosophy, combining _`:`-directives_ with emerging _signals_.
394
364
 
395
365
  <!--
396
366
  | | [AlpineJS](https://github.com/alpinejs/alpine) | [Petite-Vue](https://github.com/vuejs/petite-vue) | Sprae |
package/signal.js CHANGED
@@ -1,43 +1,10 @@
1
- // ulive minimal signal impl (decoupled from ulive to keep internal dep adjustable easily)
2
- let current
1
+ // signals adapter - allows switching signals implementation and not depend on core
2
+ export let signal, effect, untracked, batch, computed;
3
3
 
4
- export const signal = (v, s, obs = new Set) => (
5
- s = {
6
- get value() {
7
- current?.deps.push(obs.add(current));
8
- return v
9
- },
10
- set value(val) {
11
- if (val === v) return
12
- v = val;
13
- for (let sub of obs) sub(val); // notify effects
14
- },
15
- peek() { return v },
16
- },
17
- s.toJSON = s.then = s.toString = s.valueOf = () => s.value,
18
- s
19
- ),
20
- effect = (fn, teardown, run, deps) => (
21
- run = (prev) => {
22
- teardown?.call?.();
23
- prev = current, current = run;
24
- try { teardown = fn(); } finally { current = prev; }
25
- },
26
- deps = run.deps = [],
27
-
28
- run(),
29
- (dep) => { teardown?.call?.(); while (dep = deps.pop()) dep.delete(run); }
30
- ),
31
- computed = (fn, s = signal(), c, e) => (
32
- c = {
33
- get value() {
34
- e ||= effect(() => s.value = fn());
35
- return s.value
36
- },
37
- peek: s.peek
38
- },
39
- c.toJSON = c.then = c.toString = c.valueOf = () => c.value,
40
- c
41
- ),
42
- batch = (fn) => fn(),
43
- untracked = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
4
+ export function use(s) {
5
+ signal = s.signal
6
+ effect = s.effect
7
+ computed = s.computed
8
+ batch = s.batch || (fn => fn())
9
+ untracked = s.untracked || batch
10
+ }
package/sprae.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import sprae from './core.js'
2
2
 
3
- import * as signals from './signal.js'
3
+ import * as signals from 'ulive'
4
4
  import swap from 'swapdom/deflate'
5
5
 
6
6
  // default directives
7
7
  import './directive/if.js'
8
8
  import './directive/each.js'
9
9
  import './directive/ref.js'
10
- import './directive/scope.js'
10
+ import './directive/with.js'
11
11
  import './directive/html.js'
12
12
  import './directive/text.js'
13
13
  import './directive/class.js'
@@ -26,4 +26,3 @@ sprae.use({ compile: expr => sprae.constructor(`__scope`, `with (__scope) { retu
26
26
  sprae.use({ swap })
27
27
 
28
28
  export default sprae
29
- export * from './core.js'