sprae 2.14.1 → 3.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/package.json +3 -5
- package/r&d.md +33 -30
- package/readme.md +6 -88
- package/sprae.js +248 -590
- package/sprae.min.js +1 -1
- package/src/core.js +12 -6
- package/src/directives.js +13 -16
- package/src/state.js +113 -0
- package/src/weakish-map.js +29 -0
- package/test/dom.js +935 -0
- package/test/index.html +2 -1
- package/test/state.js +274 -0
- package/test/test.js +2 -915
- package/todo.md +4 -4
package/sprae.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(){throw new Error("Cycle detected")}function e(){if(n>1)n--;else{for(var t,e=!1;void 0!==i;){var r=i;for(i=void 0,o++;void 0!==r;){var s=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&f(r))try{r.c()}catch(r){e||(t=r,e=!0)}r=s}}if(o=0,n--,e)throw t}}var r=void 0,i=void 0,n=0,o=0,s=0;function l(t){if(void 0!==r){var e=t.n;if(void 0===e||e.t!==r)return e={i:0,S:t,p:r.s,n:void 0,t:r,e:void 0,x:void 0,r:e},void 0!==r.s&&(r.s.n=e),r.s=e,t.n=e,32&r.f&&t.S(e),e;if(-1===e.i)return e.i=0,void 0!==e.n&&(e.n.p=e.p,void 0!==e.p&&(e.p.n=e.n),e.p=r.s,e.n=void 0,r.s.n=e,r.s=e),e}}function a(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function f(t){for(var e=t.s;void 0!==e;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function u(t){for(var e=t.s;void 0!==e;e=e.n){var r=e.S.n;if(void 0!==r&&(e.r=r),e.S.n=e,e.i=-1,void 0===e.n){t.s=e;break}}}function c(t){for(var e=t.s,r=void 0;void 0!==e;){var i=e.p;-1===e.i?(e.S.U(e),void 0!==i&&(i.n=e.n),void 0!==e.n&&(e.n.p=i)):r=e,e.S.n=e.r,void 0!==e.r&&(e.r=void 0),e=i}t.s=r}function h(t){a.call(this,void 0),this.x=t,this.s=void 0,this.g=s-1,this.f=4}function v(t){var i=t.u;if(t.u=void 0,"function"==typeof i){n++;var o=r;r=void 0;try{i()}catch(e){throw t.f&=-2,t.f|=8,p(t),e}finally{r=o,e()}}}function p(t){for(var e=t.s;void 0!==e;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,v(t)}function d(t){if(r!==this)throw new Error("Out-of-order effect");c(this),r=t,this.f&=-2,8&this.f&&p(this),e()}function y(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}function b(t){var e=new y(t);try{e.c()}catch(t){throw e.d(),t}return e.d.bind(e)}a.prototype.h=function(){return!0},a.prototype.S=function(t){this.t!==t&&void 0===t.e&&(t.x=this.t,void 0!==this.t&&(this.t.e=t),this.t=t)},a.prototype.U=function(t){if(void 0!==this.t){var e=t.e,r=t.x;void 0!==e&&(e.x=r,t.e=void 0),void 0!==r&&(r.e=e,t.x=void 0),t===this.t&&(this.t=r)}},a.prototype.subscribe=function(t){var e=this;return b((function(){var r=e.value,i=32&this.f;this.f&=-33;try{t(r)}finally{this.f|=i}}))},a.prototype.valueOf=function(){return this.value},a.prototype.toString=function(){return this.value+""},a.prototype.peek=function(){return this.v},Object.defineProperty(a.prototype,"value",{get:function(){var t=l(this);return void 0!==t&&(t.i=this.i),this.v},set:function(r){if(r!==this.v){o>100&&t(),this.v=r,this.i++,s++,n++;try{for(var i=this.t;void 0!==i;i=i.x)i.t.N()}finally{e()}}}}),(h.prototype=new a).h=function(){if(this.f&=-3,1&this.f)return!1;if(32==(36&this.f))return!0;if(this.f&=-5,this.g===s)return!0;if(this.g=s,this.f|=1,this.i>0&&!f(this))return this.f&=-2,!0;var t=r;try{u(this),r=this;var e=this.x();(16&this.f||this.v!==e||0===this.i)&&(this.v=e,this.f&=-17,this.i++)}catch(t){this.v=t,this.f|=16,this.i++}return r=t,c(this),this.f&=-2,!0},h.prototype.S=function(t){if(void 0===this.t){this.f|=36;for(var e=this.s;void 0!==e;e=e.n)e.S.S(e)}a.prototype.S.call(this,t)},h.prototype.U=function(t){if(void 0!==this.t&&(a.prototype.U.call(this,t),void 0===this.t)){this.f&=-33;for(var e=this.s;void 0!==e;e=e.n)e.S.U(e)}},h.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},h.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(h.prototype,"value",{get:function(){1&this.f&&t();var e=l(this);if(this.h(),void 0!==e&&(e.i=this.i),16&this.f)throw this.v;return this.v}}),y.prototype.c=function(){var t=this.S();try{8&this.f||void 0===this.x||(this.u=this.x())}finally{t()}},y.prototype.S=function(){1&this.f&&t(),this.f|=1,this.f&=-9,v(this),u(this),n++;var e=r;return r=this,d.bind(this,e)},y.prototype.N=function(){2&this.f||(this.f|=2,this.o=i,i=this)},y.prototype.d=function(){this.f|=8,1&this.f||p(this)},Symbol.observable||=Symbol("observable");var g=new FinalizationRegistry((t=>t.call?.())),m=(t,e,r,i,n,o)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,r,i),o=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(n,e)||(t.then?.((t=>(!n&&e(t),i?.())),r)||(async o=>{try{for await(o of t){if(n)return;e(o)}i?.()}catch(t){r?.(t)}})())&&(t=>n=1),g.register(t,o),o);var s},w=t=>t&&t[k],k=Symbol("signal-struct");function S(t,e){if(w(t)&&!e)return t;if(A(t)){const n=Object.create(e||Object.getPrototypeOf(t)),o={},s=Object.getOwnPropertyDescriptors(t);for(let t in s){let e=s[t];if(e.get){let r=o[t]=new h(e.get.bind(n));Object.defineProperty(n,t,{get:()=>r.value,set:e.set?.bind(n),configurable:!1,enumerable:!0})}else{let s=e.value,l=(i=s)&&!!(i[Symbol.observable]||i[Symbol.asyncIterator]||i.call&&i.set||i.subscribe||i.then),f=o[t]=(r=s)&&r.peek?s:new a(l?void 0:A(s)?Object.seal(S(s)):Array.isArray(s)?S(s):s);l&&m(s,(t=>f.value=t)),Object.defineProperty(n,t,{get:()=>f.value,set(t){if(A(t)){if(A(f.value))try{return void Object.assign(f.value,t)}catch(t){}f.value=Object.seal(S(t))}else Array.isArray(t)?f.value=S(t):f.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,k,{configurable:!1,enumerable:!1,value:!0}),n}var r,i;if(Array.isArray(t)&&!w(t[0]))for(let e=0;e<t.length;e++)t[e]=S(t[e]);return t}function A(t){return t&&t.constructor===Object}S.isStruct=w;var x={},O={},j={},N=t=>null===t?O:void 0===t?j:"number"==typeof t||t instanceof Number?x[t]||(x[t]=new Number(t)):"string"==typeof t||t instanceof String?x[t]||(x[t]=new String(t)):"boolean"==typeof t||t instanceof Boolean?x[t]||(x[t]=new Boolean(t)):t,E={},W={};E.if=(t,e)=>{let r=document.createTextNode(""),i=[_(t,e,":if")],n=[t],o=t;for(;(o=t.nextElementSibling)&&o.hasAttribute(":else");)o.removeAttribute(":else"),(e=o.getAttribute(":if"))?(o.removeAttribute(":if"),o.remove(),n.push(o),i.push(_(t,e,":else :if"))):(o.remove(),n.push(o),i.push((()=>1)));return t.replaceWith(o=r),t=>{let e=i.findIndex((e=>e(t)));n[e]!=o&&((o[$]||o).replaceWith(o=n[e]||r),F(o,t))}},E.with=(t,e,r)=>{F(t,S(_(t,e,"with")(r),r))};var $=Symbol(":each");E.each=(t,e)=>{let r=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let i=r[2].trim(),n=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),i]:[n,"",i]}(e);if(!r)return L(new Error,t,e);const i=t[$]=document.createTextNode("");t.replaceWith(i);const n=_(t,r[2],":each"),o=t.getAttribute(":key"),s=o?_(null,o):null;t.removeAttribute(":key");const l=new WeakMap,a=new WeakMap;let f=[];return o=>{let u=n(o);u?"number"==typeof u?u=Array.from({length:u},((t,e)=>[e,e+1])):Array.isArray(u)?u=u.map(((t,e)=>[e+1,t])):"object"==typeof u?u=Object.entries(u):L(Error("Bad list value"),t,e,":each"):u=[];let c=[],h=[];for(let[e,i]of u){let n,f,u=s?.({[r[0]]:i,[r[1]]:e});("string"==typeof(v=u)||"boolean"==typeof v||"number"==typeof v)&&(u=N(u)),null==u?n=t.cloneNode(!0):(n=a.get(u))||a.set(u,n=t.cloneNode(!0)),c.push(n),null!=u&&(f=l.get(u))?f[r[0]]=i:(f=S({[r[0]]:i,[r[1]]:e},o),null!=u&&l.set(u,f)),h.push(f)}var v;!function(t,e,r,i){const n=new Map,o=new Map;let s,l;for(s=0;s<e.length;s++)n.set(e[s],s);for(s=0;s<r.length;s++)o.set(r[s],s);for(s=l=0;s!==e.length||l!==r.length;){var a=e[s],f=r[l];if(null===a)s++;else if(r.length<=l)t.removeChild(e[s]),s++;else if(e.length<=s)t.insertBefore(f,e[s]||i),l++;else if(a===f)s++,l++;else{var u=o.get(a),c=n.get(f);void 0===u?(t.removeChild(e[s]),s++):void 0===c?(t.insertBefore(f,e[s]||i),l++):(t.insertBefore(e[c],e[s]||i),e[c]=null,c>s+1&&s++,l++)}}}(i.parentNode,f,c,i),f=c;for(let t=0;t<c.length;t++)F(c[t],h[t])}},W.ref=(t,e,r)=>{r[e]=t},W.id=(t,e)=>{let r=_(t,e,":id");return e=>{return i=r(e),t.id=i||0===i?i:"";var i}},W.class=(t,e)=>{let r=_(t,e,":class"),i=t.className;return e=>{let n=r(e),o="string"==typeof n?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ");t.className=[i,o].filter(Boolean).join(" ")}},W.style=(t,e)=>{let r=_(t,e,":style"),i=t.getAttribute("style")||"";return i.endsWith(";")||(i+="; "),e=>{let n=r(e);if("string"==typeof n)t.setAttribute("style",i+n);else{t.setAttribute("style",i);for(let e in n)t.style.setProperty(e,n[e])}}},W.text=(t,e)=>{let r=_(t,e,":text");return e=>{let i=r(e);t.textContent=null==i?"":i}},W.data=(t,e)=>{let r=_(t,e,":data");return e=>{let i=r(e);for(let e in i)t.dataset[e]=i[e]}},W.aria=(t,e)=>{let r=_(t,e,":aria");return e=>(e=>{for(let r in e)U(t,"aria-"+R(r),null==e[r]?null:e[r]+"")})(r(e))},W[""]=(t,e)=>{let r=_(t,e,":");if(r)return e=>{let i=r(e);for(let e in i)U(t,R(e),i[e])}},W.value=(t,e)=>{let r,i,n=_(t,e,":value"),o="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(r=t.selectionStart,i=t.selectionEnd,t.setAttribute("value",t.value=null==e?"":e),r&&t.setSelectionRange(r,i)):"checkbox"===t.type?e=>(t.value=e?"on":"",U(t,"checked",e)):"select-one"===t.type?e=>{for(let e in t.options)e.removeAttribute("selected");t.value=e,t.selectedOptions[0]?.setAttribute("selected","")}:e=>t.value=e;return t=>o(n(t))},W.on=(t,e)=>{let r=_(t,e,":on");return e=>{let i=r(e),n=[];for(let e in i)n.push(B(t,e,i[e]));return()=>{for(let t of n)t()}}};var C=(t,e,r,i)=>{let n=i.startsWith("on")&&i.slice(2),o=_(t,e,":"+i);if(o)return n?e=>{let r=o(e)||(()=>{});return B(t,n,r)}:e=>U(t,i,o(e))},B=(t,e,r)=>{if(!r)return;let i=e.split("..").map((e=>{let r={evt:"",target:t,test:()=>!0};return r.evt=(e.startsWith("on")?e.slice(2):e).replace(/\.(\w+)?-?([-\w]+)?/g,((t,e,i="")=>(r.test=P[e]?.(r,...i.split("-"))||r.test,""))),r}));if(1==i.length)return s(r,i[0]);const n=(e,r=0)=>{let o;return o=s((s=>{r&&o();let l=e.call(t,s);"function"!=typeof l&&(l=()=>{}),r+1<i.length&&n(l,r?r+1:1)}),i[r])};let o=n(r);return()=>o();function s(t,{evt:e,target:r,test:i,defer:n,stop:o,prevent:s,...l}){n&&(t=n(t));let a=e=>i(e)&&(o&&e.stopPropagation(),s&&e.preventDefault(),t.call(r,e));return r.addEventListener(e,a,l),()=>r.removeEventListener(e,a,l)}},P={prevent(t){t.prevent=!0},stop(t){t.stop=!0},once(t){t.once=!0},passive(t){t.passive=!0},capture(t){t.capture=!0},window(t){t.target=window},document(t){t.target=document},toggle(t){t.defer=(e,r)=>i=>r?(r.call?.(t.target,i),r=null):r=e()},throttle(t,e){t.defer=t=>D(t,e?Number(e)||0:108)},debounce(t,e){t.defer=t=>M(t,e?Number(e)||0:108)},outside:t=>e=>{let r=t.target;return!(r.contains(e.target)||!1===e.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:t=>e=>e.target===t.target,ctrl:(t,...e)=>t=>T.ctrl(t)&&e.every((e=>T[e]?T[e](t):t.key===e)),shift:(t,...e)=>t=>T.shift(t)&&e.every((e=>T[e]?T[e](t):t.key===e)),alt:(t,...e)=>t=>T.alt(t)&&e.every((e=>T[e]?T[e](t):t.key===e)),meta:(t,...e)=>t=>T.meta(t)&&e.every((e=>T[e]?T[e](t):t.key===e)),arrow:t=>T.arrow,enter:t=>T.enter,escape:t=>T.escape,tab:t=>T.tab,space:t=>T.space,backspace:t=>T.backspace,delete:t=>T.delete,digit:t=>T.digit,letter:t=>T.letter,character:t=>T.character},T={ctrl:t=>t.ctrlKey||"Control"===t.key||"Ctrl"===t.key,shift:t=>t.shiftKey||"Shift"===t.key,alt:t=>t.altKey||"Alt"===t.key,meta:t=>t.metaKey||"Meta"===t.key||"Command"===t.key,arrow:t=>t.key.startsWith("Arrow"),enter:t=>"Enter"===t.key,escape:t=>t.key.startsWith("Esc"),tab:t=>"Tab"===t.key,space:t=>" "===t.key||"Space"===t.key||" "===t.key,backspace:t=>"Backspace"===t.key,delete:t=>"Delete"===t.key,digit:t=>/^\d$/.test(t.key),letter:t=>/^[a-zA-Z]$/.test(t.key),character:t=>/^\S$/.test(t.key)},D=(t,e)=>{let r,i,n=o=>{r=!0,setTimeout((()=>{if(r=!1,i)return i=!1,n(o),t(o)}),e)};return e=>r?i=!0:(n(e),t(e))},M=(t,e)=>{let r;return i=>{clearTimeout(r),r=setTimeout((()=>{r=null,t(i)}),e)}},U=(t,e,r)=>{null==r||!1===r?t.removeAttribute(e):t.setAttribute(e,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},K={};function _(t,e,r){let i=K[e];if(!i){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/\b(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{i=K[e]=new Function("__scope",`with (__scope) { return ${n.trim()} };`)}catch(i){return L(i,t,e,r)}}return n=>{let o;try{o=i.call(t,n)}catch(i){return L(i,t,e,r)}return o}}function L(t,e,r,i){Object.assign(t,{element:e,expression:r}),console.warn(`∴ ${t.message}\n\n${i}=${r?`"${r}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function R(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var z=new WeakMap;function F(t,r){if(!t.children)return;if(z.has(t)){let i=z.get(t);return function(t){if(n>0)return t();n++;try{t()}finally{e()}}((()=>Object.assign(i,r))),i}const i=S(r||{}),o=[],s=(t,e=t.parentNode)=>{for(let r in E){let n=":"+r;if(t.hasAttribute?.(n)){let s=t.getAttribute(n);if(t.removeAttribute(n),o.push(E[r](t,s,i,r)),z.has(t)||t.parentNode!==e)return!1}}if(t.attributes)for(let r=0;r<t.attributes.length;){let n=t.attributes[r];if(":"!==n.name[0]){r++;continue}t.removeAttribute(n.name);let s=n.value,l=n.name.slice(1).split(":");for(let r of l){let n=W[r]||C;if(o.push(n(t,s,i,r)),z.has(t)||t.parentNode!==e)return!1}}for(let e,r=0;e=t.children[r];r++)!1===s(e,t)&&r--};s(t);for(let t of o)if(t){let e;b((()=>{"function"==typeof e&&e(),e=t(i)}))}return Object.seal(i),z.set(t,i),i}var I=F;export{I as default};
|
|
1
|
+
var e,t,r=new WeakMap,n=new WeakMap,l=new WeakMap,s=Symbol("parent"),a={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console},i={has:()=>!0,get(t,l){if("symbol"==typeof l)return t[l];if(!(l in t))return t[s]?.[l];if(Array.isArray(t)&&l in Array.prototype)return t[l];let a=t[l];if(e){let n=r.get(t);n||r.set(t,n={}),n[l]?n[l].includes(e)||n[l].push(e):n[l]=[e]}if(a&&a.constructor===Object||Array.isArray(a)){let e=n.get(a);return e||n.set(a,e=new Proxy(a,i)),e}return a},set(e,n,l){if(!(n in e)&&e[s]&&n in e[s])return e[s][n]=l;if(Array.isArray(e)&&n in Array.prototype)return e[n]=l;const a=e[n];if(Object.is(a,l))return!0;e[n]=l;let i=r.get(e)?.[n];if(i)for(let e of i)t?t.add(e):e.call();return!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},o=(e,t)=>{if(n.has(e))return n.get(e);if(l.has(e))return e;let r=new Proxy(e,i);return n.set(e,r),l.set(r,e),e[s]=t?o(t):a,r},u=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},c=new WeakMap,f=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>c.get(e)||(e=>{const t=new WeakRef(e);return c.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},p={},y={};p.if=(e,t)=>{let r=document.createTextNode(""),n=[x(e,t,":if")],l=[e],s=e;for(;(s=e.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(t=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),l.push(s),n.push(x(e,t,":else :if"))):(s.remove(),l.push(s),n.push((()=>1)));return e.replaceWith(s=r),e=>{let t=n.findIndex((t=>t(e)));l[t]!=s&&((s[h]||s).replaceWith(s=l[t]||r),j(s,e))}},p.with=(e,t,r)=>{const n=x(e,t,"with")(r);j(e,o(n,r))};var h=Symbol(":each");p.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),l=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),s=l.match(t);return s?[l.replace(t,"").trim(),s[1].trim(),n]:[l,"",n]}(t);if(!r)return W(new Error,e,t);const n=e[h]=document.createTextNode("");e.replaceWith(n);const l=x(e,r[2],":each"),s=e.getAttribute(":key"),a=s?x(null,s):null;e.removeAttribute(":key");const i=e.getAttribute(":ref"),u=new f,c=new f;let p=[];return s=>{let f=l(s);f?"number"==typeof f?f=Array.from({length:f},((e,t)=>[t,t+1])):Array.isArray(f)?f=f.map(((e,t)=>[t+1,e])):"object"==typeof f?f=Object.entries(f):W(Error("Bad list value"),e,t,":each"):f=[];let y=[],h=[];for(let[t,n]of f){let l,f,p=a?.({[r[0]]:n,[r[1]]:t});null==p?l=e.cloneNode(!0):(l=c.get(p))||c.set(p,l=e.cloneNode(!0)),y.push(l),null!=p&&(f=u.get(p))?f[r[0]]=n:(f=o({[r[0]]:n,[i||""]:null,[r[1]]:t},s),null!=p&&u.set(p,f)),h.push(f)}!function(e,t,r,n){const l=new Map,s=new Map;let a,i;for(a=0;a<t.length;a++)l.set(t[a],a);for(a=0;a<r.length;a++)s.set(r[a],a);for(a=i=0;a!==t.length||i!==r.length;){var o=t[a],u=r[i];if(null===o)a++;else if(r.length<=i)e.removeChild(t[a]),a++;else if(t.length<=a)e.insertBefore(u,t[a]||n),i++;else if(o===u)a++,i++;else{var c=s.get(o),f=l.get(u);void 0===c?(e.removeChild(t[a]),a++):void 0===f?(e.insertBefore(u,t[a]||n),i++):(e.insertBefore(t[f],t[a]||n),t[f]=null,f>a+1&&a++,i++)}}}(n.parentNode,p,y,n),p=y;for(let e=0;e<y.length;e++)j(y[e],h[e])}},y.ref=(e,t,r)=>{r[t]=e},y.id=(e,t)=>{let r=x(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},y.class=(e,t)=>{let r=x(e,t,":class"),n=e.className;return t=>{let l=r(t),s="string"==typeof l?l:(Array.isArray(l)?l:Object.entries(l).map((([e,t])=>t?e:""))).filter(Boolean).join(" ");e.className=[n,s].filter(Boolean).join(" ")}},y.style=(e,t)=>{let r=x(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let l=r(t);if("string"==typeof l)e.setAttribute("style",n+l);else{e.setAttribute("style",n);for(let t in l)e.style.setProperty(t,l[t])}}},y.text=(e,t)=>{let r=x(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},y.data=(e,t)=>{let r=x(e,t,":data");return t=>{let n=r(t);for(let t in n)e.dataset[t]=n[t]}},y.aria=(e,t)=>{let r=x(e,t,":aria");return t=>(t=>{for(let r in t)k(e,"aria-"+N(r),null==t[r]?null:t[r]+"")})(r(t))},y[""]=(e,t)=>{let r=x(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)k(e,N(t),n[t])}},y.value=(e,t)=>{let r,n,l=x(e,t,":value"),s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",k(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 e=>s(l(e))},y.on=(e,t)=>{let r=x(e,t,":on");return t=>{let n=r(t),l=[];for(let t in n)l.push(d(e,t,n[t]));return()=>{for(let e of l)e()}}};var g=(e,t,r,n)=>{let l=n.startsWith("on")&&n.slice(2),s=x(e,t,":"+n);if(s)return l?t=>{let r=s(t)||(()=>{});return d(e,l,r)}:t=>k(e,n,s(t))},d=(e,t,r)=>{if(!r)return;let n=t.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,n="")=>(r.test=m[t]?.(r,...n.split("-"))||r.test,""))),r}));if(1==n.length)return a(r,n[0]);const l=(t,r=0)=>{let s;return s=a((a=>{r&&s();let i=t.call(e,a);"function"!=typeof i&&(i=()=>{}),r+1<n.length&&l(i,r?r+1:1)}),n[r])};let s=l(r);return()=>s();function a(e,{evt:t,target:r,test:n,defer:l,stop:s,prevent:a,...i}){l&&(e=l(e));let o=t=>n(t)&&(s&&t.stopPropagation(),a&&t.preventDefault(),e.call(r,t));return r.addEventListener(t,o,i),()=>r.removeEventListener(t,o,i)}},m={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},toggle(e){e.defer=(t,r)=>n=>r?(r.call?.(e.target,n),r=null):r=t()},throttle(e,t){e.defer=e=>v(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>A(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=>b.ctrl(e)&&t.every((t=>b[t]?b[t](e):e.key===t)),shift:(e,...t)=>e=>b.shift(e)&&t.every((t=>b[t]?b[t](e):e.key===t)),alt:(e,...t)=>e=>b.alt(e)&&t.every((t=>b[t]?b[t](e):e.key===t)),meta:(e,...t)=>e=>b.meta(e)&&t.every((t=>b[t]?b[t](e):e.key===t)),arrow:e=>b.arrow,enter:e=>b.enter,escape:e=>b.escape,tab:e=>b.tab,space:e=>b.space,backspace:e=>b.backspace,delete:e=>b.delete,digit:e=>b.digit,letter:e=>b.letter,character:e=>b.character},b={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)},v=(e,t)=>{let r,n,l=s=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,l(s),e(s)}),t)};return t=>r?n=!0:(l(t),e(t))},A=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},k=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},w={};function x(e,t,r){let n=w[t];if(!n){let l=/^[\n\s]*if.*\(.*\)/.test(t)||/\b(let|const)\s/.test(t)&&!r.startsWith(":on")?`(() => {${t}})()`:t;try{n=w[t]=new Function("__scope",`with (__scope) { return ${l.trim()} };`)}catch(n){return W(n,e,t,r)}}return l=>{let s;try{s=n.call(e,l)}catch(n){return W(n,e,t,r)}return s}}function W(e,t,r,n){Object.assign(e,{element:t,expression:r}),console.warn(`∴ ${e.message}\n\n${n}=${r?`"${r}"\n\n`:""}`,t),queueMicrotask((()=>{throw e}),0)}function N(e){return e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase()))}j.sandbox=a;var S=new WeakMap;function j(e,r){if(!e.children)return;if(S.has(e)){let n=S.get(e);return(e=>{let l=t;t=new Set,Object.assign(n,r);for(let e of t)e.call();t.clear(),t=l})(),n}const n=o(r||{}),l=[],s=(e,t=e.parentNode)=>{for(let r in p){let s=":"+r;if(e.hasAttribute?.(s)){let a=e.getAttribute(s);if(e.removeAttribute(s),l.push(p[r](e,a,n,r)),S.has(e)||e.parentNode!==t)return!1}}if(e.attributes)for(let r=0;r<e.attributes.length;){let s=e.attributes[r];if(":"!==s.name[0]){r++;continue}e.removeAttribute(s.name);let a=s.value,i=s.name.slice(1).split(":");for(let r of i){let s=y[r]||g;if(l.push(s(e,a,n,r)),S.has(e)||e.parentNode!==t)return!1}}for(let t,r=0;t=e.children[r];r++)!1===s(t,e)&&r--};s(e);for(let e of l)if(e){let t;u((()=>{"function"==typeof t&&t(),t=e(n)}))}return S.set(e,n),n}var E=j;export{E as default};
|
package/src/core.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { state as createState, fx, batch, sandbox } from './state.js';
|
|
2
2
|
import defaultDirective, { primary, secondary } from './directives.js';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
sprae.sandbox=sandbox
|
|
4
5
|
|
|
5
6
|
// sprae element: apply directives
|
|
6
7
|
const memo = new WeakMap
|
|
@@ -12,8 +13,14 @@ export default function sprae(container, values) {
|
|
|
12
13
|
return state
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
-
|
|
16
|
+
// subscribe to reactives
|
|
17
|
+
// for (let prop in values) {
|
|
18
|
+
// if (observable(values[prop])) {
|
|
19
|
+
// let value = values[prop]; values[prop] = null
|
|
20
|
+
// sube(value, value => state[prop] = value)
|
|
21
|
+
// }
|
|
22
|
+
// }
|
|
23
|
+
const state = createState(values || {});
|
|
17
24
|
const updates = []
|
|
18
25
|
|
|
19
26
|
// init directives on element
|
|
@@ -64,13 +71,12 @@ export default function sprae(container, values) {
|
|
|
64
71
|
// state is created after inits because directives can extend init values (expose refs etc)
|
|
65
72
|
for (let update of updates) if (update) {
|
|
66
73
|
let teardown
|
|
67
|
-
|
|
74
|
+
fx(() => {
|
|
68
75
|
if (typeof teardown === 'function') teardown()
|
|
69
76
|
teardown = update(state)
|
|
70
77
|
});
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
Object.seal(state);
|
|
74
80
|
memo.set(container, state);
|
|
75
81
|
|
|
76
82
|
return state;
|
package/src/directives.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// directives & parsing
|
|
2
2
|
import sprae from './core.js'
|
|
3
3
|
import swap from './domdiff.js'
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import { state as createState} from './state.js'
|
|
5
|
+
import { WeakishMap } from './weakish-map.js'
|
|
6
6
|
|
|
7
7
|
// reserved directives - order matters!
|
|
8
8
|
// primary initialized first by selector, secondary initialized by iterating attributes
|
|
@@ -47,7 +47,10 @@ primary['if'] = (el, expr) => {
|
|
|
47
47
|
// :with must come before :each, but :if has primary importance
|
|
48
48
|
primary['with'] = (el, expr, rootState) => {
|
|
49
49
|
let evaluate = parseExpr(el, expr, 'with')
|
|
50
|
-
|
|
50
|
+
const localState = evaluate(rootState)
|
|
51
|
+
let state = createState(localState, rootState)
|
|
52
|
+
// console.log(123, state.foo, state.bar)
|
|
53
|
+
sprae(el, state);
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
const _each = Symbol(':each')
|
|
@@ -68,9 +71,10 @@ primary['each'] = (tpl, expr) => {
|
|
|
68
71
|
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
69
72
|
tpl.removeAttribute(':key')
|
|
70
73
|
|
|
74
|
+
const refExpr = tpl.getAttribute(':ref');
|
|
71
75
|
|
|
72
|
-
const scopes = new
|
|
73
|
-
const itemEls = new
|
|
76
|
+
const scopes = new WeakishMap() // stores scope per data item
|
|
77
|
+
const itemEls = new WeakishMap() // element per data item
|
|
74
78
|
let curEls = []
|
|
75
79
|
|
|
76
80
|
return (state) => {
|
|
@@ -88,7 +92,6 @@ primary['each'] = (tpl, expr) => {
|
|
|
88
92
|
|
|
89
93
|
for (let [idx, item] of list) {
|
|
90
94
|
let el, scope, key = itemKey?.({[each[0]]: item, [each[1]]: idx})
|
|
91
|
-
if (isPrimitive(key)) key = p(key); // singletonize key
|
|
92
95
|
|
|
93
96
|
// we consider if data items are primitive, then nodes needn't be cached
|
|
94
97
|
// since likely they're very simple to create
|
|
@@ -98,7 +101,7 @@ primary['each'] = (tpl, expr) => {
|
|
|
98
101
|
newEls.push(el)
|
|
99
102
|
|
|
100
103
|
if (key == null || !(scope = scopes.get(key))) {
|
|
101
|
-
scope =
|
|
104
|
+
scope = createState({[each[0]]: item, [refExpr||'']: null, [each[1]]: idx}, state)
|
|
102
105
|
if (key != null) scopes.set(key, scope)
|
|
103
106
|
}
|
|
104
107
|
// need to explicitly set item to update existing children's values
|
|
@@ -107,7 +110,6 @@ primary['each'] = (tpl, expr) => {
|
|
|
107
110
|
elScopes.push(scope)
|
|
108
111
|
}
|
|
109
112
|
|
|
110
|
-
// swap is really fast & tiny
|
|
111
113
|
swap(holder.parentNode, curEls, newEls, holder)
|
|
112
114
|
curEls = newEls
|
|
113
115
|
|
|
@@ -179,7 +181,6 @@ secondary['style'] = (el, expr) => {
|
|
|
179
181
|
|
|
180
182
|
secondary['text'] = (el, expr) => {
|
|
181
183
|
let evaluate = parseExpr(el, expr, ':text')
|
|
182
|
-
|
|
183
184
|
return (state) => {
|
|
184
185
|
let value = evaluate(state)
|
|
185
186
|
el.textContent = value == null ? '' : value;
|
|
@@ -422,8 +423,8 @@ function parseExpr(el, expression, dir) {
|
|
|
422
423
|
// Support expressions starting with "if" statements like: "if (...) doSomething()"
|
|
423
424
|
|| /^[\n\s]*if.*\(.*\)/.test(expression)
|
|
424
425
|
// Support expressions starting with "let/const" like: "let foo = 'bar'"
|
|
425
|
-
|| /\b(let|const)\s/.test(expression)
|
|
426
|
-
? `(() => {
|
|
426
|
+
|| (/\b(let|const)\s/.test(expression) && !dir.startsWith(':on'))
|
|
427
|
+
? `(() => {${expression}})()`
|
|
427
428
|
: expression;
|
|
428
429
|
|
|
429
430
|
try {
|
|
@@ -445,13 +446,9 @@ function parseExpr(el, expression, dir) {
|
|
|
445
446
|
function exprError(error, element, expression, dir) {
|
|
446
447
|
Object.assign( error, { element, expression } )
|
|
447
448
|
console.warn(`∴ ${error.message}\n\n${dir}=${ expression ? `"${expression}"\n\n` : '' }`, element)
|
|
448
|
-
|
|
449
|
+
queueMicrotask(() => { throw error }, 0)
|
|
449
450
|
}
|
|
450
451
|
|
|
451
452
|
function dashcase(str) {
|
|
452
453
|
return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
|
|
453
454
|
};
|
|
454
|
-
|
|
455
|
-
function isPrimitive(obj) {
|
|
456
|
-
return typeof obj === 'string' || typeof obj === 'boolean' || typeof obj === 'number'
|
|
457
|
-
}
|
package/src/state.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// currentFx stack of listeners
|
|
2
|
+
let currentFx, currentBatch
|
|
3
|
+
|
|
4
|
+
const targetFxs = new WeakMap
|
|
5
|
+
const targetProxy = new WeakMap
|
|
6
|
+
const proxyTarget = new WeakMap
|
|
7
|
+
const _parent = Symbol('parent')
|
|
8
|
+
|
|
9
|
+
// default root sandbox
|
|
10
|
+
export const sandbox = {
|
|
11
|
+
Array, Object, Number, String, Boolean, Date,
|
|
12
|
+
console
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const handler = {
|
|
16
|
+
has(){
|
|
17
|
+
// sandbox everything
|
|
18
|
+
return true
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
get(target, prop) {
|
|
22
|
+
if (typeof prop === 'symbol') return target[prop]
|
|
23
|
+
if (!(prop in target)) return target[_parent]?.[prop]
|
|
24
|
+
if (Array.isArray(target) && prop in Array.prototype) return target[prop];
|
|
25
|
+
let value = target[prop]
|
|
26
|
+
|
|
27
|
+
if (currentFx) {
|
|
28
|
+
// get actual target from prototype chain
|
|
29
|
+
// while (!target.hasOwnProperty(prop)) target = Object.getPrototypeOf(target)
|
|
30
|
+
|
|
31
|
+
// register an fx for target-prop path
|
|
32
|
+
let propFxs = targetFxs.get(target)
|
|
33
|
+
if (!propFxs) targetFxs.set(target, propFxs = {})
|
|
34
|
+
if (!propFxs[prop]) propFxs[prop] = [currentFx]
|
|
35
|
+
else if (!propFxs[prop].includes(currentFx)) propFxs[prop].push(currentFx)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// if internal is trackable path - return proxy
|
|
39
|
+
if ((value && value.constructor === Object) || Array.isArray(value)) {
|
|
40
|
+
let proxy = targetProxy.get(value)
|
|
41
|
+
// FIXME: we can avoid saving it here, since it's created by new state
|
|
42
|
+
if (!proxy) targetProxy.set(value, proxy = new Proxy(value, handler))
|
|
43
|
+
return proxy
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return value
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
set(target, prop, value) {
|
|
50
|
+
if (!(prop in target) && (target[_parent] && prop in target[_parent])) return target[_parent][prop] = value
|
|
51
|
+
if (Array.isArray(target) && prop in Array.prototype) return target[prop] = value;
|
|
52
|
+
|
|
53
|
+
const prev = target[prop]
|
|
54
|
+
|
|
55
|
+
// avoid bumping unchanged values
|
|
56
|
+
if (Object.is(prev, value)) return true
|
|
57
|
+
|
|
58
|
+
target[prop] = value
|
|
59
|
+
|
|
60
|
+
// whenever target prop is set, call all dependent fxs
|
|
61
|
+
let propFxs = targetFxs.get(target)?.[prop]
|
|
62
|
+
|
|
63
|
+
if (propFxs) for (let fx of propFxs) currentBatch ? currentBatch.add(fx) : fx.call()
|
|
64
|
+
|
|
65
|
+
// FIXME: unsubscribe / delete effects by setting null/undefined
|
|
66
|
+
// if (value == null) targetFxs.delete(prev)
|
|
67
|
+
|
|
68
|
+
return true
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
deleteProperty(target, prop) {
|
|
72
|
+
target[prop] = undefined
|
|
73
|
+
delete target[prop]
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const state = (obj, parent) => {
|
|
79
|
+
if (targetProxy.has(obj)) return targetProxy.get(obj)
|
|
80
|
+
if (proxyTarget.has(obj)) return obj // is proxy already
|
|
81
|
+
|
|
82
|
+
let proxy = new Proxy(obj, handler)
|
|
83
|
+
targetProxy.set(obj, proxy)
|
|
84
|
+
proxyTarget.set(proxy, obj)
|
|
85
|
+
|
|
86
|
+
// inherit from parent state
|
|
87
|
+
obj[_parent] = parent ? state(parent) : sandbox
|
|
88
|
+
|
|
89
|
+
return proxy
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const fx = (fn) => {
|
|
93
|
+
const call = () => {
|
|
94
|
+
let prev = currentFx
|
|
95
|
+
currentFx = call
|
|
96
|
+
fn()
|
|
97
|
+
currentFx = prev
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// collect deps from the first call
|
|
101
|
+
call()
|
|
102
|
+
|
|
103
|
+
return call
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const batch = fn => {
|
|
107
|
+
let prevBatch = currentBatch
|
|
108
|
+
currentBatch = new Set
|
|
109
|
+
fn()
|
|
110
|
+
for (let fx of currentBatch) fx.call()
|
|
111
|
+
currentBatch.clear()
|
|
112
|
+
currentBatch = prevBatch
|
|
113
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// based on https://github.com/WebReflection/not-so-weak/
|
|
2
|
+
const refs = new WeakMap;
|
|
3
|
+
|
|
4
|
+
const set = value => {
|
|
5
|
+
const ref = new WeakRef(value);
|
|
6
|
+
refs.set(value, ref);
|
|
7
|
+
return ref;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const get = value => refs.get(value) || set(value);
|
|
11
|
+
|
|
12
|
+
export class WeakishMap extends Map {
|
|
13
|
+
#registry = new FinalizationRegistry(key => super.delete(key));
|
|
14
|
+
get size() { return [...this].length }
|
|
15
|
+
constructor(entries = []) {
|
|
16
|
+
super();
|
|
17
|
+
for (const [key, value] of entries) this.set(key, value);
|
|
18
|
+
}
|
|
19
|
+
get(key) {
|
|
20
|
+
return super.get(key)?.deref();
|
|
21
|
+
}
|
|
22
|
+
set(key, value) {
|
|
23
|
+
let ref = super.get(key);
|
|
24
|
+
if (ref) this.#registry.unregister(ref);
|
|
25
|
+
ref = get(value);
|
|
26
|
+
this.#registry.register(value, key, ref);
|
|
27
|
+
return super.set(key, ref);
|
|
28
|
+
}
|
|
29
|
+
}
|