@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.
- package/dist/{chunk-OXFZ575O.mjs → chunk-5Q2VEEUH.mjs} +352 -186
- package/dist/index.js +418 -215
- package/dist/index.mjs +67 -30
- package/dist/jsx-runtime.js +352 -186
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/jsx.js +352 -186
- package/dist/jsx.mjs +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +2 -2
- package/src/base-component.ts +27 -0
- package/src/light-component.ts +20 -8
- package/src/render-context.ts +4 -0
- package/src/utils/cache-key.ts +27 -21
- package/src/utils/element-creation.ts +5 -0
- package/src/utils/element-update.ts +192 -309
- package/src/utils/update-children-helpers.ts +508 -0
- package/src/web-component.ts +72 -41
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
|
|
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") {
|
|
@@ -621,10 +626,269 @@ function createElementWithPropsAndChildren(tag, props, children) {
|
|
|
621
626
|
return element;
|
|
622
627
|
}
|
|
623
628
|
|
|
629
|
+
// src/utils/update-children-helpers.ts
|
|
630
|
+
function collectPreservedElements(element) {
|
|
631
|
+
const preserved = [];
|
|
632
|
+
for (let i = 0; i < element.childNodes.length; i++) {
|
|
633
|
+
const child = element.childNodes[i];
|
|
634
|
+
if (shouldPreserveElement(child)) {
|
|
635
|
+
preserved.push(child);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return preserved;
|
|
639
|
+
}
|
|
640
|
+
function findDOMNodeByReference(oldChild, parent) {
|
|
641
|
+
if (oldChild.parentNode === parent && !shouldPreserveElement(oldChild)) {
|
|
642
|
+
return oldChild;
|
|
643
|
+
}
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
function findDOMNodeByCacheKey(cacheKey, parent) {
|
|
647
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
648
|
+
const child = parent.childNodes[i];
|
|
649
|
+
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
650
|
+
if (shouldPreserveElement(child)) continue;
|
|
651
|
+
if (getElementCacheKey(child) === cacheKey) {
|
|
652
|
+
return child;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
function findElementNode(oldChild, parent) {
|
|
659
|
+
const byRef = findDOMNodeByReference(oldChild, parent);
|
|
660
|
+
if (byRef) return byRef;
|
|
661
|
+
const cacheKey = getElementCacheKey(oldChild);
|
|
662
|
+
if (cacheKey) {
|
|
663
|
+
return findDOMNodeByCacheKey(cacheKey, parent);
|
|
664
|
+
}
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
function findTextNode(parent, domIndex) {
|
|
668
|
+
while (domIndex.value < parent.childNodes.length) {
|
|
669
|
+
const node = parent.childNodes[domIndex.value];
|
|
670
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
|
|
671
|
+
const textNode = node;
|
|
672
|
+
domIndex.value++;
|
|
673
|
+
return textNode;
|
|
674
|
+
}
|
|
675
|
+
domIndex.value++;
|
|
676
|
+
}
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
function updateOrCreateTextNode(parent, oldNode, newText) {
|
|
680
|
+
if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
|
|
681
|
+
if (oldNode.textContent !== newText) {
|
|
682
|
+
oldNode.textContent = newText;
|
|
683
|
+
}
|
|
684
|
+
return oldNode;
|
|
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
|
+
}
|
|
694
|
+
const newTextNode = document.createTextNode(newText);
|
|
695
|
+
if (oldNode && !shouldPreserveElement(oldNode)) {
|
|
696
|
+
parent.replaceChild(newTextNode, oldNode);
|
|
697
|
+
} else {
|
|
698
|
+
parent.insertBefore(newTextNode, oldNode || null);
|
|
699
|
+
}
|
|
700
|
+
return newTextNode;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function removeNodeIfNotPreserved(parent, node) {
|
|
704
|
+
if (node && !shouldPreserveElement(node) && node.parentNode === parent) {
|
|
705
|
+
parent.removeChild(node);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
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) {
|
|
713
|
+
if (newChild.parentNode && newChild.parentNode !== parent) {
|
|
714
|
+
newChild.parentNode.removeChild(newChild);
|
|
715
|
+
}
|
|
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)) {
|
|
725
|
+
if (oldNode !== newChild) {
|
|
726
|
+
parent.replaceChild(newChild, oldNode);
|
|
727
|
+
}
|
|
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);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function appendNewChild(parent, child, processedNodes) {
|
|
750
|
+
if (child === null || child === void 0 || child === false) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
754
|
+
const newTextNode = document.createTextNode(String(child));
|
|
755
|
+
parent.appendChild(newTextNode);
|
|
756
|
+
if (processedNodes) {
|
|
757
|
+
processedNodes.add(newTextNode);
|
|
758
|
+
}
|
|
759
|
+
} else if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
760
|
+
if (child.parentNode === parent) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (child.parentNode && child.parentNode !== parent) {
|
|
764
|
+
child.parentNode.removeChild(child);
|
|
765
|
+
}
|
|
766
|
+
parent.appendChild(child);
|
|
767
|
+
if (processedNodes) {
|
|
768
|
+
processedNodes.add(child);
|
|
769
|
+
}
|
|
770
|
+
} else if (child instanceof DocumentFragment) {
|
|
771
|
+
parent.appendChild(child);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function buildNewChildrenMaps(flatNew) {
|
|
775
|
+
const elementSet = /* @__PURE__ */ new Set();
|
|
776
|
+
const cacheKeyMap = /* @__PURE__ */ new Map();
|
|
777
|
+
for (const child of flatNew) {
|
|
778
|
+
if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
|
|
779
|
+
elementSet.add(child);
|
|
780
|
+
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
781
|
+
const cacheKey = getElementCacheKey(child);
|
|
782
|
+
if (cacheKey) {
|
|
783
|
+
cacheKeyMap.set(cacheKey, child);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return { elementSet, cacheKeyMap };
|
|
789
|
+
}
|
|
790
|
+
function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
|
|
791
|
+
if (shouldPreserveElement(node)) {
|
|
792
|
+
return false;
|
|
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
|
+
}
|
|
806
|
+
if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
|
|
807
|
+
if (elementSet.has(node)) {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
if (node instanceof HTMLElement || node instanceof SVGElement) {
|
|
811
|
+
const cacheKey = getElementCacheKey(node);
|
|
812
|
+
if (cacheKey && cacheKeyMap.has(cacheKey)) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return true;
|
|
818
|
+
}
|
|
819
|
+
function deduplicateCacheKeys(parent, cacheKeyMap) {
|
|
820
|
+
const processedCacheKeys = /* @__PURE__ */ new Set();
|
|
821
|
+
for (let i = parent.childNodes.length - 1; i >= 0; i--) {
|
|
822
|
+
const child = parent.childNodes[i];
|
|
823
|
+
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
824
|
+
if (shouldPreserveElement(child)) {
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
const cacheKey = getElementCacheKey(child);
|
|
828
|
+
if (cacheKey && cacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
|
|
829
|
+
processedCacheKeys.add(cacheKey);
|
|
830
|
+
const newChild = cacheKeyMap.get(cacheKey);
|
|
831
|
+
if (child !== newChild) {
|
|
832
|
+
parent.replaceChild(newChild, child);
|
|
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
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
|
|
844
|
+
const nodesToRemove = [];
|
|
845
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
846
|
+
const node = parent.childNodes[i];
|
|
847
|
+
if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
|
|
848
|
+
nodesToRemove.push(node);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return nodesToRemove;
|
|
852
|
+
}
|
|
853
|
+
function removeNodes(parent, nodes, cacheManager) {
|
|
854
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
855
|
+
const node = nodes[i];
|
|
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
|
+
}
|
|
867
|
+
parent.removeChild(node);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
function reinsertPreservedElements(parent, preservedElements) {
|
|
872
|
+
for (const element of preservedElements) {
|
|
873
|
+
if (element.parentNode !== parent) {
|
|
874
|
+
parent.appendChild(element);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function flattenChildrenSafe(children) {
|
|
879
|
+
return flattenChildren(children);
|
|
880
|
+
}
|
|
881
|
+
|
|
624
882
|
// src/utils/element-update.ts
|
|
625
883
|
function removeProp(element, key, oldValue, tag) {
|
|
626
884
|
const isSVG = shouldUseSVGNamespace(tag);
|
|
627
885
|
if (key === "ref") {
|
|
886
|
+
if (typeof oldValue === "function") {
|
|
887
|
+
try {
|
|
888
|
+
oldValue(null);
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
}
|
|
628
892
|
return;
|
|
629
893
|
}
|
|
630
894
|
if (key === "className" || key === "class") {
|
|
@@ -640,6 +904,13 @@ function removeProp(element, key, oldValue, tag) {
|
|
|
640
904
|
return;
|
|
641
905
|
}
|
|
642
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
|
+
}
|
|
643
914
|
return;
|
|
644
915
|
}
|
|
645
916
|
if (key === "value") {
|
|
@@ -683,7 +954,13 @@ function applySingleProp2(element, key, value, tag, isSVG) {
|
|
|
683
954
|
}
|
|
684
955
|
if (key.startsWith("on") && typeof value === "function") {
|
|
685
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
|
+
}
|
|
686
962
|
element.addEventListener(eventName, value);
|
|
963
|
+
element[listenerKey] = value;
|
|
687
964
|
return;
|
|
688
965
|
}
|
|
689
966
|
if (typeof value === "boolean") {
|
|
@@ -738,49 +1015,36 @@ function updateProps(element, oldProps, newProps, tag) {
|
|
|
738
1015
|
applySingleProp2(element, key, newValue, tag, isSVG);
|
|
739
1016
|
}
|
|
740
1017
|
}
|
|
741
|
-
function updateChildren(element, oldChildren, newChildren) {
|
|
742
|
-
const flatOld =
|
|
743
|
-
const flatNew =
|
|
1018
|
+
function updateChildren(element, oldChildren, newChildren, _cacheManager) {
|
|
1019
|
+
const flatOld = flattenChildrenSafe(oldChildren);
|
|
1020
|
+
const flatNew = flattenChildrenSafe(newChildren);
|
|
1021
|
+
const preservedElements = collectPreservedElements(element);
|
|
744
1022
|
const minLength = Math.min(flatOld.length, flatNew.length);
|
|
745
|
-
|
|
1023
|
+
const domIndex = { value: 0 };
|
|
1024
|
+
const processedNodes = /* @__PURE__ */ new Set();
|
|
746
1025
|
for (let i = 0; i < minLength; i++) {
|
|
747
1026
|
const oldChild = flatOld[i];
|
|
748
1027
|
const newChild = flatNew[i];
|
|
749
1028
|
let oldNode = null;
|
|
750
1029
|
if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
const oldCacheKey = getElementCacheKey(oldChild);
|
|
757
|
-
if (oldCacheKey) {
|
|
758
|
-
for (let j = 0; j < element.childNodes.length; j++) {
|
|
759
|
-
const domChild = element.childNodes[j];
|
|
760
|
-
if (domChild instanceof HTMLElement || domChild instanceof SVGElement) {
|
|
761
|
-
if (shouldPreserveElement(domChild)) {
|
|
762
|
-
continue;
|
|
763
|
-
}
|
|
764
|
-
const domCacheKey = getElementCacheKey(domChild);
|
|
765
|
-
if (domCacheKey === oldCacheKey) {
|
|
766
|
-
oldNode = domChild;
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
1030
|
+
oldNode = findElementNode(oldChild, element);
|
|
1031
|
+
if (oldNode && oldNode.parentNode === element) {
|
|
1032
|
+
const nodeIndex = Array.from(element.childNodes).indexOf(oldNode);
|
|
1033
|
+
if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
|
|
1034
|
+
domIndex.value = nodeIndex + 1;
|
|
771
1035
|
}
|
|
772
1036
|
}
|
|
773
1037
|
} else if (typeof oldChild === "string" || typeof oldChild === "number") {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
1038
|
+
oldNode = findTextNode(element, domIndex);
|
|
1039
|
+
if (!oldNode && element.childNodes.length > 0) {
|
|
1040
|
+
const oldText = String(oldChild);
|
|
1041
|
+
for (let j = domIndex.value; j < element.childNodes.length; j++) {
|
|
1042
|
+
const node = element.childNodes[j];
|
|
1043
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
|
|
1044
|
+
oldNode = node;
|
|
1045
|
+
domIndex.value = j + 1;
|
|
1046
|
+
break;
|
|
1047
|
+
}
|
|
784
1048
|
}
|
|
785
1049
|
}
|
|
786
1050
|
}
|
|
@@ -789,27 +1053,20 @@ function updateChildren(element, oldChildren, newChildren) {
|
|
|
789
1053
|
const oldText = String(oldChild);
|
|
790
1054
|
const newText = String(newChild);
|
|
791
1055
|
const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
|
|
792
|
-
if (
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1056
|
+
if (needsUpdate) {
|
|
1057
|
+
const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
|
|
1058
|
+
if (updatedNode && !processedNodes.has(updatedNode)) {
|
|
1059
|
+
processedNodes.add(updatedNode);
|
|
1060
|
+
}
|
|
797
1061
|
} else {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
element.replaceChild(newTextNode, oldNode);
|
|
801
|
-
} else {
|
|
802
|
-
element.insertBefore(newTextNode, oldNode || null);
|
|
1062
|
+
if (oldNode && oldNode.parentNode === element) {
|
|
1063
|
+
processedNodes.add(oldNode);
|
|
803
1064
|
}
|
|
804
1065
|
}
|
|
805
1066
|
} else {
|
|
806
|
-
|
|
807
|
-
element.removeChild(oldNode);
|
|
808
|
-
}
|
|
1067
|
+
removeNodeIfNotPreserved(element, oldNode);
|
|
809
1068
|
if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
810
|
-
|
|
811
|
-
element.insertBefore(newChild, oldNode || null);
|
|
812
|
-
}
|
|
1069
|
+
replaceOrInsertElement(element, newChild, oldNode);
|
|
813
1070
|
} else if (newChild instanceof DocumentFragment) {
|
|
814
1071
|
element.insertBefore(newChild, oldNode || null);
|
|
815
1072
|
}
|
|
@@ -818,54 +1075,48 @@ function updateChildren(element, oldChildren, newChildren) {
|
|
|
818
1075
|
if (oldNode && shouldPreserveElement(oldNode)) {
|
|
819
1076
|
continue;
|
|
820
1077
|
}
|
|
821
|
-
if (newChild
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
if (hasSameCacheKey) {
|
|
832
|
-
if (newChild !== oldNode) {
|
|
833
|
-
element.replaceChild(newChild, oldNode);
|
|
834
|
-
}
|
|
835
|
-
} else {
|
|
836
|
-
element.removeChild(newChild);
|
|
837
|
-
element.replaceChild(newChild, oldNode);
|
|
838
|
-
}
|
|
839
|
-
} else if (newChild.parentNode) {
|
|
840
|
-
newChild.parentNode.removeChild(newChild);
|
|
841
|
-
element.replaceChild(newChild, oldNode);
|
|
842
|
-
} else {
|
|
843
|
-
element.replaceChild(newChild, oldNode);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
} else {
|
|
847
|
-
if (newChild.parentNode !== element) {
|
|
848
|
-
if (newChild.parentNode) {
|
|
849
|
-
newChild.parentNode.removeChild(newChild);
|
|
850
|
-
}
|
|
851
|
-
element.insertBefore(newChild, oldNode.nextSibling);
|
|
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;
|
|
852
1088
|
}
|
|
853
1089
|
}
|
|
854
|
-
} else {
|
|
855
|
-
if (newChild.parentNode !== element) {
|
|
856
|
-
if (newChild.parentNode) {
|
|
857
|
-
newChild.parentNode.removeChild(newChild);
|
|
858
|
-
}
|
|
859
|
-
element.appendChild(newChild);
|
|
860
|
-
}
|
|
861
1090
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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);
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
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);
|
|
865
1112
|
}
|
|
1113
|
+
processedNodes.add(newChild);
|
|
1114
|
+
} else {
|
|
1115
|
+
removeNodeIfNotPreserved(element, oldNode);
|
|
866
1116
|
if (typeof newChild === "string" || typeof newChild === "number") {
|
|
867
1117
|
const newTextNode = document.createTextNode(String(newChild));
|
|
868
1118
|
element.insertBefore(newTextNode, oldNode?.nextSibling || null);
|
|
1119
|
+
processedNodes.add(newTextNode);
|
|
869
1120
|
} else if (newChild instanceof DocumentFragment) {
|
|
870
1121
|
element.insertBefore(newChild, oldNode?.nextSibling || null);
|
|
871
1122
|
}
|
|
@@ -873,98 +1124,13 @@ function updateChildren(element, oldChildren, newChildren) {
|
|
|
873
1124
|
}
|
|
874
1125
|
}
|
|
875
1126
|
for (let i = minLength; i < flatNew.length; i++) {
|
|
876
|
-
|
|
877
|
-
if (newChild === null || newChild === void 0 || newChild === false) {
|
|
878
|
-
continue;
|
|
879
|
-
}
|
|
880
|
-
if (typeof newChild === "string" || typeof newChild === "number") {
|
|
881
|
-
element.appendChild(document.createTextNode(String(newChild)));
|
|
882
|
-
} else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
883
|
-
if (newChild.parentNode === element) {
|
|
884
|
-
const currentIndex = Array.from(element.childNodes).indexOf(newChild);
|
|
885
|
-
const expectedIndex = element.childNodes.length - 1;
|
|
886
|
-
if (currentIndex !== expectedIndex) {
|
|
887
|
-
element.removeChild(newChild);
|
|
888
|
-
element.appendChild(newChild);
|
|
889
|
-
}
|
|
890
|
-
continue;
|
|
891
|
-
} else if (newChild.parentNode) {
|
|
892
|
-
newChild.parentNode.removeChild(newChild);
|
|
893
|
-
}
|
|
894
|
-
element.appendChild(newChild);
|
|
895
|
-
} else if (newChild instanceof DocumentFragment) {
|
|
896
|
-
element.appendChild(newChild);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
const nodesToRemove = [];
|
|
900
|
-
const newChildSet = /* @__PURE__ */ new Set();
|
|
901
|
-
const newChildCacheKeyMap = /* @__PURE__ */ new Map();
|
|
902
|
-
for (const child of flatNew) {
|
|
903
|
-
if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
|
|
904
|
-
newChildSet.add(child);
|
|
905
|
-
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
906
|
-
const cacheKey = getElementCacheKey(child);
|
|
907
|
-
if (cacheKey) {
|
|
908
|
-
newChildCacheKeyMap.set(cacheKey, child);
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
const processedCacheKeys = /* @__PURE__ */ new Set();
|
|
914
|
-
const newChildToIndexMap = /* @__PURE__ */ new Map();
|
|
915
|
-
for (let i = 0; i < flatNew.length; i++) {
|
|
916
|
-
const child = flatNew[i];
|
|
917
|
-
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
918
|
-
newChildToIndexMap.set(child, i);
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
for (let i = element.childNodes.length - 1; i >= 0; i--) {
|
|
922
|
-
const child = element.childNodes[i];
|
|
923
|
-
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
924
|
-
if (shouldPreserveElement(child)) {
|
|
925
|
-
continue;
|
|
926
|
-
}
|
|
927
|
-
const cacheKey = getElementCacheKey(child);
|
|
928
|
-
if (cacheKey && newChildCacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
|
|
929
|
-
processedCacheKeys.add(cacheKey);
|
|
930
|
-
const newChild = newChildCacheKeyMap.get(cacheKey);
|
|
931
|
-
if (child !== newChild) {
|
|
932
|
-
if (newChild.parentNode === element) {
|
|
933
|
-
element.replaceChild(newChild, child);
|
|
934
|
-
} else {
|
|
935
|
-
element.replaceChild(newChild, child);
|
|
936
|
-
}
|
|
937
|
-
} else {
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
for (let i = 0; i < element.childNodes.length; i++) {
|
|
943
|
-
const child = element.childNodes[i];
|
|
944
|
-
if (shouldPreserveElement(child)) {
|
|
945
|
-
continue;
|
|
946
|
-
}
|
|
947
|
-
if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
948
|
-
if (newChildSet.has(child)) {
|
|
949
|
-
continue;
|
|
950
|
-
}
|
|
951
|
-
const cacheKey = getElementCacheKey(child);
|
|
952
|
-
if (cacheKey && newChildCacheKeyMap.has(cacheKey)) {
|
|
953
|
-
continue;
|
|
954
|
-
}
|
|
955
|
-
} else if (child instanceof DocumentFragment) {
|
|
956
|
-
if (newChildSet.has(child)) {
|
|
957
|
-
continue;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
nodesToRemove.push(child);
|
|
961
|
-
}
|
|
962
|
-
for (let i = nodesToRemove.length - 1; i >= 0; i--) {
|
|
963
|
-
const node = nodesToRemove[i];
|
|
964
|
-
if (node.parentNode === element) {
|
|
965
|
-
element.removeChild(node);
|
|
966
|
-
}
|
|
1127
|
+
appendNewChild(element, flatNew[i], processedNodes);
|
|
967
1128
|
}
|
|
1129
|
+
const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
|
|
1130
|
+
deduplicateCacheKeys(element, cacheKeyMap);
|
|
1131
|
+
const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap, processedNodes);
|
|
1132
|
+
removeNodes(element, nodesToRemove, _cacheManager);
|
|
1133
|
+
reinsertPreservedElements(element, preservedElements);
|
|
968
1134
|
}
|
|
969
1135
|
function updateElement(element, newProps, newChildren, tag, cacheManager) {
|
|
970
1136
|
const oldMetadata = cacheManager.getMetadata(element);
|
|
@@ -975,7 +1141,7 @@ function updateElement(element, newProps, newChildren, tag, cacheManager) {
|
|
|
975
1141
|
children: newChildren
|
|
976
1142
|
});
|
|
977
1143
|
updateProps(element, oldProps, newProps, tag);
|
|
978
|
-
updateChildren(element, oldChildren, newChildren);
|
|
1144
|
+
updateChildren(element, oldChildren, newChildren, cacheManager);
|
|
979
1145
|
}
|
|
980
1146
|
|
|
981
1147
|
// src/jsx-factory.ts
|