@wsxjs/wsx-core 0.0.27 → 0.0.30

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/jsx.js CHANGED
@@ -32,6 +32,7 @@ function parseHTMLToNodes(html) {
32
32
  temp.innerHTML = html;
33
33
  return Array.from(temp.childNodes).map((node) => {
34
34
  if (node instanceof HTMLElement || node instanceof SVGElement) {
35
+ node.__wsxManaged = true;
35
36
  return node;
36
37
  } else {
37
38
  return node.textContent || "";
@@ -44,7 +45,13 @@ function isHTMLString(str) {
44
45
  const htmlTagPattern = /<[a-z][a-z0-9]*(\s[^>]*)?(\/>|>)/i;
45
46
  const looksLikeMath = /^[^<]*<[^>]*>[^>]*$/.test(trimmed) && !htmlTagPattern.test(trimmed);
46
47
  if (looksLikeMath) return false;
47
- return htmlTagPattern.test(trimmed);
48
+ const result = htmlTagPattern.test(trimmed);
49
+ if (result) {
50
+ console.log(`[WSX Debug] isHTMLString("${trimmed.substring(0, 50)}..."): ${result}`, {
51
+ looksLikeMath
52
+ });
53
+ }
54
+ return result;
48
55
  }
49
56
  function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
50
57
  if (depth > 10) {
@@ -85,6 +92,17 @@ function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
85
92
  } else {
86
93
  result.push(child);
87
94
  }
95
+ } else if (child instanceof DocumentFragment) {
96
+ const fragmentChildren = Array.from(child.childNodes);
97
+ for (const fragChild of fragmentChildren) {
98
+ if (fragChild instanceof HTMLElement || fragChild instanceof SVGElement) {
99
+ result.push(fragChild);
100
+ } else if (fragChild.nodeType === Node.TEXT_NODE) {
101
+ result.push(fragChild.textContent || "");
102
+ } else if (fragChild instanceof DocumentFragment) {
103
+ result.push(...flattenChildren([fragChild], skipHTMLDetection, depth + 1));
104
+ }
105
+ }
88
106
  } else {
89
107
  result.push(child);
90
108
  }
@@ -185,12 +203,12 @@ function isCreatedByH(element) {
185
203
  }
186
204
  function shouldPreserveElement(element) {
187
205
  if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
188
- return true;
206
+ return false;
189
207
  }
190
- if (!isCreatedByH(element)) {
208
+ if (!isCreatedByH(element) && element.__wsxManaged !== true) {
191
209
  return true;
192
210
  }
193
- if (element.hasAttribute("data-wsx-preserve")) {
211
+ if (element instanceof HTMLElement && element.hasAttribute("data-wsx-preserve")) {
194
212
  return true;
195
213
  }
196
214
  return false;
@@ -636,7 +654,9 @@ function appendChildrenToElement(element, children) {
636
654
  return;
637
655
  }
638
656
  if (typeof child === "string" || typeof child === "number") {
639
- element.appendChild(document.createTextNode(String(child)));
657
+ const textNode = document.createTextNode(String(child));
658
+ textNode.__wsxManaged = true;
659
+ element.appendChild(textNode);
640
660
  } else if (child instanceof HTMLElement || child instanceof SVGElement) {
641
661
  element.appendChild(child);
642
662
  } else if (child instanceof DocumentFragment) {
@@ -656,6 +676,9 @@ function collectPreservedElements(element) {
656
676
  const preserved = [];
657
677
  for (let i = 0; i < element.childNodes.length; i++) {
658
678
  const child = element.childNodes[i];
679
+ if (child.nodeType === Node.TEXT_NODE) {
680
+ continue;
681
+ }
659
682
  if (shouldPreserveElement(child)) {
660
683
  preserved.push(child);
661
684
  }
@@ -689,38 +712,40 @@ function findElementNode(oldChild, parent) {
689
712
  }
690
713
  return null;
691
714
  }
692
- function findTextNode(parent, domIndex) {
693
- while (domIndex.value < parent.childNodes.length) {
694
- const node = parent.childNodes[domIndex.value];
695
- if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
696
- const textNode = node;
697
- domIndex.value++;
698
- return textNode;
715
+ function findTextNode(parent, domIndex, processedNodes) {
716
+ for (let i = domIndex.value; i < parent.childNodes.length; i++) {
717
+ const node = parent.childNodes[i];
718
+ if (node.nodeType === Node.TEXT_NODE && node.__wsxManaged === true && !processedNodes.has(node)) {
719
+ domIndex.value = i + 1;
720
+ return node;
699
721
  }
700
- domIndex.value++;
701
722
  }
702
723
  return null;
703
724
  }
704
- function updateOrCreateTextNode(parent, oldNode, newText) {
725
+ function updateOrCreateTextNode(parent, oldNode, newText, insertBeforeNode) {
726
+ if (shouldPreserveElement(parent)) {
727
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
728
+ return oldNode;
729
+ }
730
+ return document.createTextNode(newText);
731
+ }
705
732
  if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
706
733
  if (oldNode.textContent !== newText) {
707
734
  oldNode.textContent = newText;
708
735
  }
709
- return oldNode;
710
- } else {
711
- if (!oldNode) {
712
- for (let i = 0; i < parent.childNodes.length; i++) {
713
- const node = parent.childNodes[i];
714
- if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent && node.textContent === newText) {
715
- return node;
716
- }
736
+ if (insertBeforeNode !== void 0) {
737
+ if (oldNode !== insertBeforeNode && oldNode.nextSibling !== insertBeforeNode) {
738
+ parent.insertBefore(oldNode, insertBeforeNode);
717
739
  }
718
740
  }
741
+ return oldNode;
742
+ } else {
719
743
  const newTextNode = document.createTextNode(newText);
744
+ newTextNode.__wsxManaged = true;
720
745
  if (oldNode && !shouldPreserveElement(oldNode)) {
721
746
  parent.replaceChild(newTextNode, oldNode);
722
747
  } else {
723
- parent.insertBefore(newTextNode, oldNode || null);
748
+ parent.insertBefore(newTextNode, insertBeforeNode ?? null);
724
749
  }
725
750
  return newTextNode;
726
751
  }
@@ -730,25 +755,36 @@ function removeNodeIfNotPreserved(parent, node) {
730
755
  parent.removeChild(node);
731
756
  }
732
757
  }
733
- function replaceOrInsertElement(parent, newChild, oldNode) {
734
- const targetNextSibling = oldNode && shouldPreserveElement(oldNode) ? oldNode : oldNode?.nextSibling || null;
735
- replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling);
736
- }
737
- function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling) {
758
+ function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling, processedNodes) {
738
759
  if (newChild.parentNode && newChild.parentNode !== parent) {
739
760
  newChild.parentNode.removeChild(newChild);
740
761
  }
741
- const isInCorrectPosition = newChild.parentNode === parent && newChild.nextSibling === targetNextSibling;
762
+ const isInCorrectPosition = newChild.parentNode === parent && (newChild.nextSibling === targetNextSibling || targetNextSibling === newChild);
742
763
  if (isInCorrectPosition) {
764
+ if (processedNodes) processedNodes.add(newChild);
743
765
  return;
744
766
  }
745
767
  if (newChild.parentNode === parent) {
746
768
  parent.insertBefore(newChild, targetNextSibling);
769
+ if (processedNodes) processedNodes.add(newChild);
747
770
  return;
748
771
  }
749
772
  if (oldNode && oldNode.parentNode === parent && !shouldPreserveElement(oldNode)) {
750
773
  if (oldNode !== newChild) {
774
+ const oldCacheKey = getElementCacheKey(oldNode);
775
+ const newCacheKey = getElementCacheKey(newChild);
776
+ if (!oldCacheKey && !newCacheKey && oldNode.__wsxManaged === true) {
777
+ const oldTag = oldNode.tagName.toLowerCase();
778
+ const newTag = newChild.tagName.toLowerCase();
779
+ if (oldTag === newTag && oldNode.textContent === newChild.textContent) {
780
+ if (processedNodes) processedNodes.add(oldNode);
781
+ return;
782
+ }
783
+ }
751
784
  parent.replaceChild(newChild, oldNode);
785
+ if (processedNodes) processedNodes.add(newChild);
786
+ } else {
787
+ if (processedNodes) processedNodes.add(newChild);
752
788
  }
753
789
  } else {
754
790
  if (newChild.parentNode === parent) {
@@ -763,6 +799,12 @@ function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextS
763
799
  if (existingNode instanceof HTMLElement || existingNode instanceof SVGElement) {
764
800
  const existingCacheKey = getElementCacheKey(existingNode);
765
801
  if (!existingCacheKey && existingNode.tagName.toLowerCase() === newChildTag && existingNode.textContent === newChildContent && existingNode !== newChild) {
802
+ console.log(
803
+ "[WSX Debug] Found duplicate content, keeping existing:",
804
+ existingNode.tagName,
805
+ existingNode.textContent
806
+ );
807
+ if (processedNodes) processedNodes.add(existingNode);
766
808
  return;
767
809
  }
768
810
  }
@@ -777,6 +819,7 @@ function appendNewChild(parent, child, processedNodes) {
777
819
  }
778
820
  if (typeof child === "string" || typeof child === "number") {
779
821
  const newTextNode = document.createTextNode(String(child));
822
+ newTextNode.__wsxManaged = true;
780
823
  parent.appendChild(newTextNode);
781
824
  if (processedNodes) {
782
825
  processedNodes.add(newTextNode);
@@ -793,6 +836,11 @@ function appendNewChild(parent, child, processedNodes) {
793
836
  processedNodes.add(child);
794
837
  }
795
838
  } else if (child instanceof DocumentFragment) {
839
+ if (processedNodes) {
840
+ for (let i = 0; i < child.childNodes.length; i++) {
841
+ processedNodes.add(child.childNodes[i]);
842
+ }
843
+ }
796
844
  parent.appendChild(child);
797
845
  }
798
846
  }
@@ -813,20 +861,31 @@ function buildNewChildrenMaps(flatNew) {
813
861
  return { elementSet, cacheKeyMap };
814
862
  }
815
863
  function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
816
- if (shouldPreserveElement(node)) {
817
- return false;
818
- }
819
- if (node.nodeType === Node.TEXT_NODE && processedNodes && processedNodes.has(node)) {
820
- return false;
821
- }
822
- if (node.nodeType === Node.TEXT_NODE && processedNodes) {
823
- let parent = node.parentNode;
824
- while (parent) {
825
- if (processedNodes.has(parent) && parent.parentNode) {
864
+ if (node.nodeType === Node.TEXT_NODE) {
865
+ if (node.__wsxManaged === true) {
866
+ if (processedNodes && processedNodes.has(node)) {
826
867
  return false;
827
868
  }
828
- parent = parent.parentNode;
869
+ return true;
829
870
  }
871
+ const parent = node.parentNode;
872
+ if (parent && (parent instanceof HTMLElement || parent instanceof SVGElement)) {
873
+ if (shouldPreserveElement(parent)) {
874
+ return false;
875
+ }
876
+ }
877
+ return true;
878
+ } else {
879
+ if (shouldPreserveElement(node)) {
880
+ return false;
881
+ }
882
+ }
883
+ const isProcessed = processedNodes && processedNodes.has(node);
884
+ if (isProcessed) {
885
+ return false;
886
+ }
887
+ if (shouldPreserveElement(node)) {
888
+ return false;
830
889
  }
831
890
  if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
832
891
  if (elementSet.has(node)) {
@@ -869,7 +928,8 @@ function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
869
928
  const nodesToRemove = [];
870
929
  for (let i = 0; i < parent.childNodes.length; i++) {
871
930
  const node = parent.childNodes[i];
872
- if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
931
+ const removed = shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes);
932
+ if (removed) {
873
933
  nodesToRemove.push(node);
874
934
  }
875
935
  }
@@ -1071,6 +1131,7 @@ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
1071
1131
  const preservedElements = collectPreservedElements(element);
1072
1132
  const minLength = Math.min(flatOld.length, flatNew.length);
1073
1133
  const domIndex = { value: 0 };
1134
+ const insertionIndex = { value: 0 };
1074
1135
  const processedNodes = /* @__PURE__ */ new Set();
1075
1136
  for (let i = 0; i < minLength; i++) {
1076
1137
  const oldChild = flatOld[i];
@@ -1085,48 +1146,54 @@ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
1085
1146
  }
1086
1147
  }
1087
1148
  } else if (typeof oldChild === "string" || typeof oldChild === "number") {
1088
- oldNode = findTextNode(element, domIndex);
1089
- if (!oldNode && element.childNodes.length > 0) {
1090
- const oldText = String(oldChild);
1091
- for (let j = domIndex.value; j < element.childNodes.length; j++) {
1092
- const node = element.childNodes[j];
1093
- if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
1094
- oldNode = node;
1095
- domIndex.value = j + 1;
1096
- break;
1149
+ if (shouldPreserveElement(element)) {
1150
+ oldNode = null;
1151
+ } else {
1152
+ oldNode = findTextNode(element, domIndex, processedNodes);
1153
+ if (oldNode) {
1154
+ const nodeIndex = Array.from(element.childNodes).indexOf(oldNode);
1155
+ if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
1156
+ domIndex.value = nodeIndex + 1;
1097
1157
  }
1098
1158
  }
1099
1159
  }
1100
1160
  }
1101
1161
  if (typeof oldChild === "string" || typeof oldChild === "number") {
1102
1162
  if (typeof newChild === "string" || typeof newChild === "number") {
1103
- const oldText = String(oldChild);
1104
1163
  const newText = String(newChild);
1105
- const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
1106
- if (needsUpdate) {
1107
- const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
1108
- if (updatedNode && !processedNodes.has(updatedNode)) {
1109
- processedNodes.add(updatedNode);
1110
- }
1111
- } else {
1112
- if (oldNode && oldNode.parentNode === element) {
1113
- processedNodes.add(oldNode);
1114
- } else if (!oldNode && oldText === newText) {
1115
- for (let j = domIndex.value; j < element.childNodes.length; j++) {
1116
- const node = element.childNodes[j];
1117
- if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === newText && !processedNodes.has(node)) {
1118
- processedNodes.add(node);
1119
- break;
1120
- }
1121
- }
1122
- }
1164
+ if (shouldPreserveElement(element)) {
1165
+ continue;
1166
+ }
1167
+ const insertBeforeNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
1168
+ const updatedNode = updateOrCreateTextNode(
1169
+ element,
1170
+ oldNode,
1171
+ newText,
1172
+ insertBeforeNode
1173
+ );
1174
+ if (updatedNode) {
1175
+ processedNodes.add(updatedNode);
1176
+ insertionIndex.value++;
1123
1177
  }
1124
1178
  } else {
1125
- removeNodeIfNotPreserved(element, oldNode);
1179
+ const targetNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
1126
1180
  if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
1127
- replaceOrInsertElement(element, newChild, oldNode);
1181
+ if (oldNode && oldNode === targetNode && oldNode.parentNode === element) {
1182
+ element.replaceChild(newChild, oldNode);
1183
+ } else {
1184
+ element.insertBefore(newChild, targetNode);
1185
+ removeNodeIfNotPreserved(element, oldNode);
1186
+ }
1187
+ processedNodes.add(newChild);
1188
+ insertionIndex.value++;
1128
1189
  } else if (newChild instanceof DocumentFragment) {
1129
- element.insertBefore(newChild, oldNode || null);
1190
+ if (processedNodes) {
1191
+ for (let i2 = 0; i2 < newChild.childNodes.length; i2++) {
1192
+ processedNodes.add(newChild.childNodes[i2]);
1193
+ }
1194
+ }
1195
+ element.insertBefore(newChild, targetNode);
1196
+ removeNodeIfNotPreserved(element, oldNode);
1130
1197
  }
1131
1198
  }
1132
1199
  } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
@@ -1134,49 +1201,36 @@ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
1134
1201
  continue;
1135
1202
  }
1136
1203
  if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
1137
- let targetNextSibling = null;
1138
- let foundPreviousElement = false;
1139
- for (let j = i - 1; j >= 0; j--) {
1140
- const prevChild = flatNew[j];
1141
- if (prevChild instanceof HTMLElement || prevChild instanceof SVGElement) {
1142
- if (prevChild.parentNode === element) {
1143
- targetNextSibling = prevChild.nextSibling;
1144
- foundPreviousElement = true;
1145
- break;
1146
- }
1147
- }
1148
- }
1149
- if (!foundPreviousElement) {
1150
- const firstChild = Array.from(element.childNodes).find(
1151
- (node) => !shouldPreserveElement(node) && !processedNodes.has(node)
1152
- );
1153
- targetNextSibling = firstChild || null;
1154
- }
1155
- const isInCorrectPosition = newChild.parentNode === element && newChild.nextSibling === targetNextSibling;
1156
- if (newChild === oldChild && isInCorrectPosition) {
1157
- if (oldNode) processedNodes.add(oldNode);
1158
- processedNodes.add(newChild);
1159
- continue;
1160
- }
1161
- const referenceNode = oldNode && oldNode.parentNode === element ? oldNode : null;
1204
+ const insertBeforeNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
1162
1205
  replaceOrInsertElementAtPosition(
1163
1206
  element,
1164
1207
  newChild,
1165
- referenceNode,
1166
- targetNextSibling
1208
+ oldNode,
1209
+ insertBeforeNode,
1210
+ processedNodes
1167
1211
  );
1168
- if (oldNode && oldNode !== newChild) {
1169
- processedNodes.delete(oldNode);
1170
- }
1171
- processedNodes.add(newChild);
1212
+ insertionIndex.value++;
1172
1213
  } else {
1173
- removeNodeIfNotPreserved(element, oldNode);
1214
+ const targetNode = insertionIndex.value < element.childNodes.length ? element.childNodes[insertionIndex.value] : null;
1174
1215
  if (typeof newChild === "string" || typeof newChild === "number") {
1175
1216
  const newTextNode = document.createTextNode(String(newChild));
1176
- element.insertBefore(newTextNode, oldNode?.nextSibling || null);
1217
+ newTextNode.__wsxManaged = true;
1218
+ if (oldNode && oldNode === targetNode && oldNode.parentNode === element) {
1219
+ element.replaceChild(newTextNode, oldNode);
1220
+ } else {
1221
+ element.insertBefore(newTextNode, targetNode);
1222
+ removeNodeIfNotPreserved(element, oldNode);
1223
+ }
1177
1224
  processedNodes.add(newTextNode);
1225
+ insertionIndex.value++;
1178
1226
  } else if (newChild instanceof DocumentFragment) {
1179
- element.insertBefore(newChild, oldNode?.nextSibling || null);
1227
+ if (processedNodes) {
1228
+ for (let i2 = 0; i2 < newChild.childNodes.length; i2++) {
1229
+ processedNodes.add(newChild.childNodes[i2]);
1230
+ }
1231
+ }
1232
+ element.insertBefore(newChild, targetNode);
1233
+ removeNodeIfNotPreserved(element, oldNode);
1180
1234
  }
1181
1235
  }
1182
1236
  }
@@ -1298,7 +1352,9 @@ function Fragment(_props, children) {
1298
1352
  return;
1299
1353
  }
1300
1354
  if (typeof child === "string" || typeof child === "number") {
1301
- fragment.appendChild(document.createTextNode(String(child)));
1355
+ const textNode = document.createTextNode(String(child));
1356
+ textNode.__wsxManaged = true;
1357
+ fragment.appendChild(textNode);
1302
1358
  } else if (child instanceof HTMLElement || child instanceof SVGElement) {
1303
1359
  fragment.appendChild(child);
1304
1360
  } else if (child instanceof DocumentFragment) {
package/dist/jsx.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Fragment,
3
3
  h
4
- } from "./chunk-DYG2LIOG.mjs";
4
+ } from "./chunk-2ER76KOQ.mjs";
5
5
  export {
6
6
  Fragment,
7
7
  h