sprae 2.6.0 → 2.7.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.6.0",
4
+ "version": "2.7.0",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
7
7
  "type": "module",
package/readme.md CHANGED
@@ -261,7 +261,21 @@ This way, for example, _@preact/signals_ or _rxjs_ can be connected directly byp
261
261
 
262
262
  ## Hints
263
263
 
264
- **1.** Data supports signal values, which can be an alternative way to control template state:
264
+ **1.** To batch-update state (avoid multiple DOM changes), rerun sprae with new state:
265
+
266
+ ```html
267
+ <li :each="item, id in items" :key="id" :text="item"></li>
268
+
269
+ <script type="module">
270
+ sprae(el, {items: ['foo', 'bar', 'baz']})
271
+ // <li>foo</li><li>bar</li><li>baz</li>
272
+
273
+ sprae(el, {items: ['foo', 'qux']})
274
+ // <li>foo</li><li>qux</li>
275
+ </script>
276
+ ```
277
+
278
+ **2.** Data supports signal values, which can be an alternative way to control template state:
265
279
 
266
280
  ```html
267
281
  <div id="done" :text="loading ? 'loading' : result">...</div>
@@ -283,7 +297,7 @@ This way, for example, _@preact/signals_ or _rxjs_ can be connected directly byp
283
297
  </script>
284
298
  ```
285
299
 
286
- **2.** Data recognizes reactive values as inputs as well: _Promise_ / _Thenable_, _Observable_ / _Subscribable_, _AsyncIterable_ (etc., see [sube](https://github.com/dy/sube/blob/main/README.md)). This way, for example, _rxjs_ can be connected to template directly.
300
+ **3.** Data recognizes reactive values as inputs as well: _Promise_ / _Thenable_, _Observable_ / _Subscribable_, _AsyncIterable_ (etc., see [sube](https://github.com/dy/sube/blob/main/README.md)). This way, for example, _rxjs_ can be connected to template directly.
287
301
 
288
302
  ```html
289
303
  <div :text="clicks">#</div> clicks
@@ -297,7 +311,7 @@ This way, for example, _@preact/signals_ or _rxjs_ can be connected directly byp
297
311
  </script>
298
312
  ```
299
313
 
300
- **3.** Getters turn into computed values automatically:
314
+ **4.** Getters turn into computed values automatically (setters remain as is):
301
315
 
302
316
  ```html
303
317
  <div id="x-plus-y">
package/sprae.js CHANGED
@@ -6,23 +6,23 @@ function t() {
6
6
  if (!(n > 1)) {
7
7
  var i2, t2 = false;
8
8
  while (void 0 !== r) {
9
- var h = r;
9
+ var h2 = r;
10
10
  r = void 0;
11
11
  s++;
12
- while (void 0 !== h) {
13
- var o2 = h.o;
14
- h.o = void 0;
15
- h.f &= -3;
16
- if (!(8 & h.f) && d(h))
12
+ while (void 0 !== h2) {
13
+ var o2 = h2.o;
14
+ h2.o = void 0;
15
+ h2.f &= -3;
16
+ if (!(8 & h2.f) && d(h2))
17
17
  try {
18
- h.c();
19
- } catch (h2) {
18
+ h2.c();
19
+ } catch (h3) {
20
20
  if (!t2) {
21
- i2 = h2;
21
+ i2 = h3;
22
22
  t2 = true;
23
23
  }
24
24
  }
25
- h = o2;
25
+ h2 = o2;
26
26
  }
27
27
  }
28
28
  s = 0;
@@ -32,6 +32,16 @@ function t() {
32
32
  } else
33
33
  n--;
34
34
  }
35
+ function h(i2) {
36
+ if (n > 0)
37
+ return i2();
38
+ n++;
39
+ try {
40
+ return i2();
41
+ } finally {
42
+ t();
43
+ }
44
+ }
35
45
  var o = void 0;
36
46
  var r = void 0;
37
47
  var n = 0;
@@ -79,25 +89,25 @@ e.prototype.S = function(i2) {
79
89
  }
80
90
  };
81
91
  e.prototype.U = function(i2) {
82
- var t2 = i2.e, h = i2.x;
92
+ var t2 = i2.e, h2 = i2.x;
83
93
  if (void 0 !== t2) {
84
- t2.x = h;
94
+ t2.x = h2;
85
95
  i2.e = void 0;
86
96
  }
87
- if (void 0 !== h) {
88
- h.e = t2;
97
+ if (void 0 !== h2) {
98
+ h2.e = t2;
89
99
  i2.x = void 0;
90
100
  }
91
101
  if (i2 === this.t)
92
- this.t = h;
102
+ this.t = h2;
93
103
  };
94
104
  e.prototype.subscribe = function(i2) {
95
105
  var t2 = this;
96
106
  return b(function() {
97
- var h = t2.value, o2 = 32 & this.f;
107
+ var h2 = t2.value, o2 = 32 & this.f;
98
108
  this.f &= -33;
99
109
  try {
100
- i2(h);
110
+ i2(h2);
101
111
  } finally {
102
112
  this.f |= o2;
103
113
  }
@@ -117,11 +127,11 @@ Object.defineProperty(e.prototype, "value", { get: function() {
117
127
  if (void 0 !== i2)
118
128
  i2.i = this.i;
119
129
  return this.v;
120
- }, set: function(h) {
121
- if (h !== this.v) {
130
+ }, set: function(h2) {
131
+ if (h2 !== this.v) {
122
132
  if (s > 100)
123
133
  i();
124
- this.v = h;
134
+ this.v = h2;
125
135
  this.i++;
126
136
  f++;
127
137
  n++;
@@ -144,33 +154,33 @@ function d(i2) {
144
154
  }
145
155
  function c(i2) {
146
156
  for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) {
147
- var h = t2.S.n;
148
- if (void 0 !== h)
149
- t2.r = h;
157
+ var h2 = t2.S.n;
158
+ if (void 0 !== h2)
159
+ t2.r = h2;
150
160
  t2.S.n = t2;
151
161
  t2.i = -1;
152
162
  }
153
163
  }
154
164
  function a(i2) {
155
- var t2 = i2.s, h = void 0;
165
+ var t2 = i2.s, h2 = void 0;
156
166
  while (void 0 !== t2) {
157
167
  var o2 = t2.n;
158
168
  if (-1 === t2.i) {
159
169
  t2.S.U(t2);
160
170
  t2.n = void 0;
161
171
  } else {
162
- if (void 0 !== h)
163
- h.p = t2;
172
+ if (void 0 !== h2)
173
+ h2.p = t2;
164
174
  t2.p = void 0;
165
- t2.n = h;
166
- h = t2;
175
+ t2.n = h2;
176
+ h2 = t2;
167
177
  }
168
178
  t2.S.n = t2.r;
169
179
  if (void 0 !== t2.r)
170
180
  t2.r = void 0;
171
181
  t2 = o2;
172
182
  }
173
- i2.s = h;
183
+ i2.s = h2;
174
184
  }
175
185
  function l(i2) {
176
186
  e.call(this, void 0);
@@ -259,14 +269,14 @@ function w(i2) {
259
269
  return new l(i2);
260
270
  }
261
271
  function y(i2) {
262
- var h = i2.u;
272
+ var h2 = i2.u;
263
273
  i2.u = void 0;
264
- if ("function" == typeof h) {
274
+ if ("function" == typeof h2) {
265
275
  n++;
266
276
  var r2 = o;
267
277
  o = void 0;
268
278
  try {
269
- h();
279
+ h2();
270
280
  } catch (t2) {
271
281
  i2.f &= -2;
272
282
  i2.f |= 8;
@@ -474,39 +484,13 @@ var primitive_pool_default = (key) => {
474
484
  };
475
485
 
476
486
  // src/directives.js
477
- var directives = {};
478
- var directives_default = (el, expr, values, name) => {
479
- let evt = name.startsWith("on") && name.slice(2);
480
- let evaluate = parseExpr(el, expr, ":" + name);
481
- if (evaluate)
482
- return evt ? (state) => {
483
- let value = evaluate(state);
484
- if (value) {
485
- addListener(el, evt, value);
486
- return () => removeListener(el, evt, value);
487
- }
488
- } : (state) => attr(el, name, evaluate(state));
489
- };
490
- var attr = (el, name, v2) => {
491
- if (v2 == null || v2 === false)
492
- el.removeAttribute(name);
493
- else
494
- el.setAttribute(name, v2 === true ? "" : typeof v2 === "number" || typeof v2 === "string" ? v2 : "");
495
- };
496
- directives[""] = (el, expr) => {
497
- let evaluate = parseExpr(el, expr, ":");
498
- if (evaluate)
499
- return (state) => {
500
- let value = evaluate(state);
501
- for (let key in value)
502
- attr(el, dashcase(key), value[key]);
503
- };
504
- };
505
- directives["with"] = (el, expr, rootState) => {
487
+ var primary = {};
488
+ var secondary = {};
489
+ primary["with"] = (el, expr, rootState) => {
506
490
  let evaluate = parseExpr(el, expr, "with");
507
491
  sprae(el, signalStruct(evaluate(rootState), rootState));
508
492
  };
509
- directives["if"] = (el, expr) => {
493
+ primary["if"] = (el, expr) => {
510
494
  let holder = document.createTextNode(""), clauses = [parseExpr(el, expr, ":if")], els = [el], cur = el;
511
495
  while (cur = el.nextElementSibling) {
512
496
  if (cur.hasAttribute(":else")) {
@@ -533,31 +517,14 @@ directives["if"] = (el, expr) => {
533
517
  };
534
518
  };
535
519
  var _each = Symbol(":each");
536
- var _ref = Symbol(":ref");
537
- var _key = Symbol(":key");
538
- directives["ref"] = (el, expr, state) => {
539
- if (el.hasAttribute(":each")) {
540
- el[_ref] = expr;
541
- return;
542
- }
543
- ;
544
- state[expr] = el;
545
- };
546
- directives["key"] = (el, expr, state) => {
547
- if (el.hasAttribute(":each")) {
548
- el[_key] = expr;
549
- return;
550
- }
551
- ;
552
- };
553
- directives["each"] = (tpl, expr) => {
520
+ primary["each"] = (tpl, expr) => {
554
521
  let each = parseForExpression(expr);
555
522
  if (!each)
556
523
  return exprError(new Error(), tpl, expr);
557
524
  const holder = tpl[_each] = document.createTextNode("");
558
525
  tpl.replaceWith(holder);
559
- const evaluate = parseExpr(tpl, each.items, ":each");
560
- const keyExpr = tpl[_key] || tpl.getAttribute(":key");
526
+ const evaluate = parseExpr(tpl, each[2], ":each");
527
+ const keyExpr = tpl.getAttribute(":key");
561
528
  const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
562
529
  tpl.removeAttribute(":key");
563
530
  const scopes = /* @__PURE__ */ new WeakMap();
@@ -577,7 +544,7 @@ directives["each"] = (tpl, expr) => {
577
544
  exprError(Error("Bad list value"), tpl, expr, ":each", list);
578
545
  let newEls = [], elScopes = [];
579
546
  for (let [idx, item] of list) {
580
- let el, scope, key = itemKey?.({ [each.item]: item });
547
+ let el, scope, key = itemKey?.({ [each[0]]: item, [each[1]]: idx });
581
548
  if (isPrimitive(key))
582
549
  key = primitive_pool_default(key);
583
550
  if (key == null)
@@ -586,15 +553,11 @@ directives["each"] = (tpl, expr) => {
586
553
  (el = itemEls.get(key)) || itemEls.set(key, el = tpl.cloneNode(true));
587
554
  newEls.push(el);
588
555
  if (key == null || !(scope = scopes.get(key))) {
589
- scope = Object.create(state);
590
- scope[each.item] = item;
591
- if (each.index)
592
- scope[each.index] = idx;
593
- if (tpl[_ref])
594
- scope[tpl[_ref]] = el;
556
+ scope = signalStruct({ [each[0]]: item, [each[1]]: idx }, state);
595
557
  if (key != null)
596
558
  scopes.set(key, scope);
597
- }
559
+ } else
560
+ scope[each[0]] = item;
598
561
  elScopes.push(scope);
599
562
  }
600
563
  swap_inflate_default(holder.parentNode, curEls, newEls, holder);
@@ -611,24 +574,26 @@ function parseForExpression(expression) {
611
574
  let inMatch = expression.match(forAliasRE);
612
575
  if (!inMatch)
613
576
  return;
614
- let res = {};
615
- res.items = inMatch[2].trim();
577
+ let items = inMatch[2].trim();
616
578
  let item = inMatch[1].replace(stripParensRE, "").trim();
617
579
  let iteratorMatch = item.match(forIteratorRE);
618
- if (iteratorMatch) {
619
- res.item = item.replace(forIteratorRE, "").trim();
620
- res.index = iteratorMatch[1].trim();
621
- } else {
622
- res.item = item;
623
- }
624
- return res;
580
+ if (iteratorMatch)
581
+ return [
582
+ item.replace(forIteratorRE, "").trim(),
583
+ iteratorMatch[1].trim(),
584
+ items
585
+ ];
586
+ return [item, "", items];
625
587
  }
626
- directives["id"] = (el, expr) => {
588
+ secondary["ref"] = (el, expr, state) => {
589
+ state[expr] = el;
590
+ };
591
+ secondary["id"] = (el, expr) => {
627
592
  let evaluate = parseExpr(el, expr, ":id");
628
593
  const update = (v2) => el.id = v2 || v2 === 0 ? v2 : "";
629
594
  return (state) => update(evaluate(state));
630
595
  };
631
- directives["class"] = (el, expr) => {
596
+ secondary["class"] = (el, expr) => {
632
597
  let evaluate = parseExpr(el, expr, ":class");
633
598
  let initClassName = el.className;
634
599
  return (state) => {
@@ -636,7 +601,7 @@ directives["class"] = (el, expr) => {
636
601
  el.className = initClassName + typeof v2 === "string" ? v2 : (Array.isArray(v2) ? v2 : Object.entries(v2).map(([k, v3]) => v3 ? k : "")).filter(Boolean).join(" ");
637
602
  };
638
603
  };
639
- directives["style"] = (el, expr) => {
604
+ secondary["style"] = (el, expr) => {
640
605
  let evaluate = parseExpr(el, expr, ":style");
641
606
  let initStyle = el.getAttribute("style") || "";
642
607
  if (!initStyle.endsWith(";"))
@@ -650,14 +615,14 @@ directives["style"] = (el, expr) => {
650
615
  el.style[k] = v2[k];
651
616
  };
652
617
  };
653
- directives["text"] = (el, expr) => {
618
+ secondary["text"] = (el, expr) => {
654
619
  let evaluate = parseExpr(el, expr, ":text");
655
620
  return (state) => {
656
621
  let value = evaluate(state);
657
622
  el.textContent = value == null ? "" : value;
658
623
  };
659
624
  };
660
- directives["value"] = (el, expr) => {
625
+ secondary["value"] = (el, expr) => {
661
626
  let evaluate = parseExpr(el, expr, ":value");
662
627
  let from, to;
663
628
  let update = el.type === "text" || el.type === "" ? (value) => el.setAttribute("value", el.value = value == null ? "" : value) : el.tagName === "TEXTAREA" || el.type === "text" || el.type === "" ? (value) => (from = el.selectionStart, to = el.selectionEnd, el.setAttribute("value", el.value = value == null ? "" : value), from && el.setSelectionRange(from, to)) : el.type === "checkbox" ? (value) => (el.value = value ? "on" : "", attr(el, "checked", value)) : el.type === "select-one" ? (value) => {
@@ -668,7 +633,7 @@ directives["value"] = (el, expr) => {
668
633
  } : (value) => el.value = value;
669
634
  return (state) => update(evaluate(state));
670
635
  };
671
- directives["on"] = (el, expr) => {
636
+ secondary["on"] = (el, expr) => {
672
637
  let evaluate = parseExpr(el, expr, ":on");
673
638
  return (state) => {
674
639
  let listeners = evaluate(state);
@@ -707,7 +672,7 @@ var removeListener = (el, evt, fn) => {
707
672
  fn[_stop] = true;
708
673
  el.removeEventListener(evt, fn);
709
674
  };
710
- directives["data"] = (el, expr) => {
675
+ secondary["data"] = (el, expr) => {
711
676
  let evaluate = parseExpr(el, expr, ":data");
712
677
  return (state) => {
713
678
  let value = evaluate(state);
@@ -715,7 +680,7 @@ directives["data"] = (el, expr) => {
715
680
  el.dataset[key] = value[key];
716
681
  };
717
682
  };
718
- directives["aria"] = (el, expr) => {
683
+ secondary["aria"] = (el, expr) => {
719
684
  let evaluate = parseExpr(el, expr, ":aria");
720
685
  const update = (value) => {
721
686
  for (let key in value)
@@ -723,6 +688,33 @@ directives["aria"] = (el, expr) => {
723
688
  };
724
689
  return (state) => update(evaluate(state));
725
690
  };
691
+ secondary[""] = (el, expr) => {
692
+ let evaluate = parseExpr(el, expr, ":");
693
+ if (evaluate)
694
+ return (state) => {
695
+ let value = evaluate(state);
696
+ for (let key in value)
697
+ attr(el, dashcase(key), value[key]);
698
+ };
699
+ };
700
+ var directives_default = (el, expr, values, name) => {
701
+ let evt = name.startsWith("on") && name.slice(2);
702
+ let evaluate = parseExpr(el, expr, ":" + name);
703
+ if (evaluate)
704
+ return evt ? (state) => {
705
+ let value = evaluate(state);
706
+ if (value) {
707
+ addListener(el, evt, value);
708
+ return () => removeListener(el, evt, value);
709
+ }
710
+ } : (state) => attr(el, name, evaluate(state));
711
+ };
712
+ var attr = (el, name, v2) => {
713
+ if (v2 == null || v2 === false)
714
+ el.removeAttribute(name);
715
+ else
716
+ el.setAttribute(name, v2 === true ? "" : typeof v2 === "number" || typeof v2 === "string" ? v2 : "");
717
+ };
726
718
  var evaluatorMemo = {};
727
719
  function parseExpr(el, expression, dir) {
728
720
  let evaluate = evaluatorMemo[expression];
@@ -767,11 +759,26 @@ var memo = /* @__PURE__ */ new WeakMap();
767
759
  function sprae(container, values) {
768
760
  if (!container.children)
769
761
  return;
770
- if (memo.has(container))
771
- return memo.get(container);
762
+ if (memo.has(container)) {
763
+ let state2 = memo.get(container);
764
+ h(() => Object.assign(state2, values));
765
+ return state2;
766
+ }
772
767
  const state = signalStruct(values || {});
773
768
  const updates = [];
774
769
  const init = (el, parent = el.parentNode) => {
770
+ for (let name in primary) {
771
+ let attrName = ":" + name;
772
+ if (el.hasAttribute?.(attrName)) {
773
+ let expr = el.getAttribute(attrName);
774
+ el.removeAttribute(attrName);
775
+ if (!expr)
776
+ continue;
777
+ updates.push(primary[name](el, expr, state, name));
778
+ if (memo.has(el) || el.parentNode !== parent)
779
+ return false;
780
+ }
781
+ }
775
782
  if (el.attributes) {
776
783
  for (let i2 = 0; i2 < el.attributes.length; ) {
777
784
  let attr2 = el.attributes[i2];
@@ -785,9 +792,8 @@ function sprae(container, values) {
785
792
  continue;
786
793
  let attrNames = attr2.name.slice(1).split(":");
787
794
  for (let attrName of attrNames) {
788
- let dir = directives[attrName] || directives_default;
789
- updates.push(dir(el, expr, state, attrName) || (() => {
790
- }));
795
+ let dir = secondary[attrName] || directives_default;
796
+ updates.push(dir(el, expr, state, attrName));
791
797
  if (memo.has(el) || el.parentNode !== parent)
792
798
  return false;
793
799
  }
@@ -799,14 +805,15 @@ function sprae(container, values) {
799
805
  }
800
806
  };
801
807
  init(container);
802
- for (let update of updates) {
803
- let teardown;
804
- b(() => {
805
- if (typeof teardown === "function")
806
- teardown();
807
- teardown = update(state);
808
- });
809
- }
808
+ for (let update of updates)
809
+ if (update) {
810
+ let teardown;
811
+ b(() => {
812
+ if (typeof teardown === "function")
813
+ teardown();
814
+ teardown = update(state);
815
+ });
816
+ }
810
817
  Object.seal(state);
811
818
  memo.set(container, state);
812
819
  return state;
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)&&f(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 a(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function f(t){for(var e=t.s;void 0!==e;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function u(t){for(var e=t.s;void 0!==e;e=e.n){var 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){a.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)}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,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)},a.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}}))},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(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 a).h=function(){if(this.f&=-3,1&this.f)return!1;if(32==(36&this.f))return!0;if(this.f&=-5,this.g===s)return!0;if(this.g=s,this.f|=1,this.i>0&&!f(this))return this.f&=-2,!0;var t=i;try{u(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)}a.prototype.S.call(this,t)},c.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)}},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),u(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[x],x=Symbol("signal-struct");function A(t,e){if(S(t)&&!e)return t;if(w(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),f=o[t]=(i=s)&&i.peek?s:new a(l?void 0:w(s)?Object.seal(A(s)):Array.isArray(s)?A(s):s);l&&g(s,(t=>f.value=t)),Object.defineProperty(n,t,{get:()=>f.value,set(t){if(w(t)){if(w(f.value))try{return void Object.assign(f.value,t)}catch(t){}f.value=Object.seal(A(t))}else Array.isArray(t)?f.value=A(t):f.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,x,{configurable:!1,enumerable:!1,value:!0}),n}var i,r;return Array.isArray(t)&&!S(t[0])?t.map((t=>A(t))):t}function w(t){return t&&t.constructor===Object}A.isStruct=S;var O=(t,e,i,r=null)=>{let n,o,s,l=0,a=i.length,f=e.length,{remove:u,same:h,insert:c,replace:v}=O;for(;l<a&&l<f&&h(e[l],i[l]);)l++;for(;l<a&&l<f&&h(i[a-1],e[f-1]);)r=i[(--f,--a)];if(l==f)for(;l<a;)c(r,i[l++],t);else{for(n=e[l];l<a;)s=i[l++],o=n?n.nextSibling:r,h(n,s)?n=o:l<a&&h(i[l],o)?(v(n,s,t),n=o):c(n,s,t);for(;!h(n,r);)o=n.nextSibling,u(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=(t,e,i,r)=>{let n=r.startsWith("on")&&r.slice(2),o=R(t,e,":"+r);if(o)return n?e=>{let i=o(e);if(i)return D(t,n,i),()=>_(t,n,i)}:e=>C(t,r,o(e))},C=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")};$[""]=(t,e)=>{let i=R(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)C(t,I(e),r[e])}},$.with=(t,e,i)=>{X(t,A(R(t,e,"with")(i),i))},$.if=(t,e)=>{let i=document.createTextNode(""),r=[R(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(R(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[U]||o).replaceWith(o=n[e]||i),X(o,t))}};var U=Symbol(":each"),B=Symbol(":ref"),L=Symbol(":key");$.ref=(t,e,i)=>{t.hasAttribute(":each")?t[B]=e:i[e]=t},$.key=(t,e,i)=>{t.hasAttribute(":each")&&(t[L]=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={};r.items=i[2].trim();let n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?(r.item=n.replace(e,"").trim(),r.index=o[1].trim()):r.item=n,r}(e);if(!i)return F(new Error,t,e);const r=t[U]=document.createTextNode("");t.replaceWith(r);const n=R(t,i.items,":each"),o=t[L]||t.getAttribute(":key"),s=o?R(null,o):null;t.removeAttribute(":key");const l=new WeakMap,a=new WeakMap;let f=[];return o=>{let u=n(o);u?"number"==typeof u?u=Array.from({length:u},((t,e)=>[e,e+1])):Array.isArray(u)?u=u.map(((t,e)=>[e+1,t])):"object"==typeof u?u=Object.entries(u):F(Error("Bad list value"),t,e,":each"):u=[];let h=[],c=[];for(let[e,r]of u){let n,f,u=s?.({[i.item]:r});("string"==typeof(v=u)||"boolean"==typeof v||"number"==typeof v)&&(u=W(u)),null==u?n=t.cloneNode(!0):(n=a.get(u))||a.set(u,n=t.cloneNode(!0)),h.push(n),null!=u&&(f=l.get(u))||(f=Object.create(o),f[i.item]=r,i.index&&(f[i.index]=e),t[B]&&(f[t[B]]=n),null!=u&&l.set(u,f)),c.push(f)}var v;j(r.parentNode,f,h,r),f=h;for(let t=0;t<h.length;t++)X(h[t],c[t])}},$.id=(t,e)=>{let i=R(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},$.class=(t,e)=>{let i=R(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(" ")}},$.style=(t,e)=>{let i=R(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]}},$.text=(t,e)=>{let i=R(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},$.value=(t,e)=>{let i,r,n=R(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":"",C(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))},$.on=(t,e)=>{let i=R(t,e,":on");return e=>{let r=i(e);for(let e in r)D(t,e,r[e]);return()=>{for(let e in r)_(t,e,r[e])}}};var T=Symbol("stop"),D=(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[T]||n(i)};t.addEventListener(r[o],s)};n(i)}},_=(t,e,i)=>{e.indexOf("..")>=0&&(i[T]=!0),t.removeEventListener(e,i)};$.data=(t,e)=>{let i=R(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},$.aria=(t,e)=>{let i=R(t,e,":aria");return e=>(e=>{for(let i in e)C(t,"aria-"+I(i),null==e[i]?null:e[i]+"")})(i(e))};var M={};function R(t,e,i){let r=M[e];if(!r){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=M[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(r){return F(r,t,e,i)}}return n=>{let o;try{o=r.call(t,n)}catch(r){return F(r,t,e,i)}return o}}function F(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 I(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))return z.get(t);const i=A(e||{}),r=[],n=(t,e=t.parentNode)=>{if(t.attributes)for(let n=0;n<t.attributes.length;){let o=t.attributes[n];if(":"!==o.name[0]){n++;continue}t.removeAttribute(o.name);let s=o.value;if(!s)continue;let l=o.name.slice(1).split(":");for(let n of l){let o=$[n]||P;if(r.push(o(t,s,i,n)||(()=>{})),z.has(t)||t.parentNode!==e)return!1}}for(let e,i=0;e=t.children[i];i++)!1===n(e,t)&&i--};n(t);for(let t of r){let e;b((()=>{"function"==typeof e&&e(),e=t(i)}))}return Object.seal(i),z.set(t,i),i}var Z=X;export{Z as default};
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={};$.with=(t,e,i)=>{z(t,w(M(t,e,"with")(i),i))},$.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))}};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};
package/src/core.js CHANGED
@@ -1,12 +1,16 @@
1
1
  import signalStruct from 'signal-struct';
2
- import defaultDirective, { directives } from './directives.js';
3
- import { effect } from '@preact/signals-core'
2
+ import defaultDirective, { primary, secondary } from './directives.js';
3
+ import { effect, batch } from '@preact/signals-core'
4
4
 
5
5
  // sprae element: apply directives
6
6
  const memo = new WeakMap
7
7
  export default function sprae(container, values) {
8
8
  if (!container.children) return
9
- if (memo.has(container)) return memo.get(container)
9
+ if (memo.has(container)) {
10
+ let state = memo.get(container)
11
+ batch(() => Object.assign(state, values))
12
+ return state
13
+ }
10
14
 
11
15
  // signalStruct returns values if it's signalStruct already
12
16
  const state = signalStruct(values || {});
@@ -14,6 +18,21 @@ export default function sprae(container, values) {
14
18
 
15
19
  // init directives on element
16
20
  const init = (el, parent=el.parentNode) => {
21
+ // init primary attributes first
22
+ for (let name in primary) {
23
+ let attrName = ':' + name
24
+ if (el.hasAttribute?.(attrName)) {
25
+ let expr = el.getAttribute(attrName)
26
+ el.removeAttribute(attrName)
27
+ if (!expr) continue
28
+ updates.push(primary[name](el, expr, state, name))
29
+
30
+ // stop if element was spraed by directive or skipped (detached)
31
+ if (memo.has(el) || el.parentNode !== parent) return false
32
+ }
33
+ }
34
+
35
+ // catch other attributes as secondary
17
36
  if (el.attributes) {
18
37
  for (let i = 0; i < el.attributes.length;) {
19
38
  let attr = el.attributes[i]
@@ -21,12 +40,13 @@ export default function sprae(container, values) {
21
40
  el.removeAttribute(attr.name)
22
41
  let expr = attr.value
23
42
  if (!expr) continue
43
+ // multiple attributes like :id:for=""
24
44
  let attrNames = attr.name.slice(1).split(':')
25
45
  for (let attrName of attrNames) {
26
- let dir = directives[attrName] || defaultDirective;
27
- updates.push(dir(el, expr, state, attrName) || (()=>{}));
46
+ let dir = secondary[attrName] || defaultDirective;
47
+ updates.push(dir(el, expr, state, attrName));
28
48
 
29
- // stop if element was spraed by directive or skipped
49
+ // stop if element was spraed by directive or skipped (detached)
30
50
  if (memo.has(el) || el.parentNode !== parent) return false
31
51
  }
32
52
  }
@@ -42,7 +62,7 @@ export default function sprae(container, values) {
42
62
 
43
63
  // call updates: subscribes directives to state;
44
64
  // state is created after inits because directives can extend init values (expose refs etc)
45
- for (let update of updates) {
65
+ for (let update of updates) if (update) {
46
66
  let teardown
47
67
  effect(() => {
48
68
  if (typeof teardown === 'function') teardown()
package/src/directives.js CHANGED
@@ -5,42 +5,18 @@ import signalStruct from 'signal-struct'
5
5
  import p from 'primitive-pool'
6
6
 
7
7
  // reserved directives - order matters!
8
- export const directives = {}
8
+ // primary initialized first by selector, secondary initialized by iterating attributes
9
+ export const primary = {}, secondary = {}
9
10
 
10
- // any-prop directives
11
- export default (el, expr, values, name) => {
12
- let evt = name.startsWith('on') && name.slice(2)
13
- let evaluate = parseExpr(el, expr, ':'+name)
14
- if (evaluate) return evt ? state => {
15
- let value = evaluate(state)
16
- if (value) {
17
- addListener(el, evt, value)
18
- return () => removeListener(el, evt, value)
19
- }
20
- }
21
- : state => attr(el, name, evaluate(state))
22
- }
23
-
24
- // set attr
25
- const attr = (el, name, v) => {
26
- if (v == null || v === false) el.removeAttribute(name)
27
- else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
28
- }
29
11
 
30
- directives[''] = (el, expr) => {
31
- let evaluate = parseExpr(el, expr, ':')
32
- if (evaluate) return (state) => {
33
- let value = evaluate(state)
34
- for (let key in value) attr(el, dashcase(key), value[key]);
35
- }
36
- }
37
-
38
- directives['with'] = (el, expr, rootState) => {
12
+ // :with must come before :if or :each or anyone else
13
+ primary['with'] = (el, expr, rootState) => {
39
14
  let evaluate = parseExpr(el, expr, 'with')
40
15
  sprae(el, signalStruct(evaluate(rootState), rootState));
41
16
  }
42
17
 
43
- directives['if'] = (el, expr) => {
18
+ // :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
19
+ primary['if'] = (el, expr) => {
44
20
  let holder = document.createTextNode(''),
45
21
  clauses = [parseExpr(el, expr, ':if')],
46
22
  els = [el], cur = el
@@ -71,23 +47,10 @@ directives['if'] = (el, expr) => {
71
47
  }
72
48
  }
73
49
 
74
- const _each = Symbol(':each'), _ref = Symbol(':ref'), _key = Symbol(':key')
75
-
76
- directives['ref'] = (el, expr, state) => {
77
- // make sure :ref is initialized after :each (return to avoid initializing as signal)
78
- if (el.hasAttribute(':each')) {el[_ref] = expr; return};
50
+ const _each = Symbol(':each')
79
51
 
80
- // FIXME: wait for complex ref use-case
81
- // parseExpr(el, `__scope[${expr}]=this`, ':ref')(values)
82
- state[expr] = el;
83
- }
84
-
85
- directives['key'] = (el, expr, state) => {
86
- // make sure :ref is initialized after :each (return to avoid initializing as signal)
87
- if (el.hasAttribute(':each')) {el[_key] = expr; return};
88
- }
89
-
90
- directives['each'] = (tpl, expr) => {
52
+ // :each must init before :ref, :id or any others, since it defines scope
53
+ primary['each'] = (tpl, expr) => {
91
54
  let each = parseForExpression(expr);
92
55
  if (!each) return exprError(new Error, tpl, expr);
93
56
 
@@ -96,9 +59,9 @@ directives['each'] = (tpl, expr) => {
96
59
  const holder = tpl[_each] = document.createTextNode('')
97
60
  tpl.replaceWith(holder)
98
61
 
99
- const evaluate = parseExpr(tpl, each.items, ':each');
62
+ const evaluate = parseExpr(tpl, each[2], ':each');
100
63
 
101
- const keyExpr = tpl[_key] || tpl.getAttribute(':key');
64
+ const keyExpr = tpl.getAttribute(':key');
102
65
  const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
103
66
  tpl.removeAttribute(':key')
104
67
 
@@ -121,7 +84,7 @@ directives['each'] = (tpl, expr) => {
121
84
  let newEls = [], elScopes = []
122
85
 
123
86
  for (let [idx, item] of list) {
124
- let el, scope, key = itemKey?.({[each.item]: item})
87
+ let el, scope, key = itemKey?.({[each[0]]: item, [each[1]]: idx})
125
88
  if (isPrimitive(key)) key = p(key); // singletonize key
126
89
 
127
90
  // we consider if data items are primitive, then nodes needn't be cached
@@ -132,13 +95,12 @@ directives['each'] = (tpl, expr) => {
132
95
  newEls.push(el)
133
96
 
134
97
  if (key == null || !(scope = scopes.get(key))) {
135
- scope = Object.create(state)
136
- scope[each.item] = item
137
- if (each.index) scope[each.index] = idx;
138
- // provide ref, if indicated
139
- if (tpl[_ref]) scope[tpl[_ref]] = el
98
+ scope = signalStruct({[each[0]]: item, [each[1]]:idx}, state)
140
99
  if (key != null) scopes.set(key, scope)
141
100
  }
101
+ // need to explicitly set item to update existing children's values
102
+ else scope[each[0]] = item
103
+
142
104
  elScopes.push(scope)
143
105
  }
144
106
 
@@ -162,28 +124,33 @@ function parseForExpression(expression) {
162
124
 
163
125
  if (!inMatch) return
164
126
 
165
- let res = {}
166
- res.items = inMatch[2].trim()
127
+ let items = inMatch[2].trim()
167
128
  let item = inMatch[1].replace(stripParensRE, '').trim()
168
129
  let iteratorMatch = item.match(forIteratorRE)
169
130
 
170
- if (iteratorMatch) {
171
- res.item = item.replace(forIteratorRE, '').trim()
172
- res.index = iteratorMatch[1].trim()
173
- } else {
174
- res.item = item
175
- }
131
+ if (iteratorMatch) return [
132
+ item.replace(forIteratorRE, '').trim(),
133
+ iteratorMatch[1].trim(),
134
+ items
135
+ ]
176
136
 
177
- return res
137
+ return [item, '', items]
178
138
  }
179
139
 
180
- directives['id'] = (el, expr) => {
140
+
141
+ secondary['ref'] = (el, expr, state) => {
142
+ // FIXME: wait for complex ref use-case
143
+ // parseExpr(el, `__scope[${expr}]=this`, ':ref')(values)
144
+ state[expr] = el;
145
+ }
146
+
147
+ secondary['id'] = (el, expr) => {
181
148
  let evaluate = parseExpr(el, expr, ':id')
182
149
  const update = v => el.id = v || v === 0 ? v : ''
183
150
  return (state) => update(evaluate(state))
184
151
  }
185
152
 
186
- directives['class'] = (el, expr) => {
153
+ secondary['class'] = (el, expr) => {
187
154
  let evaluate = parseExpr(el, expr, ':class')
188
155
  let initClassName = el.className
189
156
  return (state) => {
@@ -192,7 +159,7 @@ directives['class'] = (el, expr) => {
192
159
  }
193
160
  }
194
161
 
195
- directives['style'] = (el, expr) => {
162
+ secondary['style'] = (el, expr) => {
196
163
  let evaluate = parseExpr(el, expr, ':style')
197
164
  let initStyle = el.getAttribute('style') || ''
198
165
  if (!initStyle.endsWith(';')) initStyle += '; '
@@ -203,7 +170,7 @@ directives['style'] = (el, expr) => {
203
170
  }
204
171
  }
205
172
 
206
- directives['text'] = (el, expr) => {
173
+ secondary['text'] = (el, expr) => {
207
174
  let evaluate = parseExpr(el, expr, ':text')
208
175
 
209
176
  return (state) => {
@@ -213,7 +180,7 @@ directives['text'] = (el, expr) => {
213
180
  }
214
181
 
215
182
  // connect expr to element value
216
- directives['value'] = (el, expr) => {
183
+ secondary['value'] = (el, expr) => {
217
184
  let evaluate = parseExpr(el, expr, ':value')
218
185
 
219
186
  let from, to
@@ -237,7 +204,7 @@ directives['value'] = (el, expr) => {
237
204
  return (state) => update(evaluate(state))
238
205
  }
239
206
 
240
- directives['on'] = (el, expr) => {
207
+ secondary['on'] = (el, expr) => {
241
208
  let evaluate = parseExpr(el, expr, ':on')
242
209
 
243
210
  return (state) => {
@@ -273,7 +240,7 @@ const removeListener = (el, evt, fn) => {
273
240
  el.removeEventListener(evt, fn);
274
241
  }
275
242
 
276
- directives['data'] = (el, expr) => {
243
+ secondary['data'] = (el, expr) => {
277
244
  let evaluate = parseExpr(el, expr, ':data')
278
245
 
279
246
  return ((state) => {
@@ -282,7 +249,7 @@ directives['data'] = (el, expr) => {
282
249
  })
283
250
  }
284
251
 
285
- directives['aria'] = (el, expr) => {
252
+ secondary['aria'] = (el, expr) => {
286
253
  let evaluate = parseExpr(el, expr, ':aria')
287
254
  const update = (value) => {
288
255
  for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
@@ -290,6 +257,35 @@ directives['aria'] = (el, expr) => {
290
257
  return ((state) => update(evaluate(state)))
291
258
  }
292
259
 
260
+ // set props in-bulk or run effect
261
+ secondary[''] = (el, expr) => {
262
+ let evaluate = parseExpr(el, expr, ':')
263
+ if (evaluate) return (state) => {
264
+ let value = evaluate(state)
265
+ for (let key in value) attr(el, dashcase(key), value[key]);
266
+ }
267
+ }
268
+
269
+ // any other prop directive
270
+ export default (el, expr, values, name) => {
271
+ let evt = name.startsWith('on') && name.slice(2)
272
+ let evaluate = parseExpr(el, expr, ':'+name)
273
+ if (evaluate) return evt ? state => {
274
+ let value = evaluate(state)
275
+ if (value) {
276
+ addListener(el, evt, value)
277
+ return () => removeListener(el, evt, value)
278
+ }
279
+ }
280
+ : state => attr(el, name, evaluate(state))
281
+ }
282
+
283
+ // set attr
284
+ const attr = (el, name, v) => {
285
+ if (v == null || v === false) el.removeAttribute(name)
286
+ else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
287
+ }
288
+
293
289
 
294
290
  let evaluatorMemo = {}
295
291
 
package/test/test.js CHANGED
@@ -404,7 +404,24 @@ test('each: keyed', async () => {
404
404
  })
405
405
 
406
406
  test.todo('each: unmounted elements remove listeners', async () => {
407
+ // let's hope they get removed without memory leaks :')
408
+ })
409
+
410
+ test('each: internal children get updated by state update, also: update by running again', () => {
411
+ let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
412
+ sprae(el, { items: [1,2,3] })
413
+ is(el.textContent, '123')
414
+ let state = sprae(el, { items: [0,2,3] })
415
+ is(el.textContent, '023')
416
+ state.items[0] = 1
417
+ state.items = state.items
418
+ is(el.textContent, '123')
419
+ })
407
420
 
421
+ test('each: :id and others must receive value from context', () => {
422
+ let el = h`<div><x :id="idx" :each="item, idx in items"></x></div>`
423
+ sprae(el, {items:[1,2,3]})
424
+ is(el.innerHTML,`<x id="1"></x><x id="2"></x><x id="3"></x>`)
408
425
  })
409
426
 
410
427
  test('on: base', () => {
package/todo.md CHANGED
@@ -34,8 +34,8 @@
34
34
  * [x] implement :with
35
35
  * [x] update :value without losing focus / position
36
36
  * ~~[x] run tiredown if element got removed from condition or loop (free memory)~~ no need just make sure no refs to elements stored
37
- * [ ] `sprae(el, newState)` can update element's state directly (as batch!?) -> must be tested against repeats in directives
38
- * [ ] :if :ref, :if :with -> context setters must come first always
37
+ * [x] `sprae(el, newState)` can update element's state directly (as batch!?) -> must be tested against repeats in directives
38
+ * [x] :if :ref, :if :with -> context setters must come first always
39
39
  * [ ] frameworks benchmark
40
40
  * [ ] examples
41
41
  * [x] todomvc