@wsxjs/wsx-core 0.0.30 → 0.1.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/dist/chunk-NEHWERG6.mjs +1424 -0
- package/dist/chunk-PIKDVFOA.mjs +1337 -0
- package/dist/chunk-PNIWQQN6.mjs +1330 -0
- package/dist/chunk-PP54HBAY.mjs +1337 -0
- package/dist/index.js +1720 -1988
- package/dist/index.mjs +170 -345
- package/dist/jsx-runtime.js +110 -154
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/jsx.js +110 -154
- package/dist/jsx.mjs +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/base-component.ts +8 -309
- package/src/index.ts +1 -0
- package/src/jsx-factory.ts +3 -1
- package/src/light-component.ts +111 -123
- package/src/utils/cache-key.ts +17 -2
- package/src/utils/dom-utils.ts +7 -47
- package/src/utils/element-update.ts +107 -231
- package/src/utils/update-children-helpers.ts +67 -78
- package/src/web-component.ts +108 -96
package/dist/jsx-runtime.js
CHANGED
|
@@ -47,11 +47,6 @@ function isHTMLString(str) {
|
|
|
47
47
|
const looksLikeMath = /^[^<]*<[^>]*>[^>]*$/.test(trimmed) && !htmlTagPattern.test(trimmed);
|
|
48
48
|
if (looksLikeMath) return false;
|
|
49
49
|
const result = htmlTagPattern.test(trimmed);
|
|
50
|
-
if (result) {
|
|
51
|
-
console.log(`[WSX Debug] isHTMLString("${trimmed.substring(0, 50)}..."): ${result}`, {
|
|
52
|
-
looksLikeMath
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
50
|
return result;
|
|
56
51
|
}
|
|
57
52
|
function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
|
|
@@ -77,11 +72,7 @@ function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
|
|
|
77
72
|
const nodes = parseHTMLToNodes(child);
|
|
78
73
|
if (nodes.length > 0) {
|
|
79
74
|
for (const node of nodes) {
|
|
80
|
-
|
|
81
|
-
result.push(node);
|
|
82
|
-
} else {
|
|
83
|
-
result.push(node);
|
|
84
|
-
}
|
|
75
|
+
result.push(node);
|
|
85
76
|
}
|
|
86
77
|
} else {
|
|
87
78
|
result.push(child);
|
|
@@ -95,15 +86,7 @@ function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
|
|
|
95
86
|
}
|
|
96
87
|
} else if (child instanceof DocumentFragment) {
|
|
97
88
|
const fragmentChildren = Array.from(child.childNodes);
|
|
98
|
-
|
|
99
|
-
if (fragChild instanceof HTMLElement || fragChild instanceof SVGElement) {
|
|
100
|
-
result.push(fragChild);
|
|
101
|
-
} else if (fragChild.nodeType === Node.TEXT_NODE) {
|
|
102
|
-
result.push(fragChild.textContent || "");
|
|
103
|
-
} else if (fragChild instanceof DocumentFragment) {
|
|
104
|
-
result.push(...flattenChildren([fragChild], skipHTMLDetection, depth + 1));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
89
|
+
result.push(...flattenChildren(fragmentChildren, skipHTMLDetection, depth + 1));
|
|
107
90
|
} else {
|
|
108
91
|
result.push(child);
|
|
109
92
|
}
|
|
@@ -148,6 +131,8 @@ var RenderContext = _RenderContext;
|
|
|
148
131
|
var INDEX_KEY = "__wsxIndex";
|
|
149
132
|
var componentElementCounters = /* @__PURE__ */ new WeakMap();
|
|
150
133
|
var componentIdCache = /* @__PURE__ */ new WeakMap();
|
|
134
|
+
var instanceAutoIds = /* @__PURE__ */ new WeakMap();
|
|
135
|
+
var globalAutoId = 0;
|
|
151
136
|
function generateCacheKey(tag, props, componentId, component) {
|
|
152
137
|
const userKey = props?.key;
|
|
153
138
|
const index = props?.[INDEX_KEY];
|
|
@@ -179,7 +164,13 @@ function getComponentId() {
|
|
|
179
164
|
if (cachedId) {
|
|
180
165
|
return cachedId;
|
|
181
166
|
}
|
|
182
|
-
|
|
167
|
+
let instanceId = component._wsxInstanceId;
|
|
168
|
+
if (instanceId === void 0 || instanceId === null) {
|
|
169
|
+
if (!instanceAutoIds.has(component)) {
|
|
170
|
+
instanceAutoIds.set(component, ++globalAutoId);
|
|
171
|
+
}
|
|
172
|
+
instanceId = String(instanceAutoIds.get(component));
|
|
173
|
+
}
|
|
183
174
|
cachedId = `${component.constructor.name}:${instanceId}`;
|
|
184
175
|
componentIdCache.set(component, cachedId);
|
|
185
176
|
return cachedId;
|
|
@@ -716,8 +707,8 @@ function findElementNode(oldChild, parent) {
|
|
|
716
707
|
function findTextNode(parent, domIndex, processedNodes) {
|
|
717
708
|
for (let i = domIndex.value; i < parent.childNodes.length; i++) {
|
|
718
709
|
const node = parent.childNodes[i];
|
|
719
|
-
if (node.nodeType === Node.TEXT_NODE && node.__wsxManaged === true && !processedNodes.has(node)) {
|
|
720
|
-
domIndex.value = i
|
|
710
|
+
if (node.nodeType === Node.TEXT_NODE && node.__wsxManaged === true && (!processedNodes || !processedNodes.has(node))) {
|
|
711
|
+
domIndex.value = i;
|
|
721
712
|
return node;
|
|
722
713
|
}
|
|
723
714
|
}
|
|
@@ -800,11 +791,6 @@ function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextS
|
|
|
800
791
|
if (existingNode instanceof HTMLElement || existingNode instanceof SVGElement) {
|
|
801
792
|
const existingCacheKey = getElementCacheKey(existingNode);
|
|
802
793
|
if (!existingCacheKey && existingNode.tagName.toLowerCase() === newChildTag && existingNode.textContent === newChildContent && existingNode !== newChild) {
|
|
803
|
-
console.log(
|
|
804
|
-
"[WSX Debug] Found duplicate content, keeping existing:",
|
|
805
|
-
existingNode.tagName,
|
|
806
|
-
existingNode.textContent
|
|
807
|
-
);
|
|
808
794
|
if (processedNodes) processedNodes.add(existingNode);
|
|
809
795
|
return;
|
|
810
796
|
}
|
|
@@ -838,35 +824,53 @@ function appendNewChild(parent, child, processedNodes) {
|
|
|
838
824
|
}
|
|
839
825
|
} else if (child instanceof DocumentFragment) {
|
|
840
826
|
if (processedNodes) {
|
|
841
|
-
|
|
842
|
-
|
|
827
|
+
const fragmentChildren = Array.from(child.childNodes);
|
|
828
|
+
for (const fragmentChild of fragmentChildren) {
|
|
829
|
+
processedNodes.add(fragmentChild);
|
|
843
830
|
}
|
|
844
831
|
}
|
|
845
832
|
parent.appendChild(child);
|
|
833
|
+
} else if (child instanceof Node) {
|
|
834
|
+
if (child.parentNode && child.parentNode !== parent) {
|
|
835
|
+
child.parentNode.removeChild(child);
|
|
836
|
+
}
|
|
837
|
+
if (child.parentNode !== parent) {
|
|
838
|
+
parent.appendChild(child);
|
|
839
|
+
}
|
|
840
|
+
if (processedNodes) {
|
|
841
|
+
processedNodes.add(child);
|
|
842
|
+
}
|
|
846
843
|
}
|
|
847
844
|
}
|
|
848
|
-
function
|
|
845
|
+
function buildNodeMaps(flatNodes) {
|
|
849
846
|
const elementSet = /* @__PURE__ */ new Set();
|
|
850
847
|
const cacheKeyMap = /* @__PURE__ */ new Map();
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
848
|
+
const nodeSet = /* @__PURE__ */ new Set();
|
|
849
|
+
for (const child of flatNodes) {
|
|
850
|
+
if (child instanceof Node) {
|
|
851
|
+
nodeSet.add(child);
|
|
852
|
+
if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
|
|
853
|
+
elementSet.add(child);
|
|
854
|
+
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
855
|
+
const cacheKey = getElementCacheKey(child);
|
|
856
|
+
if (cacheKey) {
|
|
857
|
+
cacheKeyMap.set(cacheKey, child);
|
|
858
|
+
}
|
|
858
859
|
}
|
|
859
860
|
}
|
|
860
861
|
}
|
|
861
862
|
}
|
|
862
|
-
return { elementSet, cacheKeyMap };
|
|
863
|
+
return { elementSet, cacheKeyMap, nodeSet };
|
|
863
864
|
}
|
|
864
|
-
function shouldRemoveNode(node,
|
|
865
|
+
function shouldRemoveNode(node, _elementSet, _cacheKeyMap, processedNodes, nodeSet) {
|
|
866
|
+
if (processedNodes && processedNodes.has(node)) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
if (nodeSet && nodeSet.has(node)) {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
865
872
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
866
873
|
if (node.__wsxManaged === true) {
|
|
867
|
-
if (processedNodes && processedNodes.has(node)) {
|
|
868
|
-
return false;
|
|
869
|
-
}
|
|
870
874
|
return true;
|
|
871
875
|
}
|
|
872
876
|
const parent = node.parentNode;
|
|
@@ -876,29 +880,10 @@ function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
|
|
|
876
880
|
}
|
|
877
881
|
}
|
|
878
882
|
return true;
|
|
879
|
-
} else {
|
|
880
|
-
if (shouldPreserveElement(node)) {
|
|
881
|
-
return false;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
const isProcessed = processedNodes && processedNodes.has(node);
|
|
885
|
-
if (isProcessed) {
|
|
886
|
-
return false;
|
|
887
883
|
}
|
|
888
884
|
if (shouldPreserveElement(node)) {
|
|
889
885
|
return false;
|
|
890
886
|
}
|
|
891
|
-
if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
|
|
892
|
-
if (elementSet.has(node)) {
|
|
893
|
-
return false;
|
|
894
|
-
}
|
|
895
|
-
if (node instanceof HTMLElement || node instanceof SVGElement) {
|
|
896
|
-
const cacheKey = getElementCacheKey(node);
|
|
897
|
-
if (cacheKey && cacheKeyMap.has(cacheKey)) {
|
|
898
|
-
return false;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
887
|
return true;
|
|
903
888
|
}
|
|
904
889
|
function deduplicateCacheKeys(parent, cacheKeyMap) {
|
|
@@ -925,11 +910,11 @@ function deduplicateCacheKeys(parent, cacheKeyMap) {
|
|
|
925
910
|
}
|
|
926
911
|
}
|
|
927
912
|
}
|
|
928
|
-
function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
|
|
913
|
+
function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes, nodeSet) {
|
|
929
914
|
const nodesToRemove = [];
|
|
930
915
|
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
931
916
|
const node = parent.childNodes[i];
|
|
932
|
-
const removed = shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes);
|
|
917
|
+
const removed = shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes, nodeSet);
|
|
933
918
|
if (removed) {
|
|
934
919
|
nodesToRemove.push(node);
|
|
935
920
|
}
|
|
@@ -1130,6 +1115,8 @@ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
|
|
|
1130
1115
|
const flatOld = flattenChildrenSafe(oldChildren);
|
|
1131
1116
|
const flatNew = flattenChildrenSafe(newChildren);
|
|
1132
1117
|
const preservedElements = collectPreservedElements(element);
|
|
1118
|
+
const { cacheKeyMap: oldKeyMap } = buildNodeMaps(flatOld);
|
|
1119
|
+
const newMaps = buildNodeMaps(flatNew);
|
|
1133
1120
|
const minLength = Math.min(flatOld.length, flatNew.length);
|
|
1134
1121
|
const domIndex = { value: 0 };
|
|
1135
1122
|
const insertionIndex = { value: 0 };
|
|
@@ -1138,110 +1125,77 @@ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
|
|
|
1138
1125
|
const oldChild = flatOld[i];
|
|
1139
1126
|
const newChild = flatNew[i];
|
|
1140
1127
|
let oldNode = null;
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1143
|
-
if (
|
|
1144
|
-
const
|
|
1145
|
-
if (
|
|
1146
|
-
|
|
1128
|
+
if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
1129
|
+
const key = getElementCacheKey(newChild);
|
|
1130
|
+
if (key) {
|
|
1131
|
+
const matchedOld = oldKeyMap.get(key);
|
|
1132
|
+
if (matchedOld && matchedOld.parentNode === element) {
|
|
1133
|
+
oldNode = matchedOld;
|
|
1147
1134
|
}
|
|
1148
1135
|
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1136
|
+
}
|
|
1137
|
+
if (!oldNode) {
|
|
1138
|
+
if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
|
|
1139
|
+
oldNode = findElementNode(oldChild, element);
|
|
1140
|
+
} else if (typeof oldChild === "string" || typeof oldChild === "number" || oldChild instanceof Node) {
|
|
1153
1141
|
oldNode = findTextNode(element, domIndex, processedNodes);
|
|
1154
|
-
if (oldNode) {
|
|
1155
|
-
const nodeIndex = Array.from(element.childNodes).indexOf(oldNode);
|
|
1156
|
-
if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
|
|
1157
|
-
domIndex.value = nodeIndex + 1;
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
1142
|
}
|
|
1161
1143
|
}
|
|
1162
|
-
if (
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1168
|
-
const insertBeforeNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
|
|
1169
|
-
const updatedNode = updateOrCreateTextNode(
|
|
1170
|
-
element,
|
|
1171
|
-
oldNode,
|
|
1172
|
-
newText,
|
|
1173
|
-
insertBeforeNode
|
|
1174
|
-
);
|
|
1175
|
-
if (updatedNode) {
|
|
1176
|
-
processedNodes.add(updatedNode);
|
|
1177
|
-
insertionIndex.value++;
|
|
1178
|
-
}
|
|
1179
|
-
} else {
|
|
1180
|
-
const targetNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
|
|
1181
|
-
if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
1182
|
-
if (oldNode && oldNode === targetNode && oldNode.parentNode === element) {
|
|
1183
|
-
element.replaceChild(newChild, oldNode);
|
|
1184
|
-
} else {
|
|
1185
|
-
element.insertBefore(newChild, targetNode);
|
|
1186
|
-
removeNodeIfNotPreserved(element, oldNode);
|
|
1187
|
-
}
|
|
1188
|
-
processedNodes.add(newChild);
|
|
1189
|
-
insertionIndex.value++;
|
|
1190
|
-
} else if (newChild instanceof DocumentFragment) {
|
|
1191
|
-
if (processedNodes) {
|
|
1192
|
-
for (let i2 = 0; i2 < newChild.childNodes.length; i2++) {
|
|
1193
|
-
processedNodes.add(newChild.childNodes[i2]);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
element.insertBefore(newChild, targetNode);
|
|
1197
|
-
removeNodeIfNotPreserved(element, oldNode);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
} else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
|
|
1201
|
-
if (oldNode && shouldPreserveElement(oldNode)) {
|
|
1202
|
-
continue;
|
|
1144
|
+
if (oldNode && oldNode.parentNode === element) {
|
|
1145
|
+
const childrenArray = Array.from(element.childNodes);
|
|
1146
|
+
const nodeIndex = childrenArray.indexOf(oldNode);
|
|
1147
|
+
if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
|
|
1148
|
+
domIndex.value = nodeIndex + 1;
|
|
1203
1149
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1150
|
+
}
|
|
1151
|
+
const targetNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
|
|
1152
|
+
const isNewTextChild = typeof newChild === "string" || typeof newChild === "number" || newChild instanceof Node && newChild.nodeType === Node.TEXT_NODE;
|
|
1153
|
+
if (isNewTextChild) {
|
|
1154
|
+
const newTextContent = newChild instanceof Node ? newChild.textContent || "" : String(newChild);
|
|
1155
|
+
if (shouldPreserveElement(element)) continue;
|
|
1156
|
+
const targetMatchingNode = newChild instanceof Node ? newChild : oldNode;
|
|
1157
|
+
const updatedNode = updateOrCreateTextNode(
|
|
1158
|
+
element,
|
|
1159
|
+
targetMatchingNode,
|
|
1160
|
+
newTextContent,
|
|
1161
|
+
targetNode
|
|
1162
|
+
);
|
|
1163
|
+
if (updatedNode) {
|
|
1164
|
+
processedNodes.add(updatedNode);
|
|
1213
1165
|
insertionIndex.value++;
|
|
1214
|
-
} else {
|
|
1215
|
-
const targetNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
|
|
1216
|
-
if (typeof newChild === "string" || typeof newChild === "number") {
|
|
1217
|
-
const newTextNode = document.createTextNode(String(newChild));
|
|
1218
|
-
newTextNode.__wsxManaged = true;
|
|
1219
|
-
if (oldNode && oldNode === targetNode && oldNode.parentNode === element) {
|
|
1220
|
-
element.replaceChild(newTextNode, oldNode);
|
|
1221
|
-
} else {
|
|
1222
|
-
element.insertBefore(newTextNode, targetNode);
|
|
1223
|
-
removeNodeIfNotPreserved(element, oldNode);
|
|
1224
|
-
}
|
|
1225
|
-
processedNodes.add(newTextNode);
|
|
1226
|
-
insertionIndex.value++;
|
|
1227
|
-
} else if (newChild instanceof DocumentFragment) {
|
|
1228
|
-
if (processedNodes) {
|
|
1229
|
-
for (let i2 = 0; i2 < newChild.childNodes.length; i2++) {
|
|
1230
|
-
processedNodes.add(newChild.childNodes[i2]);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
element.insertBefore(newChild, targetNode);
|
|
1234
|
-
removeNodeIfNotPreserved(element, oldNode);
|
|
1235
|
-
}
|
|
1236
1166
|
}
|
|
1167
|
+
} else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
1168
|
+
replaceOrInsertElementAtPosition(
|
|
1169
|
+
element,
|
|
1170
|
+
newChild,
|
|
1171
|
+
oldNode,
|
|
1172
|
+
targetNode,
|
|
1173
|
+
processedNodes
|
|
1174
|
+
);
|
|
1175
|
+
insertionIndex.value++;
|
|
1176
|
+
} else if (newChild instanceof DocumentFragment) {
|
|
1177
|
+
const fragmentChildren = Array.from(newChild.childNodes);
|
|
1178
|
+
for (const fc of fragmentChildren) {
|
|
1179
|
+
processedNodes.add(fc);
|
|
1180
|
+
}
|
|
1181
|
+
element.insertBefore(newChild, targetNode);
|
|
1182
|
+
if (oldNode && !processedNodes.has(oldNode)) {
|
|
1183
|
+
removeNodeIfNotPreserved(element, oldNode);
|
|
1184
|
+
}
|
|
1185
|
+
insertionIndex.value++;
|
|
1237
1186
|
}
|
|
1238
1187
|
}
|
|
1239
1188
|
for (let i = minLength; i < flatNew.length; i++) {
|
|
1240
1189
|
appendNewChild(element, flatNew[i], processedNodes);
|
|
1241
1190
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1191
|
+
deduplicateCacheKeys(element, newMaps.cacheKeyMap);
|
|
1192
|
+
const nodesToRemove = collectNodesToRemove(
|
|
1193
|
+
element,
|
|
1194
|
+
newMaps.elementSet,
|
|
1195
|
+
newMaps.cacheKeyMap,
|
|
1196
|
+
processedNodes,
|
|
1197
|
+
newMaps.nodeSet
|
|
1198
|
+
);
|
|
1245
1199
|
removeNodes(element, nodesToRemove, _cacheManager);
|
|
1246
1200
|
reinsertPreservedElements(element, preservedElements);
|
|
1247
1201
|
}
|
|
@@ -1360,6 +1314,8 @@ function Fragment(_props, children) {
|
|
|
1360
1314
|
fragment.appendChild(child);
|
|
1361
1315
|
} else if (child instanceof DocumentFragment) {
|
|
1362
1316
|
fragment.appendChild(child);
|
|
1317
|
+
} else if (child instanceof Node) {
|
|
1318
|
+
fragment.appendChild(child);
|
|
1363
1319
|
}
|
|
1364
1320
|
});
|
|
1365
1321
|
return fragment;
|