sprae 2.7.1 → 2.8.1

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,14 +1,14 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "2.7.1",
4
+ "version": "2.8.1",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
7
7
  "type": "module",
8
8
  "dependencies": {
9
9
  "@preact/signals-core": "^1.2.2",
10
10
  "primitive-pool": "^2.0.0",
11
- "signal-struct": "^1.9.0",
11
+ "signal-struct": "^1.10.0",
12
12
  "swapdom": "^1.1.1"
13
13
  },
14
14
  "devDependencies": {
package/r&d.md CHANGED
@@ -289,9 +289,9 @@
289
289
  * @sprae/item: `<x :item="{type:a, scope:b}"` – provide microdata
290
290
  - can be solved naturally, unless there's special meaning
291
291
  * @sprae/hcodes: `<x :hcode=""` – provide microformats
292
- * @sprae/with
293
- * @sprae/onconnected
294
292
  * @sprae/onvisible?
293
+ - can be solved externally
294
+ * @sprae/onintersects
295
295
 
296
296
  ## [x] Write any-attributes via `:<prop>? -> yep`
297
297
 
@@ -330,7 +330,7 @@
330
330
  + Provides precisely controlled sandbox
331
331
  - Some limited lang opportunities
332
332
  - need to match many syntax quirks, can be tedious
333
- ~ can be fine to limit expressions to meaningful default: why Proxy, generators, awaits, global access etc.
333
+ ~ can be fine to limit expressions to meaningful default: no Proxy, generators, awaits, global access etc.
334
334
  - Somewhat heavy to bundle
335
335
  ~ 1-2kb is not super-heavy, besides kicks out signal-struct (with preact signals?)
336
336
  + Scope is easier to provide: no need for signal proxy
@@ -340,6 +340,7 @@
340
340
  + Deps can be analyzed / implemented without signals
341
341
  - Screwed up debugging / stacktrace (unless errored properly)
342
342
  ~+ can actually provide better trace since no internal framework stuff is shown
343
+ + can let means to enhance subscript's logs
343
344
  + that "unlimits" returned struct, so that any property can be added/deleted.
344
345
  - doesn't really save from `new (()=>{}).constructor` hack: we gotta substitute objects too.
345
346
  + allows easier handle of `:with="a=1,b=2,c=3"` - we just naturally get local variables without messup with global
@@ -347,11 +348,18 @@
347
348
  - not having "comfy" compatible JS at hand: cognitive load of whole language "layer" in-between
348
349
  + allows `let a = 1; a;` case instead of `let a = 1; return a;`
349
350
 
351
+ -> We can benchmark if updating set of known dependencies is faster than using preact subscriptions.
352
+ + it seems more logical min-ground to know in advance what we depend on, rather than detect by-call as signals do.
353
+ + it's safer not to depend on external tech, considering there's so much competition and changes in reactive land
354
+ ~ it indeed takes some reactive-struct, capable of notifying which paths have been changed
355
+ ? maybe define setters such that when they're set
356
+
350
357
  2. Use sandboxed proxy
351
358
  - tough evaluation
352
- - tough implementation
359
+ - implementation hiccups
353
360
  - screwed up data
354
361
  - no full protection
362
+ - relatively slow
355
363
  + does minimal catch
356
364
 
357
365
  ## [x] :onclick="direct code" ? -> no: immediately invoked.
@@ -374,19 +382,23 @@
374
382
  ? maybe id should have same signature
375
383
  ? should it be very similar mechanism to `:with="a=1,b=2"`
376
384
 
377
- ## [ ] Event modifiers :ona.once, `:ona`
385
+ ## [x] Event modifiers :ona.once, `:ona` -> let's try, there's a lot of use for both props and event
378
386
 
379
387
  - .prevent,.stop - not needed since expects a function
380
388
  ? or should we just trigger it for user?
381
389
  ? :onclick.outside
382
390
  ? :onclick.window, :onclick.document
383
- ? :onclick.once
384
- ? :onclick.debounce
385
- ? :onclick.throttle.750ms
391
+ + can be needed, eg. mousedown..up can happen outside of current element (stop caret tracking in waveplay)
392
+ ? :onclick.once, :onclick.passive, :onclick.capture
393
+ + can pass props to event listener: there's no other way to do that
394
+ ? :onclick.debounce-330
395
+ ? :onclick.throttle-750
396
+ + ...just handy everydayers and saves tons of noise
386
397
  ? :onclick.self
398
+ ~ clicked on self, not the child
387
399
  ? :onspecial-event.camel, :onx-y.dot
388
- ? :onclick.passive
389
- ? :onkeypress.shift.enter
400
+ ~
401
+ ? :onkeypress.shift.enter, :onmousemove.shift, :onmousemove.alt
390
402
  .shift Shift
391
403
  .enter Enter
392
404
  .space Space
@@ -394,15 +406,57 @@
394
406
  .cmd Cmd
395
407
  .meta Cmd on Mac, Windows key on Windows
396
408
  .alt Alt
397
- .up .down .left .right Up/Down/Left/Right arrows
409
+ .up .down .left .right
398
410
  .escape Escape
399
411
  .tab Tab
400
412
  .caps-lock Caps Lock
401
- .equal Equal, =
402
- .period Period, .
403
- .slash Foward Slash, /
413
+ .equal Equal
414
+ .period Period
415
+ .slash Foward Slash
416
+ + allows separating various key handlers: atm waveplay handles separate keys in the same method `handleKey`
417
+ + allows tracking mouse interactions with shift hold
404
418
  - conflict with dot-separated events
419
+ ~not so popular nor encouraged
405
420
  - lots of ad-hoc non-standard rules, can be handled in code
421
+ + allow multiple setters for same props or multiple listeners for same events
422
+ + oldschool jquery-compatible events
423
+
424
+ ## [x] Mods design -> use event modifiers, not props modifiers
425
+
426
+ * [ ] ~~Prop modifiers~~
427
+ - overall seems code complication without much benefit
428
+ * [ ] value.bind? value.watch?
429
+ - let's wait for use-case: value can be too big to set it every time
430
+ * [ ] prop.reflect, prop.observe
431
+ - let's wait for use-case
432
+ * [ ] prop.boolean, .number, .string, .array, .object
433
+ - let's wait for use-case
434
+ * [ ] prop.once, prop.fx ? prop.init?
435
+ - doesn't seem required, let's wait for use case
436
+ * [ ] prop.change - run only if value changes
437
+ - seems like unnecessary manual optimization that must be done always automatically
438
+ ? are there cases where force-update is necessary?
439
+ * [ ] prop.throttle-xxx, prop.debounce-xxx
440
+ - let's wait until that's really a problem
441
+ * [ ] prop.class
442
+ ? what's the use-case
443
+
444
+ * [x] Event modifiers
445
+ * [x] onevt.x, onevt.y
446
+ + jquery-like
447
+ + multiple same events
448
+ * [x] onevt.once, onevt.passive, onevt.capture
449
+ + standard props passing
450
+ * [x] onevt.prevent, onevt.stop
451
+ + conventional mods
452
+ * [x] onevt.outside onevt.window, onevt.document, onevt.self
453
+ + useful handlers, conventional mods
454
+ * [x] onevt.throttle-xxx, onevt.debounce-xxx
455
+ + conventional
456
+ * [x] onevt.shift, onevt.cmd.shift, onevt.meta
457
+ + conventional
458
+ * [x] onkey.enter, .space, .up|.down|.left|.right, .escape, .tab, .period, .slash, .caps-lock
459
+ + conventional
406
460
 
407
461
  ## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
408
462
 
package/readme.md CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  > DOM microhydration with `:` attributes
4
4
 
5
- A lightweight essential alternative to [alpine](https://github.com/alpinejs/alpine), [petite-vue](https://github.com/vuejs/petite-vue), [templize](https://github.com/dy/templize) or JSX with better ergonomics[*](#justification).<br>
6
- It is reminiscent of [XSLT](https://www.w3schools.com/xml/xsl_intro.asp), considered a [buried treasure](https://github.com/bahrus/be-restated) by web-connoisseurs.
7
-
8
5
 
9
6
  ## Usage
10
7
 
@@ -163,10 +160,22 @@ Add event listeners.
163
160
  }
164
161
  }">
165
162
 
163
+ <!-- Event modifiers -->
164
+ <button :onclick.throttle-500="handler">Not too often</button>
165
+
166
166
  <!-- Bulk/custom events -->
167
167
  <button :on="{ click: handler, touch: handler, special: handler }">Submit</button>
168
168
  ```
169
169
 
170
+ ##### Event modifiers
171
+
172
+ * `.once`, `.passive`, `.capture` – listener [options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
173
+ * `.prevent`, `.stop` – prevent default or stop propagation.
174
+ * `.window`, `.document`, `.outside`, `.self` – specify event target.
175
+ * `.throttle-108`, `.debounce-108` – define throttling or postponing callback with (optional) timeout in ms.
176
+ * `.ctrl`, `.shift`, `.alt`, `.meta`, `.cmd`, `.down`, `.up`, `.left`, `.right`, `.end`, `.home`, `.pagedown`, `.pageup`, `.enter`, `.plus`, `.minus`, `.star`, `.slash`, `.period`, `.equal`, `.underscore`, `.esc`, `.escape`, `.tab`, `.space`, `.backspace`, `.delete` – filter by [`event.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values).
177
+ * `.*` – any other modifier has no effect, but allows binding multiple handlers to same event (like jQuery event classes).
178
+
170
179
  #### `:data="values"`
171
180
 
172
181
  Set [data-*](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*) attributes. CamelCase is converted to dash-case.
@@ -334,11 +343,13 @@ This way, for example, _@preact/signals_ or _rxjs_ can be connected directly byp
334
343
 
335
344
  ## Justification
336
345
 
346
+ _Sprae_ is lightweight essential alternative to [alpine](https://github.com/alpinejs/alpine), [petite-vue](https://github.com/vuejs/petite-vue), [templize](https://github.com/dy/templize) or JSX with better ergonomics[*](#justification).
347
+
337
348
  * [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). Also ergonomics of `attr="{{}}"` is inferior to `:attr=""` since it creates flash of uninitialized values.
338
349
  * [Alpine](https://github.com/alpinejs/alpine) / [vue](https://github.com/vuejs/petite-vue) / [lit](https://github.com/lit/lit/tree/main/packages/lit-html) escapes native HTML quirks, but the syntax is a bit scattered: `:attr`, `v-*`,`x-*`, `@evt`, `{{}}` can be expressed with single convention. Besides, functionality is too broad and can be reduced to essence: perfection is when there's nothing to take away, not add. Also they tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223), making interop hard.
339
350
  * React/[preact](https://ghub.io/preact) does the job wiring up JS to HTML, but with an extreme of migrating HTML to JSX and enforcing SPA, which is not organic for HTML. Also it doesn't support reactive fields (needs render call).
340
351
 
341
- _sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and builds upon [_@preact/signals_](https://ghub.io/@preact/signals).
352
+ _Sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and builds upon [_@preact/signals_](https://ghub.io/@preact/signals).
342
353
 
343
354
  * It doesn't break static html markup.
344
355
  * It falls back to element content if uninitialized.
@@ -349,4 +360,8 @@ _sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and bui
349
360
  * Input data may contain [signals](https://ghub.io/@preact/signals) or [reactive values](https://ghub.io/sube).
350
361
  * Elements / data API is open and enable easy interop.
351
362
 
363
+
364
+ It is reminiscent of [XSLT](https://www.w3schools.com/xml/xsl_intro.asp), considered a [buried treasure](https://github.com/bahrus/be-restated) by web-connoisseurs.
365
+
366
+
352
367
  <p align="center"><a href="https://github.com/krsnzd/license/">🕉</a></p>
package/sprae.js CHANGED
@@ -71,16 +71,16 @@ function v(i2) {
71
71
  }
72
72
  }
73
73
  }
74
- function e(i2) {
74
+ function e2(i2) {
75
75
  this.v = i2;
76
76
  this.i = 0;
77
77
  this.n = void 0;
78
78
  this.t = void 0;
79
79
  }
80
- e.prototype.h = function() {
80
+ e2.prototype.h = function() {
81
81
  return true;
82
82
  };
83
- e.prototype.S = function(i2) {
83
+ e2.prototype.S = function(i2) {
84
84
  if (this.t !== i2 && void 0 === i2.e) {
85
85
  i2.x = this.t;
86
86
  if (void 0 !== this.t)
@@ -88,7 +88,7 @@ e.prototype.S = function(i2) {
88
88
  this.t = i2;
89
89
  }
90
90
  };
91
- e.prototype.U = function(i2) {
91
+ e2.prototype.U = function(i2) {
92
92
  var t2 = i2.e, h2 = i2.x;
93
93
  if (void 0 !== t2) {
94
94
  t2.x = h2;
@@ -101,7 +101,7 @@ e.prototype.U = function(i2) {
101
101
  if (i2 === this.t)
102
102
  this.t = h2;
103
103
  };
104
- e.prototype.subscribe = function(i2) {
104
+ e2.prototype.subscribe = function(i2) {
105
105
  var t2 = this;
106
106
  return b(function() {
107
107
  var h2 = t2.value, o2 = 32 & this.f;
@@ -113,16 +113,16 @@ e.prototype.subscribe = function(i2) {
113
113
  }
114
114
  });
115
115
  };
116
- e.prototype.valueOf = function() {
116
+ e2.prototype.valueOf = function() {
117
117
  return this.value;
118
118
  };
119
- e.prototype.toString = function() {
119
+ e2.prototype.toString = function() {
120
120
  return this.value + "";
121
121
  };
122
- e.prototype.peek = function() {
122
+ e2.prototype.peek = function() {
123
123
  return this.v;
124
124
  };
125
- Object.defineProperty(e.prototype, "value", { get: function() {
125
+ Object.defineProperty(e2.prototype, "value", { get: function() {
126
126
  var i2 = v(this);
127
127
  if (void 0 !== i2)
128
128
  i2.i = this.i;
@@ -144,7 +144,7 @@ Object.defineProperty(e.prototype, "value", { get: function() {
144
144
  }
145
145
  } });
146
146
  function u(i2) {
147
- return new e(i2);
147
+ return new e2(i2);
148
148
  }
149
149
  function d(i2) {
150
150
  for (var t2 = i2.s; void 0 !== t2; t2 = t2.n)
@@ -183,13 +183,13 @@ function a(i2) {
183
183
  i2.s = h2;
184
184
  }
185
185
  function l(i2) {
186
- e.call(this, void 0);
186
+ e2.call(this, void 0);
187
187
  this.x = i2;
188
188
  this.s = void 0;
189
189
  this.g = f - 1;
190
190
  this.f = 4;
191
191
  }
192
- (l.prototype = new e()).h = function() {
192
+ (l.prototype = new e2()).h = function() {
193
193
  this.f &= -3;
194
194
  if (1 & this.f)
195
195
  return false;
@@ -230,10 +230,10 @@ l.prototype.S = function(i2) {
230
230
  for (var t2 = this.s; void 0 !== t2; t2 = t2.n)
231
231
  t2.S.S(t2);
232
232
  }
233
- e.prototype.S.call(this, i2);
233
+ e2.prototype.S.call(this, i2);
234
234
  };
235
235
  l.prototype.U = function(i2) {
236
- e.prototype.U.call(this, i2);
236
+ e2.prototype.U.call(this, i2);
237
237
  if (void 0 === this.t) {
238
238
  this.f &= -33;
239
239
  for (var t2 = this.s; void 0 !== t2; t2 = t2.n)
@@ -408,7 +408,7 @@ function signalStruct(values, proto) {
408
408
  try {
409
409
  Object.assign(s2.value, v2);
410
410
  return;
411
- } catch (e2) {
411
+ } catch (e3) {
412
412
  }
413
413
  s2.value = Object.seal(signalStruct(v2));
414
414
  } else if (Array.isArray(v2))
@@ -425,7 +425,8 @@ function signalStruct(values, proto) {
425
425
  return state;
426
426
  }
427
427
  if (Array.isArray(values) && !isStruct(values[0])) {
428
- return values.map((v2) => signalStruct(v2));
428
+ for (let i2 = 0; i2 < values.length; i2++)
429
+ values[i2] = signalStruct(values[i2]);
429
430
  }
430
431
  return values;
431
432
  }
@@ -623,6 +624,31 @@ secondary["text"] = (el, expr) => {
623
624
  el.textContent = value == null ? "" : value;
624
625
  };
625
626
  };
627
+ secondary["data"] = (el, expr) => {
628
+ let evaluate = parseExpr(el, expr, ":data");
629
+ return (state) => {
630
+ let value = evaluate(state);
631
+ for (let key in value)
632
+ el.dataset[key] = value[key];
633
+ };
634
+ };
635
+ secondary["aria"] = (el, expr) => {
636
+ let evaluate = parseExpr(el, expr, ":aria");
637
+ const update = (value) => {
638
+ for (let key in value)
639
+ attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
640
+ };
641
+ return (state) => update(evaluate(state));
642
+ };
643
+ secondary[""] = (el, expr) => {
644
+ let evaluate = parseExpr(el, expr, ":");
645
+ if (evaluate)
646
+ return (state) => {
647
+ let value = evaluate(state);
648
+ for (let key in value)
649
+ attr(el, dashcase(key), value[key]);
650
+ };
651
+ };
626
652
  secondary["value"] = (el, expr) => {
627
653
  let evaluate = parseExpr(el, expr, ":value");
628
654
  let from, to;
@@ -646,16 +672,38 @@ secondary["on"] = (el, expr) => {
646
672
  };
647
673
  };
648
674
  };
675
+ var directives_default = (el, expr, state, name) => {
676
+ let evt = name.startsWith("on") && name.slice(2);
677
+ let evaluate = parseExpr(el, expr, ":" + name);
678
+ if (!evaluate)
679
+ return;
680
+ if (evt)
681
+ return (state2) => {
682
+ let value = evaluate(state2);
683
+ if (value) {
684
+ addListener(el, evt, value);
685
+ return () => removeListener(el, evt, value);
686
+ }
687
+ };
688
+ return (state2) => attr(el, name, evaluate(state2));
689
+ };
649
690
  var _stop = Symbol("stop");
650
691
  var addListener = (el, evt, startFn) => {
651
- if (evt.indexOf("..") < 0)
652
- el.addEventListener(evt, startFn);
692
+ let evts = evt.split("..").map((e3) => e3.startsWith("on") ? e3.slice(2) : e3), opts = {};
693
+ evts[0] = evts[0].replace(
694
+ /\.(\w+)?-?([\w]+)?/g,
695
+ (match, mod, param) => {
696
+ (mod = mods[mod]) ? ([el, startFn] = mod(el, startFn, opts, param), "") : "";
697
+ return "";
698
+ }
699
+ );
700
+ if (evts.length == 1)
701
+ el.addEventListener(evts[0], startFn, opts);
653
702
  else {
654
- const evts = evt.split("..").map((e2) => e2.startsWith("on") ? e2.slice(2) : e2);
655
703
  const nextEvt = (fn, cur = 0) => {
656
- let curListener = (e2) => {
704
+ let curListener = (e3) => {
657
705
  el.removeEventListener(evts[cur], curListener);
658
- if (typeof (fn = fn.call(el, e2)) !== "function")
706
+ if (typeof (fn = fn.call(el, e3)) !== "function")
659
707
  fn = () => {
660
708
  };
661
709
  if (++cur < evts.length)
@@ -663,7 +711,7 @@ var addListener = (el, evt, startFn) => {
663
711
  else if (!startFn[_stop])
664
712
  nextEvt(startFn);
665
713
  };
666
- el.addEventListener(evts[cur], curListener);
714
+ el.addEventListener(evts[cur], curListener, opts);
667
715
  };
668
716
  nextEvt(startFn);
669
717
  }
@@ -673,43 +721,119 @@ var removeListener = (el, evt, fn) => {
673
721
  fn[_stop] = true;
674
722
  el.removeEventListener(evt, fn);
675
723
  };
676
- secondary["data"] = (el, expr) => {
677
- let evaluate = parseExpr(el, expr, ":data");
678
- return (state) => {
679
- let value = evaluate(state);
680
- for (let key in value)
681
- el.dataset[key] = value[key];
682
- };
683
- };
684
- secondary["aria"] = (el, expr) => {
685
- let evaluate = parseExpr(el, expr, ":aria");
686
- const update = (value) => {
687
- for (let key in value)
688
- attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
689
- };
690
- return (state) => update(evaluate(state));
691
- };
692
- secondary[""] = (el, expr) => {
693
- let evaluate = parseExpr(el, expr, ":");
694
- if (evaluate)
695
- return (state) => {
696
- let value = evaluate(state);
697
- for (let key in value)
698
- attr(el, dashcase(key), value[key]);
724
+ var mods = {
725
+ throttle(el, cb, opts, limit) {
726
+ limit = Number(limit) || 108;
727
+ let pause, planned, block = () => {
728
+ pause = true;
729
+ setTimeout(() => {
730
+ pause = false;
731
+ if (planned)
732
+ cb(e), planned = false, block();
733
+ });
699
734
  };
735
+ return [el, (e3) => {
736
+ if (pause)
737
+ return planned = true, _stop;
738
+ cb(e3);
739
+ block();
740
+ }];
741
+ },
742
+ debounce(el, cb, opts, wait) {
743
+ wait = Number(wait) || 108;
744
+ let timeout, later = () => {
745
+ timeout = null;
746
+ cb(e);
747
+ };
748
+ return [el, (e3) => {
749
+ clearTimeout(timeout);
750
+ timeout = setTimeout(later, wait);
751
+ }];
752
+ },
753
+ window(el, cb) {
754
+ return [window, cb];
755
+ },
756
+ document(el, cb) {
757
+ return [document, cb];
758
+ },
759
+ outside(el, cb) {
760
+ return [el, (e3) => {
761
+ if (el.contains(e3.target))
762
+ return _stop;
763
+ if (e3.target.isConnected === false)
764
+ return _stop;
765
+ if (el.offsetWidth < 1 && el.offsetHeight < 1)
766
+ return _stop;
767
+ cb(e3);
768
+ }];
769
+ },
770
+ prevent(el, cb) {
771
+ return [el, (e3) => {
772
+ if (cb(e3) !== _stop)
773
+ e3.preventDefault();
774
+ }];
775
+ },
776
+ stop(el, cb) {
777
+ return [el, (e3) => {
778
+ if (cb(e3) !== _stop)
779
+ e3.stopPropagation();
780
+ }];
781
+ },
782
+ self(el, cb) {
783
+ return [el, (e3) => {
784
+ e3.target === el && cb(e3);
785
+ }];
786
+ },
787
+ once(el, cb, opts) {
788
+ opts.once = true;
789
+ return [el, cb];
790
+ },
791
+ passive(el, cb, opts) {
792
+ opts.passive = true;
793
+ return [el, cb];
794
+ },
795
+ capture(el, cb, opts) {
796
+ opts.capture = true;
797
+ return [el, cb];
798
+ }
700
799
  };
701
- var directives_default = (el, expr, values, name) => {
702
- let evt = name.startsWith("on") && name.slice(2);
703
- let evaluate = parseExpr(el, expr, ":" + name);
704
- if (evaluate)
705
- return evt ? (state) => {
706
- let value = evaluate(state);
707
- if (value) {
708
- addListener(el, evt, value);
709
- return () => removeListener(el, evt, value);
710
- }
711
- } : (state) => attr(el, name, evaluate(state));
712
- };
800
+ var keys = {
801
+ ctrl: "Control Ctrl",
802
+ shift: "Shift",
803
+ alt: "Alt",
804
+ meta: "Meta",
805
+ cmd: "Meta",
806
+ down: "ArrowDown",
807
+ up: "ArrowUp",
808
+ left: "ArrowLeft",
809
+ right: "ArrowRight",
810
+ end: "End",
811
+ home: "Home",
812
+ pagedown: "PageDown",
813
+ pageup: "PageUp",
814
+ enter: "Enter",
815
+ plus: "+",
816
+ minus: "-",
817
+ star: "*",
818
+ slash: "/",
819
+ period: ".",
820
+ equal: "=",
821
+ underscore: "_",
822
+ esc: "Escape",
823
+ escape: "Escape",
824
+ tab: "Tab",
825
+ space: " ",
826
+ backspace: "Backspace",
827
+ delete: "Delete"
828
+ };
829
+ for (let keyAttr in keys) {
830
+ let keyName = keys[keyAttr];
831
+ mods[keyAttr] = (el, cb, opts, extraKey) => [el, (e3) => {
832
+ if (!e3.key || !keyName.includes(e3.key))
833
+ return _stop;
834
+ cb(e3);
835
+ }];
836
+ }
713
837
  var attr = (el, name, v2) => {
714
838
  if (v2 == null || v2 === false)
715
839
  el.removeAttribute(name);
@@ -723,16 +847,16 @@ function parseExpr(el, expression, dir) {
723
847
  let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression) || /^(let|const)\s/.test(expression) ? `(() => { ${expression} })()` : expression;
724
848
  try {
725
849
  evaluate = evaluatorMemo[expression] = new Function(`__scope`, `with (__scope) { return ${rightSideSafeExpression} };`);
726
- } catch (e2) {
727
- return exprError(e2, el, expression, dir);
850
+ } catch (e3) {
851
+ return exprError(e3, el, expression, dir);
728
852
  }
729
853
  }
730
854
  return (state) => {
731
855
  let result;
732
856
  try {
733
857
  result = evaluate.call(el, state);
734
- } catch (e2) {
735
- return exprError(e2, el, expression, dir);
858
+ } catch (e3) {
859
+ return exprError(e3, el, expression, dir);
736
860
  }
737
861
  return result;
738
862
  };
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!==r;){var i=r;for(r=void 0,o++;void 0!==i;){var s=i.o;if(i.o=void 0,i.f&=-3,!(8&i.f)&&u(i))try{i.c()}catch(i){e||(t=i,e=!0)}i=s}}if(o=0,n--,e)throw t}}var i=void 0,r=void 0,n=0,o=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 f(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 a(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){f.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){n++;var o=i;i=void 0;try{r()}catch(e){throw t.f&=-2,t.f|=8,p(t),e}finally{i=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(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)}f.prototype.h=function(){return!0},f.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)},f.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)},f.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}}))},f.prototype.valueOf=function(){return this.value},f.prototype.toString=function(){return this.value+""},f.prototype.peek=function(){return this.v},Object.defineProperty(f.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){o>100&&t(),this.v=i,this.i++,s++,n++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N()}finally{e()}}}}),(c.prototype=new f).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=i;try{a(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)}f.prototype.S.call(this,t)},c.prototype.U=function(t){if(f.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),a(this),n++;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 m=new FinalizationRegistry((t=>t.call?.())),g=(t,e,i,r,n,o)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,i,r),o=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(n,e)||(t.then?.((t=>(!n&&e(t),r?.())),i)||(async o=>{try{for await(o of t){if(n)return;e(o)}r?.()}catch(t){i?.(t)}})())&&(t=>n=1),m.register(t,o),o);var s},S=t=>t&&t[A],A=Symbol("signal-struct");function w(t,e){if(S(t)&&!e)return t;if(x(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 i=o[t]=new c(e.get.bind(n));Object.defineProperty(n,t,{get:()=>i.value,set:e.set?.bind(n),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),u=o[t]=(i=s)&&i.peek?s:new f(l?void 0:x(s)?Object.seal(w(s)):Array.isArray(s)?w(s):s);l&&g(s,(t=>u.value=t)),Object.defineProperty(n,t,{get:()=>u.value,set(t){if(x(t)){if(x(u.value))try{return void Object.assign(u.value,t)}catch(t){}u.value=Object.seal(w(t))}else Array.isArray(t)?u.value=w(t):u.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,A,{configurable:!1,enumerable:!1,value:!0}),n}var i,r;return Array.isArray(t)&&!S(t[0])?t.map((t=>w(t))):t}function x(t){return t&&t.constructor===Object}w.isStruct=S;var O=(t,e,i,r=null)=>{let n,o,s,l=0,f=i.length,u=e.length,{remove:a,same:h,insert:c,replace:v}=O;for(;l<f&&l<u&&h(e[l],i[l]);)l++;for(;l<f&&l<u&&h(i[f-1],e[u-1]);)r=i[(--u,--f)];if(l==u)for(;l<f;)c(r,i[l++],t);else{for(n=e[l];l<f;)s=i[l++],o=n?n.nextSibling:r,h(n,s)?n=o:l<f&&h(i[l],o)?(v(n,s,t),n=o):c(n,s,t);for(;!h(n,r);)o=n.nextSibling,a(n,t),n=o}return i};O.same=(t,e)=>t==e,O.replace=(t,e,i)=>i.replaceChild(e,t),O.insert=(t,e,i)=>i.insertBefore(e,t),O.remove=(t,e)=>e.removeChild(t);var j=O,N={},E={},k={},W=t=>null===t?E:void 0===t?k:"number"==typeof t||t instanceof Number?N[t]||(N[t]=new Number(t)):"string"==typeof t||t instanceof String?N[t]||(N[t]=new String(t)):"boolean"==typeof t||t instanceof Boolean?N[t]||(N[t]=new Boolean(t)):t,$={},P={};$.if=(t,e)=>{let i=document.createTextNode(""),r=[M(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),r.push(M(t,e,":else :if"))):(o.remove(),n.push(o),r.push((()=>1)));return t.replaceWith(o=i),t=>{let e=r.findIndex((e=>e(t)));n[e]!=o&&((o[C]||o).replaceWith(o=n[e]||i),z(o,t))}},$.with=(t,e,i)=>{z(t,w(M(t,e,"with")(i),i))};var C=Symbol(":each");$.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(),n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),r]:[n,"",r]}(e);if(!i)return R(new Error,t,e);const r=t[C]=document.createTextNode("");t.replaceWith(r);const n=M(t,i[2],":each"),o=t.getAttribute(":key"),s=o?M(null,o):null;t.removeAttribute(":key");const l=new WeakMap,f=new WeakMap;let u=[];return o=>{let a=n(o);a?"number"==typeof a?a=Array.from({length:a},((t,e)=>[e,e+1])):Array.isArray(a)?a=a.map(((t,e)=>[e+1,t])):"object"==typeof a?a=Object.entries(a):R(Error("Bad list value"),t,e,":each"):a=[];let h=[],c=[];for(let[e,r]of a){let n,u,a=s?.({[i[0]]:r,[i[1]]:e});("string"==typeof(v=a)||"boolean"==typeof v||"number"==typeof v)&&(a=W(a)),null==a?n=t.cloneNode(!0):(n=f.get(a))||f.set(a,n=t.cloneNode(!0)),h.push(n),null!=a&&(u=l.get(a))?u[i[0]]=r:(u=w({[i[0]]:r,[i[1]]:e},o),null!=a&&l.set(a,u)),c.push(u)}var v;j(r.parentNode,u,h,r),u=h;for(let t=0;t<h.length;t++)z(h[t],c[t])}},P.ref=(t,e,i)=>{i[e]=t},P.id=(t,e)=>{let i=M(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},P.class=(t,e)=>{let i=M(t,e,":class"),r=t.className;return e=>{let n=i(e);t.className=r+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},P.style=(t,e)=>{let i=M(t,e,":style"),r=t.getAttribute("style")||"";return r.endsWith(";")||(r+="; "),e=>{let n=i(e);if("string"==typeof n)t.setAttribute("style",r+n);else for(let e in n)t.style[e]=n[e]}},P.text=(t,e)=>{let i=M(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},P.value=(t,e)=>{let i,r,n=M(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=>(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":"",D(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))},P.on=(t,e)=>{let i=M(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)L(t,e,r[e])}}};var U=Symbol("stop"),B=(t,e,i)=>{if(e.indexOf("..")<0)t.addEventListener(e,i);else{const r=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),n=(e,o=0)=>{let s=l=>{t.removeEventListener(r[o],s),"function"!=typeof(e=e.call(t,l))&&(e=()=>{}),++o<r.length?n(e,o):i[U]||n(i)};t.addEventListener(r[o],s)};n(i)}},L=(t,e,i)=>{e.indexOf("..")>=0&&(i[U]=!0),t.removeEventListener(e,i)};P.data=(t,e)=>{let i=M(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},P.aria=(t,e)=>{let i=M(t,e,":aria");return e=>(e=>{for(let i in e)D(t,"aria-"+F(i),null==e[i]?null:e[i]+"")})(i(e))},P[""]=(t,e)=>{let i=M(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)D(t,F(e),r[e])}};var T=(t,e,i,r)=>{let n=r.startsWith("on")&&r.slice(2),o=M(t,e,":"+r);if(o)return n?e=>{let i=o(e);if(i)return B(t,n,i),()=>L(t,n,i)}:e=>D(t,r,o(e))},D=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")},_={};function M(t,e,i){let r=_[e];if(!r){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=_[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(r){return R(r,t,e,i)}}return n=>{let o;try{o=r.call(t,n)}catch(r){return R(r,t,e,i)}return o}}function R(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 F(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var I=new WeakMap;function z(t,i){if(!t.children)return;if(I.has(t)){let r=I.get(t);return function(t){if(n>0)return t();n++;try{t()}finally{e()}}((()=>Object.assign(r,i))),r}const r=w(i||{}),o=[],s=(t,e=t.parentNode)=>{for(let i in $){let n=":"+i;if(t.hasAttribute?.(n)){let s=t.getAttribute(n);if(t.removeAttribute(n),!s)continue;if(o.push($[i](t,s,r,i)),I.has(t)||t.parentNode!==e)return!1}}if(t.attributes)for(let i=0;i<t.attributes.length;){let n=t.attributes[i];if(":"!==n.name[0]){i++;continue}t.removeAttribute(n.name);let s=n.value;if(!s)continue;let l=n.name.slice(1).split(":");for(let i of l){let n=P[i]||T;if(o.push(n(t,s,r,i)),I.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 o)if(t){let e;b((()=>{"function"==typeof e&&e(),e=t(r)}))}return Object.seal(r),I.set(t,r),r}var X=z;export{X as default};
1
+ function t(){throw new Error("Cycle detected")}function i(){if(o>1)o--;else{for(var t,e=!1;void 0!==n;){var i=n;for(n=void 0,s++;void 0!==i;){var r=i.o;if(i.o=void 0,i.f&=-3,!(8&i.f)&&f(i))try{i.c()}catch(i){e||(t=i,e=!0)}i=r}}if(s=0,o--,e)throw t}}var r=void 0,n=void 0,o=0,s=0,l=0;function a(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 u(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 c(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 v(t){u.call(this,void 0),this.x=t,this.s=void 0,this.g=l-1,this.f=4}function p(t){var e=t.u;if(t.u=void 0,"function"==typeof e){o++;var n=r;r=void 0;try{e()}catch(e){throw t.f&=-2,t.f|=8,d(t),e}finally{r=n,i()}}}function d(t){for(var e=t.s;void 0!==e;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,p(t)}function y(t){if(r!==this)throw new Error("Out-of-order effect");h(this),r=t,this.f&=-2,8&this.f&&d(this),i()}function b(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}function m(t){var e=new b(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 m((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=a(this);return void 0!==t&&(t.i=this.i),this.v},set:function(e){if(e!==this.v){s>100&&t(),this.v=e,this.i++,l++,o++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N()}finally{i()}}}}),(v.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===l)return!0;if(this.g=l,this.f|=1,this.i>0&&!f(this))return this.f&=-2,!0;var t=r;try{c(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,h(this),this.f&=-2,!0},v.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)},v.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)}},v.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},v.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(v.prototype,"value",{get:function(){1&this.f&&t();var e=a(this);if(this.h(),void 0!==e&&(e.i=this.i),16&this.f)throw this.v;return this.v}}),b.prototype.c=function(){var t=this.S();try{8&this.f||void 0===this.x||(this.u=this.x())}finally{t()}},b.prototype.S=function(){1&this.f&&t(),this.f|=1,this.f&=-9,p(this),c(this),o++;var e=r;return r=this,y.bind(this,e)},b.prototype.N=function(){2&this.f||(this.f|=2,this.o=n,n=this)},b.prototype.d=function(){this.f|=8,1&this.f||d(this)},Symbol.observable||=Symbol("observable");var g=new FinalizationRegistry((t=>t.call?.())),w=(t,e,i,r,n,o)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,i,r),o=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(n,e)||(t.then?.((t=>(!n&&e(t),r?.())),i)||(async o=>{try{for await(o of t){if(n)return;e(o)}r?.()}catch(t){i?.(t)}})())&&(t=>n=1),g.register(t,o),o);var s},S=t=>t&&t[A],A=Symbol("signal-struct");function x(t,e){if(S(t)&&!e)return t;if(O(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 i=o[t]=new v(e.get.bind(n));Object.defineProperty(n,t,{get:()=>i.value,set:e.set?.bind(n),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=o[t]=(i=s)&&i.peek?s:new u(l?void 0:O(s)?Object.seal(x(s)):Array.isArray(s)?x(s):s);l&&w(s,(t=>a.value=t)),Object.defineProperty(n,t,{get:()=>a.value,set(t){if(O(t)){if(O(a.value))try{return void Object.assign(a.value,t)}catch(t){}a.value=Object.seal(x(t))}else Array.isArray(t)?a.value=x(t):a.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,A,{configurable:!1,enumerable:!1,value:!0}),n}var i,r;if(Array.isArray(t)&&!S(t[0]))for(let e=0;e<t.length;e++)t[e]=x(t[e]);return t}function O(t){return t&&t.constructor===Object}x.isStruct=S;var j=(t,e,i,r=null)=>{let n,o,s,l=0,a=i.length,u=e.length,{remove:f,same:c,insert:h,replace:v}=j;for(;l<a&&l<u&&c(e[l],i[l]);)l++;for(;l<a&&l<u&&c(i[a-1],e[u-1]);)r=i[(--u,--a)];if(l==u)for(;l<a;)h(r,i[l++],t);else{for(n=e[l];l<a;)s=i[l++],o=n?n.nextSibling:r,c(n,s)?n=o:l<a&&c(i[l],o)?(v(n,s,t),n=o):h(n,s,t);for(;!c(n,r);)o=n.nextSibling,f(n,t),n=o}return i};j.same=(t,e)=>t==e,j.replace=(t,e,i)=>i.replaceChild(e,t),j.insert=(t,e,i)=>i.insertBefore(e,t),j.remove=(t,e)=>e.removeChild(t);var N=j,E={},k={},P={},W=t=>null===t?k:void 0===t?P:"number"==typeof t||t instanceof Number?E[t]||(E[t]=new Number(t)):"string"==typeof t||t instanceof String?E[t]||(E[t]=new String(t)):"boolean"==typeof t||t instanceof Boolean?E[t]||(E[t]=new Boolean(t)):t,C={},T={};C.if=(t,e)=>{let i=document.createTextNode(""),r=[H(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),r.push(H(t,e,":else :if"))):(o.remove(),n.push(o),r.push((()=>1)));return t.replaceWith(o=i),t=>{let e=r.findIndex((e=>e(t)));n[e]!=o&&((o[D]||o).replaceWith(o=n[e]||i),X(o,t))}},C.with=(t,e,i)=>{X(t,x(H(t,e,"with")(i),i))};var D=Symbol(":each");C.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(),n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),r]:[n,"",r]}(e);if(!i)return I(new Error,t,e);const r=t[D]=document.createTextNode("");t.replaceWith(r);const n=H(t,i[2],":each"),o=t.getAttribute(":key"),s=o?H(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):I(Error("Bad list value"),t,e,":each"):f=[];let c=[],h=[];for(let[e,r]of f){let n,u,f=s?.({[i[0]]:r,[i[1]]:e});("string"==typeof(v=f)||"boolean"==typeof v||"number"==typeof v)&&(f=W(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[i[0]]=r:(u=x({[i[0]]:r,[i[1]]:e},o),null!=f&&l.set(f,u)),h.push(u)}var v;N(r.parentNode,u,c,r),u=c;for(let t=0;t<c.length;t++)X(c[t],h[t])}},T.ref=(t,e,i)=>{i[e]=t},T.id=(t,e)=>{let i=H(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},T.class=(t,e)=>{let i=H(t,e,":class"),r=t.className;return e=>{let n=i(e);t.className=r+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},T.style=(t,e)=>{let i=H(t,e,":style"),r=t.getAttribute("style")||"";return r.endsWith(";")||(r+="; "),e=>{let n=i(e);if("string"==typeof n)t.setAttribute("style",r+n);else for(let e in n)t.style[e]=n[e]}},T.text=(t,e)=>{let i=H(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},T.data=(t,e)=>{let i=H(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},T.aria=(t,e)=>{let i=H(t,e,":aria");return e=>(e=>{for(let i in e)R(t,"aria-"+q(i),null==e[i]?null:e[i]+"")})(i(e))},T[""]=(t,e)=>{let i=H(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)R(t,q(e),r[e])}},T.value=(t,e)=>{let i,r,n=H(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=>(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":"",R(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))},T.on=(t,e)=>{let i=H(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)L(t,e,r[e])}}};var U=(t,e,i,r)=>{let n=r.startsWith("on")&&r.slice(2),o=H(t,e,":"+r);if(o)return n?e=>{let i=o(e);if(i)return B(t,n,i),()=>L(t,n,i)}:e=>R(t,r,o(e))},$=Symbol("stop"),B=(t,e,i)=>{let r=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),n={};if(r[0]=r[0].replace(/\.(\w+)?-?([\w]+)?/g,((e,r,o)=>((r=M[r])&&([t,i]=r(t,i,n,o)),""))),1==r.length)t.addEventListener(r[0],i,n);else{const e=(o,s=0)=>{let l=n=>{t.removeEventListener(r[s],l),"function"!=typeof(o=o.call(t,n))&&(o=()=>{}),++s<r.length?e(o,s):i[$]||e(i)};t.addEventListener(r[s],l,n)};e(i)}},L=(t,e,i)=>{e.indexOf("..")>=0&&(i[$]=!0),t.removeEventListener(e,i)},M={throttle(t,i,r,n){n=Number(n)||108;let o,s,l=()=>{o=!0,setTimeout((()=>{o=!1,s&&(i(e),s=!1,l())}))};return[t,t=>{if(o)return s=!0,$;i(t),l()}]},debounce(t,i,r,n){n=Number(n)||108;let o,s=()=>{o=null,i(e)};return[t,t=>{clearTimeout(o),o=setTimeout(s,n)}]},window:(t,e)=>[window,e],document:(t,e)=>[document,e],outside:(t,e)=>[t,i=>t.contains(i.target)||!1===i.target.isConnected||t.offsetWidth<1&&t.offsetHeight<1?$:void e(i)],prevent:(t,e)=>[t,t=>{e(t)!==$&&t.preventDefault()}],stop:(t,e)=>[t,t=>{e(t)!==$&&t.stopPropagation()}],self:(t,e)=>[t,i=>{i.target===t&&e(i)}],once:(t,e,i)=>(i.once=!0,[t,e]),passive:(t,e,i)=>(i.passive=!0,[t,e]),capture:(t,e,i)=>(i.capture=!0,[t,e])},_={ctrl:"Control Ctrl",shift:"Shift",alt:"Alt",meta:"Meta",cmd:"Meta",down:"ArrowDown",up:"ArrowUp",left:"ArrowLeft",right:"ArrowRight",end:"End",home:"Home",pagedown:"PageDown",pageup:"PageUp",enter:"Enter",plus:"+",minus:"-",star:"*",slash:"/",period:".",equal:"=",underscore:"_",esc:"Escape",escape:"Escape",tab:"Tab",space:" ",backspace:"Backspace",delete:"Delete"};for(let t in _){let e=_[t];M[t]=(t,i,r,n)=>[t,t=>{if(!t.key||!e.includes(t.key))return $;i(t)}]}var R=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")},F={};function H(t,e,i){let r=F[e];if(!r){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=F[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(r){return I(r,t,e,i)}}return n=>{let o;try{o=r.call(t,n)}catch(r){return I(r,t,e,i)}return o}}function I(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 q(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var z=new WeakMap;function X(t,e){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{i()}}((()=>Object.assign(r,e))),r}const r=x(e||{}),n=[],s=(t,e=t.parentNode)=>{for(let i in C){let o=":"+i;if(t.hasAttribute?.(o)){let s=t.getAttribute(o);if(t.removeAttribute(o),!s)continue;if(n.push(C[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;if(!s)continue;let l=o.name.slice(1).split(":");for(let i of l){let o=T[i]||U;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;m((()=>{"function"==typeof e&&e(),e=t(r)}))}return Object.seal(r),z.set(t,r),r}var Z=X;export{Z as default};
package/src/directives.js CHANGED
@@ -182,6 +182,32 @@ secondary['text'] = (el, expr) => {
182
182
  }
183
183
  }
184
184
 
185
+ secondary['data'] = (el, expr) => {
186
+ let evaluate = parseExpr(el, expr, ':data')
187
+
188
+ return ((state) => {
189
+ let value = evaluate(state)
190
+ for (let key in value) el.dataset[key] = value[key];
191
+ })
192
+ }
193
+
194
+ secondary['aria'] = (el, expr) => {
195
+ let evaluate = parseExpr(el, expr, ':aria')
196
+ const update = (value) => {
197
+ for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
198
+ }
199
+ return ((state) => update(evaluate(state)))
200
+ }
201
+
202
+ // set props in-bulk or run effect
203
+ secondary[''] = (el, expr) => {
204
+ let evaluate = parseExpr(el, expr, ':')
205
+ if (evaluate) return (state) => {
206
+ let value = evaluate(state)
207
+ for (let key in value) attr(el, dashcase(key), value[key]);
208
+ }
209
+ }
210
+
185
211
  // connect expr to element value
186
212
  secondary['value'] = (el, expr) => {
187
213
  let evaluate = parseExpr(el, expr, ':value')
@@ -219,13 +245,41 @@ secondary['on'] = (el, expr) => {
219
245
  }
220
246
  }
221
247
 
248
+ // any unknown directive
249
+ export default (el, expr, state, name) => {
250
+ let evt = name.startsWith('on') && name.slice(2)
251
+ let evaluate = parseExpr(el, expr, ':'+name)
252
+
253
+ if (!evaluate) return
254
+
255
+ if (evt) return state => {
256
+ let value = evaluate(state)
257
+ if (value) {
258
+ addListener(el, evt, value)
259
+ return () => removeListener(el, evt, value)
260
+ }
261
+ }
262
+
263
+ return state => attr(el, name, evaluate(state))
264
+ }
265
+
222
266
  const _stop = Symbol('stop')
223
267
  const addListener = (el, evt, startFn) => {
224
- if (evt.indexOf('..')<0) el.addEventListener(evt, startFn);
268
+ // ona..onb
269
+ let evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e),
270
+ opts = {}
271
+
272
+ // onevt.debounce-108
273
+ evts[0] = evts[0].replace(
274
+ /\.(\w+)?-?([\w]+)?/g,
275
+ (match, mod, param) => {
276
+ (mod=mods[mod]) ? ([el, startFn] = mod(el, startFn, opts, param), '') : ''
277
+ return ''
278
+ }
279
+ );
225
280
 
226
- // sequences like `a..b`: fn
281
+ if (evts.length == 1) el.addEventListener(evts[0], startFn, opts);
227
282
  else {
228
- const evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e)
229
283
  const nextEvt = (fn, cur=0) => {
230
284
  let curListener = e => {
231
285
  el.removeEventListener(evts[cur], curListener)
@@ -233,7 +287,7 @@ const addListener = (el, evt, startFn) => {
233
287
  if (++cur < evts.length) nextEvt(fn, cur);
234
288
  else if (!startFn[_stop]) nextEvt(startFn); // update only if chain isn't stopped
235
289
  }
236
- el.addEventListener(evts[cur],curListener)
290
+ el.addEventListener(evts[cur], curListener, opts)
237
291
  }
238
292
  nextEvt(startFn)
239
293
  }
@@ -243,44 +297,68 @@ const removeListener = (el, evt, fn) => {
243
297
  el.removeEventListener(evt, fn);
244
298
  }
245
299
 
246
- secondary['data'] = (el, expr) => {
247
- let evaluate = parseExpr(el, expr, ':data')
248
-
249
- return ((state) => {
250
- let value = evaluate(state)
251
- for (let key in value) el.dataset[key] = value[key];
252
- })
253
- }
254
-
255
- secondary['aria'] = (el, expr) => {
256
- let evaluate = parseExpr(el, expr, ':aria')
257
- const update = (value) => {
258
- for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
259
- }
260
- return ((state) => update(evaluate(state)))
261
- }
262
-
263
- // set props in-bulk or run effect
264
- secondary[''] = (el, expr) => {
265
- let evaluate = parseExpr(el, expr, ':')
266
- if (evaluate) return (state) => {
267
- let value = evaluate(state)
268
- for (let key in value) attr(el, dashcase(key), value[key]);
269
- }
270
- }
271
-
272
- // any other prop directive
273
- export default (el, expr, values, name) => {
274
- let evt = name.startsWith('on') && name.slice(2)
275
- let evaluate = parseExpr(el, expr, ':'+name)
276
- if (evaluate) return evt ? state => {
277
- let value = evaluate(state)
278
- if (value) {
279
- addListener(el, evt, value)
280
- return () => removeListener(el, evt, value)
300
+ // event modifiers
301
+ const mods = {
302
+ throttle(el, cb, opts, limit) {
303
+ limit = Number(limit) || 108
304
+ let pause, planned, block = () => {
305
+ pause = true
306
+ setTimeout(() => {
307
+ pause = false
308
+ // if event happened during blocked time, it schedules call by the end
309
+ if (planned) cb(e), planned = false, block();
310
+ })
281
311
  }
282
- }
283
- : state => attr(el, name, evaluate(state))
312
+ return [el, e => {
313
+ if (pause) return (planned = true, _stop)
314
+ cb(e); block();
315
+ }]
316
+ },
317
+
318
+ debounce(el, cb, opts, wait) {
319
+ wait = Number(wait) || 108;
320
+ let timeout, later = () => { timeout = null; cb(e) }
321
+ return [el, (e) => {
322
+ clearTimeout(timeout)
323
+ timeout = setTimeout(later, wait)
324
+ }]
325
+ },
326
+
327
+ window(el, cb) { return [window, cb] },
328
+ document(el, cb) { return [document, cb] },
329
+ outside(el, cb) {
330
+ return [el, (e) => {
331
+ if (el.contains(e.target)) return _stop
332
+ if (e.target.isConnected === false) return _stop
333
+ if (el.offsetWidth < 1 && el.offsetHeight < 1) return _stop
334
+ cb(e)
335
+ }]
336
+ },
337
+ prevent(el, cb) { return [el, e => { if (cb(e) !== _stop) e.preventDefault(); } ]},
338
+ stop(el, cb) { return [el, e => { if (cb(e) !== _stop) e.stopPropagation(); } ]},
339
+ self(el, cb) { return [el, e => { e.target === el && cb(e) } ]},
340
+ once(el, cb, opts) { opts.once = true; return [el, cb] },
341
+ passive(el, cb, opts) { opts.passive = true; return [el, cb] },
342
+ capture(el, cb, opts) { opts.capture = true; return [el, cb] },
343
+ };
344
+ let keys = {
345
+ ctrl:'Control Ctrl',
346
+ shift:'Shift',
347
+ alt:'Alt',
348
+ meta:'Meta',cmd:'Meta',
349
+ down:'ArrowDown',up:'ArrowUp',left:'ArrowLeft',right:'ArrowRight',
350
+ end:'End',home:'Home',pagedown:'PageDown',pageup:'PageUp',
351
+ enter:'Enter',plus:'+',minus:'-',star:'*',slash:'/',period:'.',equal:'=',underscore:'_',
352
+ esc:'Escape',escape:'Escape',tab:'Tab',space:' ',
353
+ backspace:'Backspace', delete:'Delete'
354
+ }
355
+ for (let keyAttr in keys) {
356
+ let keyName = keys[keyAttr]
357
+ mods[keyAttr] = (el, cb, opts, extraKey) => [el, e => {
358
+ // _stop indicates skip subsequent modifiers
359
+ if (!e.key || !keyName.includes(e.key)) return _stop
360
+ cb(e)
361
+ }]
284
362
  }
285
363
 
286
364
  // set attr
@@ -289,7 +367,6 @@ const attr = (el, name, v) => {
289
367
  else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
290
368
  }
291
369
 
292
-
293
370
  let evaluatorMemo = {}
294
371
 
295
372
  // borrowed from alpine: https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L61
@@ -326,7 +403,7 @@ function parseExpr(el, expression, dir) {
326
403
  }
327
404
  }
328
405
 
329
- export function exprError(error, element, expression, dir) {
406
+ function exprError(error, element, expression, dir) {
330
407
  Object.assign( error, { element, expression } )
331
408
  console.warn(`∴ ${error.message}\n\n${dir}=${ expression ? `"${expression}"\n\n` : '' }`, element)
332
409
  setTimeout(() => { throw error }, 0)
package/test/test.js CHANGED
@@ -424,12 +424,16 @@ test.todo('each: unmounted elements remove listeners', async () => {
424
424
 
425
425
  test('each: internal children get updated by state update, also: update by running again', () => {
426
426
  let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
427
- sprae(el, { items: [1,2,3] })
427
+ let state = sprae(el, { items: [1,2,3] })
428
428
  is(el.textContent, '123')
429
- let state = sprae(el, { items: [0,2,3] })
429
+ state.items = [2, 2, 3]
430
+ is(el.textContent, '223')
431
+ state = sprae(el, { items: [0,2,3] })
430
432
  is(el.textContent, '023')
433
+ // NOTE: this doesn't update items, since they're new array
434
+ console.log('set items')
431
435
  state.items[0] = 1
432
- state.items = state.items
436
+ state.items = [...state.items]
433
437
  is(el.textContent, '123')
434
438
  })
435
439
 
@@ -569,6 +573,65 @@ test('on: state changes between chain of events', e => {
569
573
  is(log, [1, 1.1, 2])
570
574
  })
571
575
 
576
+ test('on: once', e => {
577
+ // NOTE: if callback updates it's still rebound
578
+ let el = h`<x :onx.once="(e=>x&&log.push(this))" ></x>`
579
+ let log = []
580
+ let state = sprae(el, {log, x:1})
581
+ el.dispatchEvent(new window.Event('x'));
582
+ is(log, [el])
583
+ el.dispatchEvent(new window.Event('x'));
584
+ is(log, [el])
585
+ state.x = 2
586
+ el.dispatchEvent(new window.Event('x'));
587
+ el.dispatchEvent(new window.Event('x'));
588
+ is(log, [el])
589
+ })
590
+
591
+ test('on: capture, stop, prevent', e => {
592
+ let el = h`<x :onx.capture="e=>log.push(1)"><y :onx="e=>log.push(2)"></y></x>`
593
+ let state = sprae(el, {log:[]})
594
+ el.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
595
+ is(state.log, [1,2])
596
+
597
+ let el2 = h`<x :onx="e=>log.push(1)"><y :onx.stop="e=>log.push(2)"></y></x>`
598
+ let state2 = sprae(el2, {log:[]})
599
+ el2.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
600
+ is(state2.log, [2])
601
+ })
602
+
603
+ test('on: window, self', e => {
604
+ let el = h`<x :onx.self="e=>log.push(1)"><y :onx.window="e=>log.push(2)"></y></x>`
605
+ let state = sprae(el, {log:[]})
606
+ el.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
607
+ is(state.log, [])
608
+ el.dispatchEvent(new window.Event('x', {bubbles:true}));
609
+ is(state.log, [1])
610
+ window.dispatchEvent(new window.Event('x', {bubbles:true}));
611
+ is(state.log, [1,2])
612
+ })
613
+
614
+ test('on: keys', e => {
615
+ let el = h`<x :onkeydown.enter="e=>log.push(1)"></x>`
616
+ let state = {log:[]}
617
+ sprae(el, state)
618
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: '' }));
619
+ is(state.log,[])
620
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' }));
621
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: '' }));
622
+ is(state.log,[1])
623
+ el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' }));
624
+ is(state.log,[1,1])
625
+ })
626
+
627
+ test('on: keys with prevent', e => {
628
+ let el = h`<y :onkeydown="e=>log.push(e.key)"><x :ref="x" :onkeydown.enter.stop="e=>1"></x></y>`
629
+ let state = sprae(el, {log:[]})
630
+ state.x.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'x', bubbles: true }));
631
+ state.x.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
632
+ is(state.log,['x'])
633
+ })
634
+
572
635
  test('with: inline', () => {
573
636
  let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
574
637
  let state = sprae(el, {baz: 'qux'})
package/todo.md CHANGED
@@ -39,4 +39,7 @@
39
39
  * [ ] frameworks benchmark
40
40
  * [ ] examples
41
41
  * [x] todomvc
42
- * [x] waveplay
42
+ * [x] waveplay
43
+ * [x] evt modifiers
44
+ * [x] once, capture, passive
45
+ * [x] ...rest