@lark.js/mvc 0.0.8 → 0.0.9
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/README.md +2 -2
- package/dist/index.cjs +49 -68
- package/dist/index.d.cts +31 -29
- package/dist/index.d.ts +31 -29
- package/dist/index.js +39 -58
- package/package.json +4 -4
- package/src/client.d.ts +2 -2
package/README.md
CHANGED
|
@@ -235,7 +235,7 @@ this.updater.set({ count: newCount });
|
|
|
235
235
|
this.updater.digest();
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
-
Full pipeline: `updater.set(data)` shallow-merges data into the internal data object and collects changed keys. `updater.digest()` calls the compiled template function to generate an HTML string. `
|
|
238
|
+
Full pipeline: `updater.set(data)` shallow-merges data into the internal data object and collects changed keys. `updater.digest()` calls the compiled template function to generate an HTML string. `domGetNode` uses `tmp.innerHTML = wrap + html` to parse it into temporary DOM. `domSetChildNodes` compares against the live DOM to produce a keyed diff. DOM operations are applied in batch. `endUpdate()` notifies child Frames to complete mounting.
|
|
239
239
|
|
|
240
240
|
Supports digest re-entry: calling `updater.digest()` during an active digest does not nest; instead it queues to `digestingQueue` and executes after the current digest completes. `null` serves as a digest boundary sentinel in the queue.
|
|
241
241
|
|
|
@@ -713,7 +713,7 @@ The compiler converts JS object literal parameters (`{a:1}`) to URL query string
|
|
|
713
713
|
|
|
714
714
|
With query strings, parameters are translated into the first argument of the child view's `init`. When containing SPLITTER reference tokens, `translateData` resolves original JS values from the parent view's refData before passing them to the child.
|
|
715
715
|
|
|
716
|
-
###
|
|
716
|
+
### DOM Optimization Hints
|
|
717
717
|
|
|
718
718
|
| Attribute | Purpose |
|
|
719
719
|
| --------- | -------------------------------------------------------------------------- |
|
package/dist/index.cjs
CHANGED
|
@@ -40,16 +40,23 @@ __export(index_exports, {
|
|
|
40
40
|
Updater: () => Updater,
|
|
41
41
|
VIEW_EVENT_METHOD_REGEXP: () => VIEW_EVENT_METHOD_REGEXP,
|
|
42
42
|
View: () => View,
|
|
43
|
+
applyDomOps: () => applyDomOps,
|
|
43
44
|
applyIdUpdates: () => applyIdUpdates,
|
|
44
45
|
applyStyle: () => applyStyle,
|
|
45
|
-
applyVdomOps: () => applyVdomOps,
|
|
46
46
|
assign: () => assign,
|
|
47
47
|
bindStore: () => bindStore,
|
|
48
48
|
computed: () => computed,
|
|
49
49
|
create: () => create,
|
|
50
|
-
|
|
50
|
+
createDomRef: () => createDomRef,
|
|
51
51
|
defineStore: () => defineStore,
|
|
52
52
|
defineView: () => defineView,
|
|
53
|
+
domGetCompareKey: () => domGetCompareKey,
|
|
54
|
+
domGetNode: () => domGetNode,
|
|
55
|
+
domSetAttributes: () => domSetAttributes,
|
|
56
|
+
domSetChildNodes: () => domSetChildNodes,
|
|
57
|
+
domSetNode: () => domSetNode,
|
|
58
|
+
domSpecialDiff: () => domSpecialDiff,
|
|
59
|
+
domUnmountFrames: () => domUnmountFrames,
|
|
53
60
|
encodeHTML: () => encodeHTML,
|
|
54
61
|
encodeQ: () => encodeQ,
|
|
55
62
|
encodeSafe: () => encodeSafe,
|
|
@@ -87,14 +94,7 @@ __export(index_exports, {
|
|
|
87
94
|
translateData: () => translateData,
|
|
88
95
|
unmark: () => unmark,
|
|
89
96
|
use: () => use,
|
|
90
|
-
useUrlState: () => useUrlState
|
|
91
|
-
vdomGetCompareKey: () => vdomGetCompareKey,
|
|
92
|
-
vdomGetNode: () => vdomGetNode,
|
|
93
|
-
vdomSetAttributes: () => vdomSetAttributes,
|
|
94
|
-
vdomSetChildNodes: () => vdomSetChildNodes,
|
|
95
|
-
vdomSetNode: () => vdomSetNode,
|
|
96
|
-
vdomSpecialDiff: () => vdomSpecialDiff,
|
|
97
|
-
vdomUnmountFrames: () => vdomUnmountFrames
|
|
97
|
+
useUrlState: () => useUrlState
|
|
98
98
|
});
|
|
99
99
|
module.exports = __toCommonJS(index_exports);
|
|
100
100
|
|
|
@@ -106,14 +106,6 @@ var RouterEvents = {
|
|
|
106
106
|
CHANGED: "changed",
|
|
107
107
|
PAGE_UNLOAD: "page_unload"
|
|
108
108
|
};
|
|
109
|
-
var LarkInnerKeys = {
|
|
110
|
-
/** Attribute name: ldk (static key for skipping VDOM diff) */
|
|
111
|
-
DIFF_KEY: "ldk",
|
|
112
|
-
/** Attribute name: lak (static attribute key) */
|
|
113
|
-
ATTR_KEY: "lak",
|
|
114
|
-
/** Attribute name: lvk (view key for assign) */
|
|
115
|
-
VIEW_KEY: "lvk"
|
|
116
|
-
};
|
|
117
109
|
var LARK_VIEW = "v-lark";
|
|
118
110
|
var EVENT_METHOD_REGEXP = new RegExp(
|
|
119
111
|
`(?:([\\w-]+)${SPLITTER})?([^(]+)\\(([\\s\\S]*?)?\\)`
|
|
@@ -1473,7 +1465,7 @@ var EventDelegator = {
|
|
|
1473
1465
|
}
|
|
1474
1466
|
};
|
|
1475
1467
|
|
|
1476
|
-
// src/
|
|
1468
|
+
// src/dom.ts
|
|
1477
1469
|
var wrapMeta = {
|
|
1478
1470
|
option: [1, "<select multiple>"],
|
|
1479
1471
|
thead: [1, "<table>"],
|
|
@@ -1493,12 +1485,12 @@ var VDoc = document.implementation.createHTMLDocument("");
|
|
|
1493
1485
|
var VBase = VDoc.createElement("base");
|
|
1494
1486
|
VBase.href = document.location.href;
|
|
1495
1487
|
VDoc.head.appendChild(VBase);
|
|
1496
|
-
var
|
|
1488
|
+
var DomSpecials = {
|
|
1497
1489
|
INPUT: ["value", "checked"],
|
|
1498
1490
|
TEXTAREA: ["value"],
|
|
1499
1491
|
OPTION: ["selected"]
|
|
1500
1492
|
};
|
|
1501
|
-
function
|
|
1493
|
+
function domUnmountFrames(frame, node) {
|
|
1502
1494
|
if (!(node instanceof Element)) return;
|
|
1503
1495
|
const id = node.getAttribute("id");
|
|
1504
1496
|
if (!id) return;
|
|
@@ -1507,7 +1499,7 @@ function vdomUnmountFrames(frame, node) {
|
|
|
1507
1499
|
frame.unmountFrame(id);
|
|
1508
1500
|
}
|
|
1509
1501
|
}
|
|
1510
|
-
function
|
|
1502
|
+
function domGetNode(html, refNode) {
|
|
1511
1503
|
const tmp = VDoc.createElement("div");
|
|
1512
1504
|
const ns = refNode.namespaceURI;
|
|
1513
1505
|
let tag;
|
|
@@ -1528,16 +1520,13 @@ function vdomGetNode(html, refNode) {
|
|
|
1528
1520
|
}
|
|
1529
1521
|
return tmp;
|
|
1530
1522
|
}
|
|
1531
|
-
function
|
|
1523
|
+
function domGetCompareKey(node) {
|
|
1532
1524
|
if (node.nodeType !== 1) return void 0;
|
|
1533
1525
|
const el = node;
|
|
1534
1526
|
if (el.compareKeyCached) {
|
|
1535
1527
|
return el.cachedCompareKey;
|
|
1536
1528
|
}
|
|
1537
1529
|
let key = el.autoId ? "" : el.getAttribute("id") || void 0;
|
|
1538
|
-
if (!key) {
|
|
1539
|
-
key = el.getAttribute(LarkInnerKeys.DIFF_KEY) || void 0;
|
|
1540
|
-
}
|
|
1541
1530
|
if (!key) {
|
|
1542
1531
|
const larkView = el.getAttribute(LARK_VIEW);
|
|
1543
1532
|
if (larkView) {
|
|
@@ -1548,8 +1537,8 @@ function vdomGetCompareKey(node) {
|
|
|
1548
1537
|
el.cachedCompareKey = key || "";
|
|
1549
1538
|
return key;
|
|
1550
1539
|
}
|
|
1551
|
-
function
|
|
1552
|
-
const specials =
|
|
1540
|
+
function domSpecialDiff(oldNode, newNode) {
|
|
1541
|
+
const specials = DomSpecials[oldNode.nodeName];
|
|
1553
1542
|
if (!specials) return 0;
|
|
1554
1543
|
const oldEl = oldNode;
|
|
1555
1544
|
const newEl = newNode;
|
|
@@ -1562,7 +1551,7 @@ function vdomSpecialDiff(oldNode, newNode) {
|
|
|
1562
1551
|
}
|
|
1563
1552
|
return result;
|
|
1564
1553
|
}
|
|
1565
|
-
function
|
|
1554
|
+
function domSetAttributes(oldNode, newNode, ref, keepId) {
|
|
1566
1555
|
const oldEl = oldNode;
|
|
1567
1556
|
Reflect.deleteProperty(oldEl, "compareKeyCached");
|
|
1568
1557
|
const oldAttrs = oldNode.attributes;
|
|
@@ -1594,7 +1583,7 @@ function vdomSetAttributes(oldNode, newNode, ref, keepId) {
|
|
|
1594
1583
|
}
|
|
1595
1584
|
}
|
|
1596
1585
|
}
|
|
1597
|
-
function
|
|
1586
|
+
function domSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
1598
1587
|
let oldNode = oldParent.lastChild;
|
|
1599
1588
|
let newNode = newParent.firstChild;
|
|
1600
1589
|
let extra = 0;
|
|
@@ -1602,7 +1591,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1602
1591
|
const newKeyedNodes = /* @__PURE__ */ new Map();
|
|
1603
1592
|
while (oldNode) {
|
|
1604
1593
|
extra++;
|
|
1605
|
-
const nodeKey =
|
|
1594
|
+
const nodeKey = domGetCompareKey(oldNode);
|
|
1606
1595
|
if (nodeKey) {
|
|
1607
1596
|
let bucket = keyedNodes.get(nodeKey);
|
|
1608
1597
|
if (!bucket) {
|
|
@@ -1614,7 +1603,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1614
1603
|
oldNode = oldNode.previousSibling;
|
|
1615
1604
|
}
|
|
1616
1605
|
while (newNode) {
|
|
1617
|
-
const nodeKey =
|
|
1606
|
+
const nodeKey = domGetCompareKey(newNode);
|
|
1618
1607
|
if (nodeKey) {
|
|
1619
1608
|
newKeyedNodes.set(nodeKey, (newKeyedNodes.get(nodeKey) ?? 0) + 1);
|
|
1620
1609
|
}
|
|
@@ -1626,7 +1615,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1626
1615
|
extra--;
|
|
1627
1616
|
const tempNew = newNode;
|
|
1628
1617
|
newNode = newNode.nextSibling;
|
|
1629
|
-
const nodeKey =
|
|
1618
|
+
const nodeKey = domGetCompareKey(tempNew);
|
|
1630
1619
|
let foundNode = nodeKey ? keyedNodes.get(nodeKey) : void 0;
|
|
1631
1620
|
if (foundNode && (foundNode = foundNode.slice()) && foundNode.length) {
|
|
1632
1621
|
const matched = foundNode.pop();
|
|
@@ -1641,17 +1630,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1641
1630
|
const c = newKeyedNodes.get(nodeKey);
|
|
1642
1631
|
if (c) newKeyedNodes.set(nodeKey, c - 1);
|
|
1643
1632
|
}
|
|
1644
|
-
|
|
1633
|
+
domSetNode(matched, tempNew, oldParent, ref, frame, keys_);
|
|
1645
1634
|
} else if (oldNode) {
|
|
1646
1635
|
const tempOld2 = oldNode;
|
|
1647
|
-
const oldKey =
|
|
1636
|
+
const oldKey = domGetCompareKey(tempOld2);
|
|
1648
1637
|
if (oldKey && keyedNodes.has(oldKey) && newKeyedNodes.get(oldKey)) {
|
|
1649
1638
|
extra++;
|
|
1650
1639
|
ref.hasChanged = 1;
|
|
1651
1640
|
ref.domOps.push([8, oldParent, tempNew, tempOld2]);
|
|
1652
1641
|
} else {
|
|
1653
1642
|
oldNode = oldNode.nextSibling;
|
|
1654
|
-
|
|
1643
|
+
domSetNode(tempOld2, tempNew, oldParent, ref, frame, keys_);
|
|
1655
1644
|
}
|
|
1656
1645
|
} else {
|
|
1657
1646
|
ref.hasChanged = 1;
|
|
@@ -1661,29 +1650,23 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1661
1650
|
let tempOld = oldParent.lastChild;
|
|
1662
1651
|
while (extra-- > 0) {
|
|
1663
1652
|
if (tempOld) {
|
|
1664
|
-
|
|
1653
|
+
domUnmountFrames(frame, tempOld);
|
|
1665
1654
|
ref.domOps.push([2, oldParent, tempOld]);
|
|
1666
1655
|
tempOld = tempOld.previousSibling;
|
|
1667
1656
|
ref.hasChanged = 1;
|
|
1668
1657
|
}
|
|
1669
1658
|
}
|
|
1670
1659
|
}
|
|
1671
|
-
function
|
|
1660
|
+
function domSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
1672
1661
|
const oldAsEl = oldNode instanceof Element ? oldNode : null;
|
|
1673
1662
|
const newAsEl = newNode instanceof Element ? newNode : null;
|
|
1674
|
-
const hasViewKey = !!oldAsEl?.hasAttribute(LarkInnerKeys.VIEW_KEY);
|
|
1675
1663
|
const equalAsNodes = oldAsEl !== null && newAsEl !== null && oldAsEl.isEqualNode && oldAsEl.isEqualNode(newAsEl);
|
|
1676
|
-
if (
|
|
1664
|
+
if (domSpecialDiff(oldNode, newNode) || !equalAsNodes) {
|
|
1677
1665
|
if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
|
|
1678
1666
|
if (oldAsEl !== null && newAsEl !== null) {
|
|
1679
1667
|
const oldEl = oldAsEl;
|
|
1680
1668
|
const newEl = newAsEl;
|
|
1681
|
-
const staticKey = newEl.getAttribute(LarkInnerKeys.DIFF_KEY);
|
|
1682
|
-
if (staticKey && staticKey === oldEl.getAttribute(LarkInnerKeys.DIFF_KEY)) {
|
|
1683
|
-
return;
|
|
1684
|
-
}
|
|
1685
1669
|
const newLarkView = newEl.getAttribute(LARK_VIEW);
|
|
1686
|
-
const updateAttribute = !newEl.getAttribute(LarkInnerKeys.ATTR_KEY) || newEl.getAttribute(LarkInnerKeys.ATTR_KEY) !== oldEl.getAttribute(LarkInnerKeys.ATTR_KEY);
|
|
1687
1670
|
let updateChildren = true;
|
|
1688
1671
|
if (newLarkView) {
|
|
1689
1672
|
const oldFrameId = oldEl.getAttribute("id") || "";
|
|
@@ -1694,11 +1677,9 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1694
1677
|
updateChildren = false;
|
|
1695
1678
|
}
|
|
1696
1679
|
}
|
|
1697
|
-
|
|
1698
|
-
vdomSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1699
|
-
}
|
|
1680
|
+
domSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1700
1681
|
if (updateChildren) {
|
|
1701
|
-
|
|
1682
|
+
domSetChildNodes(oldEl, newEl, ref, frame, keys_);
|
|
1702
1683
|
}
|
|
1703
1684
|
} else if (oldNode.nodeValue !== newNode.nodeValue) {
|
|
1704
1685
|
ref.hasChanged = 1;
|
|
@@ -1706,12 +1687,12 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1706
1687
|
}
|
|
1707
1688
|
} else {
|
|
1708
1689
|
ref.hasChanged = 1;
|
|
1709
|
-
|
|
1690
|
+
domUnmountFrames(frame, oldNode);
|
|
1710
1691
|
ref.domOps.push([4, oldParent, newNode, oldNode]);
|
|
1711
1692
|
}
|
|
1712
1693
|
}
|
|
1713
1694
|
}
|
|
1714
|
-
function
|
|
1695
|
+
function createDomRef() {
|
|
1715
1696
|
return {
|
|
1716
1697
|
idUpdates: [],
|
|
1717
1698
|
views: [],
|
|
@@ -1719,7 +1700,7 @@ function createVdomRef() {
|
|
|
1719
1700
|
hasChanged: 0
|
|
1720
1701
|
};
|
|
1721
1702
|
}
|
|
1722
|
-
function
|
|
1703
|
+
function applyDomOps(ops) {
|
|
1723
1704
|
for (const op of ops) {
|
|
1724
1705
|
switch (op[0]) {
|
|
1725
1706
|
case 1:
|
|
@@ -1858,11 +1839,11 @@ var Updater = class {
|
|
|
1858
1839
|
return this;
|
|
1859
1840
|
}
|
|
1860
1841
|
/**
|
|
1861
|
-
* Detect changes and trigger
|
|
1842
|
+
* Detect changes and trigger DOM re-render.
|
|
1862
1843
|
*
|
|
1863
1844
|
* The core rendering pipeline:
|
|
1864
1845
|
* 1. Set data if provided
|
|
1865
|
-
* 2. If changed, run
|
|
1846
|
+
* 2. If changed, run DOM diff (template → new DOM → diff against old DOM)
|
|
1866
1847
|
* 3. Apply DOM operations
|
|
1867
1848
|
* 4. Apply ID updates
|
|
1868
1849
|
* 5. Call endUpdate on views that need re-rendering
|
|
@@ -1907,11 +1888,11 @@ var Updater = class {
|
|
|
1907
1888
|
updaterRef,
|
|
1908
1889
|
encodeQ
|
|
1909
1890
|
);
|
|
1910
|
-
const newDom =
|
|
1911
|
-
const ref =
|
|
1912
|
-
|
|
1891
|
+
const newDom = domGetNode(html, node);
|
|
1892
|
+
const ref = createDomRef();
|
|
1893
|
+
domSetChildNodes(node, newDom, ref, frame, keys2);
|
|
1913
1894
|
applyIdUpdates(ref.idUpdates);
|
|
1914
|
-
|
|
1895
|
+
applyDomOps(ref.domOps);
|
|
1915
1896
|
for (const v of ref.views) {
|
|
1916
1897
|
if (v.render) {
|
|
1917
1898
|
funcWithTry(v.render, [], v, noop);
|
|
@@ -4356,16 +4337,23 @@ var defineStore = create;
|
|
|
4356
4337
|
Updater,
|
|
4357
4338
|
VIEW_EVENT_METHOD_REGEXP,
|
|
4358
4339
|
View,
|
|
4340
|
+
applyDomOps,
|
|
4359
4341
|
applyIdUpdates,
|
|
4360
4342
|
applyStyle,
|
|
4361
|
-
applyVdomOps,
|
|
4362
4343
|
assign,
|
|
4363
4344
|
bindStore,
|
|
4364
4345
|
computed,
|
|
4365
4346
|
create,
|
|
4366
|
-
|
|
4347
|
+
createDomRef,
|
|
4367
4348
|
defineStore,
|
|
4368
4349
|
defineView,
|
|
4350
|
+
domGetCompareKey,
|
|
4351
|
+
domGetNode,
|
|
4352
|
+
domSetAttributes,
|
|
4353
|
+
domSetChildNodes,
|
|
4354
|
+
domSetNode,
|
|
4355
|
+
domSpecialDiff,
|
|
4356
|
+
domUnmountFrames,
|
|
4369
4357
|
encodeHTML,
|
|
4370
4358
|
encodeQ,
|
|
4371
4359
|
encodeSafe,
|
|
@@ -4403,12 +4391,5 @@ var defineStore = create;
|
|
|
4403
4391
|
translateData,
|
|
4404
4392
|
unmark,
|
|
4405
4393
|
use,
|
|
4406
|
-
useUrlState
|
|
4407
|
-
vdomGetCompareKey,
|
|
4408
|
-
vdomGetNode,
|
|
4409
|
-
vdomSetAttributes,
|
|
4410
|
-
vdomSetChildNodes,
|
|
4411
|
-
vdomSetNode,
|
|
4412
|
-
vdomSpecialDiff,
|
|
4413
|
-
vdomUnmountFrames
|
|
4394
|
+
useUrlState
|
|
4414
4395
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -461,7 +461,7 @@ declare class Cache<T = unknown> implements CacheInterface<T> {
|
|
|
461
461
|
* (recommended for complex cases)
|
|
462
462
|
* - Service: API request management with caching, queuing, and deduplication
|
|
463
463
|
* - Frame: view frame managing view mount/unmount lifecycle
|
|
464
|
-
* - Updater: view data binding and
|
|
464
|
+
* - Updater: view data binding and DOM diff (in-memory real DOM diff) renderer
|
|
465
465
|
*
|
|
466
466
|
* Designed for single-page application (SPA) development.
|
|
467
467
|
*/
|
|
@@ -643,23 +643,23 @@ interface RouteChangeEvent extends ChangeEvent {
|
|
|
643
643
|
* Carries route diff information. Triggered after route change is confirmed and URL is updated.
|
|
644
644
|
*/
|
|
645
645
|
type RouteChangedEvent = LocationDiff & ChangeEvent;
|
|
646
|
-
interface
|
|
646
|
+
interface DomRef {
|
|
647
647
|
/** ID update list: [element, newId][] */
|
|
648
648
|
idUpdates: [Element, string][];
|
|
649
649
|
/** Views that need post-processing */
|
|
650
650
|
views: ViewInterface[];
|
|
651
651
|
/** DOM operation list: [opCode, parent, newChild?, oldChild?][] */
|
|
652
|
-
domOps:
|
|
652
|
+
domOps: DomOp[];
|
|
653
653
|
/** Whether anything changed */
|
|
654
654
|
hasChanged: number;
|
|
655
655
|
}
|
|
656
656
|
/**
|
|
657
|
-
* Encoded
|
|
657
|
+
* Encoded DOM mutation. The op code matches `Node.appendChild` family at the
|
|
658
658
|
* DOM level — parents are always Elements (you can't appendChild onto text)
|
|
659
659
|
* but the moving / replaced child can be any ChildNode (Element / Text /
|
|
660
660
|
* Comment), so the child slots are typed as ChildNode.
|
|
661
661
|
*/
|
|
662
|
-
type
|
|
662
|
+
type DomOp = [1, Element, ChildNode] | [2, Element, ChildNode] | [4, Element, ChildNode, ChildNode] | [8, Element, ChildNode, ChildNode];
|
|
663
663
|
interface FrameInvokeEntry {
|
|
664
664
|
/** Method name */
|
|
665
665
|
name: string;
|
|
@@ -841,7 +841,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
841
841
|
*/
|
|
842
842
|
owner: FrameInterface | number;
|
|
843
843
|
/**
|
|
844
|
-
* Updater instance managing view data binding and
|
|
844
|
+
* Updater instance managing view data binding and DOM rendering.
|
|
845
845
|
*/
|
|
846
846
|
updater: UpdaterInterface;
|
|
847
847
|
/**
|
|
@@ -892,7 +892,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
892
892
|
endUpdatePendingFlag?: number;
|
|
893
893
|
/**
|
|
894
894
|
* Notify view that HTML update is about to begin for a specific region.
|
|
895
|
-
* Framework unmounts child Frames in that region to prevent
|
|
895
|
+
* Framework unmounts child Frames in that region to prevent DOM diff from operating on unmounted nodes.
|
|
896
896
|
* @param id Region node ID to update, defaults to current view
|
|
897
897
|
*/
|
|
898
898
|
beginUpdate: (id?: string) => void;
|
|
@@ -952,7 +952,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
952
952
|
leaveTip: (message: string, condition: () => boolean) => void;
|
|
953
953
|
/**
|
|
954
954
|
* Assign method for incremental DOM updates.
|
|
955
|
-
* Framework uses
|
|
955
|
+
* Framework uses DOM diff (in-memory real DOM diff) to update only changed portions,
|
|
956
956
|
* automatically handling child view mounting and unmounting.
|
|
957
957
|
* Returns true if DOM changed, undefined if no change.
|
|
958
958
|
* @param options Incremental update config, used internally by framework
|
|
@@ -1083,7 +1083,7 @@ interface FrameInterface extends EventEmitterInterface<FrameInterface> {
|
|
|
1083
1083
|
* Minimal Updater interface needed by View.
|
|
1084
1084
|
* View updater responsible for view data binding and data/page updates.
|
|
1085
1085
|
* Each View instance has an Updater, triggering data/page updates via set/digest.
|
|
1086
|
-
* Internally executes complete pipeline: template rendering →
|
|
1086
|
+
* Internally executes complete pipeline: template rendering → DOM diff (in-memory real DOM diff) → DOM operations.
|
|
1087
1087
|
*/
|
|
1088
1088
|
interface UpdaterInterface {
|
|
1089
1089
|
/**
|
|
@@ -1103,7 +1103,7 @@ interface UpdaterInterface {
|
|
|
1103
1103
|
/**
|
|
1104
1104
|
* Trigger page re-render.
|
|
1105
1105
|
* After set, must explicitly call `digest()` to commit changes to page.
|
|
1106
|
-
* Internally executes complete pipeline: template rendering →
|
|
1106
|
+
* Internally executes complete pipeline: template rendering → DOM diff (in-memory real DOM diff) → DOM operations.
|
|
1107
1107
|
* @param data Optional data object, if provided calls `set()` first to set data
|
|
1108
1108
|
* @param excludes Set of keys to exclude from change tracking
|
|
1109
1109
|
* @param callback Callback executed after render completes
|
|
@@ -1714,6 +1714,8 @@ interface FrameworkConfig {
|
|
|
1714
1714
|
* Also accessible via `window.crossConfigs` for build-time injection.
|
|
1715
1715
|
*/
|
|
1716
1716
|
crossConfigs?: CrossSiteConfig[];
|
|
1717
|
+
/** Default false. */
|
|
1718
|
+
virtualDOM?: boolean;
|
|
1717
1719
|
/** Dynamic config access, custom config items */
|
|
1718
1720
|
[key: string]: unknown;
|
|
1719
1721
|
}
|
|
@@ -1740,8 +1742,8 @@ interface CrossSiteConfig {
|
|
|
1740
1742
|
/** Optional business code for multi-tenant scenarios */
|
|
1741
1743
|
bizCode?: string;
|
|
1742
1744
|
}
|
|
1743
|
-
/** Element with
|
|
1744
|
-
interface
|
|
1745
|
+
/** Element with DOM diff cached compare key */
|
|
1746
|
+
interface DomElement extends Element {
|
|
1745
1747
|
/** Whether compare key is cached */
|
|
1746
1748
|
compareKeyCached?: number | undefined;
|
|
1747
1749
|
/** Cached compare key */
|
|
@@ -1993,45 +1995,45 @@ declare const CrossSite: typeof View;
|
|
|
1993
1995
|
/**
|
|
1994
1996
|
* Unmount frames within a DOM node.
|
|
1995
1997
|
*/
|
|
1996
|
-
declare function
|
|
1998
|
+
declare function domUnmountFrames(frame: FrameInterface, node: ChildNode): void;
|
|
1997
1999
|
/**
|
|
1998
2000
|
* Parse HTML string into a DOM element.
|
|
1999
2001
|
* Handles special elements (table, SVG, MathML) with wrapper elements.
|
|
2000
2002
|
*/
|
|
2001
|
-
declare function
|
|
2003
|
+
declare function domGetNode(html: string, refNode: Element): Element;
|
|
2002
2004
|
/**
|
|
2003
2005
|
* Get compare key for a DOM node (for keyed diff).
|
|
2004
|
-
* Uses id
|
|
2006
|
+
* Uses id or v-lark path.
|
|
2005
2007
|
*/
|
|
2006
|
-
declare function
|
|
2008
|
+
declare function domGetCompareKey(node: ChildNode): string | undefined;
|
|
2007
2009
|
/**
|
|
2008
2010
|
* Special diff for form elements (value, checked, selected).
|
|
2009
2011
|
* Form elements carry state on the DOM node (e.g. `input.value`) that isn't
|
|
2010
2012
|
* reflected in attributes, so we have to sync those properties separately.
|
|
2011
2013
|
*/
|
|
2012
|
-
declare function
|
|
2014
|
+
declare function domSpecialDiff(oldNode: ChildNode, newNode: ChildNode): number;
|
|
2013
2015
|
/**
|
|
2014
2016
|
* Set attributes from new element onto old element, tracking changes in ref.
|
|
2015
2017
|
*/
|
|
2016
|
-
declare function
|
|
2018
|
+
declare function domSetAttributes(oldNode: Element, newNode: Element, ref: DomRef, keepId?: boolean): void;
|
|
2017
2019
|
/**
|
|
2018
2020
|
* Set child nodes from new parent onto old parent using keyed diff algorithm.
|
|
2019
2021
|
*/
|
|
2020
|
-
declare function
|
|
2022
|
+
declare function domSetChildNodes(oldParent: Element, newParent: Element, ref: DomRef, frame: FrameInterface, keys_?: ReadonlySet<string>): void;
|
|
2021
2023
|
/**
|
|
2022
2024
|
* Diff two DOM nodes and apply changes.
|
|
2023
2025
|
*/
|
|
2024
|
-
declare function
|
|
2026
|
+
declare function domSetNode(oldNode: ChildNode, newNode: ChildNode, oldParent: Element, ref: DomRef, frame: FrameInterface, keys_?: ReadonlySet<string>): void;
|
|
2025
2027
|
/**
|
|
2026
|
-
* Create an empty
|
|
2028
|
+
* Create an empty DomRef for tracking diff operations.
|
|
2027
2029
|
*/
|
|
2028
|
-
declare function
|
|
2030
|
+
declare function createDomRef(): DomRef;
|
|
2029
2031
|
/**
|
|
2030
|
-
* Apply
|
|
2032
|
+
* Apply DOM diff operations to the DOM.
|
|
2031
2033
|
*/
|
|
2032
|
-
declare function
|
|
2034
|
+
declare function applyDomOps(ops: DomOp[]): void;
|
|
2033
2035
|
/**
|
|
2034
|
-
* Apply ID updates from
|
|
2036
|
+
* Apply ID updates from DOM diff.
|
|
2035
2037
|
*/
|
|
2036
2038
|
declare function applyIdUpdates(updates: [Element, string][]): void;
|
|
2037
2039
|
/** Encode value for safe HTML output */
|
|
@@ -2045,7 +2047,7 @@ declare function encodeQ(v: unknown): string;
|
|
|
2045
2047
|
|
|
2046
2048
|
/**
|
|
2047
2049
|
* Updater class for view data binding.
|
|
2048
|
-
* Manages view-local data with change detection and
|
|
2050
|
+
* Manages view-local data with change detection and DOM diff triggering.
|
|
2049
2051
|
*
|
|
2050
2052
|
*/
|
|
2051
2053
|
declare class Updater implements UpdaterInterface {
|
|
@@ -2081,11 +2083,11 @@ declare class Updater implements UpdaterInterface {
|
|
|
2081
2083
|
*/
|
|
2082
2084
|
set(data: Record<string, unknown>, excludes?: ReadonlySet<string>): this;
|
|
2083
2085
|
/**
|
|
2084
|
-
* Detect changes and trigger
|
|
2086
|
+
* Detect changes and trigger DOM re-render.
|
|
2085
2087
|
*
|
|
2086
2088
|
* The core rendering pipeline:
|
|
2087
2089
|
* 1. Set data if provided
|
|
2088
|
-
* 2. If changed, run
|
|
2090
|
+
* 2. If changed, run DOM diff (template → new DOM → diff against old DOM)
|
|
2089
2091
|
* 3. Apply DOM operations
|
|
2090
2092
|
* 4. Apply ID updates
|
|
2091
2093
|
* 5. Call endUpdate on views that need re-rendering
|
|
@@ -2513,4 +2515,4 @@ declare function serializeFrameTree(): SerializedFrameTree;
|
|
|
2513
2515
|
*/
|
|
2514
2516
|
declare function installFrameVisualizerBridge(): void;
|
|
2515
2517
|
|
|
2516
|
-
export { type AnyFunc, CALL_BREAK_TIME, Cache, type CacheEntry, type CacheInterface, type CacheOptions, type ChangeEvent, type CompileOptions, CrossSite, type CrossSiteConfig, EVENT_METHOD_REGEXP, EventDelegator, EventEmitter, type EventEmitterInterface, type EventListenerEntry, Frame, type FrameBoundElement, type FrameInterface, type FrameInvokeEntry, type FrameStaticEvent, FrameVisualBridge, Framework, type FrameworkConfig, type FrameworkInterface, LARK_VIEW, type Location, type LocationDiff, type MixinEventHandler, type ParamDiff, type ParsedUri, Payload, type PayloadEntry, type PayloadInterface, type PendingCacheEntry, RouterEvents as ROUTER_EVENTS, type RouteChangeEvent, type RouteChangedEvent, type RouteViewConfig, Router, type RouterInterface, SPLITTER, type SerializedFrameNode, type SerializedFrameTree, type SerializedViewInfo, Service, type ServiceCacheInfo, type ServiceEntry, type ServiceEvent, type ServiceInterface, type ServiceMetaEntry, type ServiceOptions, State, type StateInterface, type StoreApi, TAG_NAME_REGEXP, Updater, type UpdaterInterface,
|
|
2518
|
+
export { type AnyFunc, CALL_BREAK_TIME, Cache, type CacheEntry, type CacheInterface, type CacheOptions, type ChangeEvent, type CompileOptions, CrossSite, type CrossSiteConfig, type DomElement, type DomOp, type DomRef, EVENT_METHOD_REGEXP, EventDelegator, EventEmitter, type EventEmitterInterface, type EventListenerEntry, Frame, type FrameBoundElement, type FrameInterface, type FrameInvokeEntry, type FrameStaticEvent, FrameVisualBridge, Framework, type FrameworkConfig, type FrameworkInterface, LARK_VIEW, type Location, type LocationDiff, type MixinEventHandler, type ParamDiff, type ParsedUri, Payload, type PayloadEntry, type PayloadInterface, type PendingCacheEntry, RouterEvents as ROUTER_EVENTS, type RouteChangeEvent, type RouteChangedEvent, type RouteViewConfig, Router, type RouterInterface, SPLITTER, type SerializedFrameNode, type SerializedFrameTree, type SerializedViewInfo, Service, type ServiceCacheInfo, type ServiceEntry, type ServiceEvent, type ServiceInterface, type ServiceMetaEntry, type ServiceOptions, State, type StateInterface, type StoreApi, TAG_NAME_REGEXP, Updater, type UpdaterInterface, VIEW_EVENT_METHOD_REGEXP, View, type ViewEvent, type ViewEventSelectorEntry, type ViewGlobalEventEntry, type ViewInterface, type ViewLocationObserved, type ViewObserveLocation, type ViewResourceEntry, type ViewTemplate, type VoidFunc, applyDomOps, applyIdUpdates, applyStyle, assign, bindStore, computed, create, createDomRef, defineStore, defineView, domGetCompareKey, domGetNode, domSetAttributes, domSetChildNodes, domSetNode, domSpecialDiff, domUnmountFrames, encodeHTML, encodeQ, encodeSafe, encodeURIExtra, ensureElementId, config as frameworkConfig, funcWithTry, generateId, getAttribute, getById, getRouteMode, hasOwnProperty, installFrameVisualizerBridge, invalidateViewClass, isPlainObject, isPrimitive, isPrimitiveOrFunc, keys, mark, markBooted, markRouterBooted, nextCounter, nodeInside, noop, now, parseUri, registerViewClass, resetProjectsMap, safeguard, serializeFrameTree, setData, syncCounter, toMap, toUri, translateData, unmark, use, useUrlState };
|
package/dist/index.d.ts
CHANGED
|
@@ -461,7 +461,7 @@ declare class Cache<T = unknown> implements CacheInterface<T> {
|
|
|
461
461
|
* (recommended for complex cases)
|
|
462
462
|
* - Service: API request management with caching, queuing, and deduplication
|
|
463
463
|
* - Frame: view frame managing view mount/unmount lifecycle
|
|
464
|
-
* - Updater: view data binding and
|
|
464
|
+
* - Updater: view data binding and DOM diff (in-memory real DOM diff) renderer
|
|
465
465
|
*
|
|
466
466
|
* Designed for single-page application (SPA) development.
|
|
467
467
|
*/
|
|
@@ -643,23 +643,23 @@ interface RouteChangeEvent extends ChangeEvent {
|
|
|
643
643
|
* Carries route diff information. Triggered after route change is confirmed and URL is updated.
|
|
644
644
|
*/
|
|
645
645
|
type RouteChangedEvent = LocationDiff & ChangeEvent;
|
|
646
|
-
interface
|
|
646
|
+
interface DomRef {
|
|
647
647
|
/** ID update list: [element, newId][] */
|
|
648
648
|
idUpdates: [Element, string][];
|
|
649
649
|
/** Views that need post-processing */
|
|
650
650
|
views: ViewInterface[];
|
|
651
651
|
/** DOM operation list: [opCode, parent, newChild?, oldChild?][] */
|
|
652
|
-
domOps:
|
|
652
|
+
domOps: DomOp[];
|
|
653
653
|
/** Whether anything changed */
|
|
654
654
|
hasChanged: number;
|
|
655
655
|
}
|
|
656
656
|
/**
|
|
657
|
-
* Encoded
|
|
657
|
+
* Encoded DOM mutation. The op code matches `Node.appendChild` family at the
|
|
658
658
|
* DOM level — parents are always Elements (you can't appendChild onto text)
|
|
659
659
|
* but the moving / replaced child can be any ChildNode (Element / Text /
|
|
660
660
|
* Comment), so the child slots are typed as ChildNode.
|
|
661
661
|
*/
|
|
662
|
-
type
|
|
662
|
+
type DomOp = [1, Element, ChildNode] | [2, Element, ChildNode] | [4, Element, ChildNode, ChildNode] | [8, Element, ChildNode, ChildNode];
|
|
663
663
|
interface FrameInvokeEntry {
|
|
664
664
|
/** Method name */
|
|
665
665
|
name: string;
|
|
@@ -841,7 +841,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
841
841
|
*/
|
|
842
842
|
owner: FrameInterface | number;
|
|
843
843
|
/**
|
|
844
|
-
* Updater instance managing view data binding and
|
|
844
|
+
* Updater instance managing view data binding and DOM rendering.
|
|
845
845
|
*/
|
|
846
846
|
updater: UpdaterInterface;
|
|
847
847
|
/**
|
|
@@ -892,7 +892,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
892
892
|
endUpdatePendingFlag?: number;
|
|
893
893
|
/**
|
|
894
894
|
* Notify view that HTML update is about to begin for a specific region.
|
|
895
|
-
* Framework unmounts child Frames in that region to prevent
|
|
895
|
+
* Framework unmounts child Frames in that region to prevent DOM diff from operating on unmounted nodes.
|
|
896
896
|
* @param id Region node ID to update, defaults to current view
|
|
897
897
|
*/
|
|
898
898
|
beginUpdate: (id?: string) => void;
|
|
@@ -952,7 +952,7 @@ interface ViewInterface extends EventEmitterInterface<ViewInterface> {
|
|
|
952
952
|
leaveTip: (message: string, condition: () => boolean) => void;
|
|
953
953
|
/**
|
|
954
954
|
* Assign method for incremental DOM updates.
|
|
955
|
-
* Framework uses
|
|
955
|
+
* Framework uses DOM diff (in-memory real DOM diff) to update only changed portions,
|
|
956
956
|
* automatically handling child view mounting and unmounting.
|
|
957
957
|
* Returns true if DOM changed, undefined if no change.
|
|
958
958
|
* @param options Incremental update config, used internally by framework
|
|
@@ -1083,7 +1083,7 @@ interface FrameInterface extends EventEmitterInterface<FrameInterface> {
|
|
|
1083
1083
|
* Minimal Updater interface needed by View.
|
|
1084
1084
|
* View updater responsible for view data binding and data/page updates.
|
|
1085
1085
|
* Each View instance has an Updater, triggering data/page updates via set/digest.
|
|
1086
|
-
* Internally executes complete pipeline: template rendering →
|
|
1086
|
+
* Internally executes complete pipeline: template rendering → DOM diff (in-memory real DOM diff) → DOM operations.
|
|
1087
1087
|
*/
|
|
1088
1088
|
interface UpdaterInterface {
|
|
1089
1089
|
/**
|
|
@@ -1103,7 +1103,7 @@ interface UpdaterInterface {
|
|
|
1103
1103
|
/**
|
|
1104
1104
|
* Trigger page re-render.
|
|
1105
1105
|
* After set, must explicitly call `digest()` to commit changes to page.
|
|
1106
|
-
* Internally executes complete pipeline: template rendering →
|
|
1106
|
+
* Internally executes complete pipeline: template rendering → DOM diff (in-memory real DOM diff) → DOM operations.
|
|
1107
1107
|
* @param data Optional data object, if provided calls `set()` first to set data
|
|
1108
1108
|
* @param excludes Set of keys to exclude from change tracking
|
|
1109
1109
|
* @param callback Callback executed after render completes
|
|
@@ -1714,6 +1714,8 @@ interface FrameworkConfig {
|
|
|
1714
1714
|
* Also accessible via `window.crossConfigs` for build-time injection.
|
|
1715
1715
|
*/
|
|
1716
1716
|
crossConfigs?: CrossSiteConfig[];
|
|
1717
|
+
/** Default false. */
|
|
1718
|
+
virtualDOM?: boolean;
|
|
1717
1719
|
/** Dynamic config access, custom config items */
|
|
1718
1720
|
[key: string]: unknown;
|
|
1719
1721
|
}
|
|
@@ -1740,8 +1742,8 @@ interface CrossSiteConfig {
|
|
|
1740
1742
|
/** Optional business code for multi-tenant scenarios */
|
|
1741
1743
|
bizCode?: string;
|
|
1742
1744
|
}
|
|
1743
|
-
/** Element with
|
|
1744
|
-
interface
|
|
1745
|
+
/** Element with DOM diff cached compare key */
|
|
1746
|
+
interface DomElement extends Element {
|
|
1745
1747
|
/** Whether compare key is cached */
|
|
1746
1748
|
compareKeyCached?: number | undefined;
|
|
1747
1749
|
/** Cached compare key */
|
|
@@ -1993,45 +1995,45 @@ declare const CrossSite: typeof View;
|
|
|
1993
1995
|
/**
|
|
1994
1996
|
* Unmount frames within a DOM node.
|
|
1995
1997
|
*/
|
|
1996
|
-
declare function
|
|
1998
|
+
declare function domUnmountFrames(frame: FrameInterface, node: ChildNode): void;
|
|
1997
1999
|
/**
|
|
1998
2000
|
* Parse HTML string into a DOM element.
|
|
1999
2001
|
* Handles special elements (table, SVG, MathML) with wrapper elements.
|
|
2000
2002
|
*/
|
|
2001
|
-
declare function
|
|
2003
|
+
declare function domGetNode(html: string, refNode: Element): Element;
|
|
2002
2004
|
/**
|
|
2003
2005
|
* Get compare key for a DOM node (for keyed diff).
|
|
2004
|
-
* Uses id
|
|
2006
|
+
* Uses id or v-lark path.
|
|
2005
2007
|
*/
|
|
2006
|
-
declare function
|
|
2008
|
+
declare function domGetCompareKey(node: ChildNode): string | undefined;
|
|
2007
2009
|
/**
|
|
2008
2010
|
* Special diff for form elements (value, checked, selected).
|
|
2009
2011
|
* Form elements carry state on the DOM node (e.g. `input.value`) that isn't
|
|
2010
2012
|
* reflected in attributes, so we have to sync those properties separately.
|
|
2011
2013
|
*/
|
|
2012
|
-
declare function
|
|
2014
|
+
declare function domSpecialDiff(oldNode: ChildNode, newNode: ChildNode): number;
|
|
2013
2015
|
/**
|
|
2014
2016
|
* Set attributes from new element onto old element, tracking changes in ref.
|
|
2015
2017
|
*/
|
|
2016
|
-
declare function
|
|
2018
|
+
declare function domSetAttributes(oldNode: Element, newNode: Element, ref: DomRef, keepId?: boolean): void;
|
|
2017
2019
|
/**
|
|
2018
2020
|
* Set child nodes from new parent onto old parent using keyed diff algorithm.
|
|
2019
2021
|
*/
|
|
2020
|
-
declare function
|
|
2022
|
+
declare function domSetChildNodes(oldParent: Element, newParent: Element, ref: DomRef, frame: FrameInterface, keys_?: ReadonlySet<string>): void;
|
|
2021
2023
|
/**
|
|
2022
2024
|
* Diff two DOM nodes and apply changes.
|
|
2023
2025
|
*/
|
|
2024
|
-
declare function
|
|
2026
|
+
declare function domSetNode(oldNode: ChildNode, newNode: ChildNode, oldParent: Element, ref: DomRef, frame: FrameInterface, keys_?: ReadonlySet<string>): void;
|
|
2025
2027
|
/**
|
|
2026
|
-
* Create an empty
|
|
2028
|
+
* Create an empty DomRef for tracking diff operations.
|
|
2027
2029
|
*/
|
|
2028
|
-
declare function
|
|
2030
|
+
declare function createDomRef(): DomRef;
|
|
2029
2031
|
/**
|
|
2030
|
-
* Apply
|
|
2032
|
+
* Apply DOM diff operations to the DOM.
|
|
2031
2033
|
*/
|
|
2032
|
-
declare function
|
|
2034
|
+
declare function applyDomOps(ops: DomOp[]): void;
|
|
2033
2035
|
/**
|
|
2034
|
-
* Apply ID updates from
|
|
2036
|
+
* Apply ID updates from DOM diff.
|
|
2035
2037
|
*/
|
|
2036
2038
|
declare function applyIdUpdates(updates: [Element, string][]): void;
|
|
2037
2039
|
/** Encode value for safe HTML output */
|
|
@@ -2045,7 +2047,7 @@ declare function encodeQ(v: unknown): string;
|
|
|
2045
2047
|
|
|
2046
2048
|
/**
|
|
2047
2049
|
* Updater class for view data binding.
|
|
2048
|
-
* Manages view-local data with change detection and
|
|
2050
|
+
* Manages view-local data with change detection and DOM diff triggering.
|
|
2049
2051
|
*
|
|
2050
2052
|
*/
|
|
2051
2053
|
declare class Updater implements UpdaterInterface {
|
|
@@ -2081,11 +2083,11 @@ declare class Updater implements UpdaterInterface {
|
|
|
2081
2083
|
*/
|
|
2082
2084
|
set(data: Record<string, unknown>, excludes?: ReadonlySet<string>): this;
|
|
2083
2085
|
/**
|
|
2084
|
-
* Detect changes and trigger
|
|
2086
|
+
* Detect changes and trigger DOM re-render.
|
|
2085
2087
|
*
|
|
2086
2088
|
* The core rendering pipeline:
|
|
2087
2089
|
* 1. Set data if provided
|
|
2088
|
-
* 2. If changed, run
|
|
2090
|
+
* 2. If changed, run DOM diff (template → new DOM → diff against old DOM)
|
|
2089
2091
|
* 3. Apply DOM operations
|
|
2090
2092
|
* 4. Apply ID updates
|
|
2091
2093
|
* 5. Call endUpdate on views that need re-rendering
|
|
@@ -2513,4 +2515,4 @@ declare function serializeFrameTree(): SerializedFrameTree;
|
|
|
2513
2515
|
*/
|
|
2514
2516
|
declare function installFrameVisualizerBridge(): void;
|
|
2515
2517
|
|
|
2516
|
-
export { type AnyFunc, CALL_BREAK_TIME, Cache, type CacheEntry, type CacheInterface, type CacheOptions, type ChangeEvent, type CompileOptions, CrossSite, type CrossSiteConfig, EVENT_METHOD_REGEXP, EventDelegator, EventEmitter, type EventEmitterInterface, type EventListenerEntry, Frame, type FrameBoundElement, type FrameInterface, type FrameInvokeEntry, type FrameStaticEvent, FrameVisualBridge, Framework, type FrameworkConfig, type FrameworkInterface, LARK_VIEW, type Location, type LocationDiff, type MixinEventHandler, type ParamDiff, type ParsedUri, Payload, type PayloadEntry, type PayloadInterface, type PendingCacheEntry, RouterEvents as ROUTER_EVENTS, type RouteChangeEvent, type RouteChangedEvent, type RouteViewConfig, Router, type RouterInterface, SPLITTER, type SerializedFrameNode, type SerializedFrameTree, type SerializedViewInfo, Service, type ServiceCacheInfo, type ServiceEntry, type ServiceEvent, type ServiceInterface, type ServiceMetaEntry, type ServiceOptions, State, type StateInterface, type StoreApi, TAG_NAME_REGEXP, Updater, type UpdaterInterface,
|
|
2518
|
+
export { type AnyFunc, CALL_BREAK_TIME, Cache, type CacheEntry, type CacheInterface, type CacheOptions, type ChangeEvent, type CompileOptions, CrossSite, type CrossSiteConfig, type DomElement, type DomOp, type DomRef, EVENT_METHOD_REGEXP, EventDelegator, EventEmitter, type EventEmitterInterface, type EventListenerEntry, Frame, type FrameBoundElement, type FrameInterface, type FrameInvokeEntry, type FrameStaticEvent, FrameVisualBridge, Framework, type FrameworkConfig, type FrameworkInterface, LARK_VIEW, type Location, type LocationDiff, type MixinEventHandler, type ParamDiff, type ParsedUri, Payload, type PayloadEntry, type PayloadInterface, type PendingCacheEntry, RouterEvents as ROUTER_EVENTS, type RouteChangeEvent, type RouteChangedEvent, type RouteViewConfig, Router, type RouterInterface, SPLITTER, type SerializedFrameNode, type SerializedFrameTree, type SerializedViewInfo, Service, type ServiceCacheInfo, type ServiceEntry, type ServiceEvent, type ServiceInterface, type ServiceMetaEntry, type ServiceOptions, State, type StateInterface, type StoreApi, TAG_NAME_REGEXP, Updater, type UpdaterInterface, VIEW_EVENT_METHOD_REGEXP, View, type ViewEvent, type ViewEventSelectorEntry, type ViewGlobalEventEntry, type ViewInterface, type ViewLocationObserved, type ViewObserveLocation, type ViewResourceEntry, type ViewTemplate, type VoidFunc, applyDomOps, applyIdUpdates, applyStyle, assign, bindStore, computed, create, createDomRef, defineStore, defineView, domGetCompareKey, domGetNode, domSetAttributes, domSetChildNodes, domSetNode, domSpecialDiff, domUnmountFrames, encodeHTML, encodeQ, encodeSafe, encodeURIExtra, ensureElementId, config as frameworkConfig, funcWithTry, generateId, getAttribute, getById, getRouteMode, hasOwnProperty, installFrameVisualizerBridge, invalidateViewClass, isPlainObject, isPrimitive, isPrimitiveOrFunc, keys, mark, markBooted, markRouterBooted, nextCounter, nodeInside, noop, now, parseUri, registerViewClass, resetProjectsMap, safeguard, serializeFrameTree, setData, syncCounter, toMap, toUri, translateData, unmark, use, useUrlState };
|
package/dist/index.js
CHANGED
|
@@ -6,14 +6,6 @@ var RouterEvents = {
|
|
|
6
6
|
CHANGED: "changed",
|
|
7
7
|
PAGE_UNLOAD: "page_unload"
|
|
8
8
|
};
|
|
9
|
-
var LarkInnerKeys = {
|
|
10
|
-
/** Attribute name: ldk (static key for skipping VDOM diff) */
|
|
11
|
-
DIFF_KEY: "ldk",
|
|
12
|
-
/** Attribute name: lak (static attribute key) */
|
|
13
|
-
ATTR_KEY: "lak",
|
|
14
|
-
/** Attribute name: lvk (view key for assign) */
|
|
15
|
-
VIEW_KEY: "lvk"
|
|
16
|
-
};
|
|
17
9
|
var LARK_VIEW = "v-lark";
|
|
18
10
|
var EVENT_METHOD_REGEXP = new RegExp(
|
|
19
11
|
`(?:([\\w-]+)${SPLITTER})?([^(]+)\\(([\\s\\S]*?)?\\)`
|
|
@@ -1373,7 +1365,7 @@ var EventDelegator = {
|
|
|
1373
1365
|
}
|
|
1374
1366
|
};
|
|
1375
1367
|
|
|
1376
|
-
// src/
|
|
1368
|
+
// src/dom.ts
|
|
1377
1369
|
var wrapMeta = {
|
|
1378
1370
|
option: [1, "<select multiple>"],
|
|
1379
1371
|
thead: [1, "<table>"],
|
|
@@ -1393,12 +1385,12 @@ var VDoc = document.implementation.createHTMLDocument("");
|
|
|
1393
1385
|
var VBase = VDoc.createElement("base");
|
|
1394
1386
|
VBase.href = document.location.href;
|
|
1395
1387
|
VDoc.head.appendChild(VBase);
|
|
1396
|
-
var
|
|
1388
|
+
var DomSpecials = {
|
|
1397
1389
|
INPUT: ["value", "checked"],
|
|
1398
1390
|
TEXTAREA: ["value"],
|
|
1399
1391
|
OPTION: ["selected"]
|
|
1400
1392
|
};
|
|
1401
|
-
function
|
|
1393
|
+
function domUnmountFrames(frame, node) {
|
|
1402
1394
|
if (!(node instanceof Element)) return;
|
|
1403
1395
|
const id = node.getAttribute("id");
|
|
1404
1396
|
if (!id) return;
|
|
@@ -1407,7 +1399,7 @@ function vdomUnmountFrames(frame, node) {
|
|
|
1407
1399
|
frame.unmountFrame(id);
|
|
1408
1400
|
}
|
|
1409
1401
|
}
|
|
1410
|
-
function
|
|
1402
|
+
function domGetNode(html, refNode) {
|
|
1411
1403
|
const tmp = VDoc.createElement("div");
|
|
1412
1404
|
const ns = refNode.namespaceURI;
|
|
1413
1405
|
let tag;
|
|
@@ -1428,16 +1420,13 @@ function vdomGetNode(html, refNode) {
|
|
|
1428
1420
|
}
|
|
1429
1421
|
return tmp;
|
|
1430
1422
|
}
|
|
1431
|
-
function
|
|
1423
|
+
function domGetCompareKey(node) {
|
|
1432
1424
|
if (node.nodeType !== 1) return void 0;
|
|
1433
1425
|
const el = node;
|
|
1434
1426
|
if (el.compareKeyCached) {
|
|
1435
1427
|
return el.cachedCompareKey;
|
|
1436
1428
|
}
|
|
1437
1429
|
let key = el.autoId ? "" : el.getAttribute("id") || void 0;
|
|
1438
|
-
if (!key) {
|
|
1439
|
-
key = el.getAttribute(LarkInnerKeys.DIFF_KEY) || void 0;
|
|
1440
|
-
}
|
|
1441
1430
|
if (!key) {
|
|
1442
1431
|
const larkView = el.getAttribute(LARK_VIEW);
|
|
1443
1432
|
if (larkView) {
|
|
@@ -1448,8 +1437,8 @@ function vdomGetCompareKey(node) {
|
|
|
1448
1437
|
el.cachedCompareKey = key || "";
|
|
1449
1438
|
return key;
|
|
1450
1439
|
}
|
|
1451
|
-
function
|
|
1452
|
-
const specials =
|
|
1440
|
+
function domSpecialDiff(oldNode, newNode) {
|
|
1441
|
+
const specials = DomSpecials[oldNode.nodeName];
|
|
1453
1442
|
if (!specials) return 0;
|
|
1454
1443
|
const oldEl = oldNode;
|
|
1455
1444
|
const newEl = newNode;
|
|
@@ -1462,7 +1451,7 @@ function vdomSpecialDiff(oldNode, newNode) {
|
|
|
1462
1451
|
}
|
|
1463
1452
|
return result;
|
|
1464
1453
|
}
|
|
1465
|
-
function
|
|
1454
|
+
function domSetAttributes(oldNode, newNode, ref, keepId) {
|
|
1466
1455
|
const oldEl = oldNode;
|
|
1467
1456
|
Reflect.deleteProperty(oldEl, "compareKeyCached");
|
|
1468
1457
|
const oldAttrs = oldNode.attributes;
|
|
@@ -1494,7 +1483,7 @@ function vdomSetAttributes(oldNode, newNode, ref, keepId) {
|
|
|
1494
1483
|
}
|
|
1495
1484
|
}
|
|
1496
1485
|
}
|
|
1497
|
-
function
|
|
1486
|
+
function domSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
1498
1487
|
let oldNode = oldParent.lastChild;
|
|
1499
1488
|
let newNode = newParent.firstChild;
|
|
1500
1489
|
let extra = 0;
|
|
@@ -1502,7 +1491,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1502
1491
|
const newKeyedNodes = /* @__PURE__ */ new Map();
|
|
1503
1492
|
while (oldNode) {
|
|
1504
1493
|
extra++;
|
|
1505
|
-
const nodeKey =
|
|
1494
|
+
const nodeKey = domGetCompareKey(oldNode);
|
|
1506
1495
|
if (nodeKey) {
|
|
1507
1496
|
let bucket = keyedNodes.get(nodeKey);
|
|
1508
1497
|
if (!bucket) {
|
|
@@ -1514,7 +1503,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1514
1503
|
oldNode = oldNode.previousSibling;
|
|
1515
1504
|
}
|
|
1516
1505
|
while (newNode) {
|
|
1517
|
-
const nodeKey =
|
|
1506
|
+
const nodeKey = domGetCompareKey(newNode);
|
|
1518
1507
|
if (nodeKey) {
|
|
1519
1508
|
newKeyedNodes.set(nodeKey, (newKeyedNodes.get(nodeKey) ?? 0) + 1);
|
|
1520
1509
|
}
|
|
@@ -1526,7 +1515,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1526
1515
|
extra--;
|
|
1527
1516
|
const tempNew = newNode;
|
|
1528
1517
|
newNode = newNode.nextSibling;
|
|
1529
|
-
const nodeKey =
|
|
1518
|
+
const nodeKey = domGetCompareKey(tempNew);
|
|
1530
1519
|
let foundNode = nodeKey ? keyedNodes.get(nodeKey) : void 0;
|
|
1531
1520
|
if (foundNode && (foundNode = foundNode.slice()) && foundNode.length) {
|
|
1532
1521
|
const matched = foundNode.pop();
|
|
@@ -1541,17 +1530,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1541
1530
|
const c = newKeyedNodes.get(nodeKey);
|
|
1542
1531
|
if (c) newKeyedNodes.set(nodeKey, c - 1);
|
|
1543
1532
|
}
|
|
1544
|
-
|
|
1533
|
+
domSetNode(matched, tempNew, oldParent, ref, frame, keys_);
|
|
1545
1534
|
} else if (oldNode) {
|
|
1546
1535
|
const tempOld2 = oldNode;
|
|
1547
|
-
const oldKey =
|
|
1536
|
+
const oldKey = domGetCompareKey(tempOld2);
|
|
1548
1537
|
if (oldKey && keyedNodes.has(oldKey) && newKeyedNodes.get(oldKey)) {
|
|
1549
1538
|
extra++;
|
|
1550
1539
|
ref.hasChanged = 1;
|
|
1551
1540
|
ref.domOps.push([8, oldParent, tempNew, tempOld2]);
|
|
1552
1541
|
} else {
|
|
1553
1542
|
oldNode = oldNode.nextSibling;
|
|
1554
|
-
|
|
1543
|
+
domSetNode(tempOld2, tempNew, oldParent, ref, frame, keys_);
|
|
1555
1544
|
}
|
|
1556
1545
|
} else {
|
|
1557
1546
|
ref.hasChanged = 1;
|
|
@@ -1561,29 +1550,23 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1561
1550
|
let tempOld = oldParent.lastChild;
|
|
1562
1551
|
while (extra-- > 0) {
|
|
1563
1552
|
if (tempOld) {
|
|
1564
|
-
|
|
1553
|
+
domUnmountFrames(frame, tempOld);
|
|
1565
1554
|
ref.domOps.push([2, oldParent, tempOld]);
|
|
1566
1555
|
tempOld = tempOld.previousSibling;
|
|
1567
1556
|
ref.hasChanged = 1;
|
|
1568
1557
|
}
|
|
1569
1558
|
}
|
|
1570
1559
|
}
|
|
1571
|
-
function
|
|
1560
|
+
function domSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
1572
1561
|
const oldAsEl = oldNode instanceof Element ? oldNode : null;
|
|
1573
1562
|
const newAsEl = newNode instanceof Element ? newNode : null;
|
|
1574
|
-
const hasViewKey = !!oldAsEl?.hasAttribute(LarkInnerKeys.VIEW_KEY);
|
|
1575
1563
|
const equalAsNodes = oldAsEl !== null && newAsEl !== null && oldAsEl.isEqualNode && oldAsEl.isEqualNode(newAsEl);
|
|
1576
|
-
if (
|
|
1564
|
+
if (domSpecialDiff(oldNode, newNode) || !equalAsNodes) {
|
|
1577
1565
|
if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
|
|
1578
1566
|
if (oldAsEl !== null && newAsEl !== null) {
|
|
1579
1567
|
const oldEl = oldAsEl;
|
|
1580
1568
|
const newEl = newAsEl;
|
|
1581
|
-
const staticKey = newEl.getAttribute(LarkInnerKeys.DIFF_KEY);
|
|
1582
|
-
if (staticKey && staticKey === oldEl.getAttribute(LarkInnerKeys.DIFF_KEY)) {
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
1569
|
const newLarkView = newEl.getAttribute(LARK_VIEW);
|
|
1586
|
-
const updateAttribute = !newEl.getAttribute(LarkInnerKeys.ATTR_KEY) || newEl.getAttribute(LarkInnerKeys.ATTR_KEY) !== oldEl.getAttribute(LarkInnerKeys.ATTR_KEY);
|
|
1587
1570
|
let updateChildren = true;
|
|
1588
1571
|
if (newLarkView) {
|
|
1589
1572
|
const oldFrameId = oldEl.getAttribute("id") || "";
|
|
@@ -1594,11 +1577,9 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1594
1577
|
updateChildren = false;
|
|
1595
1578
|
}
|
|
1596
1579
|
}
|
|
1597
|
-
|
|
1598
|
-
vdomSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1599
|
-
}
|
|
1580
|
+
domSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1600
1581
|
if (updateChildren) {
|
|
1601
|
-
|
|
1582
|
+
domSetChildNodes(oldEl, newEl, ref, frame, keys_);
|
|
1602
1583
|
}
|
|
1603
1584
|
} else if (oldNode.nodeValue !== newNode.nodeValue) {
|
|
1604
1585
|
ref.hasChanged = 1;
|
|
@@ -1606,12 +1587,12 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1606
1587
|
}
|
|
1607
1588
|
} else {
|
|
1608
1589
|
ref.hasChanged = 1;
|
|
1609
|
-
|
|
1590
|
+
domUnmountFrames(frame, oldNode);
|
|
1610
1591
|
ref.domOps.push([4, oldParent, newNode, oldNode]);
|
|
1611
1592
|
}
|
|
1612
1593
|
}
|
|
1613
1594
|
}
|
|
1614
|
-
function
|
|
1595
|
+
function createDomRef() {
|
|
1615
1596
|
return {
|
|
1616
1597
|
idUpdates: [],
|
|
1617
1598
|
views: [],
|
|
@@ -1619,7 +1600,7 @@ function createVdomRef() {
|
|
|
1619
1600
|
hasChanged: 0
|
|
1620
1601
|
};
|
|
1621
1602
|
}
|
|
1622
|
-
function
|
|
1603
|
+
function applyDomOps(ops) {
|
|
1623
1604
|
for (const op of ops) {
|
|
1624
1605
|
switch (op[0]) {
|
|
1625
1606
|
case 1:
|
|
@@ -1758,11 +1739,11 @@ var Updater = class {
|
|
|
1758
1739
|
return this;
|
|
1759
1740
|
}
|
|
1760
1741
|
/**
|
|
1761
|
-
* Detect changes and trigger
|
|
1742
|
+
* Detect changes and trigger DOM re-render.
|
|
1762
1743
|
*
|
|
1763
1744
|
* The core rendering pipeline:
|
|
1764
1745
|
* 1. Set data if provided
|
|
1765
|
-
* 2. If changed, run
|
|
1746
|
+
* 2. If changed, run DOM diff (template → new DOM → diff against old DOM)
|
|
1766
1747
|
* 3. Apply DOM operations
|
|
1767
1748
|
* 4. Apply ID updates
|
|
1768
1749
|
* 5. Call endUpdate on views that need re-rendering
|
|
@@ -1807,11 +1788,11 @@ var Updater = class {
|
|
|
1807
1788
|
updaterRef,
|
|
1808
1789
|
encodeQ
|
|
1809
1790
|
);
|
|
1810
|
-
const newDom =
|
|
1811
|
-
const ref =
|
|
1812
|
-
|
|
1791
|
+
const newDom = domGetNode(html, node);
|
|
1792
|
+
const ref = createDomRef();
|
|
1793
|
+
domSetChildNodes(node, newDom, ref, frame, keys2);
|
|
1813
1794
|
applyIdUpdates(ref.idUpdates);
|
|
1814
|
-
|
|
1795
|
+
applyDomOps(ref.domOps);
|
|
1815
1796
|
for (const v of ref.views) {
|
|
1816
1797
|
if (v.render) {
|
|
1817
1798
|
funcWithTry(v.render, [], v, noop);
|
|
@@ -4255,16 +4236,23 @@ export {
|
|
|
4255
4236
|
Updater,
|
|
4256
4237
|
VIEW_EVENT_METHOD_REGEXP,
|
|
4257
4238
|
View,
|
|
4239
|
+
applyDomOps,
|
|
4258
4240
|
applyIdUpdates,
|
|
4259
4241
|
applyStyle,
|
|
4260
|
-
applyVdomOps,
|
|
4261
4242
|
assign,
|
|
4262
4243
|
bindStore,
|
|
4263
4244
|
computed,
|
|
4264
4245
|
create,
|
|
4265
|
-
|
|
4246
|
+
createDomRef,
|
|
4266
4247
|
defineStore,
|
|
4267
4248
|
defineView,
|
|
4249
|
+
domGetCompareKey,
|
|
4250
|
+
domGetNode,
|
|
4251
|
+
domSetAttributes,
|
|
4252
|
+
domSetChildNodes,
|
|
4253
|
+
domSetNode,
|
|
4254
|
+
domSpecialDiff,
|
|
4255
|
+
domUnmountFrames,
|
|
4268
4256
|
encodeHTML,
|
|
4269
4257
|
encodeQ,
|
|
4270
4258
|
encodeSafe,
|
|
@@ -4302,12 +4290,5 @@ export {
|
|
|
4302
4290
|
translateData,
|
|
4303
4291
|
unmark,
|
|
4304
4292
|
use,
|
|
4305
|
-
useUrlState
|
|
4306
|
-
vdomGetCompareKey,
|
|
4307
|
-
vdomGetNode,
|
|
4308
|
-
vdomSetAttributes,
|
|
4309
|
-
vdomSetChildNodes,
|
|
4310
|
-
vdomSetNode,
|
|
4311
|
-
vdomSpecialDiff,
|
|
4312
|
-
vdomUnmountFrames
|
|
4293
|
+
useUrlState
|
|
4313
4294
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark.js/mvc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "@lark.js/mvc - TypeScript MVC framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -90,14 +90,14 @@
|
|
|
90
90
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
91
91
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
92
92
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
93
|
-
"@types/node": "^24.13.
|
|
93
|
+
"@types/node": "^24.13.2",
|
|
94
94
|
"@vitest/coverage-v8": "4.1.6",
|
|
95
|
-
"rollup": "^4.
|
|
95
|
+
"rollup": "^4.62.0",
|
|
96
96
|
"rollup-plugin-dts": "^6.4.1",
|
|
97
97
|
"tsup": "^8.5.1",
|
|
98
98
|
"typescript": "^5.9.3",
|
|
99
99
|
"vite": "^8.0.16",
|
|
100
|
-
"vitest": "^4.1.
|
|
100
|
+
"vitest": "^4.1.9"
|
|
101
101
|
},
|
|
102
102
|
"peerDependencies": {
|
|
103
103
|
"vite": "^8.0.14"
|
package/src/client.d.ts
CHANGED
|
@@ -50,9 +50,9 @@ declare global {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
interface Element {
|
|
53
|
-
/**
|
|
53
|
+
/** DOM diff cached compare key flag */
|
|
54
54
|
compareKeyCached?: number | undefined;
|
|
55
|
-
/**
|
|
55
|
+
/** DOM diff cached compare key */
|
|
56
56
|
cachedCompareKey?: string | undefined;
|
|
57
57
|
"v-lark"?: string | undefined;
|
|
58
58
|
|