sprae 2.6.1 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/readme.md +17 -3
- package/sprae.js +131 -123
- package/sprae.min.js +1 -1
- package/src/core.js +27 -7
- package/src/directives.js +73 -74
- package/test/test.js +36 -4
- package/todo.md +2 -2
package/package.json
CHANGED
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.**
|
|
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
|
-
**
|
|
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
|
-
**
|
|
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
|
|
9
|
+
var h2 = 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 !== 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
|
-
|
|
19
|
-
} catch (
|
|
18
|
+
h2.c();
|
|
19
|
+
} catch (h3) {
|
|
20
20
|
if (!t2) {
|
|
21
|
-
i2 =
|
|
21
|
+
i2 = h3;
|
|
22
22
|
t2 = true;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
|
|
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,
|
|
92
|
+
var t2 = i2.e, h2 = i2.x;
|
|
83
93
|
if (void 0 !== t2) {
|
|
84
|
-
t2.x =
|
|
94
|
+
t2.x = h2;
|
|
85
95
|
i2.e = void 0;
|
|
86
96
|
}
|
|
87
|
-
if (void 0 !==
|
|
88
|
-
|
|
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 =
|
|
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
|
|
107
|
+
var h2 = t2.value, o2 = 32 & this.f;
|
|
98
108
|
this.f &= -33;
|
|
99
109
|
try {
|
|
100
|
-
i2(
|
|
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(
|
|
121
|
-
if (
|
|
130
|
+
}, set: function(h2) {
|
|
131
|
+
if (h2 !== this.v) {
|
|
122
132
|
if (s > 100)
|
|
123
133
|
i();
|
|
124
|
-
this.v =
|
|
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
|
|
148
|
-
if (void 0 !==
|
|
149
|
-
t2.r =
|
|
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,
|
|
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 !==
|
|
163
|
-
|
|
172
|
+
if (void 0 !== h2)
|
|
173
|
+
h2.p = t2;
|
|
164
174
|
t2.p = void 0;
|
|
165
|
-
t2.n =
|
|
166
|
-
|
|
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 =
|
|
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
|
|
272
|
+
var h2 = i2.u;
|
|
263
273
|
i2.u = void 0;
|
|
264
|
-
if ("function" == typeof
|
|
274
|
+
if ("function" == typeof h2) {
|
|
265
275
|
n++;
|
|
266
276
|
var r2 = o;
|
|
267
277
|
o = void 0;
|
|
268
278
|
try {
|
|
269
|
-
|
|
279
|
+
h2();
|
|
270
280
|
} catch (t2) {
|
|
271
281
|
i2.f &= -2;
|
|
272
282
|
i2.f |= 8;
|
|
@@ -474,39 +484,9 @@ var primitive_pool_default = (key) => {
|
|
|
474
484
|
};
|
|
475
485
|
|
|
476
486
|
// src/directives.js
|
|
477
|
-
var
|
|
478
|
-
var
|
|
479
|
-
|
|
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) => {
|
|
506
|
-
let evaluate = parseExpr(el, expr, "with");
|
|
507
|
-
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
508
|
-
};
|
|
509
|
-
directives["if"] = (el, expr) => {
|
|
487
|
+
var primary = {};
|
|
488
|
+
var secondary = {};
|
|
489
|
+
primary["if"] = (el, expr) => {
|
|
510
490
|
let holder = document.createTextNode(""), clauses = [parseExpr(el, expr, ":if")], els = [el], cur = el;
|
|
511
491
|
while (cur = el.nextElementSibling) {
|
|
512
492
|
if (cur.hasAttribute(":else")) {
|
|
@@ -527,37 +507,25 @@ directives["if"] = (el, expr) => {
|
|
|
527
507
|
return (state) => {
|
|
528
508
|
let i2 = clauses.findIndex((f2) => f2(state));
|
|
529
509
|
if (els[i2] != cur) {
|
|
510
|
+
;
|
|
530
511
|
(cur[_each] || cur).replaceWith(cur = els[i2] || holder);
|
|
531
512
|
sprae(cur, state);
|
|
532
513
|
}
|
|
533
514
|
};
|
|
534
515
|
};
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
;
|
|
516
|
+
primary["with"] = (el, expr, rootState) => {
|
|
517
|
+
let evaluate = parseExpr(el, expr, "with");
|
|
518
|
+
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
552
519
|
};
|
|
553
|
-
|
|
520
|
+
var _each = Symbol(":each");
|
|
521
|
+
primary["each"] = (tpl, expr) => {
|
|
554
522
|
let each = parseForExpression(expr);
|
|
555
523
|
if (!each)
|
|
556
524
|
return exprError(new Error(), tpl, expr);
|
|
557
525
|
const holder = tpl[_each] = document.createTextNode("");
|
|
558
526
|
tpl.replaceWith(holder);
|
|
559
|
-
const evaluate = parseExpr(tpl, each
|
|
560
|
-
const keyExpr = tpl
|
|
527
|
+
const evaluate = parseExpr(tpl, each[2], ":each");
|
|
528
|
+
const keyExpr = tpl.getAttribute(":key");
|
|
561
529
|
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
562
530
|
tpl.removeAttribute(":key");
|
|
563
531
|
const scopes = /* @__PURE__ */ new WeakMap();
|
|
@@ -577,7 +545,7 @@ directives["each"] = (tpl, expr) => {
|
|
|
577
545
|
exprError(Error("Bad list value"), tpl, expr, ":each", list);
|
|
578
546
|
let newEls = [], elScopes = [];
|
|
579
547
|
for (let [idx, item] of list) {
|
|
580
|
-
let el, scope, key = itemKey?.({ [each
|
|
548
|
+
let el, scope, key = itemKey?.({ [each[0]]: item, [each[1]]: idx });
|
|
581
549
|
if (isPrimitive(key))
|
|
582
550
|
key = primitive_pool_default(key);
|
|
583
551
|
if (key == null)
|
|
@@ -586,15 +554,11 @@ directives["each"] = (tpl, expr) => {
|
|
|
586
554
|
(el = itemEls.get(key)) || itemEls.set(key, el = tpl.cloneNode(true));
|
|
587
555
|
newEls.push(el);
|
|
588
556
|
if (key == null || !(scope = scopes.get(key))) {
|
|
589
|
-
scope =
|
|
590
|
-
scope[each.item] = item;
|
|
591
|
-
if (each.index)
|
|
592
|
-
scope[each.index] = idx;
|
|
593
|
-
if (tpl[_ref])
|
|
594
|
-
scope[tpl[_ref]] = el;
|
|
557
|
+
scope = signalStruct({ [each[0]]: item, [each[1]]: idx }, state);
|
|
595
558
|
if (key != null)
|
|
596
559
|
scopes.set(key, scope);
|
|
597
|
-
}
|
|
560
|
+
} else
|
|
561
|
+
scope[each[0]] = item;
|
|
598
562
|
elScopes.push(scope);
|
|
599
563
|
}
|
|
600
564
|
swap_inflate_default(holder.parentNode, curEls, newEls, holder);
|
|
@@ -611,24 +575,26 @@ function parseForExpression(expression) {
|
|
|
611
575
|
let inMatch = expression.match(forAliasRE);
|
|
612
576
|
if (!inMatch)
|
|
613
577
|
return;
|
|
614
|
-
let
|
|
615
|
-
res.items = inMatch[2].trim();
|
|
578
|
+
let items = inMatch[2].trim();
|
|
616
579
|
let item = inMatch[1].replace(stripParensRE, "").trim();
|
|
617
580
|
let iteratorMatch = item.match(forIteratorRE);
|
|
618
|
-
if (iteratorMatch)
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
return
|
|
581
|
+
if (iteratorMatch)
|
|
582
|
+
return [
|
|
583
|
+
item.replace(forIteratorRE, "").trim(),
|
|
584
|
+
iteratorMatch[1].trim(),
|
|
585
|
+
items
|
|
586
|
+
];
|
|
587
|
+
return [item, "", items];
|
|
625
588
|
}
|
|
626
|
-
|
|
589
|
+
secondary["ref"] = (el, expr, state) => {
|
|
590
|
+
state[expr] = el;
|
|
591
|
+
};
|
|
592
|
+
secondary["id"] = (el, expr) => {
|
|
627
593
|
let evaluate = parseExpr(el, expr, ":id");
|
|
628
594
|
const update = (v2) => el.id = v2 || v2 === 0 ? v2 : "";
|
|
629
595
|
return (state) => update(evaluate(state));
|
|
630
596
|
};
|
|
631
|
-
|
|
597
|
+
secondary["class"] = (el, expr) => {
|
|
632
598
|
let evaluate = parseExpr(el, expr, ":class");
|
|
633
599
|
let initClassName = el.className;
|
|
634
600
|
return (state) => {
|
|
@@ -636,7 +602,7 @@ directives["class"] = (el, expr) => {
|
|
|
636
602
|
el.className = initClassName + typeof v2 === "string" ? v2 : (Array.isArray(v2) ? v2 : Object.entries(v2).map(([k, v3]) => v3 ? k : "")).filter(Boolean).join(" ");
|
|
637
603
|
};
|
|
638
604
|
};
|
|
639
|
-
|
|
605
|
+
secondary["style"] = (el, expr) => {
|
|
640
606
|
let evaluate = parseExpr(el, expr, ":style");
|
|
641
607
|
let initStyle = el.getAttribute("style") || "";
|
|
642
608
|
if (!initStyle.endsWith(";"))
|
|
@@ -650,14 +616,14 @@ directives["style"] = (el, expr) => {
|
|
|
650
616
|
el.style[k] = v2[k];
|
|
651
617
|
};
|
|
652
618
|
};
|
|
653
|
-
|
|
619
|
+
secondary["text"] = (el, expr) => {
|
|
654
620
|
let evaluate = parseExpr(el, expr, ":text");
|
|
655
621
|
return (state) => {
|
|
656
622
|
let value = evaluate(state);
|
|
657
623
|
el.textContent = value == null ? "" : value;
|
|
658
624
|
};
|
|
659
625
|
};
|
|
660
|
-
|
|
626
|
+
secondary["value"] = (el, expr) => {
|
|
661
627
|
let evaluate = parseExpr(el, expr, ":value");
|
|
662
628
|
let from, to;
|
|
663
629
|
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 +634,7 @@ directives["value"] = (el, expr) => {
|
|
|
668
634
|
} : (value) => el.value = value;
|
|
669
635
|
return (state) => update(evaluate(state));
|
|
670
636
|
};
|
|
671
|
-
|
|
637
|
+
secondary["on"] = (el, expr) => {
|
|
672
638
|
let evaluate = parseExpr(el, expr, ":on");
|
|
673
639
|
return (state) => {
|
|
674
640
|
let listeners = evaluate(state);
|
|
@@ -707,7 +673,7 @@ var removeListener = (el, evt, fn) => {
|
|
|
707
673
|
fn[_stop] = true;
|
|
708
674
|
el.removeEventListener(evt, fn);
|
|
709
675
|
};
|
|
710
|
-
|
|
676
|
+
secondary["data"] = (el, expr) => {
|
|
711
677
|
let evaluate = parseExpr(el, expr, ":data");
|
|
712
678
|
return (state) => {
|
|
713
679
|
let value = evaluate(state);
|
|
@@ -715,7 +681,7 @@ directives["data"] = (el, expr) => {
|
|
|
715
681
|
el.dataset[key] = value[key];
|
|
716
682
|
};
|
|
717
683
|
};
|
|
718
|
-
|
|
684
|
+
secondary["aria"] = (el, expr) => {
|
|
719
685
|
let evaluate = parseExpr(el, expr, ":aria");
|
|
720
686
|
const update = (value) => {
|
|
721
687
|
for (let key in value)
|
|
@@ -723,6 +689,33 @@ directives["aria"] = (el, expr) => {
|
|
|
723
689
|
};
|
|
724
690
|
return (state) => update(evaluate(state));
|
|
725
691
|
};
|
|
692
|
+
secondary[""] = (el, expr) => {
|
|
693
|
+
let evaluate = parseExpr(el, expr, ":");
|
|
694
|
+
if (evaluate)
|
|
695
|
+
return (state) => {
|
|
696
|
+
let value = evaluate(state);
|
|
697
|
+
for (let key in value)
|
|
698
|
+
attr(el, dashcase(key), value[key]);
|
|
699
|
+
};
|
|
700
|
+
};
|
|
701
|
+
var directives_default = (el, expr, values, name) => {
|
|
702
|
+
let evt = name.startsWith("on") && name.slice(2);
|
|
703
|
+
let evaluate = parseExpr(el, expr, ":" + name);
|
|
704
|
+
if (evaluate)
|
|
705
|
+
return evt ? (state) => {
|
|
706
|
+
let value = evaluate(state);
|
|
707
|
+
if (value) {
|
|
708
|
+
addListener(el, evt, value);
|
|
709
|
+
return () => removeListener(el, evt, value);
|
|
710
|
+
}
|
|
711
|
+
} : (state) => attr(el, name, evaluate(state));
|
|
712
|
+
};
|
|
713
|
+
var attr = (el, name, v2) => {
|
|
714
|
+
if (v2 == null || v2 === false)
|
|
715
|
+
el.removeAttribute(name);
|
|
716
|
+
else
|
|
717
|
+
el.setAttribute(name, v2 === true ? "" : typeof v2 === "number" || typeof v2 === "string" ? v2 : "");
|
|
718
|
+
};
|
|
726
719
|
var evaluatorMemo = {};
|
|
727
720
|
function parseExpr(el, expression, dir) {
|
|
728
721
|
let evaluate = evaluatorMemo[expression];
|
|
@@ -767,11 +760,26 @@ var memo = /* @__PURE__ */ new WeakMap();
|
|
|
767
760
|
function sprae(container, values) {
|
|
768
761
|
if (!container.children)
|
|
769
762
|
return;
|
|
770
|
-
if (memo.has(container))
|
|
771
|
-
|
|
763
|
+
if (memo.has(container)) {
|
|
764
|
+
let state2 = memo.get(container);
|
|
765
|
+
h(() => Object.assign(state2, values));
|
|
766
|
+
return state2;
|
|
767
|
+
}
|
|
772
768
|
const state = signalStruct(values || {});
|
|
773
769
|
const updates = [];
|
|
774
770
|
const init = (el, parent = el.parentNode) => {
|
|
771
|
+
for (let name in primary) {
|
|
772
|
+
let attrName = ":" + name;
|
|
773
|
+
if (el.hasAttribute?.(attrName)) {
|
|
774
|
+
let expr = el.getAttribute(attrName);
|
|
775
|
+
el.removeAttribute(attrName);
|
|
776
|
+
if (!expr)
|
|
777
|
+
continue;
|
|
778
|
+
updates.push(primary[name](el, expr, state, name));
|
|
779
|
+
if (memo.has(el) || el.parentNode !== parent)
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
775
783
|
if (el.attributes) {
|
|
776
784
|
for (let i2 = 0; i2 < el.attributes.length; ) {
|
|
777
785
|
let attr2 = el.attributes[i2];
|
|
@@ -785,9 +793,8 @@ function sprae(container, values) {
|
|
|
785
793
|
continue;
|
|
786
794
|
let attrNames = attr2.name.slice(1).split(":");
|
|
787
795
|
for (let attrName of attrNames) {
|
|
788
|
-
let dir =
|
|
789
|
-
updates.push(dir(el, expr, state, attrName)
|
|
790
|
-
}));
|
|
796
|
+
let dir = secondary[attrName] || directives_default;
|
|
797
|
+
updates.push(dir(el, expr, state, attrName));
|
|
791
798
|
if (memo.has(el) || el.parentNode !== parent)
|
|
792
799
|
return false;
|
|
793
800
|
}
|
|
@@ -799,14 +806,15 @@ function sprae(container, values) {
|
|
|
799
806
|
}
|
|
800
807
|
};
|
|
801
808
|
init(container);
|
|
802
|
-
for (let update of updates)
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
teardown
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
809
|
+
for (let update of updates)
|
|
810
|
+
if (update) {
|
|
811
|
+
let teardown;
|
|
812
|
+
b(() => {
|
|
813
|
+
if (typeof teardown === "function")
|
|
814
|
+
teardown();
|
|
815
|
+
teardown = update(state);
|
|
816
|
+
});
|
|
817
|
+
}
|
|
810
818
|
Object.seal(state);
|
|
811
819
|
memo.set(container, state);
|
|
812
820
|
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,[i.index||""]:e});("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={};$.if=(t,e)=>{let i=document.createTextNode(""),r=[M(t,e,":if")],n=[t],o=t;for(;(o=t.nextElementSibling)&&o.hasAttribute(":else");)o.removeAttribute(":else"),(e=o.getAttribute(":if"))?(o.removeAttribute(":if"),o.remove(),n.push(o),r.push(M(t,e,":else :if"))):(o.remove(),n.push(o),r.push((()=>1)));return t.replaceWith(o=i),t=>{let e=r.findIndex((e=>e(t)));n[e]!=o&&((o[C]||o).replaceWith(o=n[e]||i),z(o,t))}},$.with=(t,e,i)=>{z(t,w(M(t,e,"with")(i),i))};var C=Symbol(":each");$.each=(t,e)=>{let i=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,i=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!i)return;let r=i[2].trim(),n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),r]:[n,"",r]}(e);if(!i)return R(new Error,t,e);const r=t[C]=document.createTextNode("");t.replaceWith(r);const n=M(t,i[2],":each"),o=t.getAttribute(":key"),s=o?M(null,o):null;t.removeAttribute(":key");const l=new WeakMap,f=new WeakMap;let u=[];return o=>{let a=n(o);a?"number"==typeof a?a=Array.from({length:a},((t,e)=>[e,e+1])):Array.isArray(a)?a=a.map(((t,e)=>[e+1,t])):"object"==typeof a?a=Object.entries(a):R(Error("Bad list value"),t,e,":each"):a=[];let h=[],c=[];for(let[e,r]of a){let n,u,a=s?.({[i[0]]:r,[i[1]]:e});("string"==typeof(v=a)||"boolean"==typeof v||"number"==typeof v)&&(a=W(a)),null==a?n=t.cloneNode(!0):(n=f.get(a))||f.set(a,n=t.cloneNode(!0)),h.push(n),null!=a&&(u=l.get(a))?u[i[0]]=r:(u=w({[i[0]]:r,[i[1]]:e},o),null!=a&&l.set(a,u)),c.push(u)}var v;j(r.parentNode,u,h,r),u=h;for(let t=0;t<h.length;t++)z(h[t],c[t])}},P.ref=(t,e,i)=>{i[e]=t},P.id=(t,e)=>{let i=M(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},P.class=(t,e)=>{let i=M(t,e,":class"),r=t.className;return e=>{let n=i(e);t.className=r+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},P.style=(t,e)=>{let i=M(t,e,":style"),r=t.getAttribute("style")||"";return r.endsWith(";")||(r+="; "),e=>{let n=i(e);if("string"==typeof n)t.setAttribute("style",r+n);else for(let e in n)t.style[e]=n[e]}},P.text=(t,e)=>{let i=M(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},P.value=(t,e)=>{let i,r,n=M(t,e,":value"),o="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(i=t.selectionStart,r=t.selectionEnd,t.setAttribute("value",t.value=null==e?"":e),i&&t.setSelectionRange(i,r)):"checkbox"===t.type?e=>(t.value=e?"on":"",D(t,"checked",e)):"select-one"===t.type?e=>{for(let e in t.options)e.removeAttribute("selected");t.value=e,t.selectedOptions[0]?.setAttribute("selected","")}:e=>t.value=e;return t=>o(n(t))},P.on=(t,e)=>{let i=M(t,e,":on");return e=>{let r=i(e);for(let e in r)B(t,e,r[e]);return()=>{for(let e in r)L(t,e,r[e])}}};var U=Symbol("stop"),B=(t,e,i)=>{if(e.indexOf("..")<0)t.addEventListener(e,i);else{const r=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),n=(e,o=0)=>{let s=l=>{t.removeEventListener(r[o],s),"function"!=typeof(e=e.call(t,l))&&(e=()=>{}),++o<r.length?n(e,o):i[U]||n(i)};t.addEventListener(r[o],s)};n(i)}},L=(t,e,i)=>{e.indexOf("..")>=0&&(i[U]=!0),t.removeEventListener(e,i)};P.data=(t,e)=>{let i=M(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},P.aria=(t,e)=>{let i=M(t,e,":aria");return e=>(e=>{for(let i in e)D(t,"aria-"+F(i),null==e[i]?null:e[i]+"")})(i(e))},P[""]=(t,e)=>{let i=M(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)D(t,F(e),r[e])}};var T=(t,e,i,r)=>{let n=r.startsWith("on")&&r.slice(2),o=M(t,e,":"+r);if(o)return n?e=>{let i=o(e);if(i)return B(t,n,i),()=>L(t,n,i)}:e=>D(t,r,o(e))},D=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")},_={};function M(t,e,i){let r=_[e];if(!r){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=_[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(r){return R(r,t,e,i)}}return n=>{let o;try{o=r.call(t,n)}catch(r){return R(r,t,e,i)}return o}}function R(t,e,i,r){Object.assign(t,{element:e,expression:i}),console.warn(`∴ ${t.message}\n\n${r}=${i?`"${i}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function F(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var I=new WeakMap;function z(t,i){if(!t.children)return;if(I.has(t)){let r=I.get(t);return function(t){if(n>0)return t();n++;try{t()}finally{e()}}((()=>Object.assign(r,i))),r}const r=w(i||{}),o=[],s=(t,e=t.parentNode)=>{for(let i in $){let n=":"+i;if(t.hasAttribute?.(n)){let s=t.getAttribute(n);if(t.removeAttribute(n),!s)continue;if(o.push($[i](t,s,r,i)),I.has(t)||t.parentNode!==e)return!1}}if(t.attributes)for(let i=0;i<t.attributes.length;){let n=t.attributes[i];if(":"!==n.name[0]){i++;continue}t.removeAttribute(n.name);let s=n.value;if(!s)continue;let l=n.name.slice(1).split(":");for(let i of l){let n=P[i]||T;if(o.push(n(t,s,r,i)),I.has(t)||t.parentNode!==e)return!1}}for(let e,i=0;e=t.children[i];i++)!1===s(e,t)&&i--};s(t);for(let t of o)if(t){let e;b((()=>{"function"==typeof e&&e(),e=t(r)}))}return Object.seal(r),I.set(t,r),r}var X=z;export{X as default};
|
package/src/core.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import signalStruct from 'signal-struct';
|
|
2
|
-
import defaultDirective, {
|
|
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))
|
|
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 =
|
|
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,14 @@ import signalStruct from 'signal-struct'
|
|
|
5
5
|
import p from 'primitive-pool'
|
|
6
6
|
|
|
7
7
|
// reserved directives - order matters!
|
|
8
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
for (let key in value) attr(el, dashcase(key), value[key]);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
directives['with'] = (el, expr, rootState) => {
|
|
39
|
-
let evaluate = parseExpr(el, expr, 'with')
|
|
40
|
-
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
directives['if'] = (el, expr) => {
|
|
12
|
+
// :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
|
|
13
|
+
// as for :if :with - :if must init first, since it is lazy, to avoid initializing component ahead of time by :with
|
|
14
|
+
// we consider :with={x} :if={x} case insignificant
|
|
15
|
+
primary['if'] = (el, expr) => {
|
|
44
16
|
let holder = document.createTextNode(''),
|
|
45
17
|
clauses = [parseExpr(el, expr, ':if')],
|
|
46
18
|
els = [el], cur = el
|
|
@@ -64,30 +36,24 @@ directives['if'] = (el, expr) => {
|
|
|
64
36
|
return (state) => {
|
|
65
37
|
let i = clauses.findIndex(f => f(state))
|
|
66
38
|
if (els[i] != cur) {
|
|
67
|
-
(cur[_each] || cur).replaceWith(cur = els[i] || holder);
|
|
39
|
+
;(cur[_each] || cur).replaceWith(cur = els[i] || holder);
|
|
68
40
|
// NOTE: it lazily initializes elements on insertion, it's safe to sprae multiple times
|
|
41
|
+
// but :if must come first to avoid preliminary caching
|
|
69
42
|
sprae(cur, state);
|
|
70
43
|
}
|
|
71
44
|
}
|
|
72
45
|
}
|
|
73
46
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
47
|
+
// :with must come before :each, but :if has primary importance
|
|
48
|
+
primary['with'] = (el, expr, rootState) => {
|
|
49
|
+
let evaluate = parseExpr(el, expr, 'with')
|
|
50
|
+
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
83
51
|
}
|
|
84
52
|
|
|
85
|
-
|
|
86
|
-
// make sure :ref is initialized after :each (return to avoid initializing as signal)
|
|
87
|
-
if (el.hasAttribute(':each')) {el[_key] = expr; return};
|
|
88
|
-
}
|
|
53
|
+
const _each = Symbol(':each')
|
|
89
54
|
|
|
90
|
-
|
|
55
|
+
// :each must init before :ref, :id or any others, since it defines scope
|
|
56
|
+
primary['each'] = (tpl, expr) => {
|
|
91
57
|
let each = parseForExpression(expr);
|
|
92
58
|
if (!each) return exprError(new Error, tpl, expr);
|
|
93
59
|
|
|
@@ -96,9 +62,9 @@ directives['each'] = (tpl, expr) => {
|
|
|
96
62
|
const holder = tpl[_each] = document.createTextNode('')
|
|
97
63
|
tpl.replaceWith(holder)
|
|
98
64
|
|
|
99
|
-
const evaluate = parseExpr(tpl, each
|
|
65
|
+
const evaluate = parseExpr(tpl, each[2], ':each');
|
|
100
66
|
|
|
101
|
-
const keyExpr = tpl
|
|
67
|
+
const keyExpr = tpl.getAttribute(':key');
|
|
102
68
|
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
103
69
|
tpl.removeAttribute(':key')
|
|
104
70
|
|
|
@@ -121,7 +87,7 @@ directives['each'] = (tpl, expr) => {
|
|
|
121
87
|
let newEls = [], elScopes = []
|
|
122
88
|
|
|
123
89
|
for (let [idx, item] of list) {
|
|
124
|
-
let el, scope, key = itemKey?.({[each
|
|
90
|
+
let el, scope, key = itemKey?.({[each[0]]: item, [each[1]]: idx})
|
|
125
91
|
if (isPrimitive(key)) key = p(key); // singletonize key
|
|
126
92
|
|
|
127
93
|
// we consider if data items are primitive, then nodes needn't be cached
|
|
@@ -132,13 +98,12 @@ directives['each'] = (tpl, expr) => {
|
|
|
132
98
|
newEls.push(el)
|
|
133
99
|
|
|
134
100
|
if (key == null || !(scope = scopes.get(key))) {
|
|
135
|
-
scope =
|
|
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
|
|
101
|
+
scope = signalStruct({[each[0]]: item, [each[1]]:idx}, state)
|
|
140
102
|
if (key != null) scopes.set(key, scope)
|
|
141
103
|
}
|
|
104
|
+
// need to explicitly set item to update existing children's values
|
|
105
|
+
else scope[each[0]] = item
|
|
106
|
+
|
|
142
107
|
elScopes.push(scope)
|
|
143
108
|
}
|
|
144
109
|
|
|
@@ -162,28 +127,33 @@ function parseForExpression(expression) {
|
|
|
162
127
|
|
|
163
128
|
if (!inMatch) return
|
|
164
129
|
|
|
165
|
-
let
|
|
166
|
-
res.items = inMatch[2].trim()
|
|
130
|
+
let items = inMatch[2].trim()
|
|
167
131
|
let item = inMatch[1].replace(stripParensRE, '').trim()
|
|
168
132
|
let iteratorMatch = item.match(forIteratorRE)
|
|
169
133
|
|
|
170
|
-
if (iteratorMatch)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
134
|
+
if (iteratorMatch) return [
|
|
135
|
+
item.replace(forIteratorRE, '').trim(),
|
|
136
|
+
iteratorMatch[1].trim(),
|
|
137
|
+
items
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
return [item, '', items]
|
|
141
|
+
}
|
|
176
142
|
|
|
177
|
-
|
|
143
|
+
|
|
144
|
+
secondary['ref'] = (el, expr, state) => {
|
|
145
|
+
// FIXME: wait for complex ref use-case
|
|
146
|
+
// parseExpr(el, `__scope[${expr}]=this`, ':ref')(values)
|
|
147
|
+
state[expr] = el;
|
|
178
148
|
}
|
|
179
149
|
|
|
180
|
-
|
|
150
|
+
secondary['id'] = (el, expr) => {
|
|
181
151
|
let evaluate = parseExpr(el, expr, ':id')
|
|
182
152
|
const update = v => el.id = v || v === 0 ? v : ''
|
|
183
153
|
return (state) => update(evaluate(state))
|
|
184
154
|
}
|
|
185
155
|
|
|
186
|
-
|
|
156
|
+
secondary['class'] = (el, expr) => {
|
|
187
157
|
let evaluate = parseExpr(el, expr, ':class')
|
|
188
158
|
let initClassName = el.className
|
|
189
159
|
return (state) => {
|
|
@@ -192,7 +162,7 @@ directives['class'] = (el, expr) => {
|
|
|
192
162
|
}
|
|
193
163
|
}
|
|
194
164
|
|
|
195
|
-
|
|
165
|
+
secondary['style'] = (el, expr) => {
|
|
196
166
|
let evaluate = parseExpr(el, expr, ':style')
|
|
197
167
|
let initStyle = el.getAttribute('style') || ''
|
|
198
168
|
if (!initStyle.endsWith(';')) initStyle += '; '
|
|
@@ -203,7 +173,7 @@ directives['style'] = (el, expr) => {
|
|
|
203
173
|
}
|
|
204
174
|
}
|
|
205
175
|
|
|
206
|
-
|
|
176
|
+
secondary['text'] = (el, expr) => {
|
|
207
177
|
let evaluate = parseExpr(el, expr, ':text')
|
|
208
178
|
|
|
209
179
|
return (state) => {
|
|
@@ -213,7 +183,7 @@ directives['text'] = (el, expr) => {
|
|
|
213
183
|
}
|
|
214
184
|
|
|
215
185
|
// connect expr to element value
|
|
216
|
-
|
|
186
|
+
secondary['value'] = (el, expr) => {
|
|
217
187
|
let evaluate = parseExpr(el, expr, ':value')
|
|
218
188
|
|
|
219
189
|
let from, to
|
|
@@ -237,7 +207,7 @@ directives['value'] = (el, expr) => {
|
|
|
237
207
|
return (state) => update(evaluate(state))
|
|
238
208
|
}
|
|
239
209
|
|
|
240
|
-
|
|
210
|
+
secondary['on'] = (el, expr) => {
|
|
241
211
|
let evaluate = parseExpr(el, expr, ':on')
|
|
242
212
|
|
|
243
213
|
return (state) => {
|
|
@@ -273,7 +243,7 @@ const removeListener = (el, evt, fn) => {
|
|
|
273
243
|
el.removeEventListener(evt, fn);
|
|
274
244
|
}
|
|
275
245
|
|
|
276
|
-
|
|
246
|
+
secondary['data'] = (el, expr) => {
|
|
277
247
|
let evaluate = parseExpr(el, expr, ':data')
|
|
278
248
|
|
|
279
249
|
return ((state) => {
|
|
@@ -282,7 +252,7 @@ directives['data'] = (el, expr) => {
|
|
|
282
252
|
})
|
|
283
253
|
}
|
|
284
254
|
|
|
285
|
-
|
|
255
|
+
secondary['aria'] = (el, expr) => {
|
|
286
256
|
let evaluate = parseExpr(el, expr, ':aria')
|
|
287
257
|
const update = (value) => {
|
|
288
258
|
for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
|
|
@@ -290,6 +260,35 @@ directives['aria'] = (el, expr) => {
|
|
|
290
260
|
return ((state) => update(evaluate(state)))
|
|
291
261
|
}
|
|
292
262
|
|
|
263
|
+
// set props in-bulk or run effect
|
|
264
|
+
secondary[''] = (el, expr) => {
|
|
265
|
+
let evaluate = parseExpr(el, expr, ':')
|
|
266
|
+
if (evaluate) return (state) => {
|
|
267
|
+
let value = evaluate(state)
|
|
268
|
+
for (let key in value) attr(el, dashcase(key), value[key]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// any other prop directive
|
|
273
|
+
export default (el, expr, values, name) => {
|
|
274
|
+
let evt = name.startsWith('on') && name.slice(2)
|
|
275
|
+
let evaluate = parseExpr(el, expr, ':'+name)
|
|
276
|
+
if (evaluate) return evt ? state => {
|
|
277
|
+
let value = evaluate(state)
|
|
278
|
+
if (value) {
|
|
279
|
+
addListener(el, evt, value)
|
|
280
|
+
return () => removeListener(el, evt, value)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
: state => attr(el, name, evaluate(state))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// set attr
|
|
287
|
+
const attr = (el, name, v) => {
|
|
288
|
+
if (v == null || v === false) el.removeAttribute(name)
|
|
289
|
+
else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
|
|
290
|
+
}
|
|
291
|
+
|
|
293
292
|
|
|
294
293
|
let evaluatorMemo = {}
|
|
295
294
|
|
package/test/test.js
CHANGED
|
@@ -148,7 +148,7 @@ test('text: core', async () => {
|
|
|
148
148
|
is(el.outerHTML, `<div></div>`)
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
test('
|
|
151
|
+
test('if: base', async () => {
|
|
152
152
|
let el = h`<p>
|
|
153
153
|
<span :if="a==1">a</span>
|
|
154
154
|
<span :else :if="a==2">b</span>
|
|
@@ -166,7 +166,7 @@ test('conditions: base', async () => {
|
|
|
166
166
|
is(el.innerHTML, '<span>c</span>')
|
|
167
167
|
})
|
|
168
168
|
|
|
169
|
-
test('
|
|
169
|
+
test('if: short with insertions', async () => {
|
|
170
170
|
let el = h`<p>
|
|
171
171
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
172
172
|
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
@@ -191,7 +191,7 @@ test('conditions: short with insertions', async () => {
|
|
|
191
191
|
params.a = null
|
|
192
192
|
})
|
|
193
193
|
|
|
194
|
-
test('
|
|
194
|
+
test('if: reactive values', async () => {
|
|
195
195
|
let el = h`<p>
|
|
196
196
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
197
197
|
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
@@ -215,12 +215,27 @@ test('conditions: reactive values', async () => {
|
|
|
215
215
|
is(el.innerHTML, '<span>4</span>')
|
|
216
216
|
})
|
|
217
217
|
|
|
218
|
-
test('
|
|
218
|
+
test('if: (#3) subsequent content is not abandoned', async () => {
|
|
219
219
|
let x = h`<x><y :if="!!y"></y><z :text="123"></z></x>`
|
|
220
220
|
sprae(x, {y: false})
|
|
221
221
|
is(x.outerHTML, `<x><z>123</z></x>`)
|
|
222
222
|
})
|
|
223
223
|
|
|
224
|
+
test('if: + :with doesnt prevent secondary effects from happening', () => {
|
|
225
|
+
let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
|
|
226
|
+
let state = sprae(el, {x:''})
|
|
227
|
+
is(el.innerHTML, ``)
|
|
228
|
+
state.x = '123'
|
|
229
|
+
is(el.innerHTML, `<x>123</x>`)
|
|
230
|
+
|
|
231
|
+
// NOTE: we ignore this case
|
|
232
|
+
// let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
|
|
233
|
+
// let state2 = sprae(el, {cond:''})
|
|
234
|
+
// is(el2.innerHTML, ``)
|
|
235
|
+
// state2.cond = '123'
|
|
236
|
+
// is(el2.innerHTML, `<x>123</x>`)
|
|
237
|
+
})
|
|
238
|
+
|
|
224
239
|
test('each: array', async () => {
|
|
225
240
|
// FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
|
|
226
241
|
let el = h`<p>
|
|
@@ -404,7 +419,24 @@ test('each: keyed', async () => {
|
|
|
404
419
|
})
|
|
405
420
|
|
|
406
421
|
test.todo('each: unmounted elements remove listeners', async () => {
|
|
422
|
+
// let's hope they get removed without memory leaks :')
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
test('each: internal children get updated by state update, also: update by running again', () => {
|
|
426
|
+
let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
|
|
427
|
+
sprae(el, { items: [1,2,3] })
|
|
428
|
+
is(el.textContent, '123')
|
|
429
|
+
let state = sprae(el, { items: [0,2,3] })
|
|
430
|
+
is(el.textContent, '023')
|
|
431
|
+
state.items[0] = 1
|
|
432
|
+
state.items = state.items
|
|
433
|
+
is(el.textContent, '123')
|
|
434
|
+
})
|
|
407
435
|
|
|
436
|
+
test('each: :id and others must receive value from context', () => {
|
|
437
|
+
let el = h`<div><x :id="idx" :each="item, idx in items"></x></div>`
|
|
438
|
+
sprae(el, {items:[1,2,3]})
|
|
439
|
+
is(el.innerHTML,`<x id="1"></x><x id="2"></x><x id="3"></x>`)
|
|
408
440
|
})
|
|
409
441
|
|
|
410
442
|
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
|
-
* [
|
|
38
|
-
* [
|
|
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
|