micra.js 2.2.0 → 2.3.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/CHANGELOG.md +88 -0
- package/README.md +1 -0
- package/dist/core/bus.d.ts +6 -4
- package/dist/core/reactive.d.ts +1 -1
- package/dist/dom/each.d.ts +11 -7
- package/dist/dom/scan.d.ts +2 -6
- package/dist/index.d.ts +1 -1
- package/dist/micra.cjs.js +172 -86
- package/dist/micra.cjs.js.map +3 -3
- package/dist/micra.esm.js +172 -86
- package/dist/micra.esm.js.map +3 -3
- package/dist/micra.js +172 -86
- package/dist/micra.js.map +3 -3
- package/dist/micra.min.js +2 -2
- package/dist/types.d.ts +50 -5
- package/llms-full.txt +67 -14
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/src/core/bus.ts +15 -6
- package/src/core/mount.ts +17 -7
- package/src/core/reactive.ts +2 -1
- package/src/dom/directives.ts +5 -2
- package/src/dom/each.ts +190 -59
- package/src/dom/refs.ts +1 -0
- package/src/dom/scan.ts +2 -22
- package/src/index.ts +3 -0
- package/src/types.ts +61 -5
- package/src/utils/expr.ts +34 -21
package/dist/micra.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Micra.js v2.
|
|
1
|
+
/* Micra.js v2.3.0 — https://github.com/micra-js/micra — MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var Micra = (() => {
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -176,27 +176,32 @@ var Micra = (() => {
|
|
|
176
176
|
return false;
|
|
177
177
|
}
|
|
178
178
|
function evalExpr(expr, state) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
179
|
+
let cached = exprCache.get(expr);
|
|
180
|
+
if (!cached) {
|
|
181
|
+
if (SIMPLE_PATH.test(expr)) {
|
|
182
|
+
cached = { kind: "path", parts: expr.split(".") };
|
|
183
|
+
} else {
|
|
184
|
+
try {
|
|
185
|
+
cached = {
|
|
186
|
+
kind: "fn",
|
|
187
|
+
fn: new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
188
|
+
};
|
|
189
|
+
} catch {
|
|
190
|
+
warn(`invalid expression "${expr}"`);
|
|
191
|
+
cached = { kind: "fn", fn: () => void 0 };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exprCache.set(expr, cached);
|
|
195
|
+
}
|
|
196
|
+
if (cached.kind === "path") {
|
|
197
|
+
if (!safeStateHas(state, cached.parts[0])) return void 0;
|
|
198
|
+
return cached.parts.reduce(
|
|
183
199
|
(obj, key) => obj != null ? obj[key] : void 0,
|
|
184
200
|
state
|
|
185
201
|
);
|
|
186
202
|
}
|
|
187
|
-
if (!exprCache.has(expr)) {
|
|
188
|
-
try {
|
|
189
|
-
exprCache.set(
|
|
190
|
-
expr,
|
|
191
|
-
new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
192
|
-
);
|
|
193
|
-
} catch {
|
|
194
|
-
warn(`invalid expression "${expr}"`);
|
|
195
|
-
exprCache.set(expr, () => void 0);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
203
|
try {
|
|
199
|
-
return
|
|
204
|
+
return cached.fn(safeStateWrap(state), SAFE_OUTER);
|
|
200
205
|
} catch (e) {
|
|
201
206
|
if (!warnedRuntime.has(expr)) {
|
|
202
207
|
warnedRuntime.add(expr);
|
|
@@ -222,8 +227,9 @@ var Micra = (() => {
|
|
|
222
227
|
set.delete(handler);
|
|
223
228
|
if (set.size === 0) _bus.delete(event);
|
|
224
229
|
}
|
|
225
|
-
function emit(event,
|
|
230
|
+
function emit(event, ...args) {
|
|
226
231
|
var _a;
|
|
232
|
+
const payload = args[0];
|
|
227
233
|
(_a = _bus.get(event)) == null ? void 0 : _a.forEach((h) => {
|
|
228
234
|
try {
|
|
229
235
|
h(payload);
|
|
@@ -234,11 +240,12 @@ var Micra = (() => {
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
// src/core/reactive.ts
|
|
237
|
-
function createReactiveState(obj, schedule) {
|
|
243
|
+
function createReactiveState(obj, schedule, onKey) {
|
|
238
244
|
return new Proxy(obj, {
|
|
239
245
|
set(target, key, value) {
|
|
240
246
|
;
|
|
241
247
|
target[key] = value;
|
|
248
|
+
onKey == null ? void 0 : onKey(key);
|
|
242
249
|
schedule();
|
|
243
250
|
return true;
|
|
244
251
|
}
|
|
@@ -264,7 +271,8 @@ var Micra = (() => {
|
|
|
264
271
|
}
|
|
265
272
|
function applyHtml(el, expr, state) {
|
|
266
273
|
var _a;
|
|
267
|
-
|
|
274
|
+
const html = String((_a = evalExpr(expr, state)) != null ? _a : "");
|
|
275
|
+
if (el.innerHTML !== html) el.innerHTML = html;
|
|
268
276
|
}
|
|
269
277
|
function applyIf(binding, state) {
|
|
270
278
|
const el = binding.el;
|
|
@@ -281,7 +289,9 @@ var Micra = (() => {
|
|
|
281
289
|
}
|
|
282
290
|
}
|
|
283
291
|
function applyShow(el, expr, state) {
|
|
284
|
-
|
|
292
|
+
const desired = evalExpr(expr, state) ? "" : "none";
|
|
293
|
+
const htmlEl = el;
|
|
294
|
+
if (htmlEl.style.display !== desired) htmlEl.style.display = desired;
|
|
285
295
|
}
|
|
286
296
|
function applyBind(el, pairs, state) {
|
|
287
297
|
for (const [attr, valExpr] of pairs) {
|
|
@@ -526,23 +536,9 @@ var Micra = (() => {
|
|
|
526
536
|
}
|
|
527
537
|
return scan;
|
|
528
538
|
}
|
|
529
|
-
function scanFragment(frag) {
|
|
530
|
-
const scan = emptyScan();
|
|
531
|
-
const walker = document.createTreeWalker(
|
|
532
|
-
frag,
|
|
533
|
-
NodeFilter.SHOW_ELEMENT,
|
|
534
|
-
NESTED_COMPONENT_FILTER
|
|
535
|
-
);
|
|
536
|
-
let node = walker.nextNode();
|
|
537
|
-
while (node) {
|
|
538
|
-
classify(node, scan);
|
|
539
|
-
node = walker.nextNode();
|
|
540
|
-
}
|
|
541
|
-
return scan;
|
|
542
|
-
}
|
|
543
539
|
|
|
544
540
|
// src/dom/each.ts
|
|
545
|
-
function renderList(templates, state, rawState, instance) {
|
|
541
|
+
function renderList(templates, state, rawState, instance, triggerKey) {
|
|
546
542
|
var _a;
|
|
547
543
|
for (const tmplEl of templates) {
|
|
548
544
|
if (tmplEl.tagName !== "TEMPLATE") continue;
|
|
@@ -559,22 +555,40 @@ var Micra = (() => {
|
|
|
559
555
|
}
|
|
560
556
|
const marker = tmpl.__micraMarker;
|
|
561
557
|
const keyMap = tmpl.__micraNodes;
|
|
562
|
-
|
|
563
|
-
if (!parent) continue;
|
|
558
|
+
if (!marker.parentNode) continue;
|
|
564
559
|
if (!Array.isArray(items)) {
|
|
565
560
|
tmpl.__micraList.forEach((n) => n.remove());
|
|
566
561
|
tmpl.__micraList = [];
|
|
567
562
|
keyMap.clear();
|
|
568
563
|
continue;
|
|
569
564
|
}
|
|
565
|
+
const canSkipUnchanged = triggerKey !== null && triggerKey !== "MULTIPLE" && triggerKey === itemsExpr;
|
|
570
566
|
if (keyAttr) {
|
|
571
|
-
renderKeyed(tmpl, items, keyAttr, marker, keyMap,
|
|
567
|
+
renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged);
|
|
572
568
|
} else {
|
|
573
|
-
renderNoKey(tmpl, items, marker,
|
|
569
|
+
renderNoKey(tmpl, items, marker, state, rawState, instance, canSkipUnchanged);
|
|
574
570
|
}
|
|
575
571
|
}
|
|
576
572
|
}
|
|
577
|
-
function
|
|
573
|
+
function createRowNode(tmpl, state, instance) {
|
|
574
|
+
const frag = tmpl.content.cloneNode(true);
|
|
575
|
+
let node;
|
|
576
|
+
if (frag.childNodes.length === 1) {
|
|
577
|
+
node = frag.firstElementChild;
|
|
578
|
+
} else {
|
|
579
|
+
node = document.createElement("micra-each-item");
|
|
580
|
+
node.style.display = "contents";
|
|
581
|
+
node.append(frag);
|
|
582
|
+
}
|
|
583
|
+
const rowScan = scanComponent(node);
|
|
584
|
+
node.__micraScan = rowScan;
|
|
585
|
+
node._itemState = Object.create(state);
|
|
586
|
+
bindDataOn(rowScan.on, instance);
|
|
587
|
+
bindAtEvents(rowScan.atEvents, instance);
|
|
588
|
+
bindModels(rowScan.model, instance);
|
|
589
|
+
return node;
|
|
590
|
+
}
|
|
591
|
+
function renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged) {
|
|
578
592
|
var _a;
|
|
579
593
|
const nextKeys = /* @__PURE__ */ new Set();
|
|
580
594
|
const nextNodes = [];
|
|
@@ -593,26 +607,19 @@ var Micra = (() => {
|
|
|
593
607
|
nextKeys.add(key);
|
|
594
608
|
let node = keyMap.get(key);
|
|
595
609
|
if (!node) {
|
|
596
|
-
|
|
597
|
-
if (frag.childNodes.length === 1) {
|
|
598
|
-
node = frag.firstElementChild;
|
|
599
|
-
} else {
|
|
600
|
-
node = document.createElement("micra-each-item");
|
|
601
|
-
node.style.display = "contents";
|
|
602
|
-
node.append(frag);
|
|
603
|
-
}
|
|
610
|
+
node = createRowNode(tmpl, state, instance);
|
|
604
611
|
node.__micraKey = key;
|
|
605
612
|
keyMap.set(key, node);
|
|
606
|
-
|
|
607
|
-
node
|
|
608
|
-
|
|
609
|
-
bindAtEvents(rowScan2.atEvents, instance);
|
|
610
|
-
bindModels(rowScan2.model, instance);
|
|
613
|
+
} else if (canSkipUnchanged && node.__micraItem === item && node.__micraIndex === index) {
|
|
614
|
+
nextNodes.push(node);
|
|
615
|
+
continue;
|
|
611
616
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
617
|
+
node.__micraItem = item;
|
|
618
|
+
node.__micraIndex = index;
|
|
619
|
+
const itemState = node._itemState;
|
|
620
|
+
itemState.item = item;
|
|
621
|
+
itemState.index = index;
|
|
622
|
+
itemState.$index = index;
|
|
616
623
|
const rowScan = (_a = node.__micraScan) != null ? _a : node.__micraScan = scanComponent(node);
|
|
617
624
|
applyDirectives(rowScan, itemState, rawState, instance);
|
|
618
625
|
nextNodes.push(node);
|
|
@@ -623,40 +630,113 @@ var Micra = (() => {
|
|
|
623
630
|
keyMap.delete(key);
|
|
624
631
|
}
|
|
625
632
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
if (
|
|
629
|
-
|
|
633
|
+
const prevList = tmpl.__micraList;
|
|
634
|
+
if (prevList.length === 0) {
|
|
635
|
+
if (nextNodes.length) {
|
|
636
|
+
const frag = document.createDocumentFragment();
|
|
637
|
+
for (const node of nextNodes) frag.append(node);
|
|
638
|
+
marker.after(frag);
|
|
639
|
+
}
|
|
640
|
+
} else {
|
|
641
|
+
let orderChanged = nextNodes.length !== prevList.length;
|
|
642
|
+
if (!orderChanged) {
|
|
643
|
+
for (let i = 0; i < nextNodes.length; i++) {
|
|
644
|
+
if (nextNodes[i] !== prevList[i]) {
|
|
645
|
+
orderChanged = true;
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (orderChanged) reorderKeyed(nextNodes, prevList, marker);
|
|
630
651
|
}
|
|
631
652
|
tmpl.__micraList = nextNodes;
|
|
632
653
|
}
|
|
633
|
-
function
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
);
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
+
function reorderKeyed(nextNodes, prevList, marker) {
|
|
655
|
+
const prevPos = /* @__PURE__ */ new Map();
|
|
656
|
+
for (let i = 0; i < prevList.length; i++) prevPos.set(prevList[i], i);
|
|
657
|
+
const n = nextNodes.length;
|
|
658
|
+
const tails = [];
|
|
659
|
+
const tailIdx = [];
|
|
660
|
+
const prev = new Array(n).fill(-1);
|
|
661
|
+
for (let i = 0; i < n; i++) {
|
|
662
|
+
const p = prevPos.get(nextNodes[i]);
|
|
663
|
+
if (p === void 0) continue;
|
|
664
|
+
let lo = 0, hi = tails.length;
|
|
665
|
+
while (lo < hi) {
|
|
666
|
+
const m = lo + hi >> 1;
|
|
667
|
+
tails[m] < p ? lo = m + 1 : hi = m;
|
|
668
|
+
}
|
|
669
|
+
if (lo > 0) prev[i] = tailIdx[lo - 1];
|
|
670
|
+
tails[lo] = p;
|
|
671
|
+
tailIdx[lo] = i;
|
|
672
|
+
}
|
|
673
|
+
const stable = /* @__PURE__ */ new Set();
|
|
674
|
+
let idx = tailIdx[tails.length - 1];
|
|
675
|
+
while (idx >= 0) {
|
|
676
|
+
stable.add(idx);
|
|
677
|
+
idx = prev[idx];
|
|
678
|
+
}
|
|
679
|
+
let anchor = marker;
|
|
680
|
+
for (let i = 0; i < n; i++) {
|
|
681
|
+
const node = nextNodes[i];
|
|
682
|
+
if (stable.has(i)) {
|
|
683
|
+
anchor = node;
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
anchor.after(node);
|
|
687
|
+
anchor = node;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function renderNoKey(tmpl, items, marker, state, rawState, instance, canSkipUnchanged) {
|
|
691
|
+
const prevList = tmpl.__micraList;
|
|
692
|
+
const prevLen = prevList.length;
|
|
693
|
+
const nextLen = items.length;
|
|
694
|
+
const reuseLen = nextLen < prevLen ? nextLen : prevLen;
|
|
695
|
+
const nextList = new Array(nextLen);
|
|
696
|
+
for (let i = 0; i < reuseLen; i++) {
|
|
697
|
+
const node = prevList[i];
|
|
698
|
+
const item = items[i];
|
|
699
|
+
if (canSkipUnchanged && node.__micraItem === item && node.__micraIndex === i) {
|
|
700
|
+
nextList[i] = node;
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
node.__micraItem = item;
|
|
704
|
+
node.__micraIndex = i;
|
|
705
|
+
const itemState = node._itemState;
|
|
706
|
+
itemState.item = item;
|
|
707
|
+
itemState.index = i;
|
|
708
|
+
itemState.$index = i;
|
|
709
|
+
applyDirectives(node.__micraScan, itemState, rawState, instance);
|
|
710
|
+
nextList[i] = node;
|
|
711
|
+
}
|
|
712
|
+
for (let i = nextLen; i < prevLen; i++) {
|
|
713
|
+
prevList[i].remove();
|
|
714
|
+
}
|
|
715
|
+
if (nextLen > prevLen) {
|
|
716
|
+
const frag = document.createDocumentFragment();
|
|
717
|
+
for (let i = prevLen; i < nextLen; i++) {
|
|
718
|
+
const node = createRowNode(tmpl, state, instance);
|
|
719
|
+
const item = items[i];
|
|
720
|
+
const itemState = node._itemState;
|
|
721
|
+
itemState.item = item;
|
|
722
|
+
itemState.index = i;
|
|
723
|
+
itemState.$index = i;
|
|
724
|
+
node.__micraEach = true;
|
|
725
|
+
node.__micraItem = item;
|
|
726
|
+
node.__micraIndex = i;
|
|
727
|
+
applyDirectives(node.__micraScan, itemState, rawState, instance);
|
|
728
|
+
nextList[i] = node;
|
|
729
|
+
frag.append(node);
|
|
730
|
+
}
|
|
731
|
+
const anchor = prevLen > 0 ? nextList[prevLen - 1] : marker;
|
|
732
|
+
anchor.after(frag);
|
|
654
733
|
}
|
|
655
|
-
|
|
734
|
+
tmpl.__micraList = nextList;
|
|
656
735
|
}
|
|
657
736
|
|
|
658
737
|
// src/dom/refs.ts
|
|
659
738
|
function collectRefs(els, instance) {
|
|
739
|
+
if (!els.length) return;
|
|
660
740
|
instance.refs = {};
|
|
661
741
|
for (const el of els) {
|
|
662
742
|
const name = el.dataset["ref"];
|
|
@@ -699,8 +779,12 @@ var Micra = (() => {
|
|
|
699
779
|
return unsub;
|
|
700
780
|
};
|
|
701
781
|
let isRendering = false;
|
|
782
|
+
let _triggerKey = null;
|
|
702
783
|
const schedule = createScheduler(() => instance.render());
|
|
703
|
-
instance.state = createReactiveState(rawState, schedule)
|
|
784
|
+
instance.state = createReactiveState(rawState, schedule, (key) => {
|
|
785
|
+
if (_triggerKey === null) _triggerKey = key;
|
|
786
|
+
else if (_triggerKey !== key) _triggerKey = "MULTIPLE";
|
|
787
|
+
});
|
|
704
788
|
const boundMethods = /* @__PURE__ */ new Map();
|
|
705
789
|
const exprState = new Proxy(rawState, {
|
|
706
790
|
get(target, key) {
|
|
@@ -724,6 +808,8 @@ var Micra = (() => {
|
|
|
724
808
|
instance.render = function() {
|
|
725
809
|
var _a2;
|
|
726
810
|
if (instance.__micraDestroyed) return;
|
|
811
|
+
const triggerKey = _triggerKey;
|
|
812
|
+
_triggerKey = null;
|
|
727
813
|
if (isRendering) {
|
|
728
814
|
if (!warnedReentry) {
|
|
729
815
|
warn(
|
|
@@ -738,7 +824,7 @@ var Micra = (() => {
|
|
|
738
824
|
const mRoot2 = root;
|
|
739
825
|
const scan = (_a2 = mRoot2.__micraScan) != null ? _a2 : mRoot2.__micraScan = scanComponent(root);
|
|
740
826
|
applyDirectives(scan, exprState, rawState, instance);
|
|
741
|
-
renderList(scan.each, exprState, rawState, instance);
|
|
827
|
+
renderList(scan.each, exprState, rawState, instance, triggerKey);
|
|
742
828
|
bindDataOn(scan.on, instance);
|
|
743
829
|
bindAtEvents(scan.atEvents, instance);
|
|
744
830
|
bindModels(scan.model, instance);
|