sprae 2.5.4 → 2.6.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 +2 -2
- package/r&d.md +15 -4
- package/readme.md +1 -1
- package/sprae.js +96 -72
- package/sprae.min.js +1 -1
- package/src/core.js +8 -2
- package/src/directives.js +72 -56
- package/test/test.js +48 -0
- package/{plan.md → todo.md} +3 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprae",
|
|
3
3
|
"description": "DOM microhydration.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.6.0",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
7
7
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@preact/signals": "^1.1.2",
|
|
16
16
|
"es-module-shims": "^1.6.2",
|
|
17
17
|
"esbuild": "^0.15.14",
|
|
18
|
-
"hyperf": "^1.
|
|
18
|
+
"hyperf": "^1.5.0",
|
|
19
19
|
"jsdom": "^20.0.3",
|
|
20
20
|
"terser": "^5.15.1",
|
|
21
21
|
"tst": "^7.1.1",
|
package/r&d.md
CHANGED
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
|
|
98
98
|
-> possibly we have to just subscribe via mechanism of signals-like deps, and :with just initializes subtree with extended object
|
|
99
99
|
|
|
100
|
-
## [
|
|
100
|
+
## [x] :with? -> let's use `:with="{x:1,y:2,z:3}"` for now
|
|
101
101
|
|
|
102
102
|
1. Get rid of :with
|
|
103
103
|
+ with is bad JS practice/association
|
|
@@ -223,7 +223,15 @@
|
|
|
223
223
|
? attach-detach?
|
|
224
224
|
? onmount-onunmount?
|
|
225
225
|
- slows down domdiff
|
|
226
|
-
- can be solved as `<x :if="xxx" :="xxx
|
|
226
|
+
- can be solved as `<x :if="xxx" :="xxx && (...)'">` automatically
|
|
227
|
+
|
|
228
|
+
## [x] :onmount/onunmount? -> for now no reasons
|
|
229
|
+
|
|
230
|
+
+ useful for :if, :each
|
|
231
|
+
+ useful to dispose listeners via :onunmount (opposed to hidden symbols)
|
|
232
|
+
- doesn't really solve disposal: if element is attached again, it would need to reattach removed listeners
|
|
233
|
+
-> can be dolved via teardowns returned from updators
|
|
234
|
+
-> nah, event listeners don't need collection, just make sure no refs to element remain
|
|
227
235
|
|
|
228
236
|
## [x] :focus="direct code", :evt="direct code" -> nah, too messy.
|
|
229
237
|
|
|
@@ -324,18 +332,20 @@
|
|
|
324
332
|
- need to match many syntax quirks, can be tedious
|
|
325
333
|
~ can be fine to limit expressions to meaningful default: why Proxy, generators, awaits, global access etc.
|
|
326
334
|
- Somewhat heavy to bundle
|
|
327
|
-
~ 1-2kb is not super-heavy, besides signal-struct
|
|
335
|
+
~ 1-2kb is not super-heavy, besides kicks out signal-struct (with preact signals?)
|
|
328
336
|
+ Scope is easier to provide: no need for signal proxy
|
|
329
337
|
+ Can detect access errors in advance
|
|
330
338
|
+ Syntax-level access to signals can be inavoidable: external signals still "leak in" (via arrays or etc.).
|
|
331
339
|
+ Updating simple objects should also rerender the template parts, not just signals.
|
|
332
340
|
+ Deps can be analyzed / implemented without signals
|
|
333
|
-
- Screwed up debugging / stacktrace (unless errored)
|
|
341
|
+
- Screwed up debugging / stacktrace (unless errored properly)
|
|
342
|
+
~+ can actually provide better trace since no internal framework stuff is shown
|
|
334
343
|
+ that "unlimits" returned struct, so that any property can be added/deleted.
|
|
335
344
|
- doesn't really save from `new (()=>{}).constructor` hack: we gotta substitute objects too.
|
|
336
345
|
+ allows easier handle of `:with="a=1,b=2,c=3"` - we just naturally get local variables without messup with global
|
|
337
346
|
+ we can even define locals without `let`...
|
|
338
347
|
- not having "comfy" compatible JS at hand: cognitive load of whole language "layer" in-between
|
|
348
|
+
+ allows `let a = 1; a;` case instead of `let a = 1; return a;`
|
|
339
349
|
|
|
340
350
|
2. Use sandboxed proxy
|
|
341
351
|
- tough evaluation
|
|
@@ -392,6 +402,7 @@
|
|
|
392
402
|
.period Period, .
|
|
393
403
|
.slash Foward Slash, /
|
|
394
404
|
- conflict with dot-separated events
|
|
405
|
+
- lots of ad-hoc non-standard rules, can be handled in code
|
|
395
406
|
|
|
396
407
|
## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
|
|
397
408
|
|
package/readme.md
CHANGED
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
|
|
9
|
+
var h = r;
|
|
10
10
|
r = void 0;
|
|
11
11
|
s++;
|
|
12
|
-
while (void 0 !==
|
|
13
|
-
var o2 =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!(8 &
|
|
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))
|
|
17
17
|
try {
|
|
18
|
-
|
|
19
|
-
} catch (
|
|
18
|
+
h.c();
|
|
19
|
+
} catch (h2) {
|
|
20
20
|
if (!t2) {
|
|
21
|
-
i2 =
|
|
21
|
+
i2 = h2;
|
|
22
22
|
t2 = true;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
h = o2;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
s = 0;
|
|
@@ -79,25 +79,25 @@ e.prototype.S = function(i2) {
|
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
e.prototype.U = function(i2) {
|
|
82
|
-
var t2 = i2.e,
|
|
82
|
+
var t2 = i2.e, h = i2.x;
|
|
83
83
|
if (void 0 !== t2) {
|
|
84
|
-
t2.x =
|
|
84
|
+
t2.x = h;
|
|
85
85
|
i2.e = void 0;
|
|
86
86
|
}
|
|
87
|
-
if (void 0 !==
|
|
88
|
-
|
|
87
|
+
if (void 0 !== h) {
|
|
88
|
+
h.e = t2;
|
|
89
89
|
i2.x = void 0;
|
|
90
90
|
}
|
|
91
91
|
if (i2 === this.t)
|
|
92
|
-
this.t =
|
|
92
|
+
this.t = h;
|
|
93
93
|
};
|
|
94
94
|
e.prototype.subscribe = function(i2) {
|
|
95
95
|
var t2 = this;
|
|
96
96
|
return b(function() {
|
|
97
|
-
var
|
|
97
|
+
var h = t2.value, o2 = 32 & this.f;
|
|
98
98
|
this.f &= -33;
|
|
99
99
|
try {
|
|
100
|
-
i2(
|
|
100
|
+
i2(h);
|
|
101
101
|
} finally {
|
|
102
102
|
this.f |= o2;
|
|
103
103
|
}
|
|
@@ -117,11 +117,11 @@ Object.defineProperty(e.prototype, "value", { get: function() {
|
|
|
117
117
|
if (void 0 !== i2)
|
|
118
118
|
i2.i = this.i;
|
|
119
119
|
return this.v;
|
|
120
|
-
}, set: function(
|
|
121
|
-
if (
|
|
120
|
+
}, set: function(h) {
|
|
121
|
+
if (h !== this.v) {
|
|
122
122
|
if (s > 100)
|
|
123
123
|
i();
|
|
124
|
-
this.v =
|
|
124
|
+
this.v = h;
|
|
125
125
|
this.i++;
|
|
126
126
|
f++;
|
|
127
127
|
n++;
|
|
@@ -144,33 +144,33 @@ function d(i2) {
|
|
|
144
144
|
}
|
|
145
145
|
function c(i2) {
|
|
146
146
|
for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) {
|
|
147
|
-
var
|
|
148
|
-
if (void 0 !==
|
|
149
|
-
t2.r =
|
|
147
|
+
var h = t2.S.n;
|
|
148
|
+
if (void 0 !== h)
|
|
149
|
+
t2.r = h;
|
|
150
150
|
t2.S.n = t2;
|
|
151
151
|
t2.i = -1;
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
function a(i2) {
|
|
155
|
-
var t2 = i2.s,
|
|
155
|
+
var t2 = i2.s, h = void 0;
|
|
156
156
|
while (void 0 !== t2) {
|
|
157
157
|
var o2 = t2.n;
|
|
158
158
|
if (-1 === t2.i) {
|
|
159
159
|
t2.S.U(t2);
|
|
160
160
|
t2.n = void 0;
|
|
161
161
|
} else {
|
|
162
|
-
if (void 0 !==
|
|
163
|
-
|
|
162
|
+
if (void 0 !== h)
|
|
163
|
+
h.p = t2;
|
|
164
164
|
t2.p = void 0;
|
|
165
|
-
t2.n =
|
|
166
|
-
|
|
165
|
+
t2.n = h;
|
|
166
|
+
h = t2;
|
|
167
167
|
}
|
|
168
168
|
t2.S.n = t2.r;
|
|
169
169
|
if (void 0 !== t2.r)
|
|
170
170
|
t2.r = void 0;
|
|
171
171
|
t2 = o2;
|
|
172
172
|
}
|
|
173
|
-
i2.s =
|
|
173
|
+
i2.s = h;
|
|
174
174
|
}
|
|
175
175
|
function l(i2) {
|
|
176
176
|
e.call(this, void 0);
|
|
@@ -259,14 +259,14 @@ function w(i2) {
|
|
|
259
259
|
return new l(i2);
|
|
260
260
|
}
|
|
261
261
|
function y(i2) {
|
|
262
|
-
var
|
|
262
|
+
var h = i2.u;
|
|
263
263
|
i2.u = void 0;
|
|
264
|
-
if ("function" == typeof
|
|
264
|
+
if ("function" == typeof h) {
|
|
265
265
|
n++;
|
|
266
266
|
var r2 = o;
|
|
267
267
|
o = void 0;
|
|
268
268
|
try {
|
|
269
|
-
|
|
269
|
+
h();
|
|
270
270
|
} catch (t2) {
|
|
271
271
|
i2.f &= -2;
|
|
272
272
|
i2.f |= 8;
|
|
@@ -478,12 +478,13 @@ var directives = {};
|
|
|
478
478
|
var directives_default = (el, expr, values, name) => {
|
|
479
479
|
let evt = name.startsWith("on") && name.slice(2);
|
|
480
480
|
let evaluate = parseExpr(el, expr, ":" + name);
|
|
481
|
-
let value;
|
|
482
481
|
if (evaluate)
|
|
483
482
|
return evt ? (state) => {
|
|
484
|
-
value
|
|
485
|
-
|
|
486
|
-
|
|
483
|
+
let value = evaluate(state);
|
|
484
|
+
if (value) {
|
|
485
|
+
addListener(el, evt, value);
|
|
486
|
+
return () => removeListener(el, evt, value);
|
|
487
|
+
}
|
|
487
488
|
} : (state) => attr(el, name, evaluate(state));
|
|
488
489
|
};
|
|
489
490
|
var attr = (el, name, v2) => {
|
|
@@ -501,16 +502,6 @@ directives[""] = (el, expr) => {
|
|
|
501
502
|
attr(el, dashcase(key), value[key]);
|
|
502
503
|
};
|
|
503
504
|
};
|
|
504
|
-
var _each = Symbol(":each");
|
|
505
|
-
var _ref = Symbol(":ref");
|
|
506
|
-
directives["ref"] = (el, expr, state) => {
|
|
507
|
-
if (el.hasAttribute(":each")) {
|
|
508
|
-
el[_ref] = expr;
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
;
|
|
512
|
-
state[expr] = el;
|
|
513
|
-
};
|
|
514
505
|
directives["with"] = (el, expr, rootState) => {
|
|
515
506
|
let evaluate = parseExpr(el, expr, "with");
|
|
516
507
|
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
@@ -541,6 +532,24 @@ directives["if"] = (el, expr) => {
|
|
|
541
532
|
}
|
|
542
533
|
};
|
|
543
534
|
};
|
|
535
|
+
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
|
+
};
|
|
544
553
|
directives["each"] = (tpl, expr) => {
|
|
545
554
|
let each = parseForExpression(expr);
|
|
546
555
|
if (!each)
|
|
@@ -548,6 +557,9 @@ directives["each"] = (tpl, expr) => {
|
|
|
548
557
|
const holder = tpl[_each] = document.createTextNode("");
|
|
549
558
|
tpl.replaceWith(holder);
|
|
550
559
|
const evaluate = parseExpr(tpl, each.items, ":each");
|
|
560
|
+
const keyExpr = tpl[_key] || tpl.getAttribute(":key");
|
|
561
|
+
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
562
|
+
tpl.removeAttribute(":key");
|
|
551
563
|
const scopes = /* @__PURE__ */ new WeakMap();
|
|
552
564
|
const itemEls = /* @__PURE__ */ new WeakMap();
|
|
553
565
|
let curEls = [];
|
|
@@ -565,23 +577,25 @@ directives["each"] = (tpl, expr) => {
|
|
|
565
577
|
exprError(Error("Bad list value"), tpl, expr, ":each", list);
|
|
566
578
|
let newEls = [], elScopes = [];
|
|
567
579
|
for (let [idx, item] of list) {
|
|
568
|
-
let
|
|
569
|
-
|
|
570
|
-
|
|
580
|
+
let el, scope, key = itemKey?.({ [each.item]: item });
|
|
581
|
+
if (isPrimitive(key))
|
|
582
|
+
key = primitive_pool_default(key);
|
|
583
|
+
if (key == null)
|
|
571
584
|
el = tpl.cloneNode(true);
|
|
572
|
-
|
|
573
|
-
|
|
585
|
+
else
|
|
586
|
+
(el = itemEls.get(key)) || itemEls.set(key, el = tpl.cloneNode(true));
|
|
574
587
|
newEls.push(el);
|
|
575
|
-
if (!scopes.
|
|
576
|
-
|
|
588
|
+
if (key == null || !(scope = scopes.get(key))) {
|
|
589
|
+
scope = Object.create(state);
|
|
577
590
|
scope[each.item] = item;
|
|
578
591
|
if (each.index)
|
|
579
592
|
scope[each.index] = idx;
|
|
580
593
|
if (tpl[_ref])
|
|
581
594
|
scope[tpl[_ref]] = el;
|
|
582
|
-
|
|
595
|
+
if (key != null)
|
|
596
|
+
scopes.set(key, scope);
|
|
583
597
|
}
|
|
584
|
-
elScopes.push(
|
|
598
|
+
elScopes.push(scope);
|
|
585
599
|
}
|
|
586
600
|
swap_inflate_default(holder.parentNode, curEls, newEls, holder);
|
|
587
601
|
curEls = newEls;
|
|
@@ -654,18 +668,19 @@ directives["value"] = (el, expr) => {
|
|
|
654
668
|
} : (value) => el.value = value;
|
|
655
669
|
return (state) => update(evaluate(state));
|
|
656
670
|
};
|
|
657
|
-
var _stop = Symbol("stop");
|
|
658
671
|
directives["on"] = (el, expr) => {
|
|
659
672
|
let evaluate = parseExpr(el, expr, ":on");
|
|
660
|
-
let listeners = {};
|
|
661
673
|
return (state) => {
|
|
662
|
-
|
|
663
|
-
removeListener(el, evt, listeners[evt]);
|
|
664
|
-
listeners = evaluate(state);
|
|
674
|
+
let listeners = evaluate(state);
|
|
665
675
|
for (let evt in listeners)
|
|
666
676
|
addListener(el, evt, listeners[evt]);
|
|
677
|
+
return () => {
|
|
678
|
+
for (let evt in listeners)
|
|
679
|
+
removeListener(el, evt, listeners[evt]);
|
|
680
|
+
};
|
|
667
681
|
};
|
|
668
682
|
};
|
|
683
|
+
var _stop = Symbol("stop");
|
|
669
684
|
var addListener = (el, evt, startFn) => {
|
|
670
685
|
if (evt.indexOf("..") < 0)
|
|
671
686
|
el.addEventListener(evt, startFn);
|
|
@@ -710,19 +725,19 @@ directives["aria"] = (el, expr) => {
|
|
|
710
725
|
};
|
|
711
726
|
var evaluatorMemo = {};
|
|
712
727
|
function parseExpr(el, expression, dir) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
728
|
+
let evaluate = evaluatorMemo[expression];
|
|
729
|
+
if (!evaluate) {
|
|
730
|
+
let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression) || /^(let|const)\s/.test(expression) ? `(() => { ${expression} })()` : expression;
|
|
731
|
+
try {
|
|
732
|
+
evaluate = evaluatorMemo[expression] = new Function(`__scope`, `with (__scope) { return ${rightSideSafeExpression} };`);
|
|
733
|
+
} catch (e2) {
|
|
734
|
+
return exprError(e2, el, expression, dir);
|
|
735
|
+
}
|
|
721
736
|
}
|
|
722
|
-
return
|
|
737
|
+
return (state) => {
|
|
723
738
|
let result;
|
|
724
739
|
try {
|
|
725
|
-
result = evaluate(state);
|
|
740
|
+
result = evaluate.call(el, state);
|
|
726
741
|
} catch (e2) {
|
|
727
742
|
return exprError(e2, el, expression, dir);
|
|
728
743
|
}
|
|
@@ -743,6 +758,9 @@ ${dir}=${expression ? `"${expression}"
|
|
|
743
758
|
function dashcase(str) {
|
|
744
759
|
return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => "-" + match.toLowerCase());
|
|
745
760
|
}
|
|
761
|
+
function isPrimitive(obj) {
|
|
762
|
+
return typeof obj === "string" || typeof obj === "boolean" || typeof obj === "number";
|
|
763
|
+
}
|
|
746
764
|
|
|
747
765
|
// src/core.js
|
|
748
766
|
var memo = /* @__PURE__ */ new WeakMap();
|
|
@@ -781,8 +799,14 @@ function sprae(container, values) {
|
|
|
781
799
|
}
|
|
782
800
|
};
|
|
783
801
|
init(container);
|
|
784
|
-
for (let update of updates)
|
|
785
|
-
|
|
802
|
+
for (let update of updates) {
|
|
803
|
+
let teardown;
|
|
804
|
+
b(() => {
|
|
805
|
+
if (typeof teardown === "function")
|
|
806
|
+
teardown();
|
|
807
|
+
teardown = update(state);
|
|
808
|
+
});
|
|
809
|
+
}
|
|
786
810
|
Object.seal(state);
|
|
787
811
|
memo.set(container, state);
|
|
788
812
|
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 w(t,e){if(S(t)&&!e)return t;if(A(t)){const n=Object.create(e||Object.getPrototypeOf(t)),o={},s=Object.getOwnPropertyDescriptors(t);for(let t in s){let e=s[t];if(e.get){let 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:A(s)?Object.seal(w(s)):Array.isArray(s)?w(s):s);l&&g(s,(t=>f.value=t)),Object.defineProperty(n,t,{get:()=>f.value,set(t){if(A(t)){if(A(f.value))try{return void Object.assign(f.value,t)}catch(t){}f.value=Object.seal(w(t))}else Array.isArray(t)?f.value=w(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=>w(t))):t}function A(t){return t&&t.constructor===Object}w.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={},W={},k={},$=(t,e,i,r)=>{let n,o=r.startsWith("on")&&r.slice(2),s=_(t,e,":"+r);if(s)return o?e=>{n&&T(t,o,n),n=s(e),n&&L(t,o,n)}:e=>P(t,r,s(e))},P=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")};k[""]=(t,e)=>{let i=_(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)P(t,R(e),r[e])}};var C=Symbol(":each"),U=Symbol(":ref");k.ref=(t,e,i)=>{t.hasAttribute(":each")?t[U]=e:i[e]=t},k.with=(t,e,i)=>{I(t,w(_(t,e,"with")(i),i))},k.if=(t,e)=>{let i=document.createTextNode(""),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(_(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),I(o,t))}},k.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 M(new Error,t,e);const r=t[C]=document.createTextNode("");t.replaceWith(r);const n=_(t,i.items,":each"),o=new WeakMap,s=new WeakMap;let l=[];return a=>{let f=n(a);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):M(Error("Bad list value"),t,e,":each"):f=[];let u=[],h=[];for(let[e,r]of f){let n=null===(c=r)?E:void 0===c?W:"number"==typeof c||c instanceof Number?N[c]||(N[c]=new Number(c)):"string"==typeof c||c instanceof String?N[c]||(N[c]=new String(c)):"boolean"==typeof c||c instanceof Boolean?N[c]||(N[c]=new Boolean(c)):c,l=s.get(n);if(l||(l=t.cloneNode(!0),s.set(n,l)),u.push(l),!o.has(n)){let s=Object.create(a);s[i.item]=r,i.index&&(s[i.index]=e),t[U]&&(s[t[U]]=l),o.set(n,s)}h.push(o.get(n))}var c;j(r.parentNode,l,u,r),l=u;for(let t=0;t<u.length;t++)I(u[t],h[t])}},k.id=(t,e)=>{let i=_(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},k.class=(t,e)=>{let i=_(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(" ")}},k.style=(t,e)=>{let i=_(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]}},k.text=(t,e)=>{let i=_(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},k.value=(t,e)=>{let i,r,n=_(t,e,":value"),o="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(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":"",P(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))};var B=Symbol("stop");k.on=(t,e)=>{let i=_(t,e,":on"),r={};return e=>{for(let e in r)T(t,e,r[e]);r=i(e);for(let e in r)L(t,e,r[e])}};var L=(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[B]||n(i)};t.addEventListener(r[o],s)};n(i)}},T=(t,e,i)=>{e.indexOf("..")>=0&&(i[B]=!0),t.removeEventListener(e,i)};k.data=(t,e)=>{let i=_(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},k.aria=(t,e)=>{let i=_(t,e,":aria");return e=>(e=>{for(let i in e)P(t,"aria-"+R(i),null==e[i]?null:e[i]+"")})(i(e))};var D={};function _(t,e,i){if(D[e])return D[e];let r,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=new Function("__scope",`with (__scope) { return ${n} };`).bind(t)}catch(r){return M(r,t,e,i)}return D[e]=n=>{let o;try{o=r(n)}catch(r){return M(r,t,e,i)}return o}}function M(t,e,i,r){Object.assign(t,{element:e,expression:i}),console.warn(`∴ ${t.message}\n\n${r}=${i?`"${i}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function R(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var F=new WeakMap;function I(t,e){if(!t.children)return;if(F.has(t))return F.get(t);const i=w(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=k[n]||$;if(r.push(o(t,s,i,n)||(()=>{})),F.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)b((()=>t(i)));return Object.seal(i),F.set(t,i),i}var z=I;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)&&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};
|
package/src/core.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import signalStruct from 'signal-struct';
|
|
2
2
|
import defaultDirective, { directives } from './directives.js';
|
|
3
|
-
import { effect
|
|
3
|
+
import { effect } from '@preact/signals-core'
|
|
4
4
|
|
|
5
5
|
// sprae element: apply directives
|
|
6
6
|
const memo = new WeakMap
|
|
@@ -42,7 +42,13 @@ export default function sprae(container, values) {
|
|
|
42
42
|
|
|
43
43
|
// call updates: subscribes directives to state;
|
|
44
44
|
// state is created after inits because directives can extend init values (expose refs etc)
|
|
45
|
-
for (let update of updates)
|
|
45
|
+
for (let update of updates) {
|
|
46
|
+
let teardown
|
|
47
|
+
effect(() => {
|
|
48
|
+
if (typeof teardown === 'function') teardown()
|
|
49
|
+
teardown = update(state)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
46
52
|
|
|
47
53
|
Object.seal(state);
|
|
48
54
|
memo.set(container, state);
|
package/src/directives.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// directives & parsing
|
|
2
2
|
import sprae from './core.js'
|
|
3
3
|
import swap from 'swapdom'
|
|
4
|
-
import p from 'primitive-pool'
|
|
5
4
|
import signalStruct from 'signal-struct'
|
|
5
|
+
import p from 'primitive-pool'
|
|
6
6
|
|
|
7
7
|
// reserved directives - order matters!
|
|
8
8
|
export const directives = {}
|
|
@@ -11,12 +11,12 @@ export const directives = {}
|
|
|
11
11
|
export default (el, expr, values, name) => {
|
|
12
12
|
let evt = name.startsWith('on') && name.slice(2)
|
|
13
13
|
let evaluate = parseExpr(el, expr, ':'+name)
|
|
14
|
-
|
|
15
|
-
let value
|
|
16
14
|
if (evaluate) return evt ? state => {
|
|
17
|
-
value
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
let value = evaluate(state)
|
|
16
|
+
if (value) {
|
|
17
|
+
addListener(el, evt, value)
|
|
18
|
+
return () => removeListener(el, evt, value)
|
|
19
|
+
}
|
|
20
20
|
}
|
|
21
21
|
: state => attr(el, name, evaluate(state))
|
|
22
22
|
}
|
|
@@ -35,17 +35,6 @@ directives[''] = (el, expr) => {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const _each = Symbol(':each'), _ref = Symbol(':ref')
|
|
39
|
-
|
|
40
|
-
directives['ref'] = (el, expr, state) => {
|
|
41
|
-
// make sure :ref is initialized after :each (return to avoid initializing as signal)
|
|
42
|
-
if (el.hasAttribute(':each')) {el[_ref] = expr; return};
|
|
43
|
-
|
|
44
|
-
// FIXME: wait for complex ref use-case
|
|
45
|
-
// parseExpr(el, `__scope[${expr}]=this`, ':ref')(values)
|
|
46
|
-
state[expr] = el;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
38
|
directives['with'] = (el, expr, rootState) => {
|
|
50
39
|
let evaluate = parseExpr(el, expr, 'with')
|
|
51
40
|
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
@@ -82,6 +71,22 @@ directives['if'] = (el, expr) => {
|
|
|
82
71
|
}
|
|
83
72
|
}
|
|
84
73
|
|
|
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};
|
|
79
|
+
|
|
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
|
+
|
|
85
90
|
directives['each'] = (tpl, expr) => {
|
|
86
91
|
let each = parseForExpression(expr);
|
|
87
92
|
if (!each) return exprError(new Error, tpl, expr);
|
|
@@ -93,15 +98,19 @@ directives['each'] = (tpl, expr) => {
|
|
|
93
98
|
|
|
94
99
|
const evaluate = parseExpr(tpl, each.items, ':each');
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
const keyExpr = tpl[_key] || tpl.getAttribute(':key');
|
|
102
|
+
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
103
|
+
tpl.removeAttribute(':key')
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
const scopes = new WeakMap() // stores scope per data item
|
|
107
|
+
const itemEls = new WeakMap() // element per data item
|
|
100
108
|
let curEls = []
|
|
101
109
|
|
|
102
110
|
return (state) => {
|
|
103
111
|
// get items
|
|
104
112
|
let list = evaluate(state)
|
|
113
|
+
|
|
105
114
|
if (!list) list = []
|
|
106
115
|
else if (typeof list === 'number') list = Array.from({length: list}, (_, i)=>[i, i+1])
|
|
107
116
|
else if (Array.isArray(list)) list = list.map((item,i) => [i+1, item])
|
|
@@ -112,23 +121,25 @@ directives['each'] = (tpl, expr) => {
|
|
|
112
121
|
let newEls = [], elScopes = []
|
|
113
122
|
|
|
114
123
|
for (let [idx, item] of list) {
|
|
115
|
-
let
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
let el, scope, key = itemKey?.({[each.item]: item})
|
|
125
|
+
if (isPrimitive(key)) key = p(key); // singletonize key
|
|
126
|
+
|
|
127
|
+
// we consider if data items are primitive, then nodes needn't be cached
|
|
128
|
+
// since likely they're very simple to create
|
|
129
|
+
if (key == null) el = tpl.cloneNode(true);
|
|
130
|
+
else (el = itemEls.get(key)) || itemEls.set(key, el = tpl.cloneNode(true));
|
|
131
|
+
|
|
121
132
|
newEls.push(el)
|
|
122
133
|
|
|
123
|
-
if (!scopes.
|
|
124
|
-
|
|
134
|
+
if (key == null || !(scope = scopes.get(key))) {
|
|
135
|
+
scope = Object.create(state)
|
|
125
136
|
scope[each.item] = item
|
|
126
137
|
if (each.index) scope[each.index] = idx;
|
|
127
138
|
// provide ref, if indicated
|
|
128
139
|
if (tpl[_ref]) scope[tpl[_ref]] = el
|
|
129
|
-
scopes.set(
|
|
140
|
+
if (key != null) scopes.set(key, scope)
|
|
130
141
|
}
|
|
131
|
-
elScopes.push(
|
|
142
|
+
elScopes.push(scope)
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
// swap is really fast & tiny
|
|
@@ -226,18 +237,19 @@ directives['value'] = (el, expr) => {
|
|
|
226
237
|
return (state) => update(evaluate(state))
|
|
227
238
|
}
|
|
228
239
|
|
|
229
|
-
const _stop = Symbol('stop')
|
|
230
240
|
directives['on'] = (el, expr) => {
|
|
231
241
|
let evaluate = parseExpr(el, expr, ':on')
|
|
232
|
-
let listeners = {}
|
|
233
242
|
|
|
234
243
|
return (state) => {
|
|
235
|
-
|
|
236
|
-
listeners = evaluate(state);
|
|
244
|
+
let listeners = evaluate(state);
|
|
237
245
|
for (let evt in listeners) addListener(el, evt, listeners[evt])
|
|
246
|
+
return () => {
|
|
247
|
+
for (let evt in listeners) removeListener(el, evt, listeners[evt])
|
|
248
|
+
}
|
|
238
249
|
}
|
|
239
250
|
}
|
|
240
251
|
|
|
252
|
+
const _stop = Symbol('stop')
|
|
241
253
|
const addListener = (el, evt, startFn) => {
|
|
242
254
|
if (evt.indexOf('..')<0) el.addEventListener(evt, startFn);
|
|
243
255
|
|
|
@@ -256,7 +268,6 @@ const addListener = (el, evt, startFn) => {
|
|
|
256
268
|
nextEvt(startFn)
|
|
257
269
|
}
|
|
258
270
|
}
|
|
259
|
-
|
|
260
271
|
const removeListener = (el, evt, fn) => {
|
|
261
272
|
if (evt.indexOf('..')>=0) fn[_stop] = true
|
|
262
273
|
el.removeEventListener(evt, fn);
|
|
@@ -285,31 +296,32 @@ let evaluatorMemo = {}
|
|
|
285
296
|
// borrowed from alpine: https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L61
|
|
286
297
|
// it seems to be more robust than subscript
|
|
287
298
|
function parseExpr(el, expression, dir) {
|
|
288
|
-
if (evaluatorMemo[expression]) return evaluatorMemo[expression]
|
|
289
|
-
|
|
290
|
-
// Some expressions that are useful in Alpine are not valid as the right side of an expression.
|
|
291
|
-
// Here we'll detect if the expression isn't valid for an assignement and wrap it in a self-
|
|
292
|
-
// calling function so that we don't throw an error AND a "return" statement can b e used.
|
|
293
|
-
let rightSideSafeExpression = 0
|
|
294
|
-
// Support expressions starting with "if" statements like: "if (...) doSomething()"
|
|
295
|
-
|| /^[\n\s]*if.*\(.*\)/.test(expression)
|
|
296
|
-
// Support expressions starting with "let/const" like: "let foo = 'bar'"
|
|
297
|
-
|| /^(let|const)\s/.test(expression)
|
|
298
|
-
? `(() => { ${expression} })()`
|
|
299
|
-
: expression;
|
|
300
|
-
|
|
301
299
|
// guard static-time eval errors
|
|
302
|
-
let evaluate
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
300
|
+
let evaluate = evaluatorMemo[expression]
|
|
301
|
+
|
|
302
|
+
if (!evaluate) {
|
|
303
|
+
// Some expressions that are useful in Alpine are not valid as the right side of an expression.
|
|
304
|
+
// Here we'll detect if the expression isn't valid for an assignement and wrap it in a self-
|
|
305
|
+
// calling function so that we don't throw an error AND a "return" statement can b e used.
|
|
306
|
+
let rightSideSafeExpression = 0
|
|
307
|
+
// Support expressions starting with "if" statements like: "if (...) doSomething()"
|
|
308
|
+
|| /^[\n\s]*if.*\(.*\)/.test(expression)
|
|
309
|
+
// Support expressions starting with "let/const" like: "let foo = 'bar'"
|
|
310
|
+
|| /^(let|const)\s/.test(expression)
|
|
311
|
+
? `(() => { ${expression} })()`
|
|
312
|
+
: expression;
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
evaluate = evaluatorMemo[expression] = new Function(`__scope`,`with (__scope) { return ${rightSideSafeExpression} };`)
|
|
316
|
+
} catch ( e ) {
|
|
317
|
+
return exprError(e, el, expression, dir)
|
|
318
|
+
}
|
|
307
319
|
}
|
|
308
320
|
|
|
309
321
|
// guard runtime eval errors
|
|
310
|
-
return
|
|
322
|
+
return (state) => {
|
|
311
323
|
let result
|
|
312
|
-
try { result = evaluate(state) }
|
|
324
|
+
try { result = evaluate.call(el, state); }
|
|
313
325
|
catch (e) { return exprError(e, el, expression, dir) }
|
|
314
326
|
return result
|
|
315
327
|
}
|
|
@@ -324,3 +336,7 @@ export function exprError(error, element, expression, dir) {
|
|
|
324
336
|
function dashcase(str) {
|
|
325
337
|
return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
|
|
326
338
|
};
|
|
339
|
+
|
|
340
|
+
function isPrimitive(obj) {
|
|
341
|
+
return typeof obj === 'string' || typeof obj === 'boolean' || typeof obj === 'number'
|
|
342
|
+
}
|
package/test/test.js
CHANGED
|
@@ -94,6 +94,13 @@ test('props: multiprop', async () => {
|
|
|
94
94
|
is(el.outerHTML, `<input id="0" name="0" for="0">`)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
+
// FIXME: this must work without return
|
|
98
|
+
test.todo('props: calculation', async () => {
|
|
99
|
+
let el = h`<x :x="let a = 5; return Array.from({length:a}, (_,i)=>i).join(' ')"></x>`
|
|
100
|
+
sprae(el);
|
|
101
|
+
is(el.outerHTML, `<x x="01234"></x>`)
|
|
102
|
+
})
|
|
103
|
+
|
|
97
104
|
test('data: base', async () => {
|
|
98
105
|
let el = h`<input :data="{a:1, fooBar:2}"/>`
|
|
99
106
|
let params = sprae(el)
|
|
@@ -359,6 +366,47 @@ test('each: condition within loop', async () => {
|
|
|
359
366
|
is(el.innerHTML, '')
|
|
360
367
|
})
|
|
361
368
|
|
|
369
|
+
test('each: next items have own "this", not single one', async () => {
|
|
370
|
+
// FIXME: let el = h`<x :each="x in 3"></x>`
|
|
371
|
+
let el = h`<div><x :each="x in 3" :data="{x}" :x="log.push(x, this.dataset.x)"></x></div>`
|
|
372
|
+
let log = []
|
|
373
|
+
let state = sprae(el, {log})
|
|
374
|
+
is(state.log, [1,'1',2,'2',3,'3'])
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
test('each: unkeyed', async () => {
|
|
378
|
+
let el = h`<div><x :each="x in xs" :text="x"></x></div>`
|
|
379
|
+
let state = sprae(el, {xs:[1,2,3]})
|
|
380
|
+
is(el.children.length, 3)
|
|
381
|
+
is(el.textContent, '123')
|
|
382
|
+
// let first = el.firstChild
|
|
383
|
+
state.xs = [1,3,2]
|
|
384
|
+
// is(el.firstChild, first)
|
|
385
|
+
is(el.textContent, '132')
|
|
386
|
+
state.xs = [3,3,3]
|
|
387
|
+
is(el.textContent, '333')
|
|
388
|
+
// is(el.firstChild, first)
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
test('each: keyed', async () => {
|
|
392
|
+
// keyed
|
|
393
|
+
let el = h`<div><x :each="x in xs" :text="x" :key="x"></x></div>`
|
|
394
|
+
let state = sprae(el, {xs:[1,2,3]})
|
|
395
|
+
is(el.children.length, 3)
|
|
396
|
+
is(el.textContent, '123')
|
|
397
|
+
let first = el.firstChild
|
|
398
|
+
state.xs = [1,3,2]
|
|
399
|
+
is(el.firstChild, first)
|
|
400
|
+
is(el.textContent, '132')
|
|
401
|
+
state.xs = [3,3,3]
|
|
402
|
+
is(el.textContent, '3')
|
|
403
|
+
// is(el.firstChild, first)
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
test.todo('each: unmounted elements remove listeners', async () => {
|
|
407
|
+
|
|
408
|
+
})
|
|
409
|
+
|
|
362
410
|
test('on: base', () => {
|
|
363
411
|
let el = h`<div :on="{click(e){log.push('click')},x}"></div>`
|
|
364
412
|
let log = signal([])
|
package/{plan.md → todo.md}
RENAMED
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
* [x] :text="" empty values shouldn't throw
|
|
34
34
|
* [x] implement :with
|
|
35
35
|
* [x] update :value without losing focus / position
|
|
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
|
|
36
38
|
* [ ] :if :ref, :if :with -> context setters must come first always
|
|
37
39
|
* [ ] frameworks benchmark
|
|
38
40
|
* [ ] examples
|
|
39
41
|
* [x] todomvc
|
|
40
|
-
* [
|
|
41
|
-
* [ ] `sprae(el, newState)` can update element's state directly (as batch!?) -> must be tested against repeats in directives
|
|
42
|
+
* [x] waveplay
|