@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/{chunk-ESZYREJK.mjs → chunk-5Q2VEEUH.mjs} +160 -35
- package/dist/index.js +226 -64
- package/dist/index.mjs +67 -30
- package/dist/jsx-runtime.js +160 -35
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/jsx.js +160 -35
- package/dist/jsx.mjs +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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 +122 -45
- package/src/utils/update-children-helpers.ts +184 -18
- package/src/web-component.ts +72 -41
- package/dist/chunk-BPQGLNOQ.mjs +0 -1140
- package/dist/chunk-OGMB43J4.mjs +0 -1131
- package/dist/chunk-OXFZ575O.mjs +0 -1091
- package/dist/chunk-TKHKPLBM.mjs +0 -1142
|
@@ -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") {
|
|
@@ -635,7 +640,7 @@ function findElementNode(oldChild, parent) {
|
|
|
635
640
|
function findTextNode(parent, domIndex) {
|
|
636
641
|
while (domIndex.value < parent.childNodes.length) {
|
|
637
642
|
const node = parent.childNodes[domIndex.value];
|
|
638
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
643
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
|
|
639
644
|
const textNode = node;
|
|
640
645
|
domIndex.value++;
|
|
641
646
|
return textNode;
|
|
@@ -649,13 +654,23 @@ function updateOrCreateTextNode(parent, oldNode, newText) {
|
|
|
649
654
|
if (oldNode.textContent !== newText) {
|
|
650
655
|
oldNode.textContent = newText;
|
|
651
656
|
}
|
|
657
|
+
return oldNode;
|
|
652
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
|
+
}
|
|
653
667
|
const newTextNode = document.createTextNode(newText);
|
|
654
668
|
if (oldNode && !shouldPreserveElement(oldNode)) {
|
|
655
669
|
parent.replaceChild(newTextNode, oldNode);
|
|
656
670
|
} else {
|
|
657
671
|
parent.insertBefore(newTextNode, oldNode || null);
|
|
658
672
|
}
|
|
673
|
+
return newTextNode;
|
|
659
674
|
}
|
|
660
675
|
}
|
|
661
676
|
function removeNodeIfNotPreserved(parent, node) {
|
|
@@ -664,29 +679,66 @@ function removeNodeIfNotPreserved(parent, node) {
|
|
|
664
679
|
}
|
|
665
680
|
}
|
|
666
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) {
|
|
667
686
|
if (newChild.parentNode && newChild.parentNode !== parent) {
|
|
668
687
|
newChild.parentNode.removeChild(newChild);
|
|
669
688
|
}
|
|
670
|
-
|
|
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)) {
|
|
671
698
|
if (oldNode !== newChild) {
|
|
672
699
|
parent.replaceChild(newChild, oldNode);
|
|
673
700
|
}
|
|
674
|
-
} else
|
|
675
|
-
|
|
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);
|
|
676
720
|
}
|
|
677
721
|
}
|
|
678
|
-
function appendNewChild(parent, child) {
|
|
722
|
+
function appendNewChild(parent, child, processedNodes) {
|
|
679
723
|
if (child === null || child === void 0 || child === false) {
|
|
680
724
|
return;
|
|
681
725
|
}
|
|
682
726
|
if (typeof child === "string" || typeof child === "number") {
|
|
683
|
-
|
|
727
|
+
const newTextNode = document.createTextNode(String(child));
|
|
728
|
+
parent.appendChild(newTextNode);
|
|
729
|
+
if (processedNodes) {
|
|
730
|
+
processedNodes.add(newTextNode);
|
|
731
|
+
}
|
|
684
732
|
} else if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
733
|
+
if (child.parentNode === parent) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
685
736
|
if (child.parentNode && child.parentNode !== parent) {
|
|
686
737
|
child.parentNode.removeChild(child);
|
|
687
738
|
}
|
|
688
|
-
|
|
689
|
-
|
|
739
|
+
parent.appendChild(child);
|
|
740
|
+
if (processedNodes) {
|
|
741
|
+
processedNodes.add(child);
|
|
690
742
|
}
|
|
691
743
|
} else if (child instanceof DocumentFragment) {
|
|
692
744
|
parent.appendChild(child);
|
|
@@ -708,10 +760,22 @@ function buildNewChildrenMaps(flatNew) {
|
|
|
708
760
|
}
|
|
709
761
|
return { elementSet, cacheKeyMap };
|
|
710
762
|
}
|
|
711
|
-
function shouldRemoveNode(node, elementSet, cacheKeyMap) {
|
|
763
|
+
function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
|
|
712
764
|
if (shouldPreserveElement(node)) {
|
|
713
765
|
return false;
|
|
714
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
|
+
}
|
|
715
779
|
if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
|
|
716
780
|
if (elementSet.has(node)) {
|
|
717
781
|
return false;
|
|
@@ -740,24 +804,39 @@ function deduplicateCacheKeys(parent, cacheKeyMap) {
|
|
|
740
804
|
if (child !== newChild) {
|
|
741
805
|
parent.replaceChild(newChild, child);
|
|
742
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
|
+
}
|
|
743
812
|
}
|
|
744
813
|
}
|
|
745
814
|
}
|
|
746
815
|
}
|
|
747
|
-
function collectNodesToRemove(parent, elementSet, cacheKeyMap) {
|
|
816
|
+
function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
|
|
748
817
|
const nodesToRemove = [];
|
|
749
818
|
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
750
819
|
const node = parent.childNodes[i];
|
|
751
|
-
if (shouldRemoveNode(node, elementSet, cacheKeyMap)) {
|
|
820
|
+
if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
|
|
752
821
|
nodesToRemove.push(node);
|
|
753
822
|
}
|
|
754
823
|
}
|
|
755
824
|
return nodesToRemove;
|
|
756
825
|
}
|
|
757
|
-
function removeNodes(parent, nodes) {
|
|
826
|
+
function removeNodes(parent, nodes, cacheManager) {
|
|
758
827
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
759
828
|
const node = nodes[i];
|
|
760
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
|
+
}
|
|
761
840
|
parent.removeChild(node);
|
|
762
841
|
}
|
|
763
842
|
}
|
|
@@ -777,6 +856,12 @@ function flattenChildrenSafe(children) {
|
|
|
777
856
|
function removeProp(element, key, oldValue, tag) {
|
|
778
857
|
const isSVG = shouldUseSVGNamespace(tag);
|
|
779
858
|
if (key === "ref") {
|
|
859
|
+
if (typeof oldValue === "function") {
|
|
860
|
+
try {
|
|
861
|
+
oldValue(null);
|
|
862
|
+
} catch {
|
|
863
|
+
}
|
|
864
|
+
}
|
|
780
865
|
return;
|
|
781
866
|
}
|
|
782
867
|
if (key === "className" || key === "class") {
|
|
@@ -792,6 +877,13 @@ function removeProp(element, key, oldValue, tag) {
|
|
|
792
877
|
return;
|
|
793
878
|
}
|
|
794
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
|
+
}
|
|
795
887
|
return;
|
|
796
888
|
}
|
|
797
889
|
if (key === "value") {
|
|
@@ -835,7 +927,13 @@ function applySingleProp2(element, key, value, tag, isSVG) {
|
|
|
835
927
|
}
|
|
836
928
|
if (key.startsWith("on") && typeof value === "function") {
|
|
837
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
|
+
}
|
|
838
935
|
element.addEventListener(eventName, value);
|
|
936
|
+
element[listenerKey] = value;
|
|
839
937
|
return;
|
|
840
938
|
}
|
|
841
939
|
if (typeof value === "boolean") {
|
|
@@ -890,12 +988,13 @@ function updateProps(element, oldProps, newProps, tag) {
|
|
|
890
988
|
applySingleProp2(element, key, newValue, tag, isSVG);
|
|
891
989
|
}
|
|
892
990
|
}
|
|
893
|
-
function updateChildren(element, oldChildren, newChildren,
|
|
991
|
+
function updateChildren(element, oldChildren, newChildren, _cacheManager) {
|
|
894
992
|
const flatOld = flattenChildrenSafe(oldChildren);
|
|
895
993
|
const flatNew = flattenChildrenSafe(newChildren);
|
|
896
994
|
const preservedElements = collectPreservedElements(element);
|
|
897
995
|
const minLength = Math.min(flatOld.length, flatNew.length);
|
|
898
996
|
const domIndex = { value: 0 };
|
|
997
|
+
const processedNodes = /* @__PURE__ */ new Set();
|
|
899
998
|
for (let i = 0; i < minLength; i++) {
|
|
900
999
|
const oldChild = flatOld[i];
|
|
901
1000
|
const newChild = flatNew[i];
|
|
@@ -911,9 +1010,10 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
911
1010
|
} else if (typeof oldChild === "string" || typeof oldChild === "number") {
|
|
912
1011
|
oldNode = findTextNode(element, domIndex);
|
|
913
1012
|
if (!oldNode && element.childNodes.length > 0) {
|
|
1013
|
+
const oldText = String(oldChild);
|
|
914
1014
|
for (let j = domIndex.value; j < element.childNodes.length; j++) {
|
|
915
1015
|
const node = element.childNodes[j];
|
|
916
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
1016
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
|
|
917
1017
|
oldNode = node;
|
|
918
1018
|
domIndex.value = j + 1;
|
|
919
1019
|
break;
|
|
@@ -927,7 +1027,14 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
927
1027
|
const newText = String(newChild);
|
|
928
1028
|
const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
|
|
929
1029
|
if (needsUpdate) {
|
|
930
|
-
updateOrCreateTextNode(element, oldNode, newText);
|
|
1030
|
+
const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
|
|
1031
|
+
if (updatedNode && !processedNodes.has(updatedNode)) {
|
|
1032
|
+
processedNodes.add(updatedNode);
|
|
1033
|
+
}
|
|
1034
|
+
} else {
|
|
1035
|
+
if (oldNode && oldNode.parentNode === element) {
|
|
1036
|
+
processedNodes.add(oldNode);
|
|
1037
|
+
}
|
|
931
1038
|
}
|
|
932
1039
|
} else {
|
|
933
1040
|
removeNodeIfNotPreserved(element, oldNode);
|
|
@@ -941,30 +1048,48 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
941
1048
|
if (oldNode && shouldPreserveElement(oldNode)) {
|
|
942
1049
|
continue;
|
|
943
1050
|
}
|
|
944
|
-
if (newChild
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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;
|
|
950
1061
|
}
|
|
951
1062
|
}
|
|
952
|
-
} else {
|
|
953
|
-
if (oldNode === newChild && newChild.parentNode === element) {
|
|
954
|
-
continue;
|
|
955
|
-
}
|
|
956
1063
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
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);
|
|
960
1074
|
continue;
|
|
961
1075
|
}
|
|
962
|
-
|
|
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);
|
|
1085
|
+
}
|
|
1086
|
+
processedNodes.add(newChild);
|
|
963
1087
|
} else {
|
|
964
1088
|
removeNodeIfNotPreserved(element, oldNode);
|
|
965
1089
|
if (typeof newChild === "string" || typeof newChild === "number") {
|
|
966
1090
|
const newTextNode = document.createTextNode(String(newChild));
|
|
967
1091
|
element.insertBefore(newTextNode, oldNode?.nextSibling || null);
|
|
1092
|
+
processedNodes.add(newTextNode);
|
|
968
1093
|
} else if (newChild instanceof DocumentFragment) {
|
|
969
1094
|
element.insertBefore(newChild, oldNode?.nextSibling || null);
|
|
970
1095
|
}
|
|
@@ -972,12 +1097,12 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
972
1097
|
}
|
|
973
1098
|
}
|
|
974
1099
|
for (let i = minLength; i < flatNew.length; i++) {
|
|
975
|
-
appendNewChild(element, flatNew[i]);
|
|
1100
|
+
appendNewChild(element, flatNew[i], processedNodes);
|
|
976
1101
|
}
|
|
977
1102
|
const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
|
|
978
1103
|
deduplicateCacheKeys(element, cacheKeyMap);
|
|
979
|
-
const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap);
|
|
980
|
-
removeNodes(element, nodesToRemove);
|
|
1104
|
+
const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap, processedNodes);
|
|
1105
|
+
removeNodes(element, nodesToRemove, _cacheManager);
|
|
981
1106
|
reinsertPreservedElements(element, preservedElements);
|
|
982
1107
|
}
|
|
983
1108
|
function updateElement(element, newProps, newChildren, tag, cacheManager) {
|