sprae 2.10.2 → 2.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "2.10.2",
4
+ "version": "2.11.0",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
7
7
  "type": "module",
package/r&d.md CHANGED
@@ -350,6 +350,7 @@
350
350
  + allows `let a = 1; a;` case instead of `let a = 1; return a;`
351
351
  - we can't identify dynamic parts like `x[y]`, whereas signals subscribe dynamically
352
352
  ~ we can detect dynamic parts and handle them on proxy
353
+ + subscript allows subscriptions to async functions, unlike signals
353
354
 
354
355
  -> We can benchmark if updating set of known dependencies is faster than using preact subscriptions.
355
356
  + it seems more logical min-ground to know in advance what we depend on, rather than detect by-call as signals do.
@@ -464,6 +465,7 @@
464
465
  * [ ] prop.fx="" - run effect without changing property
465
466
  * [ ] x.prop="xyz" - set element property, rather than attribute (following topic)
466
467
  * [ ] x.raf="abc" - run regularly?
468
+ * [ ] x.watch-xyz - update by change of any of the deps
467
469
 
468
470
  ## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
469
471
 
package/sprae.js CHANGED
@@ -684,11 +684,12 @@ secondary["on"] = (el, expr) => {
684
684
  let evaluate = parseExpr(el, expr, ":on");
685
685
  return (state) => {
686
686
  let listeners = evaluate(state);
687
+ let offs = [];
687
688
  for (let evt in listeners)
688
- addListener(el, evt, listeners[evt]);
689
+ offs.push(on(el, evt, listeners[evt]));
689
690
  return () => {
690
- for (let evt in listeners)
691
- removeListener(el, evt, listeners[evt]);
691
+ for (let off of offs)
692
+ off();
692
693
  };
693
694
  };
694
695
  };
@@ -701,162 +702,127 @@ var directives_default = (el, expr, state, name) => {
701
702
  return (state2) => {
702
703
  let value = evaluate(state2) || (() => {
703
704
  });
704
- addListener(el, evt, value);
705
- return () => removeListener(el, evt, value);
705
+ return on(el, evt, value);
706
706
  };
707
707
  return (state2) => attr(el, name, evaluate(state2));
708
708
  };
709
- var _stop = Symbol("stop");
710
- var addListener = (el, evt, startFn) => {
711
- let evts = evt.split("..").map((e2) => e2.startsWith("on") ? e2.slice(2) : e2), opts = { target: el, hooks: [], fn: startFn };
712
- evts[0] = evts[0].replace(/\.(\w+)?-?([\w]+)?/g, (match, mod, param) => (mods[mod]?.(opts, param), ""));
713
- let { target, hooks, fn, ...listenerOpts } = opts;
714
- if (hooks.length) {
715
- let _fn = fn;
716
- fn = (e2) => {
717
- for (let hook of hooks)
718
- if (hook(e2) === false)
719
- return false;
720
- return _fn(e2);
709
+ var on = (target, evt, origFn) => {
710
+ let ctxs = evt.split("..").map((e2) => {
711
+ let ctx = { evt: "", target, test: () => true };
712
+ ctx.evt = (e2.startsWith("on") ? e2.slice(2) : e2).replace(
713
+ /\.(\w+)?-?([\w]+)?/g,
714
+ (match, mod, param) => (ctx.test = mods[mod]?.(ctx, param) || ctx.test, "")
715
+ );
716
+ return ctx;
717
+ });
718
+ if (!origFn)
719
+ origFn = () => {
721
720
  };
722
- }
723
- if (evts.length == 1)
724
- target.addEventListener(evts[0], fn, listenerOpts);
725
- else {
726
- const nextEvt = (handler, cur = 0) => {
727
- let curListener = (e2) => {
728
- target.removeEventListener(evts[cur], curListener);
729
- if (typeof (handler = handler.call(target, e2)) !== "function")
730
- handler = () => {
731
- };
732
- if (++cur < evts.length)
733
- nextEvt(handler, cur);
734
- else if (!fn[_stop])
735
- nextEvt(fn);
736
- };
737
- target.addEventListener(evts[cur], curListener, listenerOpts);
721
+ if (ctxs.length == 1)
722
+ return addListener(origFn, ctxs[0]);
723
+ let off;
724
+ const nextEvt = (fn, cur = 0) => {
725
+ let curListener = (e2) => {
726
+ off();
727
+ if (typeof (fn = fn.call(target, e2)) !== "function")
728
+ fn = () => {
729
+ };
730
+ if (++cur < ctxs.length)
731
+ nextEvt(fn, cur);
732
+ else
733
+ nextEvt(origFn);
738
734
  };
739
- nextEvt(fn);
740
- }
735
+ return off = addListener(curListener, ctxs[cur]);
736
+ };
737
+ nextEvt(origFn);
738
+ return () => off();
741
739
  };
742
- var removeListener = (el, evt, fn) => {
743
- if (evt.indexOf("..") >= 0)
744
- fn[_stop] = true;
745
- el.removeEventListener(evt, fn);
740
+ var addListener = (fn, { evt, target, test, delayed, stop, prevent, ...opts }) => {
741
+ if (delayed)
742
+ fn = delayed(fn);
743
+ let wrappedFn = (e2) => test(e2) && (stop && e2.stopPropagation(), prevent && e2.preventDefault(), fn.call(target, e2));
744
+ target.addEventListener(evt, wrappedFn, opts);
745
+ return () => target.removeEventListener(evt, wrappedFn, opts);
746
746
  };
747
747
  var mods = {
748
- prevent({ hooks }) {
749
- hooks.push((e2) => {
750
- e2.preventDefault();
751
- });
752
- },
753
- stop({ hooks }) {
754
- hooks.push((e2) => {
755
- e2.stopPropagation();
756
- });
757
- },
758
- throttle(opts, limit) {
759
- let { fn } = opts;
760
- limit = Number(limit) || 108;
761
- let pause, planned, block = (e2) => {
762
- pause = true;
763
- setTimeout(() => {
764
- pause = false;
765
- if (planned)
766
- return planned = false, block(), fn(e2);
767
- }, limit);
768
- };
769
- opts.fn = (e2) => {
770
- if (pause)
771
- return planned = true;
772
- block(e2);
773
- return fn(e2);
774
- };
775
- },
776
- debounce(opts, wait) {
777
- let { fn } = opts;
778
- wait = Number(wait) || 108;
779
- let timeout;
780
- opts.fn = (e2) => {
781
- clearTimeout(timeout);
782
- timeout = setTimeout(() => {
783
- timeout = null;
784
- fn(e2);
785
- }, wait);
786
- };
787
- },
788
- window(opts) {
789
- opts.target = window;
790
- },
791
- document(opts) {
792
- opts.target = document;
793
- },
794
- outside({ target, hooks }) {
795
- hooks.push((e2) => {
796
- if (target.contains(e2.target))
797
- return false;
798
- if (e2.target.isConnected === false)
799
- return false;
800
- if (target.offsetWidth < 1 && target.offsetHeight < 1)
801
- return false;
802
- });
748
+ prevent(ctx) {
749
+ ctx.prevent = true;
803
750
  },
804
- self({ target, hooks }) {
805
- hooks.push((e2) => {
806
- return e2.target === target;
807
- });
751
+ stop(ctx) {
752
+ ctx.stop = true;
808
753
  },
809
- once(opts) {
810
- opts.once = true;
754
+ once(ctx) {
755
+ ctx.once = true;
811
756
  },
812
- passive(opts) {
813
- opts.passive = true;
757
+ passive(ctx) {
758
+ ctx.passive = true;
814
759
  },
815
- capture(opts) {
816
- opts.capture = true;
760
+ capture(ctx) {
761
+ ctx.capture = true;
817
762
  },
818
- ctrl({ hooks }) {
819
- hooks.push((e2) => e2.key === "Control" || e2.key === "Ctrl");
763
+ window(ctx) {
764
+ ctx.target = window;
820
765
  },
821
- shift({ hooks }) {
822
- hooks.push((e2) => e2.key === "Shift");
766
+ document(ctx) {
767
+ ctx.target = document;
823
768
  },
824
- alt({ hooks }) {
825
- hooks.push((e2) => e2.key === "Alt");
769
+ throttle(ctx, limit) {
770
+ ctx.delayed = (fn) => throttle(fn, Number(limit) || 108);
826
771
  },
827
- meta({ hooks }) {
828
- hooks.push((e2) => e2.key === "Meta");
772
+ debounce(ctx, wait) {
773
+ ctx.delayed = (fn) => debounce(fn, Number(wait) || 108);
829
774
  },
830
- arrow({ hooks }) {
831
- hooks.push((e2) => e2.key.startsWith("Arrow"));
832
- },
833
- enter({ hooks }) {
834
- hooks.push((e2) => e2.key === "Enter");
835
- },
836
- escape({ hooks }) {
837
- hooks.push((e2) => e2.key.startsWith("Esc"));
838
- },
839
- tab({ hooks }) {
840
- hooks.push((e2) => e2.key === "Tab");
841
- },
842
- space({ hooks }) {
843
- hooks.push((e2) => e2.key === "Space" || e2.key === " ");
844
- },
845
- backspace({ hooks }) {
846
- hooks.push((e2) => e2.key === "Backspace");
847
- },
848
- delete({ hooks }) {
849
- hooks.push((e2) => e2.key === "Delete");
850
- },
851
- digit({ hooks }) {
852
- hooks.push((e2) => /\d/.test(e2.key));
853
- },
854
- letter({ hooks }) {
855
- hooks.push((e2) => /[a-zA-Z]/.test(e2.key));
775
+ outside: (ctx) => (e2) => {
776
+ let target = ctx.target;
777
+ if (target.contains(e2.target))
778
+ return false;
779
+ if (e2.target.isConnected === false)
780
+ return false;
781
+ if (target.offsetWidth < 1 && target.offsetHeight < 1)
782
+ return false;
783
+ return true;
856
784
  },
857
- character({ hooks }) {
858
- hooks.push((e2) => /^\S$/.test(e2.key));
859
- }
785
+ self: (ctx) => (e2) => e2.target === ctx.target,
786
+ ctrl: () => (e2) => e2.key === "Control" || e2.key === "Ctrl",
787
+ shift: () => (e2) => e2.key === "Shift",
788
+ alt: () => (e2) => e2.key === "Alt",
789
+ meta: () => (e2) => e2.key === "Meta",
790
+ arrow: () => (e2) => e2.key.startsWith("Arrow"),
791
+ enter: () => (e2) => e2.key === "Enter",
792
+ escape: () => (e2) => e2.key.startsWith("Esc"),
793
+ tab: () => (e2) => e2.key === "Tab",
794
+ space: () => (e2) => e2.key === "Space" || e2.key === " ",
795
+ backspace: () => (e2) => e2.key === "Backspace",
796
+ delete: () => (e2) => e2.key === "Delete",
797
+ digit: () => (e2) => /^\d$/.test(e2.key),
798
+ letter: () => (e2) => /^[a-zA-Z]$/.test(e2.key),
799
+ character: () => (e2) => /^\S$/.test(e2.key)
800
+ };
801
+ var throttle = (fn, limit) => {
802
+ let pause, planned, block = (e2) => {
803
+ pause = true;
804
+ setTimeout(() => {
805
+ pause = false;
806
+ if (planned)
807
+ return planned = false, block(e2), fn(e2);
808
+ }, limit);
809
+ };
810
+ return (e2) => {
811
+ if (pause)
812
+ return planned = true;
813
+ block(e2);
814
+ return fn(e2);
815
+ };
816
+ };
817
+ var debounce = (fn, wait) => {
818
+ let timeout;
819
+ return (e2) => {
820
+ clearTimeout(timeout);
821
+ timeout = setTimeout(() => {
822
+ timeout = null;
823
+ fn(e2);
824
+ }, wait);
825
+ };
860
826
  };
861
827
  var attr = (el, name, v2) => {
862
828
  if (v2 == null || v2 === false)
package/sprae.min.js CHANGED
@@ -1 +1 @@
1
- function t(){throw new Error("Cycle detected")}function e(){if(o>1)o--;else{for(var t,e=!1;void 0!==r;){var i=r;for(r=void 0,n++;void 0!==i;){var s=i.o;if(i.o=void 0,i.f&=-3,!(8&i.f)&&a(i))try{i.c()}catch(i){e||(t=i,e=!0)}i=s}}if(n=0,o--,e)throw t}}var i=void 0,r=void 0,o=0,n=0,s=0;function l(t){if(void 0!==i){var e=t.n;if(void 0===e||e.t!==i)return i.s=e={i:0,S:t,p:void 0,n:i.s,t:i,e:void 0,x:void 0,r:e},t.n=e,32&i.f&&t.S(e),e;if(-1===e.i)return e.i=0,void 0!==e.p&&(e.p.n=e.n,void 0!==e.n&&(e.n.p=e.p),e.p=void 0,e.n=i.s,i.s.p=e,i.s=e),e}}function u(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function a(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 f(t){for(var e=t.s;void 0!==e;e=e.n){var i=e.S.n;void 0!==i&&(e.r=i),e.S.n=e,e.i=-1}}function h(t){for(var e=t.s,i=void 0;void 0!==e;){var r=e.n;-1===e.i?(e.S.U(e),e.n=void 0):(void 0!==i&&(i.p=e),e.p=void 0,e.n=i,i=e),e.S.n=e.r,void 0!==e.r&&(e.r=void 0),e=r}t.s=i}function c(t){u.call(this,void 0),this.x=t,this.s=void 0,this.g=s-1,this.f=4}function v(t){var r=t.u;if(t.u=void 0,"function"==typeof r){o++;var n=i;i=void 0;try{r()}catch(e){throw t.f&=-2,t.f|=8,p(t),e}finally{i=n,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(i!==this)throw new Error("Out-of-order effect");h(this),i=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);return e.c(),e.d.bind(e)}u.prototype.h=function(){return!0},u.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)},u.prototype.U=function(t){var e=t.e,i=t.x;void 0!==e&&(e.x=i,t.e=void 0),void 0!==i&&(i.e=e,t.x=void 0),t===this.t&&(this.t=i)},u.prototype.subscribe=function(t){var e=this;return b((function(){var i=e.value,r=32&this.f;this.f&=-33;try{t(i)}finally{this.f|=r}}))},u.prototype.valueOf=function(){return this.value},u.prototype.toString=function(){return this.value+""},u.prototype.peek=function(){return this.v},Object.defineProperty(u.prototype,"value",{get:function(){var t=l(this);return void 0!==t&&(t.i=this.i),this.v},set:function(i){if(i!==this.v){n>100&&t(),this.v=i,this.i++,s++,o++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N()}finally{e()}}}}),(c.prototype=new u).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&&!a(this))return this.f&=-2,!0;var t=i;try{f(this),i=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 i=t,h(this),this.f&=-2,!0},c.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)}u.prototype.S.call(this,t)},c.prototype.U=function(t){if(u.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)}},c.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},c.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(c.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),f(this),o++;var e=i;return i=this,d.bind(this,e)},y.prototype.N=function(){2&this.f||(this.f|=2,this.o=r,r=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,i,r,o,n)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,i,r),n=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(o,e)||(t.then?.((t=>(!o&&e(t),r?.())),i)||(async n=>{try{for await(n of t){if(o)return;e(n)}r?.()}catch(t){i?.(t)}})())&&(t=>o=1),g.register(t,n),n);var s},k=t=>t&&t[w],w=Symbol("signal-struct");function S(t,e){if(k(t)&&!e)return t;if(A(t)){const o=Object.create(e||Object.getPrototypeOf(t)),n={},s=Object.getOwnPropertyDescriptors(t);for(let t in s){let e=s[t];if(e.get){let i=n[t]=new c(e.get.bind(o));Object.defineProperty(o,t,{get:()=>i.value,set:e.set?.bind(o),configurable:!1,enumerable:!0})}else{let s=e.value,l=(r=s)&&!!(r[Symbol.observable]||r[Symbol.asyncIterator]||r.call&&r.set||r.subscribe||r.then),a=n[t]=(i=s)&&i.peek?s:new u(l?void 0:A(s)?Object.seal(S(s)):Array.isArray(s)?S(s):s);l&&m(s,(t=>a.value=t)),Object.defineProperty(o,t,{get:()=>a.value,set(t){if(A(t)){if(A(a.value))try{return void Object.assign(a.value,t)}catch(t){}a.value=Object.seal(S(t))}else Array.isArray(t)?a.value=S(t):a.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(o,w,{configurable:!1,enumerable:!1,value:!0}),o}var i,r;if(Array.isArray(t)&&!k(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=k;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 i=document.createTextNode(""),r=[L(t,e,":if")],o=[t],n=t;for(;(n=t.nextElementSibling)&&n.hasAttribute(":else");)n.removeAttribute(":else"),(e=n.getAttribute(":if"))?(n.removeAttribute(":if"),n.remove(),o.push(n),r.push(L(t,e,":else :if"))):(n.remove(),o.push(n),r.push((()=>1)));return t.replaceWith(n=i),t=>{let e=r.findIndex((e=>e(t)));o[e]!=n&&((n[C]||n).replaceWith(n=o[e]||i),F(n,t))}},E.with=(t,e,i)=>{F(t,S(L(t,e,"with")(i),i))};var C=Symbol(":each");E.each=(t,e)=>{let i=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,i=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!i)return;let r=i[2].trim(),o=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),n=o.match(e);return n?[o.replace(e,"").trim(),n[1].trim(),r]:[o,"",r]}(e);if(!i)return _(new Error,t,e);const r=t[C]=document.createTextNode("");t.replaceWith(r);const o=L(t,i[2],":each"),n=t.getAttribute(":key"),s=n?L(null,n):null;t.removeAttribute(":key");const l=new WeakMap,u=new WeakMap;let a=[];return n=>{let f=o(n);f?"number"==typeof f?f=Array.from({length:f},((t,e)=>[e,e+1])):Array.isArray(f)?f=f.map(((t,e)=>[e+1,t])):"object"==typeof f?f=Object.entries(f):_(Error("Bad list value"),t,e,":each"):f=[];let h=[],c=[];for(let[e,r]of f){let o,a,f=s?.({[i[0]]:r,[i[1]]:e});("string"==typeof(v=f)||"boolean"==typeof v||"number"==typeof v)&&(f=N(f)),null==f?o=t.cloneNode(!0):(o=u.get(f))||u.set(f,o=t.cloneNode(!0)),h.push(o),null!=f&&(a=l.get(f))?a[i[0]]=r:(a=S({[i[0]]:r,[i[1]]:e},n),null!=f&&l.set(f,a)),c.push(a)}var v;!function(t,e,i,r){const o=new Map,n=new Map;let s,l;for(s=0;s<e.length;s++)o.set(e[s],s);for(s=0;s<i.length;s++)n.set(i[s],s);for(s=l=0;s!==e.length||l!==i.length;){var u=e[s],a=i[l];if(null===u)s++;else if(i.length<=l)t.removeChild(e[s]),s++;else if(e.length<=s)t.insertBefore(a,e[s]||r),l++;else if(u===a)s++,l++;else{var f=n.get(u),h=o.get(a);void 0===f?(t.removeChild(e[s]),s++):void 0===h?(t.insertBefore(a,e[s]||r),l++):(t.insertBefore(e[h],e[s]||r),e[h]=null,h>s+1&&s++,l++)}}}(r.parentNode,a,h,r),a=h;for(let t=0;t<h.length;t++)F(h[t],c[t])}},W.ref=(t,e,i)=>{i[e]=t},W.id=(t,e)=>{let i=L(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},W.class=(t,e)=>{let i=L(t,e,":class"),r=t.className;return e=>{let o=i(e);t.className=r+typeof o=="string"?o:(Array.isArray(o)?o:Object.entries(o).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},W.style=(t,e)=>{let i=L(t,e,":style"),r=t.getAttribute("style")||"";return r.endsWith(";")||(r+="; "),e=>{let o=i(e);if("string"==typeof o)t.setAttribute("style",r+o);else for(let e in o)t.style[e]=o[e]}},W.text=(t,e)=>{let i=L(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},W.data=(t,e)=>{let i=L(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},W.aria=(t,e)=>{let i=L(t,e,":aria");return e=>(e=>{for(let i in e)M(t,"aria-"+R(i),null==e[i]?null:e[i]+"")})(i(e))},W[""]=(t,e)=>{let i=L(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)M(t,R(e),r[e])}},W.value=(t,e)=>{let i,r,o=L(t,e,":value"),n="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(i=t.selectionStart,r=t.selectionEnd,t.setAttribute("value",t.value=null==e?"":e),i&&t.setSelectionRange(i,r)):"checkbox"===t.type?e=>(t.value=e?"on":"",M(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=>n(o(t))},W.on=(t,e)=>{let i=L(t,e,":on");return e=>{let r=i(e);for(let e in r)B(t,e,r[e]);return()=>{for(let e in r)P(t,e,r[e])}}};var T=(t,e,i,r)=>{let o=r.startsWith("on")&&r.slice(2),n=L(t,e,":"+r);if(n)return o?e=>{let i=n(e)||(()=>{});return B(t,o,i),()=>P(t,o,i)}:e=>M(t,r,n(e))},$=Symbol("stop"),B=(t,e,i)=>{let r=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),o={target:t,hooks:[],fn:i};r[0]=r[0].replace(/\.(\w+)?-?([\w]+)?/g,((t,e,i)=>(D[e]?.(o,i),"")));let{target:n,hooks:s,fn:l,...u}=o;if(s.length){let t=l;l=e=>{for(let t of s)if(!1===t(e))return!1;return t(e)}}if(1==r.length)n.addEventListener(r[0],l,u);else{const t=(e,i=0)=>{let o=s=>{n.removeEventListener(r[i],o),"function"!=typeof(e=e.call(n,s))&&(e=()=>{}),++i<r.length?t(e,i):l[$]||t(l)};n.addEventListener(r[i],o,u)};t(l)}},P=(t,e,i)=>{e.indexOf("..")>=0&&(i[$]=!0),t.removeEventListener(e,i)},D={prevent({hooks:t}){t.push((t=>{t.preventDefault()}))},stop({hooks:t}){t.push((t=>{t.stopPropagation()}))},throttle(t,e){let{fn:i}=t;e=Number(e)||108;let r,o,n=t=>{r=!0,setTimeout((()=>{if(r=!1,o)return o=!1,n(),i(t)}),e)};t.fn=t=>r?o=!0:(n(t),i(t))},debounce(t,e){let i,{fn:r}=t;e=Number(e)||108,t.fn=t=>{clearTimeout(i),i=setTimeout((()=>{i=null,r(t)}),e)}},window(t){t.target=window},document(t){t.target=document},outside({target:t,hooks:e}){e.push((e=>!t.contains(e.target)&&!1!==e.target.isConnected&&!(t.offsetWidth<1&&t.offsetHeight<1)&&void 0))},self({target:t,hooks:e}){e.push((e=>e.target===t))},once(t){t.once=!0},passive(t){t.passive=!0},capture(t){t.capture=!0},ctrl({hooks:t}){t.push((t=>"Control"===t.key||"Ctrl"===t.key))},shift({hooks:t}){t.push((t=>"Shift"===t.key))},alt({hooks:t}){t.push((t=>"Alt"===t.key))},meta({hooks:t}){t.push((t=>"Meta"===t.key))},arrow({hooks:t}){t.push((t=>t.key.startsWith("Arrow")))},enter({hooks:t}){t.push((t=>"Enter"===t.key))},escape({hooks:t}){t.push((t=>t.key.startsWith("Esc")))},tab({hooks:t}){t.push((t=>"Tab"===t.key))},space({hooks:t}){t.push((t=>"Space"===t.key||" "===t.key))},backspace({hooks:t}){t.push((t=>"Backspace"===t.key))},delete({hooks:t}){t.push((t=>"Delete"===t.key))},digit({hooks:t}){t.push((t=>/\d/.test(t.key)))},letter({hooks:t}){t.push((t=>/[a-zA-Z]/.test(t.key)))},character({hooks:t}){t.push((t=>/^\S$/.test(t.key)))}},M=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")},U={};function L(t,e,i){let r=U[e];if(!r){let o=/^[\n\s]*if.*\(.*\)/.test(e)||/\b(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=U[e]=new Function("__scope",`with (__scope) { return ${o} };`)}catch(r){return _(r,t,e,i)}}return o=>{let n;try{n=r.call(t,o)}catch(r){return _(r,t,e,i)}return n}}function _(t,e,i,r){Object.assign(t,{element:e,expression:i}),console.warn(`∴ ${t.message}\n\n${r}=${i?`"${i}"\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,i){if(!t.children)return;if(z.has(t)){let r=z.get(t);return function(t){if(o>0)return t();o++;try{t()}finally{e()}}((()=>Object.assign(r,i))),r}const r=S(i||{}),n=[],s=(t,e=t.parentNode)=>{for(let i in E){let o=":"+i;if(t.hasAttribute?.(o)){let s=t.getAttribute(o);if(t.removeAttribute(o),n.push(E[i](t,s,r,i)),z.has(t)||t.parentNode!==e)return!1}}if(t.attributes)for(let i=0;i<t.attributes.length;){let o=t.attributes[i];if(":"!==o.name[0]){i++;continue}t.removeAttribute(o.name);let s=o.value,l=o.name.slice(1).split(":");for(let i of l){let o=W[i]||T;if(n.push(o(t,s,r,i)),z.has(t)||t.parentNode!==e)return!1}}for(let e,i=0;e=t.children[i];i++)!1===s(e,t)&&i--};s(t);for(let t of n)if(t){let e;b((()=>{"function"==typeof e&&e(),e=t(r)}))}return Object.seal(r),z.set(t,r),r}var I=F;export{I as default};
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)&&u(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 r.s=e={i:0,S:t,p:void 0,n:r.s,t:r,e:void 0,x:void 0,r:e},t.n=e,32&r.f&&t.S(e),e;if(-1===e.i)return e.i=0,void 0!==e.p&&(e.p.n=e.n,void 0!==e.n&&(e.n.p=e.p),e.p=void 0,e.n=r.s,r.s.p=e,r.s=e),e}}function a(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function u(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 f(t){for(var e=t.s;void 0!==e;e=e.n){var r=e.S.n;void 0!==r&&(e.r=r),e.S.n=e,e.i=-1}}function c(t){for(var e=t.s,r=void 0;void 0!==e;){var i=e.n;-1===e.i?(e.S.U(e),e.n=void 0):(void 0!==r&&(r.p=e),e.p=void 0,e.n=r,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);return e.c(),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){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&&!u(this))return this.f&=-2,!0;var t=r;try{f(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(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),f(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[S],S=Symbol("signal-struct");function A(t,e){if(w(t)&&!e)return t;if(k(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),u=o[t]=(r=s)&&r.peek?s:new a(l?void 0:k(s)?Object.seal(A(s)):Array.isArray(s)?A(s):s);l&&m(s,(t=>u.value=t)),Object.defineProperty(n,t,{get:()=>u.value,set(t){if(k(t)){if(k(u.value))try{return void Object.assign(u.value,t)}catch(t){}u.value=Object.seal(A(t))}else Array.isArray(t)?u.value=A(t):u.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,S,{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]=A(t[e]);return t}function k(t){return t&&t.constructor===Object}A.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=[L(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(L(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),I(o,t))}},E.with=(t,e,r)=>{I(t,A(L(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 R(new Error,t,e);const i=t[$]=document.createTextNode("");t.replaceWith(i);const n=L(t,r[2],":each"),o=t.getAttribute(":key"),s=o?L(null,o):null;t.removeAttribute(":key");const l=new WeakMap,a=new WeakMap;let u=[];return o=>{let f=n(o);f?"number"==typeof f?f=Array.from({length:f},((t,e)=>[e,e+1])):Array.isArray(f)?f=f.map(((t,e)=>[e+1,t])):"object"==typeof f?f=Object.entries(f):R(Error("Bad list value"),t,e,":each"):f=[];let c=[],h=[];for(let[e,i]of f){let n,u,f=s?.({[r[0]]:i,[r[1]]:e});("string"==typeof(v=f)||"boolean"==typeof v||"number"==typeof v)&&(f=N(f)),null==f?n=t.cloneNode(!0):(n=a.get(f))||a.set(f,n=t.cloneNode(!0)),c.push(n),null!=f&&(u=l.get(f))?u[r[0]]=i:(u=A({[r[0]]:i,[r[1]]:e},o),null!=f&&l.set(f,u)),h.push(u)}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],u=r[l];if(null===a)s++;else if(r.length<=l)t.removeChild(e[s]),s++;else if(e.length<=s)t.insertBefore(u,e[s]||i),l++;else if(a===u)s++,l++;else{var f=o.get(a),c=n.get(u);void 0===f?(t.removeChild(e[s]),s++):void 0===c?(t.insertBefore(u,e[s]||i),l++):(t.insertBefore(e[c],e[s]||i),e[c]=null,c>s+1&&s++,l++)}}}(i.parentNode,u,c,i),u=c;for(let t=0;t<c.length;t++)I(c[t],h[t])}},W.ref=(t,e,r)=>{r[e]=t},W.id=(t,e)=>{let r=L(t,e,":id");return e=>{return i=r(e),t.id=i||0===i?i:"";var i}},W.class=(t,e)=>{let r=L(t,e,":class"),i=t.className;return e=>{let n=r(e);t.className=i+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},W.style=(t,e)=>{let r=L(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 for(let e in n)t.style[e]=n[e]}},W.text=(t,e)=>{let r=L(t,e,":text");return e=>{let i=r(e);t.textContent=null==i?"":i}},W.data=(t,e)=>{let r=L(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=L(t,e,":aria");return e=>(e=>{for(let r in e)U(t,"aria-"+z(r),null==e[r]?null:e[r]+"")})(r(e))},W[""]=(t,e)=>{let r=L(t,e,":");if(r)return e=>{let i=r(e);for(let e in i)U(t,z(e),i[e])}},W.value=(t,e)=>{let r,i,n=L(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=L(t,e,":on");return e=>{let i=r(e),n=[];for(let e in i)n.push(T(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=L(t,e,":"+i);if(o)return n?e=>{let r=o(e)||(()=>{});return T(t,n,r)}:e=>U(t,i,o(e))},T=(t,e,r)=>{let i,n=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)||r.test,""))),r}));if(r||(r=()=>{}),1==n.length)return B(r,n[0]);const o=(e,s=0)=>i=B((l=>{i(),"function"!=typeof(e=e.call(t,l))&&(e=()=>{}),++s<n.length?o(e,s):o(r)}),n[s]);return o(r),()=>i()},B=(t,{evt:e,target:r,test:i,delayed: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},throttle(t,e){t.delayed=t=>D(t,Number(e)||108)},debounce(t,e){t.delayed=t=>M(t,Number(e)||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=>"Control"===t.key||"Ctrl"===t.key,shift:()=>t=>"Shift"===t.key,alt:()=>t=>"Alt"===t.key,meta:()=>t=>"Meta"===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=>"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:"")},_={};function L(t,e,r){let i=_[e];if(!i){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/\b(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{i=_[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(i){return R(i,t,e,r)}}return n=>{let o;try{o=i.call(t,n)}catch(i){return R(i,t,e,r)}return o}}function R(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 z(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var F=new WeakMap;function I(t,r){if(!t.children)return;if(F.has(t)){let i=F.get(t);return function(t){if(n>0)return t();n++;try{t()}finally{e()}}((()=>Object.assign(i,r))),i}const i=A(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)),F.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)),F.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),F.set(t,i),i}var Z=I;export{Z as default};
package/src/directives.js CHANGED
@@ -238,9 +238,9 @@ secondary['on'] = (el, expr) => {
238
238
 
239
239
  return (state) => {
240
240
  let listeners = evaluate(state);
241
- for (let evt in listeners) addListener(el, evt, listeners[evt])
241
+ let offs = []; for (let evt in listeners) offs.push(on(el, evt, listeners[evt]));
242
242
  return () => {
243
- for (let evt in listeners) removeListener(el, evt, listeners[evt])
243
+ for (let off of offs) off()
244
244
  }
245
245
  }
246
246
  }
@@ -255,122 +255,139 @@ export default (el, expr, state, name) => {
255
255
  if (evt) return (state => {
256
256
  // we need anonymous callback to enable modifiers like prevent
257
257
  let value = evaluate(state) || (()=>{})
258
- addListener(el, evt, value)
259
- return () => removeListener(el, evt, value)
258
+ return on(el, evt, value)
260
259
  })
261
260
 
262
261
  return state => attr(el, name, evaluate(state))
263
262
  }
264
263
 
265
- const _stop = Symbol('stop')
266
- const addListener = (el, evt, startFn) => {
264
+ // bind event to target
265
+ const on = (target, evt, origFn) => {
267
266
  // ona..onb
268
- let evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e),
269
- opts = {target: el, hooks: [], fn: startFn}
270
-
271
- // onevt.debounce-108
272
- evts[0] = evts[0].replace(/\.(\w+)?-?([\w]+)?/g, (match, mod, param) => (mods[mod]?.(opts, param), ''));
273
- // we collect condition hooks into a sigle callback to check before throttles
274
- let {target, hooks, fn, ...listenerOpts} = opts
275
- if (hooks.length) {
276
- let _fn = fn
277
- fn = (e) => { for (let hook of hooks) if (hook(e) === false) return false; return _fn(e) }
278
- }
279
-
280
- if (evts.length == 1) target.addEventListener(evts[0], fn, listenerOpts);
281
- else {
282
- const nextEvt = (handler, cur=0) => {
283
- let curListener = e => {
284
- target.removeEventListener(evts[cur], curListener)
285
- if (typeof (handler = handler.call(target,e)) !== 'function') handler = ()=>{}
286
- if (++cur < evts.length) nextEvt(handler, cur);
287
- else if (!fn[_stop]) nextEvt(fn); // update only if chain isn't stopped
288
- }
289
- target.addEventListener(evts[cur], curListener, listenerOpts)
267
+ let ctxs = evt.split('..').map(e => {
268
+ let ctx = { evt:'', target, test:()=>true };
269
+ // onevt.debounce-108 -> evt.debounce-108
270
+ ctx.evt = (e.startsWith('on') ? e.slice(2) : e).replace(/\.(\w+)?-?([\w]+)?/g,
271
+ (match, mod, param) => (ctx.test = mods[mod]?.(ctx, param) || ctx.test, '')
272
+ );
273
+ return ctx;
274
+ });
275
+
276
+ // FIXME: must be in throttles
277
+ if (!origFn) origFn = () => {}
278
+
279
+ // single event bind
280
+ if (ctxs.length == 1) return addListener(origFn, ctxs[0])
281
+
282
+ // events chain cycler
283
+ let off
284
+ const nextEvt = (fn, cur=0) => {
285
+ let curListener = e => {
286
+ off();
287
+ if (typeof (fn = fn.call(target, e)) !== 'function') fn = ()=>{}
288
+ if (++cur < ctxs.length) nextEvt(fn, cur);
289
+ else nextEvt(origFn); // back to first event only if chain isn't stopped (by update)
290
290
  }
291
- nextEvt(fn)
291
+ return off = addListener(curListener, ctxs[cur])
292
292
  }
293
+ nextEvt(origFn)
294
+
295
+ return () => off()
293
296
  }
294
- const removeListener = (el, evt, fn) => {
295
- if (evt.indexOf('..')>=0) fn[_stop] = true
296
- el.removeEventListener(evt, fn);
297
- }
297
+ // add listener applying the context
298
+ const addListener = (fn, {evt, target, test, delayed, stop, prevent, ...opts} ) => {
299
+ if (delayed) fn = delayed(fn)
300
+ let wrappedFn = e => (
301
+ test(e) && (
302
+ stop&&e.stopPropagation(),
303
+ prevent&&e.preventDefault(),
304
+ fn.call(target, e)
305
+ )
306
+ )
307
+ target.addEventListener(evt, wrappedFn, opts)
308
+ return () => target.removeEventListener(evt, wrappedFn, opts)
309
+ };
298
310
 
299
311
  // event modifiers
300
312
  const mods = {
301
- prevent({hooks}) { hooks.push(e => { e.preventDefault(); })},
302
- stop({hooks}) { hooks.push(e => { e.stopPropagation(); })},
303
- throttle(opts, limit) {
304
- let {fn} = opts
305
- limit = Number(limit) || 108
306
- let pause, planned, block = (e) => {
307
- pause = true
308
- setTimeout(() => {
309
- pause = false
310
- // if event happened during blocked time, it schedules call by the end
311
- if (planned) return (planned = false, block(), fn(e))
312
- }, limit)
313
- }
314
- opts.fn = e => {
315
- if (pause) return (planned = true)
316
- block(e);
317
- return fn(e);
318
- }
319
- },
320
- debounce(opts, wait) {
321
- let {fn} = opts
322
- wait = Number(wait) || 108;
323
- let timeout
324
- opts.fn = (e) => {
325
- clearTimeout(timeout)
326
- timeout = setTimeout(() => {timeout = null; fn(e)}, wait)
327
- }
328
- },
313
+ // actions
314
+ prevent(ctx) { ctx.prevent = true },
315
+ stop(ctx) { ctx.stop = true },
316
+
317
+ // options
318
+ once(ctx) { ctx.once = true; },
319
+ passive(ctx) { ctx.passive = true; },
320
+ capture(ctx) { ctx.capture = true; },
329
321
 
330
322
  // target
331
- window(opts) { opts.target = window },
332
- document(opts) { opts.target = document },
333
- outside({target, hooks}) {
334
- hooks.push((e) => {
335
- if (target.contains(e.target)) return false
336
- if (e.target.isConnected === false) return false
337
- if (target.offsetWidth < 1 && target.offsetHeight < 1) return false
338
- })
323
+ window(ctx) { ctx.target = window },
324
+ document(ctx) { ctx.target = document },
325
+
326
+ // FIXME: test looks very similar to test, mb it can be optimized
327
+ throttle(ctx, limit) { ctx.delayed = fn => throttle(fn, Number(limit) || 108)},
328
+ debounce(ctx, wait) { ctx.delayed = fn => debounce(fn, Number(wait) || 108) },
329
+
330
+ // test
331
+ outside: ctx => e => {
332
+ let target = ctx.target
333
+ if (target.contains(e.target)) return false
334
+ if (e.target.isConnected === false) return false
335
+ if (target.offsetWidth < 1 && target.offsetHeight < 1) return false
336
+ return true
339
337
  },
340
- self({target, hooks}) { hooks.push(e => { return e.target === target })},
341
-
342
- // options
343
- once(opts) { opts.once = true; },
344
- passive(opts) { opts.passive = true; },
345
- capture(opts) { opts.capture = true; },
338
+ self: ctx => e => e.target === ctx.target,
346
339
 
347
340
  // keyboard
348
- ctrl({hooks}) { hooks.push(e => e.key === 'Control' || e.key === 'Ctrl')},
349
- shift({hooks}) { hooks.push(e => e.key === 'Shift')},
350
- alt({hooks}) { hooks.push(e => e.key === 'Alt')},
351
- meta({hooks}) { hooks.push(e => e.key === 'Meta')},
352
- arrow({hooks}) { hooks.push(e => e.key.startsWith('Arrow'))},
353
- enter({hooks}) { hooks.push(e => e.key === 'Enter')},
354
- escape({hooks}) { hooks.push(e => e.key.startsWith('Esc'))},
355
- tab({hooks}) { hooks.push(e => e.key === 'Tab')},
356
- space({hooks}) { hooks.push(e => e.key === 'Space' || e.key === ' ')},
357
- backspace({hooks}) { hooks.push(e => e.key === 'Backspace') },
358
- delete({hooks}) { hooks.push(e => e.key === 'Delete') },
359
- digit({hooks}) { hooks.push(e => /\d/.test(e.key)) },
360
- letter({hooks}) { hooks.push(e => /[a-zA-Z]/.test(e.key)) },
361
- character({hooks}) { hooks.push(e => /^\S$/.test(e.key) ) },
341
+ ctrl: ctx => e => e.key === 'Control' || e.key === 'Ctrl',
342
+ shift: ctx => e => e.key === 'Shift',
343
+ alt: ctx => e => e.key === 'Alt',
344
+ meta: ctx => e => e.key === 'Meta',
345
+ arrow: ctx => e => e.key.startsWith('Arrow'),
346
+ enter: ctx => e => e.key === 'Enter',
347
+ escape: ctx => e => e.key.startsWith('Esc'),
348
+ tab: ctx => e => e.key === 'Tab',
349
+ space: ctx => e => e.key === 'Space' || e.key === ' ',
350
+ backspace: ctx => e => e.key === 'Backspace',
351
+ delete: ctx => e => e.key === 'Delete',
352
+ digit: ctx => e => /^\d$/.test(e.key),
353
+ letter: ctx => e => /^[a-zA-Z]$/.test(e.key),
354
+ character: ctx => e => /^\S$/.test(e.key),
362
355
  };
363
356
 
357
+ // create delayed fns
358
+ const throttle = (fn, limit) => {
359
+ let pause, planned, block = (e) => {
360
+ pause = true
361
+ setTimeout(() => {
362
+ pause = false
363
+ // if event happened during blocked time, it schedules call by the end
364
+ if (planned) return (planned = false, block(e), fn(e))
365
+ }, limit)
366
+ }
367
+ return (e) => {
368
+ if (pause) return (planned = true)
369
+ block(e);
370
+ return fn(e);
371
+ }
372
+ }
373
+ const debounce = (fn, wait) => {
374
+ let timeout
375
+ return (e) => {
376
+ clearTimeout(timeout)
377
+ timeout = setTimeout(() => {timeout = null; fn(e)}, wait)
378
+ }
379
+ }
380
+
364
381
  // set attr
365
382
  const attr = (el, name, v) => {
366
383
  if (v == null || v === false) el.removeAttribute(name)
367
384
  else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
368
385
  }
369
386
 
370
- let evaluatorMemo = {}
371
387
 
372
- // borrowed from alpine: https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L61
388
+ // borrowed from alpine with improvements https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L61
373
389
  // it seems to be more robust than subscript
390
+ let evaluatorMemo = {}
374
391
  function parseExpr(el, expression, dir) {
375
392
  // guard static-time eval errors
376
393
  let evaluate = evaluatorMemo[expression]
package/test/test.js CHANGED
@@ -468,7 +468,7 @@ test('each: key-based caching is in-sync with direct elements', () => {
468
468
  })
469
469
 
470
470
  test('on: base', () => {
471
- let el = h`<div :on="{click(e){log.push('click')},x}"></div>`
471
+ let el = h`<div :on="{click(e){log.push('click')}, x}"></div>`
472
472
  let log = signal([])
473
473
  let params = sprae(el, {x(){log.value.push('x')}, log})
474
474
 
@@ -571,30 +571,31 @@ test('on: chain of events', e => {
571
571
  test('on: state changes between chain of events', e => {
572
572
  let el = h`<x :on="{'x..y':fn}"></x>`
573
573
  let log = []
574
- let state = sprae(el, {log, fn: () => console.log('log1')||log.push(1)})
575
- console.log('xx')
574
+ let state = sprae(el, {log, fn: () => (log.push('x1'),()=>log.push('y1'))})
575
+ console.log('emit x, x')
576
576
  el.dispatchEvent(new window.Event('x'));
577
577
  el.dispatchEvent(new window.Event('x'));
578
- is(log, [1])
579
- state.fn = () => (console.log('log1.1')||log.push(1.1), () => log.push(2))
580
- is(log, [1])
578
+ is(log, ['x1'])
579
+ console.log('update fn')
580
+ state.fn = () => (log.push('x2'), () => log.push('y2'))
581
+ is(log, ['x1'])
581
582
  // console.log('xx')
582
583
  // NOTE: state update registers new chain listener before finishing prev chain
583
584
  // el.dispatchEvent(new window.Event('x'));
584
585
  // el.dispatchEvent(new window.Event('x'));
585
586
  // is(log, [1])
586
- console.log('yy')
587
+ console.log('emit y, y')
587
588
  el.dispatchEvent(new window.Event('y'));
588
589
  el.dispatchEvent(new window.Event('y'));
589
- is(log, [1])
590
- console.log('xx')
590
+ is(log, ['x1'])
591
+ console.log('emit x, x')
591
592
  el.dispatchEvent(new window.Event('x'));
592
593
  el.dispatchEvent(new window.Event('x'));
593
- is(log, [1, 1.1])
594
- console.log('yy')
594
+ is(log, ['x1','x2'])
595
+ console.log('emit y, y')
595
596
  el.dispatchEvent(new window.Event('y'));
596
597
  el.dispatchEvent(new window.Event('y'));
597
- is(log, [1, 1.1, 2])
598
+ is(log, ['x1','x2','y2'])
598
599
  })
599
600
 
600
601
  test('on: once', e => {
@@ -652,6 +653,7 @@ test('on: keys with prevent', e => {
652
653
  let el = h`<y :onkeydown="e=>log.push(e.key)"><x :ref="x" :onkeydown.enter.stop></x></y>`
653
654
  let state = sprae(el, {log:[]})
654
655
  state.x.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'x', bubbles: true }));
656
+ console.log('enter')
655
657
  state.x.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
656
658
  is(state.log,['x'])
657
659
  })
@@ -682,6 +684,17 @@ test('on: throttle', async e => {
682
684
  is(state.log, ['x', 'x', 'x'])
683
685
  })
684
686
 
687
+ test('on: modifiers chain', async e => {
688
+ let el = h`<x :onkeydown.letter..onkeyup.letter="e=>(log.push(e.key),(e)=>log.push(e.key))"></x>`
689
+ let state = sprae(el, {log:[]})
690
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'x', bubbles: true }));
691
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
692
+ is(state.log,['x'])
693
+ el.dispatchEvent(new window.KeyboardEvent('keyup', { key: 'Enter', bubbles: true }));
694
+ is(state.log,['x'])
695
+ el.dispatchEvent(new window.KeyboardEvent('keyup', { key: 'x', bubbles: true }));
696
+ is(state.log,['x', 'x'])
697
+ })
685
698
 
686
699
  test('with: inline', () => {
687
700
  let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`