@ape-egg/vibe 2.1.11 → 2.1.12
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 +6 -0
- package/package.json +1 -1
- package/runtime/index.js +54 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.12] - 2026-06-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Nodes resolving inside slot-projected branch/iteration content were orphaned from the reactive tree** (`runtime/index.js`) — `navigateTree` only walks a node's `children`, but content projected across a `<slot>` boundary (a conditional branch's or an iteration instance's slotted content) is registered in the flat manifest under a path that isn't reachable through `children` — the slot node's children don't include the projected subtree. So when a `<component src>` (or any node) mounted inside such content, `navigateTree` returned null: on add, the resolved subtree never linked into the reactive tree (so it wasn't reactive); on remove, the stale tree entry lingered beside its replacement. A new `findNodeByElement` does an identity search across the *full* tree — plain `children`, conditional branch trees (`runtime.activeInstance.parsedTree`), and iteration instance trees (`runtime.instances`) — and is used as a fallback at both the add and remove sites when path navigation can't reach the parent, so the subtree links in and cleans up regardless of slot/branch/iteration projection.
|
|
8
|
+
|
|
3
9
|
## [2.1.11] - 2026-06-22
|
|
4
10
|
|
|
5
11
|
### Fixed
|
package/package.json
CHANGED
package/runtime/index.js
CHANGED
|
@@ -81,6 +81,48 @@ const navigateTree = (tree, path) => {
|
|
|
81
81
|
return path.split('.').filter(k => k).reduce((node, key) => node?.children?.[key], tree);
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// Locate the tree node whose `.element` is `target`, searching the full tree:
|
|
85
|
+
// plain `children`, plus conditional branch trees (`runtime.activeInstance`)
|
|
86
|
+
// and iteration instance trees (`runtime.instances`). navigateTree only walks
|
|
87
|
+
// `children`, so it can't reach content projected across a <slot> boundary — a
|
|
88
|
+
// conditional branch's slotted content is registered in the flat manifest by
|
|
89
|
+
// path, but that path isn't navigable through `children` (the slot node's
|
|
90
|
+
// children don't include the projected subtree). When a <component src> resolves
|
|
91
|
+
// inside such content, navigateTree returns null and the resolved subtree would
|
|
92
|
+
// be orphaned from the reactive tree. This identity search recovers the real
|
|
93
|
+
// parent node so the subtree links in regardless of slot/branch projection.
|
|
94
|
+
const findNodeByElement = (tree, target) => {
|
|
95
|
+
if (!target) return null;
|
|
96
|
+
const seen = new Set();
|
|
97
|
+
const walk = (node) => {
|
|
98
|
+
if (!node || typeof node !== 'object' || seen.has(node)) return null;
|
|
99
|
+
seen.add(node);
|
|
100
|
+
if (node.element === target) return node;
|
|
101
|
+
if (node.children) {
|
|
102
|
+
for (const key in node.children) {
|
|
103
|
+
const hit = walk(node.children[key]);
|
|
104
|
+
if (hit) return hit;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const branchTree = node.runtime?.activeInstance?.parsedTree;
|
|
108
|
+
if (branchTree) {
|
|
109
|
+
const hit = walk(branchTree);
|
|
110
|
+
if (hit) return hit;
|
|
111
|
+
}
|
|
112
|
+
const instances = node.runtime?.instances;
|
|
113
|
+
if (instances) {
|
|
114
|
+
for (let i = 0; i < instances.length; i++) {
|
|
115
|
+
if (instances[i]?.tree) {
|
|
116
|
+
const hit = walk(instances[i].tree);
|
|
117
|
+
if (hit) return hit;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
};
|
|
123
|
+
return walk(tree);
|
|
124
|
+
};
|
|
125
|
+
|
|
84
126
|
// Get or create a node in the tree at the given path
|
|
85
127
|
const ensureNode = (tree, path) => {
|
|
86
128
|
const keys = path.split('.').filter(k => k);
|
|
@@ -853,7 +895,12 @@ const main = (s, config = {}, stringSelector = '') => {
|
|
|
853
895
|
const name = dotPath.pop();
|
|
854
896
|
const parentDotAnnotation = dotPath.join('.');
|
|
855
897
|
|
|
856
|
-
|
|
898
|
+
// Identity fallback mirrors the added-node path: a parent inside
|
|
899
|
+
// slot-projected branch content isn't reachable via navigateTree's
|
|
900
|
+
// `children` walk, so resolve it by element identity instead — otherwise
|
|
901
|
+
// the removed node's stale tree entry lingers alongside its replacement.
|
|
902
|
+
const picked =
|
|
903
|
+
navigateTree(parsedTree, parentDotAnnotation) || findNodeByElement(parsedTree, target);
|
|
857
904
|
|
|
858
905
|
// If we can't navigate to the parent, skip
|
|
859
906
|
if (!picked || !picked.element) return;
|
|
@@ -912,7 +959,12 @@ const main = (s, config = {}, stringSelector = '') => {
|
|
|
912
959
|
// registration since there's no tree branch to attach to.)
|
|
913
960
|
if (entry) {
|
|
914
961
|
const [dotAnnotation] = entry;
|
|
915
|
-
|
|
962
|
+
// navigateTree walks `children` only; when the parent lives in a
|
|
963
|
+
// conditional branch's slot-projected content its manifest path isn't
|
|
964
|
+
// navigable that way (see findNodeByElement). Fall back to an identity
|
|
965
|
+
// search so the resolved subtree still links into the reactive tree.
|
|
966
|
+
const picked =
|
|
967
|
+
navigateTree(parsedTree, dotAnnotation) || findNodeByElement(parsedTree, target);
|
|
916
968
|
|
|
917
969
|
if (picked) {
|
|
918
970
|
if (!picked.element) {
|