micra.js 2.2.0 → 2.2.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/CHANGELOG.md +13 -0
- package/dist/core/reactive.d.ts +1 -1
- package/dist/dom/each.d.ts +6 -5
- package/dist/micra.cjs.js +110 -38
- package/dist/micra.cjs.js.map +2 -2
- package/dist/micra.esm.js +110 -38
- package/dist/micra.esm.js.map +2 -2
- package/dist/micra.js +110 -38
- package/dist/micra.js.map +2 -2
- package/dist/micra.min.js +2 -2
- package/dist/types.d.ts +4 -1
- package/llms-full.txt +14 -14
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/core/mount.ts +12 -3
- package/src/core/reactive.ts +2 -1
- package/src/dom/directives.ts +5 -2
- package/src/dom/each.ts +99 -20
- package/src/dom/refs.ts +1 -0
- package/src/types.ts +4 -1
- package/src/utils/expr.ts +34 -21
package/dist/micra.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Micra.js v2.2.
|
|
1
|
+
/* Micra.js v2.2.1 — https://github.com/micra-js/micra — MIT */
|
|
2
2
|
|
|
3
3
|
// src/utils/fetch.ts
|
|
4
4
|
function getCSRF() {
|
|
@@ -141,27 +141,32 @@ function safeStateHas(state, key) {
|
|
|
141
141
|
return false;
|
|
142
142
|
}
|
|
143
143
|
function evalExpr(expr, state) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
144
|
+
let cached = exprCache.get(expr);
|
|
145
|
+
if (!cached) {
|
|
146
|
+
if (SIMPLE_PATH.test(expr)) {
|
|
147
|
+
cached = { kind: "path", parts: expr.split(".") };
|
|
148
|
+
} else {
|
|
149
|
+
try {
|
|
150
|
+
cached = {
|
|
151
|
+
kind: "fn",
|
|
152
|
+
fn: new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
153
|
+
};
|
|
154
|
+
} catch {
|
|
155
|
+
warn(`invalid expression "${expr}"`);
|
|
156
|
+
cached = { kind: "fn", fn: () => void 0 };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exprCache.set(expr, cached);
|
|
160
|
+
}
|
|
161
|
+
if (cached.kind === "path") {
|
|
162
|
+
if (!safeStateHas(state, cached.parts[0])) return void 0;
|
|
163
|
+
return cached.parts.reduce(
|
|
148
164
|
(obj, key) => obj != null ? obj[key] : void 0,
|
|
149
165
|
state
|
|
150
166
|
);
|
|
151
167
|
}
|
|
152
|
-
if (!exprCache.has(expr)) {
|
|
153
|
-
try {
|
|
154
|
-
exprCache.set(
|
|
155
|
-
expr,
|
|
156
|
-
new Function("$s", "$safe", `with($safe){with($s){return (${expr})}}`)
|
|
157
|
-
);
|
|
158
|
-
} catch {
|
|
159
|
-
warn(`invalid expression "${expr}"`);
|
|
160
|
-
exprCache.set(expr, () => void 0);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
168
|
try {
|
|
164
|
-
return
|
|
169
|
+
return cached.fn(safeStateWrap(state), SAFE_OUTER);
|
|
165
170
|
} catch (e) {
|
|
166
171
|
if (!warnedRuntime.has(expr)) {
|
|
167
172
|
warnedRuntime.add(expr);
|
|
@@ -199,11 +204,12 @@ function emit(event, payload) {
|
|
|
199
204
|
}
|
|
200
205
|
|
|
201
206
|
// src/core/reactive.ts
|
|
202
|
-
function createReactiveState(obj, schedule) {
|
|
207
|
+
function createReactiveState(obj, schedule, onKey) {
|
|
203
208
|
return new Proxy(obj, {
|
|
204
209
|
set(target, key, value) {
|
|
205
210
|
;
|
|
206
211
|
target[key] = value;
|
|
212
|
+
onKey == null ? void 0 : onKey(key);
|
|
207
213
|
schedule();
|
|
208
214
|
return true;
|
|
209
215
|
}
|
|
@@ -229,7 +235,8 @@ function applyText(el, expr, state) {
|
|
|
229
235
|
}
|
|
230
236
|
function applyHtml(el, expr, state) {
|
|
231
237
|
var _a;
|
|
232
|
-
|
|
238
|
+
const html = String((_a = evalExpr(expr, state)) != null ? _a : "");
|
|
239
|
+
if (el.innerHTML !== html) el.innerHTML = html;
|
|
233
240
|
}
|
|
234
241
|
function applyIf(binding, state) {
|
|
235
242
|
const el = binding.el;
|
|
@@ -246,7 +253,9 @@ function applyIf(binding, state) {
|
|
|
246
253
|
}
|
|
247
254
|
}
|
|
248
255
|
function applyShow(el, expr, state) {
|
|
249
|
-
|
|
256
|
+
const desired = evalExpr(expr, state) ? "" : "none";
|
|
257
|
+
const htmlEl = el;
|
|
258
|
+
if (htmlEl.style.display !== desired) htmlEl.style.display = desired;
|
|
250
259
|
}
|
|
251
260
|
function applyBind(el, pairs, state) {
|
|
252
261
|
for (const [attr, valExpr] of pairs) {
|
|
@@ -507,7 +516,7 @@ function scanFragment(frag) {
|
|
|
507
516
|
}
|
|
508
517
|
|
|
509
518
|
// src/dom/each.ts
|
|
510
|
-
function renderList(templates, state, rawState, instance) {
|
|
519
|
+
function renderList(templates, state, rawState, instance, triggerKey) {
|
|
511
520
|
var _a;
|
|
512
521
|
for (const tmplEl of templates) {
|
|
513
522
|
if (tmplEl.tagName !== "TEMPLATE") continue;
|
|
@@ -524,22 +533,22 @@ function renderList(templates, state, rawState, instance) {
|
|
|
524
533
|
}
|
|
525
534
|
const marker = tmpl.__micraMarker;
|
|
526
535
|
const keyMap = tmpl.__micraNodes;
|
|
527
|
-
|
|
528
|
-
if (!parent) continue;
|
|
536
|
+
if (!marker.parentNode) continue;
|
|
529
537
|
if (!Array.isArray(items)) {
|
|
530
538
|
tmpl.__micraList.forEach((n) => n.remove());
|
|
531
539
|
tmpl.__micraList = [];
|
|
532
540
|
keyMap.clear();
|
|
533
541
|
continue;
|
|
534
542
|
}
|
|
543
|
+
const canSkipUnchanged = triggerKey !== null && triggerKey !== "MULTIPLE" && triggerKey === itemsExpr;
|
|
535
544
|
if (keyAttr) {
|
|
536
|
-
renderKeyed(tmpl, items, keyAttr, marker, keyMap,
|
|
545
|
+
renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged);
|
|
537
546
|
} else {
|
|
538
|
-
renderNoKey(tmpl, items, marker,
|
|
547
|
+
renderNoKey(tmpl, items, marker, state, rawState, instance);
|
|
539
548
|
}
|
|
540
549
|
}
|
|
541
550
|
}
|
|
542
|
-
function renderKeyed(tmpl, items, keyAttr, marker, keyMap,
|
|
551
|
+
function renderKeyed(tmpl, items, keyAttr, marker, keyMap, state, rawState, instance, canSkipUnchanged) {
|
|
543
552
|
var _a;
|
|
544
553
|
const nextKeys = /* @__PURE__ */ new Set();
|
|
545
554
|
const nextNodes = [];
|
|
@@ -573,11 +582,17 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawSta
|
|
|
573
582
|
bindDataOn(rowScan2.on, instance);
|
|
574
583
|
bindAtEvents(rowScan2.atEvents, instance);
|
|
575
584
|
bindModels(rowScan2.model, instance);
|
|
585
|
+
node._itemState = Object.create(state);
|
|
586
|
+
} else if (canSkipUnchanged && node.__micraItem === item && node.__micraIndex === index) {
|
|
587
|
+
nextNodes.push(node);
|
|
588
|
+
continue;
|
|
576
589
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
590
|
+
node.__micraItem = item;
|
|
591
|
+
node.__micraIndex = index;
|
|
592
|
+
const itemState = node._itemState;
|
|
593
|
+
itemState.item = item;
|
|
594
|
+
itemState.index = index;
|
|
595
|
+
itemState.$index = index;
|
|
581
596
|
const rowScan = (_a = node.__micraScan) != null ? _a : node.__micraScan = scanComponent(node);
|
|
582
597
|
applyDirectives(rowScan, itemState, rawState, instance);
|
|
583
598
|
nextNodes.push(node);
|
|
@@ -588,14 +603,64 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawSta
|
|
|
588
603
|
keyMap.delete(key);
|
|
589
604
|
}
|
|
590
605
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
if (
|
|
594
|
-
|
|
606
|
+
const prevList = tmpl.__micraList;
|
|
607
|
+
if (prevList.length === 0) {
|
|
608
|
+
if (nextNodes.length) {
|
|
609
|
+
const frag = document.createDocumentFragment();
|
|
610
|
+
for (const node of nextNodes) frag.append(node);
|
|
611
|
+
marker.after(frag);
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
let orderChanged = nextNodes.length !== prevList.length;
|
|
615
|
+
if (!orderChanged) {
|
|
616
|
+
for (let i = 0; i < nextNodes.length; i++) {
|
|
617
|
+
if (nextNodes[i] !== prevList[i]) {
|
|
618
|
+
orderChanged = true;
|
|
619
|
+
break;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (orderChanged) reorderKeyed(nextNodes, prevList, marker);
|
|
595
624
|
}
|
|
596
625
|
tmpl.__micraList = nextNodes;
|
|
597
626
|
}
|
|
598
|
-
function
|
|
627
|
+
function reorderKeyed(nextNodes, prevList, marker) {
|
|
628
|
+
const prevPos = /* @__PURE__ */ new Map();
|
|
629
|
+
for (let i = 0; i < prevList.length; i++) prevPos.set(prevList[i], i);
|
|
630
|
+
const n = nextNodes.length;
|
|
631
|
+
const tails = [];
|
|
632
|
+
const tailIdx = [];
|
|
633
|
+
const prev = new Array(n).fill(-1);
|
|
634
|
+
for (let i = 0; i < n; i++) {
|
|
635
|
+
const p = prevPos.get(nextNodes[i]);
|
|
636
|
+
if (p === void 0) continue;
|
|
637
|
+
let lo = 0, hi = tails.length;
|
|
638
|
+
while (lo < hi) {
|
|
639
|
+
const m = lo + hi >> 1;
|
|
640
|
+
tails[m] < p ? lo = m + 1 : hi = m;
|
|
641
|
+
}
|
|
642
|
+
if (lo > 0) prev[i] = tailIdx[lo - 1];
|
|
643
|
+
tails[lo] = p;
|
|
644
|
+
tailIdx[lo] = i;
|
|
645
|
+
}
|
|
646
|
+
const stable = /* @__PURE__ */ new Set();
|
|
647
|
+
let idx = tailIdx[tails.length - 1];
|
|
648
|
+
while (idx >= 0) {
|
|
649
|
+
stable.add(idx);
|
|
650
|
+
idx = prev[idx];
|
|
651
|
+
}
|
|
652
|
+
let anchor = marker;
|
|
653
|
+
for (let i = 0; i < n; i++) {
|
|
654
|
+
const node = nextNodes[i];
|
|
655
|
+
if (stable.has(i)) {
|
|
656
|
+
anchor = node;
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
anchor.after(node);
|
|
660
|
+
anchor = node;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function renderNoKey(tmpl, items, marker, state, rawState, instance) {
|
|
599
664
|
tmpl.__micraList.forEach((n) => n.remove());
|
|
600
665
|
tmpl.__micraList = [];
|
|
601
666
|
const frag = document.createDocumentFragment();
|
|
@@ -617,11 +682,12 @@ function renderNoKey(tmpl, items, marker, parent, state, rawState, instance) {
|
|
|
617
682
|
});
|
|
618
683
|
tmpl.__micraList.push(...nodes);
|
|
619
684
|
}
|
|
620
|
-
|
|
685
|
+
marker.after(frag);
|
|
621
686
|
}
|
|
622
687
|
|
|
623
688
|
// src/dom/refs.ts
|
|
624
689
|
function collectRefs(els, instance) {
|
|
690
|
+
if (!els.length) return;
|
|
625
691
|
instance.refs = {};
|
|
626
692
|
for (const el of els) {
|
|
627
693
|
const name = el.dataset["ref"];
|
|
@@ -664,8 +730,12 @@ function mount(selector, definition) {
|
|
|
664
730
|
return unsub;
|
|
665
731
|
};
|
|
666
732
|
let isRendering = false;
|
|
733
|
+
let _triggerKey = null;
|
|
667
734
|
const schedule = createScheduler(() => instance.render());
|
|
668
|
-
instance.state = createReactiveState(rawState, schedule)
|
|
735
|
+
instance.state = createReactiveState(rawState, schedule, (key) => {
|
|
736
|
+
if (_triggerKey === null) _triggerKey = key;
|
|
737
|
+
else if (_triggerKey !== key) _triggerKey = "MULTIPLE";
|
|
738
|
+
});
|
|
669
739
|
const boundMethods = /* @__PURE__ */ new Map();
|
|
670
740
|
const exprState = new Proxy(rawState, {
|
|
671
741
|
get(target, key) {
|
|
@@ -689,6 +759,8 @@ function mount(selector, definition) {
|
|
|
689
759
|
instance.render = function() {
|
|
690
760
|
var _a2;
|
|
691
761
|
if (instance.__micraDestroyed) return;
|
|
762
|
+
const triggerKey = _triggerKey;
|
|
763
|
+
_triggerKey = null;
|
|
692
764
|
if (isRendering) {
|
|
693
765
|
if (!warnedReentry) {
|
|
694
766
|
warn(
|
|
@@ -703,7 +775,7 @@ function mount(selector, definition) {
|
|
|
703
775
|
const mRoot2 = root;
|
|
704
776
|
const scan = (_a2 = mRoot2.__micraScan) != null ? _a2 : mRoot2.__micraScan = scanComponent(root);
|
|
705
777
|
applyDirectives(scan, exprState, rawState, instance);
|
|
706
|
-
renderList(scan.each, exprState, rawState, instance);
|
|
778
|
+
renderList(scan.each, exprState, rawState, instance, triggerKey);
|
|
707
779
|
bindDataOn(scan.on, instance);
|
|
708
780
|
bindAtEvents(scan.atEvents, instance);
|
|
709
781
|
bindModels(scan.model, instance);
|