@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
|
@@ -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
|
|
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 =
|
|
716
|
-
const flatNew =
|
|
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
|
-
|
|
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
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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 (
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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
|
-
|
|
772
|
-
|
|
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
|
-
|
|
780
|
-
element.removeChild(oldNode);
|
|
781
|
-
}
|
|
1040
|
+
removeNodeIfNotPreserved(element, oldNode);
|
|
782
1041
|
if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
783
|
-
|
|
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
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
|
|
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
|