@wsxjs/wsx-core 0.0.21 → 0.0.22

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/index.js CHANGED
@@ -182,6 +182,10 @@ var CACHE_KEY_PROP = "__wsxCacheKey";
182
182
  function markElement(element, cacheKey) {
183
183
  element[CACHE_KEY_PROP] = cacheKey;
184
184
  }
185
+ function getElementCacheKey(element) {
186
+ const key = element[CACHE_KEY_PROP];
187
+ return key !== void 0 ? String(key) : null;
188
+ }
185
189
  function isCreatedByH(element) {
186
190
  if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
187
191
  return false;
@@ -729,9 +733,18 @@ function updateProps(element, oldProps, newProps, tag) {
729
733
  if (oldValue === newValue) {
730
734
  continue;
731
735
  }
736
+ if (oldValue === void 0) {
737
+ applySingleProp2(element, key, newValue, tag, isSVG);
738
+ continue;
739
+ }
732
740
  if (typeof oldValue === "object" && oldValue !== null && typeof newValue === "object" && newValue !== null) {
733
- if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
734
- continue;
741
+ try {
742
+ const oldJson = JSON.stringify(oldValue);
743
+ const newJson = JSON.stringify(newValue);
744
+ if (oldJson === newJson) {
745
+ continue;
746
+ }
747
+ } catch {
735
748
  }
736
749
  }
737
750
  applySingleProp2(element, key, newValue, tag, isSVG);
@@ -741,68 +754,132 @@ function updateChildren(element, oldChildren, newChildren) {
741
754
  const flatOld = flattenChildren(oldChildren);
742
755
  const flatNew = flattenChildren(newChildren);
743
756
  const minLength = Math.min(flatOld.length, flatNew.length);
757
+ let domIndex = 0;
744
758
  for (let i = 0; i < minLength; i++) {
745
759
  const oldChild = flatOld[i];
746
760
  const newChild = flatNew[i];
761
+ let oldNode = null;
762
+ if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
763
+ if (oldChild.parentNode === element) {
764
+ if (!shouldPreserveElement(oldChild)) {
765
+ oldNode = oldChild;
766
+ }
767
+ } else {
768
+ const oldCacheKey = getElementCacheKey(oldChild);
769
+ if (oldCacheKey) {
770
+ for (let j = 0; j < element.childNodes.length; j++) {
771
+ const domChild = element.childNodes[j];
772
+ if (domChild instanceof HTMLElement || domChild instanceof SVGElement) {
773
+ if (shouldPreserveElement(domChild)) {
774
+ continue;
775
+ }
776
+ const domCacheKey = getElementCacheKey(domChild);
777
+ if (domCacheKey === oldCacheKey) {
778
+ oldNode = domChild;
779
+ break;
780
+ }
781
+ }
782
+ }
783
+ }
784
+ }
785
+ } else if (typeof oldChild === "string" || typeof oldChild === "number") {
786
+ while (domIndex < element.childNodes.length) {
787
+ const node = element.childNodes[domIndex];
788
+ if (node.nodeType === Node.TEXT_NODE) {
789
+ oldNode = node;
790
+ domIndex++;
791
+ break;
792
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
793
+ domIndex++;
794
+ } else {
795
+ domIndex++;
796
+ }
797
+ }
798
+ }
747
799
  if (typeof oldChild === "string" || typeof oldChild === "number") {
748
800
  if (typeof newChild === "string" || typeof newChild === "number") {
749
- const textNode = element.childNodes[i];
750
- if (textNode && textNode.nodeType === Node.TEXT_NODE) {
751
- textNode.textContent = String(newChild);
801
+ const oldText = String(oldChild);
802
+ const newText = String(newChild);
803
+ const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
804
+ if (!needsUpdate) {
805
+ continue;
806
+ }
807
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
808
+ oldNode.textContent = newText;
752
809
  } else {
753
- const newTextNode = document.createTextNode(String(newChild));
754
- if (textNode) {
755
- element.replaceChild(newTextNode, textNode);
810
+ const newTextNode = document.createTextNode(newText);
811
+ if (oldNode && !shouldPreserveElement(oldNode)) {
812
+ element.replaceChild(newTextNode, oldNode);
756
813
  } else {
757
- element.appendChild(newTextNode);
814
+ element.insertBefore(newTextNode, oldNode || null);
758
815
  }
759
816
  }
760
817
  } else {
761
- const textNode = element.childNodes[i];
762
- if (textNode) {
763
- if (!shouldPreserveElement(textNode)) {
764
- element.removeChild(textNode);
765
- }
818
+ if (oldNode && !shouldPreserveElement(oldNode)) {
819
+ element.removeChild(oldNode);
766
820
  }
767
- if (typeof newChild === "string" || typeof newChild === "number") {
768
- element.appendChild(document.createTextNode(String(newChild)));
769
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
770
- element.appendChild(newChild);
821
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
822
+ if (newChild.parentNode !== element) {
823
+ element.insertBefore(newChild, oldNode || null);
824
+ }
771
825
  } else if (newChild instanceof DocumentFragment) {
772
- element.appendChild(newChild);
826
+ element.insertBefore(newChild, oldNode || null);
773
827
  }
774
828
  }
775
829
  } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
830
+ if (oldNode && shouldPreserveElement(oldNode)) {
831
+ continue;
832
+ }
776
833
  if (newChild === oldChild) {
777
834
  continue;
778
835
  } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
779
- const oldNode = element.childNodes[i];
836
+ const oldCacheKey = oldNode && (oldNode instanceof HTMLElement || oldNode instanceof SVGElement) ? getElementCacheKey(oldNode) : null;
837
+ const newCacheKey = getElementCacheKey(newChild);
838
+ const hasSameCacheKey = oldCacheKey && newCacheKey && oldCacheKey === newCacheKey;
780
839
  if (oldNode) {
781
840
  if (!shouldPreserveElement(oldNode)) {
782
841
  if (oldNode !== newChild) {
783
- element.replaceChild(newChild, oldNode);
842
+ if (newChild.parentNode === element) {
843
+ if (hasSameCacheKey) {
844
+ if (newChild !== oldNode) {
845
+ element.replaceChild(newChild, oldNode);
846
+ }
847
+ } else {
848
+ element.removeChild(newChild);
849
+ element.replaceChild(newChild, oldNode);
850
+ }
851
+ } else if (newChild.parentNode) {
852
+ newChild.parentNode.removeChild(newChild);
853
+ element.replaceChild(newChild, oldNode);
854
+ } else {
855
+ element.replaceChild(newChild, oldNode);
856
+ }
784
857
  }
785
858
  } else {
786
859
  if (newChild.parentNode !== element) {
787
- element.appendChild(newChild);
860
+ if (newChild.parentNode) {
861
+ newChild.parentNode.removeChild(newChild);
862
+ }
863
+ element.insertBefore(newChild, oldNode.nextSibling);
788
864
  }
789
865
  }
790
866
  } else {
791
867
  if (newChild.parentNode !== element) {
868
+ if (newChild.parentNode) {
869
+ newChild.parentNode.removeChild(newChild);
870
+ }
792
871
  element.appendChild(newChild);
793
872
  }
794
873
  }
795
874
  } else {
796
- const oldNode = element.childNodes[i];
797
- if (oldNode) {
798
- if (!shouldPreserveElement(oldNode)) {
799
- element.removeChild(oldNode);
800
- }
875
+ if (oldNode && !shouldPreserveElement(oldNode)) {
876
+ element.removeChild(oldNode);
801
877
  }
802
878
  if (typeof newChild === "string" || typeof newChild === "number") {
803
- element.appendChild(document.createTextNode(String(newChild)));
879
+ const newTextNode = document.createTextNode(String(newChild));
880
+ element.insertBefore(newTextNode, oldNode?.nextSibling || null);
804
881
  } else if (newChild instanceof DocumentFragment) {
805
- element.appendChild(newChild);
882
+ element.insertBefore(newChild, oldNode?.nextSibling || null);
806
883
  }
807
884
  }
808
885
  }
@@ -815,20 +892,85 @@ function updateChildren(element, oldChildren, newChildren) {
815
892
  if (typeof newChild === "string" || typeof newChild === "number") {
816
893
  element.appendChild(document.createTextNode(String(newChild)));
817
894
  } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
818
- if (newChild.parentNode !== element) {
819
- element.appendChild(newChild);
895
+ if (newChild.parentNode === element) {
896
+ const currentIndex = Array.from(element.childNodes).indexOf(newChild);
897
+ const expectedIndex = element.childNodes.length - 1;
898
+ if (currentIndex !== expectedIndex) {
899
+ element.removeChild(newChild);
900
+ element.appendChild(newChild);
901
+ }
902
+ continue;
903
+ } else if (newChild.parentNode) {
904
+ newChild.parentNode.removeChild(newChild);
820
905
  }
906
+ element.appendChild(newChild);
821
907
  } else if (newChild instanceof DocumentFragment) {
822
908
  element.appendChild(newChild);
823
909
  }
824
910
  }
825
911
  const nodesToRemove = [];
826
- for (let i = flatNew.length; i < element.childNodes.length; i++) {
912
+ const newChildSet = /* @__PURE__ */ new Set();
913
+ const newChildCacheKeyMap = /* @__PURE__ */ new Map();
914
+ for (const child of flatNew) {
915
+ if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
916
+ newChildSet.add(child);
917
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
918
+ const cacheKey = getElementCacheKey(child);
919
+ if (cacheKey) {
920
+ newChildCacheKeyMap.set(cacheKey, child);
921
+ }
922
+ }
923
+ }
924
+ }
925
+ const processedCacheKeys = /* @__PURE__ */ new Set();
926
+ const newChildToIndexMap = /* @__PURE__ */ new Map();
927
+ for (let i = 0; i < flatNew.length; i++) {
928
+ const child = flatNew[i];
929
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
930
+ newChildToIndexMap.set(child, i);
931
+ }
932
+ }
933
+ for (let i = element.childNodes.length - 1; i >= 0; i--) {
827
934
  const child = element.childNodes[i];
828
- if (!shouldPreserveElement(child)) {
829
- nodesToRemove.push(child);
935
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
936
+ if (shouldPreserveElement(child)) {
937
+ continue;
938
+ }
939
+ const cacheKey = getElementCacheKey(child);
940
+ if (cacheKey && newChildCacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
941
+ processedCacheKeys.add(cacheKey);
942
+ const newChild = newChildCacheKeyMap.get(cacheKey);
943
+ if (child !== newChild) {
944
+ if (newChild.parentNode === element) {
945
+ element.replaceChild(newChild, child);
946
+ } else {
947
+ element.replaceChild(newChild, child);
948
+ }
949
+ } else {
950
+ }
951
+ }
830
952
  }
831
953
  }
954
+ for (let i = 0; i < element.childNodes.length; i++) {
955
+ const child = element.childNodes[i];
956
+ if (shouldPreserveElement(child)) {
957
+ continue;
958
+ }
959
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
960
+ if (newChildSet.has(child)) {
961
+ continue;
962
+ }
963
+ const cacheKey = getElementCacheKey(child);
964
+ if (cacheKey && newChildCacheKeyMap.has(cacheKey)) {
965
+ continue;
966
+ }
967
+ } else if (child instanceof DocumentFragment) {
968
+ if (newChildSet.has(child)) {
969
+ continue;
970
+ }
971
+ }
972
+ nodesToRemove.push(child);
973
+ }
832
974
  for (let i = nodesToRemove.length - 1; i >= 0; i--) {
833
975
  const node = nodesToRemove[i];
834
976
  if (node.parentNode === element) {
@@ -840,12 +982,12 @@ function updateElement(element, newProps, newChildren, tag, cacheManager) {
840
982
  const oldMetadata = cacheManager.getMetadata(element);
841
983
  const oldProps = oldMetadata?.props || null;
842
984
  const oldChildren = oldMetadata?.children || [];
843
- updateProps(element, oldProps, newProps, tag);
844
- updateChildren(element, oldChildren, newChildren);
845
985
  cacheManager.setMetadata(element, {
846
986
  props: newProps || {},
847
987
  children: newChildren
848
988
  });
989
+ updateProps(element, oldProps, newProps, tag);
990
+ updateChildren(element, oldChildren, newChildren);
849
991
  }
850
992
 
851
993
  // src/jsx-factory.ts
@@ -859,7 +1001,36 @@ function h(tag, props = {}, ...children) {
859
1001
  if (context && cacheManager) {
860
1002
  return tryUseCacheOrCreate(tag, props, children, context, cacheManager);
861
1003
  }
862
- return createElementWithPropsAndChildren(tag, props, children);
1004
+ try {
1005
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
1006
+ globalThis.process.env?.NODE_ENV;
1007
+ if (nodeEnv === "development") {
1008
+ if (!context) {
1009
+ logger3.debug(
1010
+ `h() called without render context. Tag: "${tag}", ComponentId: "${getComponentId()}"`,
1011
+ {
1012
+ tag,
1013
+ props: props ? Object.keys(props) : [],
1014
+ hasCacheManager: !!cacheManager
1015
+ }
1016
+ );
1017
+ } else if (!cacheManager) {
1018
+ logger3.debug(
1019
+ `h() called with context but no cache manager. Tag: "${tag}", Component: "${context.constructor.name}"`,
1020
+ {
1021
+ tag,
1022
+ component: context.constructor.name
1023
+ }
1024
+ );
1025
+ }
1026
+ }
1027
+ } catch {
1028
+ }
1029
+ const element = createElementWithPropsAndChildren(tag, props, children);
1030
+ const componentId = getComponentId();
1031
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1032
+ markElement(element, cacheKey);
1033
+ return element;
863
1034
  }
864
1035
  function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
865
1036
  try {
@@ -869,6 +1040,14 @@ function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
869
1040
  if (cachedElement) {
870
1041
  const element2 = cachedElement;
871
1042
  updateElement(element2, props, children, tag, cacheManager);
1043
+ const isCustomElement = tag.includes("-") && customElements.get(tag);
1044
+ if (isCustomElement && element2.isConnected) {
1045
+ const parent = element2.parentNode;
1046
+ if (parent) {
1047
+ parent.removeChild(element2);
1048
+ parent.appendChild(element2);
1049
+ }
1050
+ }
872
1051
  return element2;
873
1052
  }
874
1053
  const element = createElementWithPropsAndChildren(tag, props, children);
@@ -892,7 +1071,12 @@ function handleCacheError(error, tag, props, children) {
892
1071
  }
893
1072
  } catch {
894
1073
  }
895
- return createElementWithPropsAndChildren(tag, props, children);
1074
+ const element = createElementWithPropsAndChildren(tag, props, children);
1075
+ const context = RenderContext.getCurrentComponent();
1076
+ const componentId = getComponentId();
1077
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1078
+ markElement(element, cacheKey);
1079
+ return element;
896
1080
  }
897
1081
  function Fragment(_props, children) {
898
1082
  const fragment = document.createDocumentFragment();
@@ -1703,7 +1887,7 @@ var WebComponent = class extends BaseComponent {
1703
1887
  const styleName = this.config.styleName || this.constructor.name;
1704
1888
  StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
1705
1889
  }
1706
- const content = this.render();
1890
+ const content = RenderContext.runInContext(this, () => this.render());
1707
1891
  this.shadowRoot.appendChild(content);
1708
1892
  }
1709
1893
  this.initializeEventListeners();
@@ -1783,9 +1967,18 @@ var WebComponent = class extends BaseComponent {
1783
1967
  }
1784
1968
  requestAnimationFrame(() => {
1785
1969
  this.shadowRoot.appendChild(content);
1786
- const oldChildren = Array.from(this.shadowRoot.children).filter(
1787
- (child) => child !== content
1788
- );
1970
+ const oldChildren = Array.from(this.shadowRoot.children).filter((child) => {
1971
+ if (child === content) {
1972
+ return false;
1973
+ }
1974
+ if (child instanceof HTMLStyleElement) {
1975
+ return false;
1976
+ }
1977
+ if (shouldPreserveElement(child)) {
1978
+ return false;
1979
+ }
1980
+ return true;
1981
+ });
1789
1982
  oldChildren.forEach((child) => child.remove());
1790
1983
  requestAnimationFrame(() => {
1791
1984
  this.restoreFocusState(focusState);
@@ -1965,6 +2158,9 @@ var LightComponent = class extends BaseComponent {
1965
2158
  if (child instanceof HTMLElement && jsxChildren.includes(child)) {
1966
2159
  return false;
1967
2160
  }
2161
+ if (shouldPreserveElement(child)) {
2162
+ return false;
2163
+ }
1968
2164
  return true;
1969
2165
  });
1970
2166
  oldChildren.forEach((child) => child.remove());
package/dist/index.mjs CHANGED
@@ -2,8 +2,9 @@ import {
2
2
  Fragment,
3
3
  RenderContext,
4
4
  createLogger,
5
- h
6
- } from "./chunk-AR3DIDLV.mjs";
5
+ h,
6
+ shouldPreserveElement
7
+ } from "./chunk-OXFZ575O.mjs";
7
8
 
8
9
  // src/styles/style-manager.ts
9
10
  var StyleManager = class {
@@ -796,7 +797,7 @@ var WebComponent = class extends BaseComponent {
796
797
  const styleName = this.config.styleName || this.constructor.name;
797
798
  StyleManager.applyStyles(this.shadowRoot, styleName, stylesToApply);
798
799
  }
799
- const content = this.render();
800
+ const content = RenderContext.runInContext(this, () => this.render());
800
801
  this.shadowRoot.appendChild(content);
801
802
  }
802
803
  this.initializeEventListeners();
@@ -876,9 +877,18 @@ var WebComponent = class extends BaseComponent {
876
877
  }
877
878
  requestAnimationFrame(() => {
878
879
  this.shadowRoot.appendChild(content);
879
- const oldChildren = Array.from(this.shadowRoot.children).filter(
880
- (child) => child !== content
881
- );
880
+ const oldChildren = Array.from(this.shadowRoot.children).filter((child) => {
881
+ if (child === content) {
882
+ return false;
883
+ }
884
+ if (child instanceof HTMLStyleElement) {
885
+ return false;
886
+ }
887
+ if (shouldPreserveElement(child)) {
888
+ return false;
889
+ }
890
+ return true;
891
+ });
882
892
  oldChildren.forEach((child) => child.remove());
883
893
  requestAnimationFrame(() => {
884
894
  this.restoreFocusState(focusState);
@@ -1058,6 +1068,9 @@ var LightComponent = class extends BaseComponent {
1058
1068
  if (child instanceof HTMLElement && jsxChildren.includes(child)) {
1059
1069
  return false;
1060
1070
  }
1071
+ if (shouldPreserveElement(child)) {
1072
+ return false;
1073
+ }
1061
1074
  return true;
1062
1075
  });
1063
1076
  oldChildren.forEach((child) => child.remove());