@wsxjs/wsx-core 0.0.23 → 0.0.24

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
@@ -100,6 +100,7 @@ var _RenderContext = class _RenderContext {
100
100
  * @param fn The function to execute (usually the render method).
101
101
  */
102
102
  static runInContext(component, fn) {
103
+ resetCounterForNewRenderCycle(component);
103
104
  const prev = _RenderContext.current;
104
105
  _RenderContext.current = component;
105
106
  try {
@@ -125,21 +126,20 @@ _RenderContext.current = null;
125
126
  var RenderContext = _RenderContext;
126
127
 
127
128
  // src/utils/cache-key.ts
128
- var POSITION_ID_KEY = "__wsxPositionId";
129
129
  var INDEX_KEY = "__wsxIndex";
130
130
  var componentElementCounters = /* @__PURE__ */ new WeakMap();
131
131
  var componentIdCache = /* @__PURE__ */ new WeakMap();
132
132
  function generateCacheKey(tag, props, componentId, component) {
133
- const positionId = props?.[POSITION_ID_KEY];
134
133
  const userKey = props?.key;
135
134
  const index = props?.[INDEX_KEY];
135
+ const positionId = props?.__wsxPositionId;
136
136
  if (userKey !== void 0 && userKey !== null) {
137
137
  return `${componentId}:${tag}:key-${String(userKey)}`;
138
138
  }
139
139
  if (index !== void 0 && index !== null) {
140
140
  return `${componentId}:${tag}:idx-${String(index)}`;
141
141
  }
142
- if (positionId !== void 0 && positionId !== null && positionId !== "no-id") {
142
+ if (positionId !== void 0 && positionId !== null) {
143
143
  return `${componentId}:${tag}:${String(positionId)}`;
144
144
  }
145
145
  if (component) {
@@ -150,6 +150,9 @@ function generateCacheKey(tag, props, componentId, component) {
150
150
  }
151
151
  return `${componentId}:${tag}:fallback-${Date.now()}-${Math.random()}`;
152
152
  }
153
+ function resetCounterForNewRenderCycle(component) {
154
+ componentElementCounters.set(component, 0);
155
+ }
153
156
  function getComponentId() {
154
157
  const component = RenderContext.getCurrentComponent();
155
158
  if (component) {
@@ -567,7 +570,9 @@ function applySingleProp(element, key, value, tag, isSVG) {
567
570
  }
568
571
  if (key.startsWith("on") && typeof value === "function") {
569
572
  const eventName = key.slice(2).toLowerCase();
573
+ const listenerKey = `__wsxListener_${eventName}`;
570
574
  element.addEventListener(eventName, value);
575
+ element[listenerKey] = value;
571
576
  return;
572
577
  }
573
578
  if (typeof value === "boolean") {
@@ -662,7 +667,7 @@ function findElementNode(oldChild, parent) {
662
667
  function findTextNode(parent, domIndex) {
663
668
  while (domIndex.value < parent.childNodes.length) {
664
669
  const node = parent.childNodes[domIndex.value];
665
- if (node.nodeType === Node.TEXT_NODE) {
670
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
666
671
  const textNode = node;
667
672
  domIndex.value++;
668
673
  return textNode;
@@ -676,13 +681,23 @@ function updateOrCreateTextNode(parent, oldNode, newText) {
676
681
  if (oldNode.textContent !== newText) {
677
682
  oldNode.textContent = newText;
678
683
  }
684
+ return oldNode;
679
685
  } else {
686
+ if (!oldNode) {
687
+ for (let i = 0; i < parent.childNodes.length; i++) {
688
+ const node = parent.childNodes[i];
689
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent && node.textContent === newText) {
690
+ return node;
691
+ }
692
+ }
693
+ }
680
694
  const newTextNode = document.createTextNode(newText);
681
695
  if (oldNode && !shouldPreserveElement(oldNode)) {
682
696
  parent.replaceChild(newTextNode, oldNode);
683
697
  } else {
684
698
  parent.insertBefore(newTextNode, oldNode || null);
685
699
  }
700
+ return newTextNode;
686
701
  }
687
702
  }
688
703
  function removeNodeIfNotPreserved(parent, node) {
@@ -691,29 +706,66 @@ function removeNodeIfNotPreserved(parent, node) {
691
706
  }
692
707
  }
693
708
  function replaceOrInsertElement(parent, newChild, oldNode) {
709
+ const targetNextSibling = oldNode && shouldPreserveElement(oldNode) ? oldNode : oldNode?.nextSibling || null;
710
+ replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling);
711
+ }
712
+ function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling) {
694
713
  if (newChild.parentNode && newChild.parentNode !== parent) {
695
714
  newChild.parentNode.removeChild(newChild);
696
715
  }
697
- if (oldNode && !shouldPreserveElement(oldNode)) {
716
+ const isInCorrectPosition = newChild.parentNode === parent && newChild.nextSibling === targetNextSibling;
717
+ if (isInCorrectPosition) {
718
+ return;
719
+ }
720
+ if (newChild.parentNode === parent) {
721
+ parent.insertBefore(newChild, targetNextSibling);
722
+ return;
723
+ }
724
+ if (oldNode && oldNode.parentNode === parent && !shouldPreserveElement(oldNode)) {
698
725
  if (oldNode !== newChild) {
699
726
  parent.replaceChild(newChild, oldNode);
700
727
  }
701
- } else if (newChild.parentNode !== parent) {
702
- parent.insertBefore(newChild, oldNode || null);
728
+ } else {
729
+ if (newChild.parentNode === parent) {
730
+ return;
731
+ }
732
+ const newChildCacheKey = getElementCacheKey(newChild);
733
+ if (!newChildCacheKey) {
734
+ const newChildContent = newChild.textContent || "";
735
+ const newChildTag = newChild.tagName.toLowerCase();
736
+ for (let i = 0; i < parent.childNodes.length; i++) {
737
+ const existingNode = parent.childNodes[i];
738
+ if (existingNode instanceof HTMLElement || existingNode instanceof SVGElement) {
739
+ const existingCacheKey = getElementCacheKey(existingNode);
740
+ if (!existingCacheKey && existingNode.tagName.toLowerCase() === newChildTag && existingNode.textContent === newChildContent && existingNode !== newChild) {
741
+ return;
742
+ }
743
+ }
744
+ }
745
+ }
746
+ parent.insertBefore(newChild, targetNextSibling);
703
747
  }
704
748
  }
705
- function appendNewChild(parent, child) {
749
+ function appendNewChild(parent, child, processedNodes) {
706
750
  if (child === null || child === void 0 || child === false) {
707
751
  return;
708
752
  }
709
753
  if (typeof child === "string" || typeof child === "number") {
710
- parent.appendChild(document.createTextNode(String(child)));
754
+ const newTextNode = document.createTextNode(String(child));
755
+ parent.appendChild(newTextNode);
756
+ if (processedNodes) {
757
+ processedNodes.add(newTextNode);
758
+ }
711
759
  } else if (child instanceof HTMLElement || child instanceof SVGElement) {
760
+ if (child.parentNode === parent) {
761
+ return;
762
+ }
712
763
  if (child.parentNode && child.parentNode !== parent) {
713
764
  child.parentNode.removeChild(child);
714
765
  }
715
- if (child.parentNode !== parent) {
716
- parent.appendChild(child);
766
+ parent.appendChild(child);
767
+ if (processedNodes) {
768
+ processedNodes.add(child);
717
769
  }
718
770
  } else if (child instanceof DocumentFragment) {
719
771
  parent.appendChild(child);
@@ -735,10 +787,22 @@ function buildNewChildrenMaps(flatNew) {
735
787
  }
736
788
  return { elementSet, cacheKeyMap };
737
789
  }
738
- function shouldRemoveNode(node, elementSet, cacheKeyMap) {
790
+ function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
739
791
  if (shouldPreserveElement(node)) {
740
792
  return false;
741
793
  }
794
+ if (node.nodeType === Node.TEXT_NODE && processedNodes && processedNodes.has(node)) {
795
+ return false;
796
+ }
797
+ if (node.nodeType === Node.TEXT_NODE && processedNodes) {
798
+ let parent = node.parentNode;
799
+ while (parent) {
800
+ if (processedNodes.has(parent) && parent.parentNode) {
801
+ return false;
802
+ }
803
+ parent = parent.parentNode;
804
+ }
805
+ }
742
806
  if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
743
807
  if (elementSet.has(node)) {
744
808
  return false;
@@ -767,24 +831,39 @@ function deduplicateCacheKeys(parent, cacheKeyMap) {
767
831
  if (child !== newChild) {
768
832
  parent.replaceChild(newChild, child);
769
833
  }
834
+ } else if (cacheKey && cacheKeyMap.has(cacheKey) && processedCacheKeys.has(cacheKey)) {
835
+ const newChild = cacheKeyMap.get(cacheKey);
836
+ if (child !== newChild) {
837
+ parent.removeChild(child);
838
+ }
770
839
  }
771
840
  }
772
841
  }
773
842
  }
774
- function collectNodesToRemove(parent, elementSet, cacheKeyMap) {
843
+ function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
775
844
  const nodesToRemove = [];
776
845
  for (let i = 0; i < parent.childNodes.length; i++) {
777
846
  const node = parent.childNodes[i];
778
- if (shouldRemoveNode(node, elementSet, cacheKeyMap)) {
847
+ if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
779
848
  nodesToRemove.push(node);
780
849
  }
781
850
  }
782
851
  return nodesToRemove;
783
852
  }
784
- function removeNodes(parent, nodes) {
853
+ function removeNodes(parent, nodes, cacheManager) {
785
854
  for (let i = nodes.length - 1; i >= 0; i--) {
786
855
  const node = nodes[i];
787
856
  if (node.parentNode === parent) {
857
+ if (cacheManager && (node instanceof HTMLElement || node instanceof SVGElement)) {
858
+ const metadata = cacheManager.getMetadata(node);
859
+ const refCallback = metadata?.ref;
860
+ if (typeof refCallback === "function") {
861
+ try {
862
+ refCallback(null);
863
+ } catch {
864
+ }
865
+ }
866
+ }
788
867
  parent.removeChild(node);
789
868
  }
790
869
  }
@@ -804,6 +883,12 @@ function flattenChildrenSafe(children) {
804
883
  function removeProp(element, key, oldValue, tag) {
805
884
  const isSVG = shouldUseSVGNamespace(tag);
806
885
  if (key === "ref") {
886
+ if (typeof oldValue === "function") {
887
+ try {
888
+ oldValue(null);
889
+ } catch {
890
+ }
891
+ }
807
892
  return;
808
893
  }
809
894
  if (key === "className" || key === "class") {
@@ -819,6 +904,13 @@ function removeProp(element, key, oldValue, tag) {
819
904
  return;
820
905
  }
821
906
  if (key.startsWith("on") && typeof oldValue === "function") {
907
+ const eventName = key.slice(2).toLowerCase();
908
+ const listenerKey = `__wsxListener_${eventName}`;
909
+ const savedListener = element[listenerKey];
910
+ if (savedListener) {
911
+ element.removeEventListener(eventName, savedListener);
912
+ delete element[listenerKey];
913
+ }
822
914
  return;
823
915
  }
824
916
  if (key === "value") {
@@ -862,7 +954,13 @@ function applySingleProp2(element, key, value, tag, isSVG) {
862
954
  }
863
955
  if (key.startsWith("on") && typeof value === "function") {
864
956
  const eventName = key.slice(2).toLowerCase();
957
+ const listenerKey = `__wsxListener_${eventName}`;
958
+ const oldListener = element[listenerKey];
959
+ if (oldListener) {
960
+ element.removeEventListener(eventName, oldListener);
961
+ }
865
962
  element.addEventListener(eventName, value);
963
+ element[listenerKey] = value;
866
964
  return;
867
965
  }
868
966
  if (typeof value === "boolean") {
@@ -917,12 +1015,13 @@ function updateProps(element, oldProps, newProps, tag) {
917
1015
  applySingleProp2(element, key, newValue, tag, isSVG);
918
1016
  }
919
1017
  }
920
- function updateChildren(element, oldChildren, newChildren, cacheManager) {
1018
+ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
921
1019
  const flatOld = flattenChildrenSafe(oldChildren);
922
1020
  const flatNew = flattenChildrenSafe(newChildren);
923
1021
  const preservedElements = collectPreservedElements(element);
924
1022
  const minLength = Math.min(flatOld.length, flatNew.length);
925
1023
  const domIndex = { value: 0 };
1024
+ const processedNodes = /* @__PURE__ */ new Set();
926
1025
  for (let i = 0; i < minLength; i++) {
927
1026
  const oldChild = flatOld[i];
928
1027
  const newChild = flatNew[i];
@@ -938,9 +1037,10 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
938
1037
  } else if (typeof oldChild === "string" || typeof oldChild === "number") {
939
1038
  oldNode = findTextNode(element, domIndex);
940
1039
  if (!oldNode && element.childNodes.length > 0) {
1040
+ const oldText = String(oldChild);
941
1041
  for (let j = domIndex.value; j < element.childNodes.length; j++) {
942
1042
  const node = element.childNodes[j];
943
- if (node.nodeType === Node.TEXT_NODE) {
1043
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
944
1044
  oldNode = node;
945
1045
  domIndex.value = j + 1;
946
1046
  break;
@@ -954,7 +1054,14 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
954
1054
  const newText = String(newChild);
955
1055
  const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
956
1056
  if (needsUpdate) {
957
- updateOrCreateTextNode(element, oldNode, newText);
1057
+ const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
1058
+ if (updatedNode && !processedNodes.has(updatedNode)) {
1059
+ processedNodes.add(updatedNode);
1060
+ }
1061
+ } else {
1062
+ if (oldNode && oldNode.parentNode === element) {
1063
+ processedNodes.add(oldNode);
1064
+ }
958
1065
  }
959
1066
  } else {
960
1067
  removeNodeIfNotPreserved(element, oldNode);
@@ -968,30 +1075,48 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
968
1075
  if (oldNode && shouldPreserveElement(oldNode)) {
969
1076
  continue;
970
1077
  }
971
- if (newChild === oldChild && (newChild instanceof HTMLElement || newChild instanceof SVGElement)) {
972
- if (cacheManager) {
973
- const childMetadata = cacheManager.getMetadata(newChild);
974
- if (childMetadata) {
975
- if (oldNode === newChild && newChild.parentNode === element) {
976
- continue;
1078
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
1079
+ let targetNextSibling = null;
1080
+ let foundPreviousElement = false;
1081
+ for (let j = i - 1; j >= 0; j--) {
1082
+ const prevChild = flatNew[j];
1083
+ if (prevChild instanceof HTMLElement || prevChild instanceof SVGElement) {
1084
+ if (prevChild.parentNode === element) {
1085
+ targetNextSibling = prevChild.nextSibling;
1086
+ foundPreviousElement = true;
1087
+ break;
977
1088
  }
978
1089
  }
979
- } else {
980
- if (oldNode === newChild && newChild.parentNode === element) {
981
- continue;
982
- }
983
1090
  }
984
- }
985
- if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
986
- if (newChild.parentNode === element && oldNode === newChild) {
1091
+ if (!foundPreviousElement) {
1092
+ const firstChild = Array.from(element.childNodes).find(
1093
+ (node) => !shouldPreserveElement(node) && !processedNodes.has(node)
1094
+ );
1095
+ targetNextSibling = firstChild || null;
1096
+ }
1097
+ const isInCorrectPosition = newChild.parentNode === element && newChild.nextSibling === targetNextSibling;
1098
+ if (newChild === oldChild && isInCorrectPosition) {
1099
+ if (oldNode) processedNodes.add(oldNode);
1100
+ processedNodes.add(newChild);
987
1101
  continue;
988
1102
  }
989
- replaceOrInsertElement(element, newChild, oldNode);
1103
+ const referenceNode = oldNode && oldNode.parentNode === element ? oldNode : null;
1104
+ replaceOrInsertElementAtPosition(
1105
+ element,
1106
+ newChild,
1107
+ referenceNode,
1108
+ targetNextSibling
1109
+ );
1110
+ if (oldNode && oldNode !== newChild) {
1111
+ processedNodes.delete(oldNode);
1112
+ }
1113
+ processedNodes.add(newChild);
990
1114
  } else {
991
1115
  removeNodeIfNotPreserved(element, oldNode);
992
1116
  if (typeof newChild === "string" || typeof newChild === "number") {
993
1117
  const newTextNode = document.createTextNode(String(newChild));
994
1118
  element.insertBefore(newTextNode, oldNode?.nextSibling || null);
1119
+ processedNodes.add(newTextNode);
995
1120
  } else if (newChild instanceof DocumentFragment) {
996
1121
  element.insertBefore(newChild, oldNode?.nextSibling || null);
997
1122
  }
@@ -999,12 +1124,12 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
999
1124
  }
1000
1125
  }
1001
1126
  for (let i = minLength; i < flatNew.length; i++) {
1002
- appendNewChild(element, flatNew[i]);
1127
+ appendNewChild(element, flatNew[i], processedNodes);
1003
1128
  }
1004
1129
  const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
1005
1130
  deduplicateCacheKeys(element, cacheKeyMap);
1006
- const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap);
1007
- removeNodes(element, nodesToRemove);
1131
+ const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap, processedNodes);
1132
+ removeNodes(element, nodesToRemove, _cacheManager);
1008
1133
  reinsertPreservedElements(element, preservedElements);
1009
1134
  }
1010
1135
  function updateElement(element, newProps, newChildren, tag, cacheManager) {
package/dist/jsx.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Fragment,
3
3
  h
4
- } from "./chunk-ESZYREJK.mjs";
4
+ } from "./chunk-5Q2VEEUH.mjs";
5
5
  export {
6
6
  Fragment,
7
7
  h