@wsxjs/wsx-core 0.0.22 → 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.
@@ -73,6 +73,7 @@ var _RenderContext = class _RenderContext {
73
73
  * @param fn The function to execute (usually the render method).
74
74
  */
75
75
  static runInContext(component, fn) {
76
+ resetCounterForNewRenderCycle(component);
76
77
  const prev = _RenderContext.current;
77
78
  _RenderContext.current = component;
78
79
  try {
@@ -98,21 +99,20 @@ _RenderContext.current = null;
98
99
  var RenderContext = _RenderContext;
99
100
 
100
101
  // src/utils/cache-key.ts
101
- var POSITION_ID_KEY = "__wsxPositionId";
102
102
  var INDEX_KEY = "__wsxIndex";
103
103
  var componentElementCounters = /* @__PURE__ */ new WeakMap();
104
104
  var componentIdCache = /* @__PURE__ */ new WeakMap();
105
105
  function generateCacheKey(tag, props, componentId, component) {
106
- const positionId = props?.[POSITION_ID_KEY];
107
106
  const userKey = props?.key;
108
107
  const index = props?.[INDEX_KEY];
108
+ const positionId = props?.__wsxPositionId;
109
109
  if (userKey !== void 0 && userKey !== null) {
110
110
  return `${componentId}:${tag}:key-${String(userKey)}`;
111
111
  }
112
112
  if (index !== void 0 && index !== null) {
113
113
  return `${componentId}:${tag}:idx-${String(index)}`;
114
114
  }
115
- if (positionId !== void 0 && positionId !== null && positionId !== "no-id") {
115
+ if (positionId !== void 0 && positionId !== null) {
116
116
  return `${componentId}:${tag}:${String(positionId)}`;
117
117
  }
118
118
  if (component) {
@@ -123,6 +123,9 @@ function generateCacheKey(tag, props, componentId, component) {
123
123
  }
124
124
  return `${componentId}:${tag}:fallback-${Date.now()}-${Math.random()}`;
125
125
  }
126
+ function resetCounterForNewRenderCycle(component) {
127
+ componentElementCounters.set(component, 0);
128
+ }
126
129
  function getComponentId() {
127
130
  const component = RenderContext.getCurrentComponent();
128
131
  if (component) {
@@ -540,7 +543,9 @@ function applySingleProp(element, key, value, tag, isSVG) {
540
543
  }
541
544
  if (key.startsWith("on") && typeof value === "function") {
542
545
  const eventName = key.slice(2).toLowerCase();
546
+ const listenerKey = `__wsxListener_${eventName}`;
543
547
  element.addEventListener(eventName, value);
548
+ element[listenerKey] = value;
544
549
  return;
545
550
  }
546
551
  if (typeof value === "boolean") {
@@ -594,10 +599,269 @@ function createElementWithPropsAndChildren(tag, props, children) {
594
599
  return element;
595
600
  }
596
601
 
602
+ // src/utils/update-children-helpers.ts
603
+ function collectPreservedElements(element) {
604
+ const preserved = [];
605
+ for (let i = 0; i < element.childNodes.length; i++) {
606
+ const child = element.childNodes[i];
607
+ if (shouldPreserveElement(child)) {
608
+ preserved.push(child);
609
+ }
610
+ }
611
+ return preserved;
612
+ }
613
+ function findDOMNodeByReference(oldChild, parent) {
614
+ if (oldChild.parentNode === parent && !shouldPreserveElement(oldChild)) {
615
+ return oldChild;
616
+ }
617
+ return null;
618
+ }
619
+ function findDOMNodeByCacheKey(cacheKey, parent) {
620
+ for (let i = 0; i < parent.childNodes.length; i++) {
621
+ const child = parent.childNodes[i];
622
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
623
+ if (shouldPreserveElement(child)) continue;
624
+ if (getElementCacheKey(child) === cacheKey) {
625
+ return child;
626
+ }
627
+ }
628
+ }
629
+ return null;
630
+ }
631
+ function findElementNode(oldChild, parent) {
632
+ const byRef = findDOMNodeByReference(oldChild, parent);
633
+ if (byRef) return byRef;
634
+ const cacheKey = getElementCacheKey(oldChild);
635
+ if (cacheKey) {
636
+ return findDOMNodeByCacheKey(cacheKey, parent);
637
+ }
638
+ return null;
639
+ }
640
+ function findTextNode(parent, domIndex) {
641
+ while (domIndex.value < parent.childNodes.length) {
642
+ const node = parent.childNodes[domIndex.value];
643
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
644
+ const textNode = node;
645
+ domIndex.value++;
646
+ return textNode;
647
+ }
648
+ domIndex.value++;
649
+ }
650
+ return null;
651
+ }
652
+ function updateOrCreateTextNode(parent, oldNode, newText) {
653
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
654
+ if (oldNode.textContent !== newText) {
655
+ oldNode.textContent = newText;
656
+ }
657
+ return oldNode;
658
+ } else {
659
+ if (!oldNode) {
660
+ for (let i = 0; i < parent.childNodes.length; i++) {
661
+ const node = parent.childNodes[i];
662
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent && node.textContent === newText) {
663
+ return node;
664
+ }
665
+ }
666
+ }
667
+ const newTextNode = document.createTextNode(newText);
668
+ if (oldNode && !shouldPreserveElement(oldNode)) {
669
+ parent.replaceChild(newTextNode, oldNode);
670
+ } else {
671
+ parent.insertBefore(newTextNode, oldNode || null);
672
+ }
673
+ return newTextNode;
674
+ }
675
+ }
676
+ function removeNodeIfNotPreserved(parent, node) {
677
+ if (node && !shouldPreserveElement(node) && node.parentNode === parent) {
678
+ parent.removeChild(node);
679
+ }
680
+ }
681
+ function replaceOrInsertElement(parent, newChild, oldNode) {
682
+ const targetNextSibling = oldNode && shouldPreserveElement(oldNode) ? oldNode : oldNode?.nextSibling || null;
683
+ replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling);
684
+ }
685
+ function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling) {
686
+ if (newChild.parentNode && newChild.parentNode !== parent) {
687
+ newChild.parentNode.removeChild(newChild);
688
+ }
689
+ const isInCorrectPosition = newChild.parentNode === parent && newChild.nextSibling === targetNextSibling;
690
+ if (isInCorrectPosition) {
691
+ return;
692
+ }
693
+ if (newChild.parentNode === parent) {
694
+ parent.insertBefore(newChild, targetNextSibling);
695
+ return;
696
+ }
697
+ if (oldNode && oldNode.parentNode === parent && !shouldPreserveElement(oldNode)) {
698
+ if (oldNode !== newChild) {
699
+ parent.replaceChild(newChild, oldNode);
700
+ }
701
+ } else {
702
+ if (newChild.parentNode === parent) {
703
+ return;
704
+ }
705
+ const newChildCacheKey = getElementCacheKey(newChild);
706
+ if (!newChildCacheKey) {
707
+ const newChildContent = newChild.textContent || "";
708
+ const newChildTag = newChild.tagName.toLowerCase();
709
+ for (let i = 0; i < parent.childNodes.length; i++) {
710
+ const existingNode = parent.childNodes[i];
711
+ if (existingNode instanceof HTMLElement || existingNode instanceof SVGElement) {
712
+ const existingCacheKey = getElementCacheKey(existingNode);
713
+ if (!existingCacheKey && existingNode.tagName.toLowerCase() === newChildTag && existingNode.textContent === newChildContent && existingNode !== newChild) {
714
+ return;
715
+ }
716
+ }
717
+ }
718
+ }
719
+ parent.insertBefore(newChild, targetNextSibling);
720
+ }
721
+ }
722
+ function appendNewChild(parent, child, processedNodes) {
723
+ if (child === null || child === void 0 || child === false) {
724
+ return;
725
+ }
726
+ if (typeof child === "string" || typeof child === "number") {
727
+ const newTextNode = document.createTextNode(String(child));
728
+ parent.appendChild(newTextNode);
729
+ if (processedNodes) {
730
+ processedNodes.add(newTextNode);
731
+ }
732
+ } else if (child instanceof HTMLElement || child instanceof SVGElement) {
733
+ if (child.parentNode === parent) {
734
+ return;
735
+ }
736
+ if (child.parentNode && child.parentNode !== parent) {
737
+ child.parentNode.removeChild(child);
738
+ }
739
+ parent.appendChild(child);
740
+ if (processedNodes) {
741
+ processedNodes.add(child);
742
+ }
743
+ } else if (child instanceof DocumentFragment) {
744
+ parent.appendChild(child);
745
+ }
746
+ }
747
+ function buildNewChildrenMaps(flatNew) {
748
+ const elementSet = /* @__PURE__ */ new Set();
749
+ const cacheKeyMap = /* @__PURE__ */ new Map();
750
+ for (const child of flatNew) {
751
+ if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
752
+ elementSet.add(child);
753
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
754
+ const cacheKey = getElementCacheKey(child);
755
+ if (cacheKey) {
756
+ cacheKeyMap.set(cacheKey, child);
757
+ }
758
+ }
759
+ }
760
+ }
761
+ return { elementSet, cacheKeyMap };
762
+ }
763
+ function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
764
+ if (shouldPreserveElement(node)) {
765
+ return false;
766
+ }
767
+ if (node.nodeType === Node.TEXT_NODE && processedNodes && processedNodes.has(node)) {
768
+ return false;
769
+ }
770
+ if (node.nodeType === Node.TEXT_NODE && processedNodes) {
771
+ let parent = node.parentNode;
772
+ while (parent) {
773
+ if (processedNodes.has(parent) && parent.parentNode) {
774
+ return false;
775
+ }
776
+ parent = parent.parentNode;
777
+ }
778
+ }
779
+ if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
780
+ if (elementSet.has(node)) {
781
+ return false;
782
+ }
783
+ if (node instanceof HTMLElement || node instanceof SVGElement) {
784
+ const cacheKey = getElementCacheKey(node);
785
+ if (cacheKey && cacheKeyMap.has(cacheKey)) {
786
+ return false;
787
+ }
788
+ }
789
+ }
790
+ return true;
791
+ }
792
+ function deduplicateCacheKeys(parent, cacheKeyMap) {
793
+ const processedCacheKeys = /* @__PURE__ */ new Set();
794
+ for (let i = parent.childNodes.length - 1; i >= 0; i--) {
795
+ const child = parent.childNodes[i];
796
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
797
+ if (shouldPreserveElement(child)) {
798
+ continue;
799
+ }
800
+ const cacheKey = getElementCacheKey(child);
801
+ if (cacheKey && cacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
802
+ processedCacheKeys.add(cacheKey);
803
+ const newChild = cacheKeyMap.get(cacheKey);
804
+ if (child !== newChild) {
805
+ parent.replaceChild(newChild, child);
806
+ }
807
+ } else if (cacheKey && cacheKeyMap.has(cacheKey) && processedCacheKeys.has(cacheKey)) {
808
+ const newChild = cacheKeyMap.get(cacheKey);
809
+ if (child !== newChild) {
810
+ parent.removeChild(child);
811
+ }
812
+ }
813
+ }
814
+ }
815
+ }
816
+ function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
817
+ const nodesToRemove = [];
818
+ for (let i = 0; i < parent.childNodes.length; i++) {
819
+ const node = parent.childNodes[i];
820
+ if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
821
+ nodesToRemove.push(node);
822
+ }
823
+ }
824
+ return nodesToRemove;
825
+ }
826
+ function removeNodes(parent, nodes, cacheManager) {
827
+ for (let i = nodes.length - 1; i >= 0; i--) {
828
+ const node = nodes[i];
829
+ if (node.parentNode === parent) {
830
+ if (cacheManager && (node instanceof HTMLElement || node instanceof SVGElement)) {
831
+ const metadata = cacheManager.getMetadata(node);
832
+ const refCallback = metadata?.ref;
833
+ if (typeof refCallback === "function") {
834
+ try {
835
+ refCallback(null);
836
+ } catch {
837
+ }
838
+ }
839
+ }
840
+ parent.removeChild(node);
841
+ }
842
+ }
843
+ }
844
+ function reinsertPreservedElements(parent, preservedElements) {
845
+ for (const element of preservedElements) {
846
+ if (element.parentNode !== parent) {
847
+ parent.appendChild(element);
848
+ }
849
+ }
850
+ }
851
+ function flattenChildrenSafe(children) {
852
+ return flattenChildren(children);
853
+ }
854
+
597
855
  // src/utils/element-update.ts
598
856
  function removeProp(element, key, oldValue, tag) {
599
857
  const isSVG = shouldUseSVGNamespace(tag);
600
858
  if (key === "ref") {
859
+ if (typeof oldValue === "function") {
860
+ try {
861
+ oldValue(null);
862
+ } catch {
863
+ }
864
+ }
601
865
  return;
602
866
  }
603
867
  if (key === "className" || key === "class") {
@@ -613,6 +877,13 @@ function removeProp(element, key, oldValue, tag) {
613
877
  return;
614
878
  }
615
879
  if (key.startsWith("on") && typeof oldValue === "function") {
880
+ const eventName = key.slice(2).toLowerCase();
881
+ const listenerKey = `__wsxListener_${eventName}`;
882
+ const savedListener = element[listenerKey];
883
+ if (savedListener) {
884
+ element.removeEventListener(eventName, savedListener);
885
+ delete element[listenerKey];
886
+ }
616
887
  return;
617
888
  }
618
889
  if (key === "value") {
@@ -656,7 +927,13 @@ function applySingleProp2(element, key, value, tag, isSVG) {
656
927
  }
657
928
  if (key.startsWith("on") && typeof value === "function") {
658
929
  const eventName = key.slice(2).toLowerCase();
930
+ const listenerKey = `__wsxListener_${eventName}`;
931
+ const oldListener = element[listenerKey];
932
+ if (oldListener) {
933
+ element.removeEventListener(eventName, oldListener);
934
+ }
659
935
  element.addEventListener(eventName, value);
936
+ element[listenerKey] = value;
660
937
  return;
661
938
  }
662
939
  if (typeof value === "boolean") {
@@ -711,49 +988,36 @@ function updateProps(element, oldProps, newProps, tag) {
711
988
  applySingleProp2(element, key, newValue, tag, isSVG);
712
989
  }
713
990
  }
714
- function updateChildren(element, oldChildren, newChildren) {
715
- const flatOld = flattenChildren(oldChildren);
716
- const flatNew = flattenChildren(newChildren);
991
+ function updateChildren(element, oldChildren, newChildren, _cacheManager) {
992
+ const flatOld = flattenChildrenSafe(oldChildren);
993
+ const flatNew = flattenChildrenSafe(newChildren);
994
+ const preservedElements = collectPreservedElements(element);
717
995
  const minLength = Math.min(flatOld.length, flatNew.length);
718
- let domIndex = 0;
996
+ const domIndex = { value: 0 };
997
+ const processedNodes = /* @__PURE__ */ new Set();
719
998
  for (let i = 0; i < minLength; i++) {
720
999
  const oldChild = flatOld[i];
721
1000
  const newChild = flatNew[i];
722
1001
  let oldNode = null;
723
1002
  if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
724
- if (oldChild.parentNode === element) {
725
- if (!shouldPreserveElement(oldChild)) {
726
- oldNode = oldChild;
727
- }
728
- } else {
729
- const oldCacheKey = getElementCacheKey(oldChild);
730
- if (oldCacheKey) {
731
- for (let j = 0; j < element.childNodes.length; j++) {
732
- const domChild = element.childNodes[j];
733
- if (domChild instanceof HTMLElement || domChild instanceof SVGElement) {
734
- if (shouldPreserveElement(domChild)) {
735
- continue;
736
- }
737
- const domCacheKey = getElementCacheKey(domChild);
738
- if (domCacheKey === oldCacheKey) {
739
- oldNode = domChild;
740
- break;
741
- }
742
- }
743
- }
1003
+ oldNode = findElementNode(oldChild, element);
1004
+ if (oldNode && oldNode.parentNode === element) {
1005
+ const nodeIndex = Array.from(element.childNodes).indexOf(oldNode);
1006
+ if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
1007
+ domIndex.value = nodeIndex + 1;
744
1008
  }
745
1009
  }
746
1010
  } else if (typeof oldChild === "string" || typeof oldChild === "number") {
747
- while (domIndex < element.childNodes.length) {
748
- const node = element.childNodes[domIndex];
749
- if (node.nodeType === Node.TEXT_NODE) {
750
- oldNode = node;
751
- domIndex++;
752
- break;
753
- } else if (node.nodeType === Node.ELEMENT_NODE) {
754
- domIndex++;
755
- } else {
756
- domIndex++;
1011
+ oldNode = findTextNode(element, domIndex);
1012
+ if (!oldNode && element.childNodes.length > 0) {
1013
+ const oldText = String(oldChild);
1014
+ for (let j = domIndex.value; j < element.childNodes.length; j++) {
1015
+ const node = element.childNodes[j];
1016
+ if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
1017
+ oldNode = node;
1018
+ domIndex.value = j + 1;
1019
+ break;
1020
+ }
757
1021
  }
758
1022
  }
759
1023
  }
@@ -762,27 +1026,20 @@ function updateChildren(element, oldChildren, newChildren) {
762
1026
  const oldText = String(oldChild);
763
1027
  const newText = String(newChild);
764
1028
  const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
765
- if (!needsUpdate) {
766
- continue;
767
- }
768
- if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
769
- oldNode.textContent = newText;
1029
+ if (needsUpdate) {
1030
+ const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
1031
+ if (updatedNode && !processedNodes.has(updatedNode)) {
1032
+ processedNodes.add(updatedNode);
1033
+ }
770
1034
  } else {
771
- const newTextNode = document.createTextNode(newText);
772
- if (oldNode && !shouldPreserveElement(oldNode)) {
773
- element.replaceChild(newTextNode, oldNode);
774
- } else {
775
- element.insertBefore(newTextNode, oldNode || null);
1035
+ if (oldNode && oldNode.parentNode === element) {
1036
+ processedNodes.add(oldNode);
776
1037
  }
777
1038
  }
778
1039
  } else {
779
- if (oldNode && !shouldPreserveElement(oldNode)) {
780
- element.removeChild(oldNode);
781
- }
1040
+ removeNodeIfNotPreserved(element, oldNode);
782
1041
  if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
783
- if (newChild.parentNode !== element) {
784
- element.insertBefore(newChild, oldNode || null);
785
- }
1042
+ replaceOrInsertElement(element, newChild, oldNode);
786
1043
  } else if (newChild instanceof DocumentFragment) {
787
1044
  element.insertBefore(newChild, oldNode || null);
788
1045
  }
@@ -791,54 +1048,48 @@ function updateChildren(element, oldChildren, newChildren) {
791
1048
  if (oldNode && shouldPreserveElement(oldNode)) {
792
1049
  continue;
793
1050
  }
794
- if (newChild === oldChild) {
795
- continue;
796
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
797
- const oldCacheKey = oldNode && (oldNode instanceof HTMLElement || oldNode instanceof SVGElement) ? getElementCacheKey(oldNode) : null;
798
- const newCacheKey = getElementCacheKey(newChild);
799
- const hasSameCacheKey = oldCacheKey && newCacheKey && oldCacheKey === newCacheKey;
800
- if (oldNode) {
801
- if (!shouldPreserveElement(oldNode)) {
802
- if (oldNode !== newChild) {
803
- if (newChild.parentNode === element) {
804
- if (hasSameCacheKey) {
805
- if (newChild !== oldNode) {
806
- element.replaceChild(newChild, oldNode);
807
- }
808
- } else {
809
- element.removeChild(newChild);
810
- element.replaceChild(newChild, oldNode);
811
- }
812
- } else if (newChild.parentNode) {
813
- newChild.parentNode.removeChild(newChild);
814
- element.replaceChild(newChild, oldNode);
815
- } else {
816
- element.replaceChild(newChild, oldNode);
817
- }
818
- }
819
- } else {
820
- if (newChild.parentNode !== element) {
821
- if (newChild.parentNode) {
822
- newChild.parentNode.removeChild(newChild);
823
- }
824
- element.insertBefore(newChild, oldNode.nextSibling);
1051
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
1052
+ let targetNextSibling = null;
1053
+ let foundPreviousElement = false;
1054
+ for (let j = i - 1; j >= 0; j--) {
1055
+ const prevChild = flatNew[j];
1056
+ if (prevChild instanceof HTMLElement || prevChild instanceof SVGElement) {
1057
+ if (prevChild.parentNode === element) {
1058
+ targetNextSibling = prevChild.nextSibling;
1059
+ foundPreviousElement = true;
1060
+ break;
825
1061
  }
826
1062
  }
827
- } else {
828
- if (newChild.parentNode !== element) {
829
- if (newChild.parentNode) {
830
- newChild.parentNode.removeChild(newChild);
831
- }
832
- element.appendChild(newChild);
833
- }
834
1063
  }
835
- } else {
836
- if (oldNode && !shouldPreserveElement(oldNode)) {
837
- element.removeChild(oldNode);
1064
+ if (!foundPreviousElement) {
1065
+ const firstChild = Array.from(element.childNodes).find(
1066
+ (node) => !shouldPreserveElement(node) && !processedNodes.has(node)
1067
+ );
1068
+ targetNextSibling = firstChild || null;
1069
+ }
1070
+ const isInCorrectPosition = newChild.parentNode === element && newChild.nextSibling === targetNextSibling;
1071
+ if (newChild === oldChild && isInCorrectPosition) {
1072
+ if (oldNode) processedNodes.add(oldNode);
1073
+ processedNodes.add(newChild);
1074
+ continue;
1075
+ }
1076
+ const referenceNode = oldNode && oldNode.parentNode === element ? oldNode : null;
1077
+ replaceOrInsertElementAtPosition(
1078
+ element,
1079
+ newChild,
1080
+ referenceNode,
1081
+ targetNextSibling
1082
+ );
1083
+ if (oldNode && oldNode !== newChild) {
1084
+ processedNodes.delete(oldNode);
838
1085
  }
1086
+ processedNodes.add(newChild);
1087
+ } else {
1088
+ removeNodeIfNotPreserved(element, oldNode);
839
1089
  if (typeof newChild === "string" || typeof newChild === "number") {
840
1090
  const newTextNode = document.createTextNode(String(newChild));
841
1091
  element.insertBefore(newTextNode, oldNode?.nextSibling || null);
1092
+ processedNodes.add(newTextNode);
842
1093
  } else if (newChild instanceof DocumentFragment) {
843
1094
  element.insertBefore(newChild, oldNode?.nextSibling || null);
844
1095
  }
@@ -846,98 +1097,13 @@ function updateChildren(element, oldChildren, newChildren) {
846
1097
  }
847
1098
  }
848
1099
  for (let i = minLength; i < flatNew.length; i++) {
849
- const newChild = flatNew[i];
850
- if (newChild === null || newChild === void 0 || newChild === false) {
851
- continue;
852
- }
853
- if (typeof newChild === "string" || typeof newChild === "number") {
854
- element.appendChild(document.createTextNode(String(newChild)));
855
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
856
- if (newChild.parentNode === element) {
857
- const currentIndex = Array.from(element.childNodes).indexOf(newChild);
858
- const expectedIndex = element.childNodes.length - 1;
859
- if (currentIndex !== expectedIndex) {
860
- element.removeChild(newChild);
861
- element.appendChild(newChild);
862
- }
863
- continue;
864
- } else if (newChild.parentNode) {
865
- newChild.parentNode.removeChild(newChild);
866
- }
867
- element.appendChild(newChild);
868
- } else if (newChild instanceof DocumentFragment) {
869
- element.appendChild(newChild);
870
- }
871
- }
872
- const nodesToRemove = [];
873
- const newChildSet = /* @__PURE__ */ new Set();
874
- const newChildCacheKeyMap = /* @__PURE__ */ new Map();
875
- for (const child of flatNew) {
876
- if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
877
- newChildSet.add(child);
878
- if (child instanceof HTMLElement || child instanceof SVGElement) {
879
- const cacheKey = getElementCacheKey(child);
880
- if (cacheKey) {
881
- newChildCacheKeyMap.set(cacheKey, child);
882
- }
883
- }
884
- }
885
- }
886
- const processedCacheKeys = /* @__PURE__ */ new Set();
887
- const newChildToIndexMap = /* @__PURE__ */ new Map();
888
- for (let i = 0; i < flatNew.length; i++) {
889
- const child = flatNew[i];
890
- if (child instanceof HTMLElement || child instanceof SVGElement) {
891
- newChildToIndexMap.set(child, i);
892
- }
893
- }
894
- for (let i = element.childNodes.length - 1; i >= 0; i--) {
895
- const child = element.childNodes[i];
896
- if (child instanceof HTMLElement || child instanceof SVGElement) {
897
- if (shouldPreserveElement(child)) {
898
- continue;
899
- }
900
- const cacheKey = getElementCacheKey(child);
901
- if (cacheKey && newChildCacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
902
- processedCacheKeys.add(cacheKey);
903
- const newChild = newChildCacheKeyMap.get(cacheKey);
904
- if (child !== newChild) {
905
- if (newChild.parentNode === element) {
906
- element.replaceChild(newChild, child);
907
- } else {
908
- element.replaceChild(newChild, child);
909
- }
910
- } else {
911
- }
912
- }
913
- }
914
- }
915
- for (let i = 0; i < element.childNodes.length; i++) {
916
- const child = element.childNodes[i];
917
- if (shouldPreserveElement(child)) {
918
- continue;
919
- }
920
- if (child instanceof HTMLElement || child instanceof SVGElement) {
921
- if (newChildSet.has(child)) {
922
- continue;
923
- }
924
- const cacheKey = getElementCacheKey(child);
925
- if (cacheKey && newChildCacheKeyMap.has(cacheKey)) {
926
- continue;
927
- }
928
- } else if (child instanceof DocumentFragment) {
929
- if (newChildSet.has(child)) {
930
- continue;
931
- }
932
- }
933
- nodesToRemove.push(child);
934
- }
935
- for (let i = nodesToRemove.length - 1; i >= 0; i--) {
936
- const node = nodesToRemove[i];
937
- if (node.parentNode === element) {
938
- element.removeChild(node);
939
- }
1100
+ appendNewChild(element, flatNew[i], processedNodes);
940
1101
  }
1102
+ const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
1103
+ deduplicateCacheKeys(element, cacheKeyMap);
1104
+ const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap, processedNodes);
1105
+ removeNodes(element, nodesToRemove, _cacheManager);
1106
+ reinsertPreservedElements(element, preservedElements);
941
1107
  }
942
1108
  function updateElement(element, newProps, newChildren, tag, cacheManager) {
943
1109
  const oldMetadata = cacheManager.getMetadata(element);
@@ -948,7 +1114,7 @@ function updateElement(element, newProps, newChildren, tag, cacheManager) {
948
1114
  children: newChildren
949
1115
  });
950
1116
  updateProps(element, oldProps, newProps, tag);
951
- updateChildren(element, oldChildren, newChildren);
1117
+ updateChildren(element, oldChildren, newChildren, cacheManager);
952
1118
  }
953
1119
 
954
1120
  // src/jsx-factory.ts