@wsxjs/wsx-core 0.0.23 → 0.0.25
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/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
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/index.js
CHANGED
|
@@ -112,6 +112,7 @@ var _RenderContext = class _RenderContext {
|
|
|
112
112
|
* @param fn The function to execute (usually the render method).
|
|
113
113
|
*/
|
|
114
114
|
static runInContext(component, fn) {
|
|
115
|
+
resetCounterForNewRenderCycle(component);
|
|
115
116
|
const prev = _RenderContext.current;
|
|
116
117
|
_RenderContext.current = component;
|
|
117
118
|
try {
|
|
@@ -137,21 +138,20 @@ _RenderContext.current = null;
|
|
|
137
138
|
var RenderContext = _RenderContext;
|
|
138
139
|
|
|
139
140
|
// src/utils/cache-key.ts
|
|
140
|
-
var POSITION_ID_KEY = "__wsxPositionId";
|
|
141
141
|
var INDEX_KEY = "__wsxIndex";
|
|
142
142
|
var componentElementCounters = /* @__PURE__ */ new WeakMap();
|
|
143
143
|
var componentIdCache = /* @__PURE__ */ new WeakMap();
|
|
144
144
|
function generateCacheKey(tag, props, componentId, component) {
|
|
145
|
-
const positionId = props?.[POSITION_ID_KEY];
|
|
146
145
|
const userKey = props?.key;
|
|
147
146
|
const index = props?.[INDEX_KEY];
|
|
147
|
+
const positionId = props?.__wsxPositionId;
|
|
148
148
|
if (userKey !== void 0 && userKey !== null) {
|
|
149
149
|
return `${componentId}:${tag}:key-${String(userKey)}`;
|
|
150
150
|
}
|
|
151
151
|
if (index !== void 0 && index !== null) {
|
|
152
152
|
return `${componentId}:${tag}:idx-${String(index)}`;
|
|
153
153
|
}
|
|
154
|
-
if (positionId !== void 0 && positionId !== null
|
|
154
|
+
if (positionId !== void 0 && positionId !== null) {
|
|
155
155
|
return `${componentId}:${tag}:${String(positionId)}`;
|
|
156
156
|
}
|
|
157
157
|
if (component) {
|
|
@@ -162,6 +162,9 @@ function generateCacheKey(tag, props, componentId, component) {
|
|
|
162
162
|
}
|
|
163
163
|
return `${componentId}:${tag}:fallback-${Date.now()}-${Math.random()}`;
|
|
164
164
|
}
|
|
165
|
+
function resetCounterForNewRenderCycle(component) {
|
|
166
|
+
componentElementCounters.set(component, 0);
|
|
167
|
+
}
|
|
165
168
|
function getComponentId() {
|
|
166
169
|
const component = RenderContext.getCurrentComponent();
|
|
167
170
|
if (component) {
|
|
@@ -579,7 +582,9 @@ function applySingleProp(element, key, value, tag, isSVG) {
|
|
|
579
582
|
}
|
|
580
583
|
if (key.startsWith("on") && typeof value === "function") {
|
|
581
584
|
const eventName = key.slice(2).toLowerCase();
|
|
585
|
+
const listenerKey = `__wsxListener_${eventName}`;
|
|
582
586
|
element.addEventListener(eventName, value);
|
|
587
|
+
element[listenerKey] = value;
|
|
583
588
|
return;
|
|
584
589
|
}
|
|
585
590
|
if (typeof value === "boolean") {
|
|
@@ -674,7 +679,7 @@ function findElementNode(oldChild, parent) {
|
|
|
674
679
|
function findTextNode(parent, domIndex) {
|
|
675
680
|
while (domIndex.value < parent.childNodes.length) {
|
|
676
681
|
const node = parent.childNodes[domIndex.value];
|
|
677
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
682
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent) {
|
|
678
683
|
const textNode = node;
|
|
679
684
|
domIndex.value++;
|
|
680
685
|
return textNode;
|
|
@@ -688,13 +693,23 @@ function updateOrCreateTextNode(parent, oldNode, newText) {
|
|
|
688
693
|
if (oldNode.textContent !== newText) {
|
|
689
694
|
oldNode.textContent = newText;
|
|
690
695
|
}
|
|
696
|
+
return oldNode;
|
|
691
697
|
} else {
|
|
698
|
+
if (!oldNode) {
|
|
699
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
700
|
+
const node = parent.childNodes[i];
|
|
701
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === parent && node.textContent === newText) {
|
|
702
|
+
return node;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
692
706
|
const newTextNode = document.createTextNode(newText);
|
|
693
707
|
if (oldNode && !shouldPreserveElement(oldNode)) {
|
|
694
708
|
parent.replaceChild(newTextNode, oldNode);
|
|
695
709
|
} else {
|
|
696
710
|
parent.insertBefore(newTextNode, oldNode || null);
|
|
697
711
|
}
|
|
712
|
+
return newTextNode;
|
|
698
713
|
}
|
|
699
714
|
}
|
|
700
715
|
function removeNodeIfNotPreserved(parent, node) {
|
|
@@ -703,29 +718,66 @@ function removeNodeIfNotPreserved(parent, node) {
|
|
|
703
718
|
}
|
|
704
719
|
}
|
|
705
720
|
function replaceOrInsertElement(parent, newChild, oldNode) {
|
|
721
|
+
const targetNextSibling = oldNode && shouldPreserveElement(oldNode) ? oldNode : oldNode?.nextSibling || null;
|
|
722
|
+
replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling);
|
|
723
|
+
}
|
|
724
|
+
function replaceOrInsertElementAtPosition(parent, newChild, oldNode, targetNextSibling) {
|
|
706
725
|
if (newChild.parentNode && newChild.parentNode !== parent) {
|
|
707
726
|
newChild.parentNode.removeChild(newChild);
|
|
708
727
|
}
|
|
709
|
-
|
|
728
|
+
const isInCorrectPosition = newChild.parentNode === parent && newChild.nextSibling === targetNextSibling;
|
|
729
|
+
if (isInCorrectPosition) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (newChild.parentNode === parent) {
|
|
733
|
+
parent.insertBefore(newChild, targetNextSibling);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (oldNode && oldNode.parentNode === parent && !shouldPreserveElement(oldNode)) {
|
|
710
737
|
if (oldNode !== newChild) {
|
|
711
738
|
parent.replaceChild(newChild, oldNode);
|
|
712
739
|
}
|
|
713
|
-
} else
|
|
714
|
-
|
|
740
|
+
} else {
|
|
741
|
+
if (newChild.parentNode === parent) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
const newChildCacheKey = getElementCacheKey(newChild);
|
|
745
|
+
if (!newChildCacheKey) {
|
|
746
|
+
const newChildContent = newChild.textContent || "";
|
|
747
|
+
const newChildTag = newChild.tagName.toLowerCase();
|
|
748
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
749
|
+
const existingNode = parent.childNodes[i];
|
|
750
|
+
if (existingNode instanceof HTMLElement || existingNode instanceof SVGElement) {
|
|
751
|
+
const existingCacheKey = getElementCacheKey(existingNode);
|
|
752
|
+
if (!existingCacheKey && existingNode.tagName.toLowerCase() === newChildTag && existingNode.textContent === newChildContent && existingNode !== newChild) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
parent.insertBefore(newChild, targetNextSibling);
|
|
715
759
|
}
|
|
716
760
|
}
|
|
717
|
-
function appendNewChild(parent, child) {
|
|
761
|
+
function appendNewChild(parent, child, processedNodes) {
|
|
718
762
|
if (child === null || child === void 0 || child === false) {
|
|
719
763
|
return;
|
|
720
764
|
}
|
|
721
765
|
if (typeof child === "string" || typeof child === "number") {
|
|
722
|
-
|
|
766
|
+
const newTextNode = document.createTextNode(String(child));
|
|
767
|
+
parent.appendChild(newTextNode);
|
|
768
|
+
if (processedNodes) {
|
|
769
|
+
processedNodes.add(newTextNode);
|
|
770
|
+
}
|
|
723
771
|
} else if (child instanceof HTMLElement || child instanceof SVGElement) {
|
|
772
|
+
if (child.parentNode === parent) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
724
775
|
if (child.parentNode && child.parentNode !== parent) {
|
|
725
776
|
child.parentNode.removeChild(child);
|
|
726
777
|
}
|
|
727
|
-
|
|
728
|
-
|
|
778
|
+
parent.appendChild(child);
|
|
779
|
+
if (processedNodes) {
|
|
780
|
+
processedNodes.add(child);
|
|
729
781
|
}
|
|
730
782
|
} else if (child instanceof DocumentFragment) {
|
|
731
783
|
parent.appendChild(child);
|
|
@@ -747,10 +799,22 @@ function buildNewChildrenMaps(flatNew) {
|
|
|
747
799
|
}
|
|
748
800
|
return { elementSet, cacheKeyMap };
|
|
749
801
|
}
|
|
750
|
-
function shouldRemoveNode(node, elementSet, cacheKeyMap) {
|
|
802
|
+
function shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes) {
|
|
751
803
|
if (shouldPreserveElement(node)) {
|
|
752
804
|
return false;
|
|
753
805
|
}
|
|
806
|
+
if (node.nodeType === Node.TEXT_NODE && processedNodes && processedNodes.has(node)) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
if (node.nodeType === Node.TEXT_NODE && processedNodes) {
|
|
810
|
+
let parent = node.parentNode;
|
|
811
|
+
while (parent) {
|
|
812
|
+
if (processedNodes.has(parent) && parent.parentNode) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
parent = parent.parentNode;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
754
818
|
if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
|
|
755
819
|
if (elementSet.has(node)) {
|
|
756
820
|
return false;
|
|
@@ -779,24 +843,39 @@ function deduplicateCacheKeys(parent, cacheKeyMap) {
|
|
|
779
843
|
if (child !== newChild) {
|
|
780
844
|
parent.replaceChild(newChild, child);
|
|
781
845
|
}
|
|
846
|
+
} else if (cacheKey && cacheKeyMap.has(cacheKey) && processedCacheKeys.has(cacheKey)) {
|
|
847
|
+
const newChild = cacheKeyMap.get(cacheKey);
|
|
848
|
+
if (child !== newChild) {
|
|
849
|
+
parent.removeChild(child);
|
|
850
|
+
}
|
|
782
851
|
}
|
|
783
852
|
}
|
|
784
853
|
}
|
|
785
854
|
}
|
|
786
|
-
function collectNodesToRemove(parent, elementSet, cacheKeyMap) {
|
|
855
|
+
function collectNodesToRemove(parent, elementSet, cacheKeyMap, processedNodes) {
|
|
787
856
|
const nodesToRemove = [];
|
|
788
857
|
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
789
858
|
const node = parent.childNodes[i];
|
|
790
|
-
if (shouldRemoveNode(node, elementSet, cacheKeyMap)) {
|
|
859
|
+
if (shouldRemoveNode(node, elementSet, cacheKeyMap, processedNodes)) {
|
|
791
860
|
nodesToRemove.push(node);
|
|
792
861
|
}
|
|
793
862
|
}
|
|
794
863
|
return nodesToRemove;
|
|
795
864
|
}
|
|
796
|
-
function removeNodes(parent, nodes) {
|
|
865
|
+
function removeNodes(parent, nodes, cacheManager) {
|
|
797
866
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
798
867
|
const node = nodes[i];
|
|
799
868
|
if (node.parentNode === parent) {
|
|
869
|
+
if (cacheManager && (node instanceof HTMLElement || node instanceof SVGElement)) {
|
|
870
|
+
const metadata = cacheManager.getMetadata(node);
|
|
871
|
+
const refCallback = metadata?.ref;
|
|
872
|
+
if (typeof refCallback === "function") {
|
|
873
|
+
try {
|
|
874
|
+
refCallback(null);
|
|
875
|
+
} catch {
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
800
879
|
parent.removeChild(node);
|
|
801
880
|
}
|
|
802
881
|
}
|
|
@@ -816,6 +895,12 @@ function flattenChildrenSafe(children) {
|
|
|
816
895
|
function removeProp(element, key, oldValue, tag) {
|
|
817
896
|
const isSVG = shouldUseSVGNamespace(tag);
|
|
818
897
|
if (key === "ref") {
|
|
898
|
+
if (typeof oldValue === "function") {
|
|
899
|
+
try {
|
|
900
|
+
oldValue(null);
|
|
901
|
+
} catch {
|
|
902
|
+
}
|
|
903
|
+
}
|
|
819
904
|
return;
|
|
820
905
|
}
|
|
821
906
|
if (key === "className" || key === "class") {
|
|
@@ -831,6 +916,13 @@ function removeProp(element, key, oldValue, tag) {
|
|
|
831
916
|
return;
|
|
832
917
|
}
|
|
833
918
|
if (key.startsWith("on") && typeof oldValue === "function") {
|
|
919
|
+
const eventName = key.slice(2).toLowerCase();
|
|
920
|
+
const listenerKey = `__wsxListener_${eventName}`;
|
|
921
|
+
const savedListener = element[listenerKey];
|
|
922
|
+
if (savedListener) {
|
|
923
|
+
element.removeEventListener(eventName, savedListener);
|
|
924
|
+
delete element[listenerKey];
|
|
925
|
+
}
|
|
834
926
|
return;
|
|
835
927
|
}
|
|
836
928
|
if (key === "value") {
|
|
@@ -874,7 +966,13 @@ function applySingleProp2(element, key, value, tag, isSVG) {
|
|
|
874
966
|
}
|
|
875
967
|
if (key.startsWith("on") && typeof value === "function") {
|
|
876
968
|
const eventName = key.slice(2).toLowerCase();
|
|
969
|
+
const listenerKey = `__wsxListener_${eventName}`;
|
|
970
|
+
const oldListener = element[listenerKey];
|
|
971
|
+
if (oldListener) {
|
|
972
|
+
element.removeEventListener(eventName, oldListener);
|
|
973
|
+
}
|
|
877
974
|
element.addEventListener(eventName, value);
|
|
975
|
+
element[listenerKey] = value;
|
|
878
976
|
return;
|
|
879
977
|
}
|
|
880
978
|
if (typeof value === "boolean") {
|
|
@@ -929,12 +1027,13 @@ function updateProps(element, oldProps, newProps, tag) {
|
|
|
929
1027
|
applySingleProp2(element, key, newValue, tag, isSVG);
|
|
930
1028
|
}
|
|
931
1029
|
}
|
|
932
|
-
function updateChildren(element, oldChildren, newChildren,
|
|
1030
|
+
function updateChildren(element, oldChildren, newChildren, _cacheManager) {
|
|
933
1031
|
const flatOld = flattenChildrenSafe(oldChildren);
|
|
934
1032
|
const flatNew = flattenChildrenSafe(newChildren);
|
|
935
1033
|
const preservedElements = collectPreservedElements(element);
|
|
936
1034
|
const minLength = Math.min(flatOld.length, flatNew.length);
|
|
937
1035
|
const domIndex = { value: 0 };
|
|
1036
|
+
const processedNodes = /* @__PURE__ */ new Set();
|
|
938
1037
|
for (let i = 0; i < minLength; i++) {
|
|
939
1038
|
const oldChild = flatOld[i];
|
|
940
1039
|
const newChild = flatNew[i];
|
|
@@ -950,9 +1049,10 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
950
1049
|
} else if (typeof oldChild === "string" || typeof oldChild === "number") {
|
|
951
1050
|
oldNode = findTextNode(element, domIndex);
|
|
952
1051
|
if (!oldNode && element.childNodes.length > 0) {
|
|
1052
|
+
const oldText = String(oldChild);
|
|
953
1053
|
for (let j = domIndex.value; j < element.childNodes.length; j++) {
|
|
954
1054
|
const node = element.childNodes[j];
|
|
955
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
1055
|
+
if (node.nodeType === Node.TEXT_NODE && node.parentNode === element && node.textContent === oldText) {
|
|
956
1056
|
oldNode = node;
|
|
957
1057
|
domIndex.value = j + 1;
|
|
958
1058
|
break;
|
|
@@ -966,7 +1066,14 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
966
1066
|
const newText = String(newChild);
|
|
967
1067
|
const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
|
|
968
1068
|
if (needsUpdate) {
|
|
969
|
-
updateOrCreateTextNode(element, oldNode, newText);
|
|
1069
|
+
const updatedNode = updateOrCreateTextNode(element, oldNode, newText);
|
|
1070
|
+
if (updatedNode && !processedNodes.has(updatedNode)) {
|
|
1071
|
+
processedNodes.add(updatedNode);
|
|
1072
|
+
}
|
|
1073
|
+
} else {
|
|
1074
|
+
if (oldNode && oldNode.parentNode === element) {
|
|
1075
|
+
processedNodes.add(oldNode);
|
|
1076
|
+
}
|
|
970
1077
|
}
|
|
971
1078
|
} else {
|
|
972
1079
|
removeNodeIfNotPreserved(element, oldNode);
|
|
@@ -980,30 +1087,48 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
980
1087
|
if (oldNode && shouldPreserveElement(oldNode)) {
|
|
981
1088
|
continue;
|
|
982
1089
|
}
|
|
983
|
-
if (newChild
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1090
|
+
if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
|
|
1091
|
+
let targetNextSibling = null;
|
|
1092
|
+
let foundPreviousElement = false;
|
|
1093
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
1094
|
+
const prevChild = flatNew[j];
|
|
1095
|
+
if (prevChild instanceof HTMLElement || prevChild instanceof SVGElement) {
|
|
1096
|
+
if (prevChild.parentNode === element) {
|
|
1097
|
+
targetNextSibling = prevChild.nextSibling;
|
|
1098
|
+
foundPreviousElement = true;
|
|
1099
|
+
break;
|
|
989
1100
|
}
|
|
990
1101
|
}
|
|
991
|
-
} else {
|
|
992
|
-
if (oldNode === newChild && newChild.parentNode === element) {
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
1102
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1103
|
+
if (!foundPreviousElement) {
|
|
1104
|
+
const firstChild = Array.from(element.childNodes).find(
|
|
1105
|
+
(node) => !shouldPreserveElement(node) && !processedNodes.has(node)
|
|
1106
|
+
);
|
|
1107
|
+
targetNextSibling = firstChild || null;
|
|
1108
|
+
}
|
|
1109
|
+
const isInCorrectPosition = newChild.parentNode === element && newChild.nextSibling === targetNextSibling;
|
|
1110
|
+
if (newChild === oldChild && isInCorrectPosition) {
|
|
1111
|
+
if (oldNode) processedNodes.add(oldNode);
|
|
1112
|
+
processedNodes.add(newChild);
|
|
999
1113
|
continue;
|
|
1000
1114
|
}
|
|
1001
|
-
|
|
1115
|
+
const referenceNode = oldNode && oldNode.parentNode === element ? oldNode : null;
|
|
1116
|
+
replaceOrInsertElementAtPosition(
|
|
1117
|
+
element,
|
|
1118
|
+
newChild,
|
|
1119
|
+
referenceNode,
|
|
1120
|
+
targetNextSibling
|
|
1121
|
+
);
|
|
1122
|
+
if (oldNode && oldNode !== newChild) {
|
|
1123
|
+
processedNodes.delete(oldNode);
|
|
1124
|
+
}
|
|
1125
|
+
processedNodes.add(newChild);
|
|
1002
1126
|
} else {
|
|
1003
1127
|
removeNodeIfNotPreserved(element, oldNode);
|
|
1004
1128
|
if (typeof newChild === "string" || typeof newChild === "number") {
|
|
1005
1129
|
const newTextNode = document.createTextNode(String(newChild));
|
|
1006
1130
|
element.insertBefore(newTextNode, oldNode?.nextSibling || null);
|
|
1131
|
+
processedNodes.add(newTextNode);
|
|
1007
1132
|
} else if (newChild instanceof DocumentFragment) {
|
|
1008
1133
|
element.insertBefore(newChild, oldNode?.nextSibling || null);
|
|
1009
1134
|
}
|
|
@@ -1011,12 +1136,12 @@ function updateChildren(element, oldChildren, newChildren, cacheManager) {
|
|
|
1011
1136
|
}
|
|
1012
1137
|
}
|
|
1013
1138
|
for (let i = minLength; i < flatNew.length; i++) {
|
|
1014
|
-
appendNewChild(element, flatNew[i]);
|
|
1139
|
+
appendNewChild(element, flatNew[i], processedNodes);
|
|
1015
1140
|
}
|
|
1016
1141
|
const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
|
|
1017
1142
|
deduplicateCacheKeys(element, cacheKeyMap);
|
|
1018
|
-
const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap);
|
|
1019
|
-
removeNodes(element, nodesToRemove);
|
|
1143
|
+
const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap, processedNodes);
|
|
1144
|
+
removeNodes(element, nodesToRemove, _cacheManager);
|
|
1020
1145
|
reinsertPreservedElements(element, preservedElements);
|
|
1021
1146
|
}
|
|
1022
1147
|
function updateElement(element, newProps, newChildren, tag, cacheManager) {
|
|
@@ -1532,6 +1657,12 @@ var BaseComponent = class extends HTMLElement {
|
|
|
1532
1657
|
* @internal
|
|
1533
1658
|
*/
|
|
1534
1659
|
this._isRendering = false;
|
|
1660
|
+
/**
|
|
1661
|
+
* 已调度渲染标志(防止在同一事件循环中重复注册 requestAnimationFrame)
|
|
1662
|
+
* 用于批量更新:同一事件循环中的多个状态变化只触发一次渲染
|
|
1663
|
+
* @internal
|
|
1664
|
+
*/
|
|
1665
|
+
this._hasScheduledRender = false;
|
|
1535
1666
|
/**
|
|
1536
1667
|
* 处理 blur 事件,在用户停止输入时执行待处理的重渲染
|
|
1537
1668
|
* @internal
|
|
@@ -1638,6 +1769,9 @@ var BaseComponent = class extends HTMLElement {
|
|
|
1638
1769
|
if (this._isRendering) {
|
|
1639
1770
|
return;
|
|
1640
1771
|
}
|
|
1772
|
+
if (this._hasScheduledRender) {
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1641
1775
|
const root = this.getActiveRoot();
|
|
1642
1776
|
let activeElement = null;
|
|
1643
1777
|
if (root instanceof ShadowRoot) {
|
|
@@ -1663,8 +1797,16 @@ var BaseComponent = class extends HTMLElement {
|
|
|
1663
1797
|
if (this._pendingRerender) {
|
|
1664
1798
|
this._pendingRerender = false;
|
|
1665
1799
|
}
|
|
1800
|
+
this._hasScheduledRender = true;
|
|
1666
1801
|
requestAnimationFrame(() => {
|
|
1802
|
+
console.warn("[scheduleRerender] RAF callback:", {
|
|
1803
|
+
component: this.constructor.name,
|
|
1804
|
+
connected: this.connected,
|
|
1805
|
+
isRendering: this._isRendering
|
|
1806
|
+
});
|
|
1807
|
+
this._hasScheduledRender = false;
|
|
1667
1808
|
if (this.connected && !this._isRendering) {
|
|
1809
|
+
console.warn("[scheduleRerender] calling _rerender()");
|
|
1668
1810
|
this._isRendering = true;
|
|
1669
1811
|
this._rerender();
|
|
1670
1812
|
} else if (!this.connected) {
|
|
@@ -1921,6 +2063,7 @@ var WebComponent = class extends BaseComponent {
|
|
|
1921
2063
|
(child) => child instanceof HTMLElement && child.style.color === "red" && child.textContent?.includes("Component Error")
|
|
1922
2064
|
);
|
|
1923
2065
|
const hasActualContent = allChildren.length > styleElements.length + slotElements.length;
|
|
2066
|
+
this.onConnected?.();
|
|
1924
2067
|
if (hasActualContent && !hasErrorElement) {
|
|
1925
2068
|
} else {
|
|
1926
2069
|
this.shadowRoot.innerHTML = "";
|
|
@@ -1932,7 +2075,6 @@ var WebComponent = class extends BaseComponent {
|
|
|
1932
2075
|
this.shadowRoot.appendChild(content);
|
|
1933
2076
|
}
|
|
1934
2077
|
this.initializeEventListeners();
|
|
1935
|
-
this.onConnected?.();
|
|
1936
2078
|
if (hasActualContent === false || hasErrorElement) {
|
|
1937
2079
|
requestAnimationFrame(() => {
|
|
1938
2080
|
this.onRendered?.();
|
|
@@ -1984,8 +2126,12 @@ var WebComponent = class extends BaseComponent {
|
|
|
1984
2126
|
const focusState = this.captureFocusState();
|
|
1985
2127
|
this._pendingFocusState = focusState;
|
|
1986
2128
|
const adoptedStyleSheets = this.shadowRoot.adoptedStyleSheets || [];
|
|
2129
|
+
const hasActualAdoptedStyles = this.shadowRoot.adoptedStyleSheets && this.shadowRoot.adoptedStyleSheets.length > 0;
|
|
2130
|
+
const hasFallbackStyleElement = Array.from(this.shadowRoot.children).some(
|
|
2131
|
+
(child) => child instanceof HTMLStyleElement
|
|
2132
|
+
);
|
|
1987
2133
|
try {
|
|
1988
|
-
if (
|
|
2134
|
+
if (!hasActualAdoptedStyles && !hasFallbackStyleElement) {
|
|
1989
2135
|
const stylesToApply = this._autoStyles || this.config.styles;
|
|
1990
2136
|
if (stylesToApply) {
|
|
1991
2137
|
const styleName = this.config.styleName || this.constructor.name;
|
|
@@ -2003,31 +2149,40 @@ var WebComponent = class extends BaseComponent {
|
|
|
2003
2149
|
}
|
|
2004
2150
|
}
|
|
2005
2151
|
}
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
}
|
|
2009
|
-
requestAnimationFrame(() => {
|
|
2152
|
+
const isContentAlreadyInShadowRoot = content.parentNode === this.shadowRoot;
|
|
2153
|
+
if (!isContentAlreadyInShadowRoot) {
|
|
2010
2154
|
this.shadowRoot.appendChild(content);
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
oldChildren.forEach((child) => child.remove());
|
|
2024
|
-
requestAnimationFrame(() => {
|
|
2025
|
-
this.restoreFocusState(focusState);
|
|
2026
|
-
this._pendingFocusState = null;
|
|
2027
|
-
this.onRendered?.();
|
|
2028
|
-
this._isRendering = false;
|
|
2029
|
-
});
|
|
2155
|
+
}
|
|
2156
|
+
const oldChildren = Array.from(this.shadowRoot.children).filter((child) => {
|
|
2157
|
+
if (child === content) {
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
if (child instanceof HTMLStyleElement) {
|
|
2161
|
+
return false;
|
|
2162
|
+
}
|
|
2163
|
+
if (shouldPreserveElement(child)) {
|
|
2164
|
+
return false;
|
|
2165
|
+
}
|
|
2166
|
+
return true;
|
|
2030
2167
|
});
|
|
2168
|
+
oldChildren.forEach((child) => child.remove());
|
|
2169
|
+
const hasStylesAfterDOM = this.shadowRoot.adoptedStyleSheets && this.shadowRoot.adoptedStyleSheets.length > 0;
|
|
2170
|
+
const hasStyleElementAfterDOM = Array.from(this.shadowRoot.children).some(
|
|
2171
|
+
(child) => child instanceof HTMLStyleElement
|
|
2172
|
+
);
|
|
2173
|
+
if (adoptedStyleSheets.length > 0) {
|
|
2174
|
+
this.shadowRoot.adoptedStyleSheets = adoptedStyleSheets;
|
|
2175
|
+
} else if (!hasStylesAfterDOM && !hasStyleElementAfterDOM) {
|
|
2176
|
+
const stylesToApply = this._autoStyles || this.config.styles;
|
|
2177
|
+
if (stylesToApply) {
|
|
2178
|
+
const styleName = this.config.styleName || this.constructor.name;
|
|
2179
|
+
StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
this.restoreFocusState(focusState);
|
|
2183
|
+
this._pendingFocusState = null;
|
|
2184
|
+
this.onRendered?.();
|
|
2185
|
+
this._isRendering = false;
|
|
2031
2186
|
} catch (error) {
|
|
2032
2187
|
logger6.error("Error in _rerender:", error);
|
|
2033
2188
|
this.renderError(error);
|
|
@@ -2089,6 +2244,7 @@ var LightComponent = class extends BaseComponent {
|
|
|
2089
2244
|
const hasActualContent = Array.from(this.children).some(
|
|
2090
2245
|
(child) => child !== styleElement && !(child instanceof HTMLSlotElement)
|
|
2091
2246
|
);
|
|
2247
|
+
this.onConnected?.();
|
|
2092
2248
|
if (hasActualContent && !hasErrorElement) {
|
|
2093
2249
|
this.markJSXChildren();
|
|
2094
2250
|
if (styleElement && styleElement !== this.firstChild) {
|
|
@@ -2106,7 +2262,6 @@ var LightComponent = class extends BaseComponent {
|
|
|
2106
2262
|
}
|
|
2107
2263
|
}
|
|
2108
2264
|
this.initializeEventListeners();
|
|
2109
|
-
this.onConnected?.();
|
|
2110
2265
|
if (hasActualContent === false || hasErrorElement) {
|
|
2111
2266
|
requestAnimationFrame(() => {
|
|
2112
2267
|
this.onRendered?.();
|
|
@@ -2205,11 +2360,18 @@ var LightComponent = class extends BaseComponent {
|
|
|
2205
2360
|
return true;
|
|
2206
2361
|
});
|
|
2207
2362
|
oldChildren.forEach((child) => child.remove());
|
|
2208
|
-
if (stylesToApply
|
|
2209
|
-
|
|
2363
|
+
if (stylesToApply) {
|
|
2364
|
+
let styleElement = this.querySelector(
|
|
2210
2365
|
`style[data-wsx-light-component="${styleName}"]`
|
|
2211
2366
|
);
|
|
2212
|
-
if (styleElement
|
|
2367
|
+
if (!styleElement) {
|
|
2368
|
+
styleElement = document.createElement("style");
|
|
2369
|
+
styleElement.setAttribute("data-wsx-light-component", styleName);
|
|
2370
|
+
styleElement.textContent = stylesToApply;
|
|
2371
|
+
this.insertBefore(styleElement, this.firstChild);
|
|
2372
|
+
} else if (styleElement.textContent !== stylesToApply) {
|
|
2373
|
+
styleElement.textContent = stylesToApply;
|
|
2374
|
+
} else if (styleElement !== this.firstChild) {
|
|
2213
2375
|
this.insertBefore(styleElement, this.firstChild);
|
|
2214
2376
|
}
|
|
2215
2377
|
}
|