@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.
@@ -143,6 +143,10 @@ var CACHE_KEY_PROP = "__wsxCacheKey";
143
143
  function markElement(element, cacheKey) {
144
144
  element[CACHE_KEY_PROP] = cacheKey;
145
145
  }
146
+ function getElementCacheKey(element) {
147
+ const key = element[CACHE_KEY_PROP];
148
+ return key !== void 0 ? String(key) : null;
149
+ }
146
150
  function isCreatedByH(element) {
147
151
  if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
148
152
  return false;
@@ -690,9 +694,18 @@ function updateProps(element, oldProps, newProps, tag) {
690
694
  if (oldValue === newValue) {
691
695
  continue;
692
696
  }
697
+ if (oldValue === void 0) {
698
+ applySingleProp2(element, key, newValue, tag, isSVG);
699
+ continue;
700
+ }
693
701
  if (typeof oldValue === "object" && oldValue !== null && typeof newValue === "object" && newValue !== null) {
694
- if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
695
- continue;
702
+ try {
703
+ const oldJson = JSON.stringify(oldValue);
704
+ const newJson = JSON.stringify(newValue);
705
+ if (oldJson === newJson) {
706
+ continue;
707
+ }
708
+ } catch {
696
709
  }
697
710
  }
698
711
  applySingleProp2(element, key, newValue, tag, isSVG);
@@ -702,68 +715,132 @@ function updateChildren(element, oldChildren, newChildren) {
702
715
  const flatOld = flattenChildren(oldChildren);
703
716
  const flatNew = flattenChildren(newChildren);
704
717
  const minLength = Math.min(flatOld.length, flatNew.length);
718
+ let domIndex = 0;
705
719
  for (let i = 0; i < minLength; i++) {
706
720
  const oldChild = flatOld[i];
707
721
  const newChild = flatNew[i];
722
+ let oldNode = null;
723
+ if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
724
+ if (oldChild.parentNode === element) {
725
+ if (!shouldPreserveElement(oldChild)) {
726
+ oldNode = oldChild;
727
+ }
728
+ } else {
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
+ }
744
+ }
745
+ }
746
+ } else if (typeof oldChild === "string" || typeof oldChild === "number") {
747
+ while (domIndex < element.childNodes.length) {
748
+ const node = element.childNodes[domIndex];
749
+ if (node.nodeType === Node.TEXT_NODE) {
750
+ oldNode = node;
751
+ domIndex++;
752
+ break;
753
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
754
+ domIndex++;
755
+ } else {
756
+ domIndex++;
757
+ }
758
+ }
759
+ }
708
760
  if (typeof oldChild === "string" || typeof oldChild === "number") {
709
761
  if (typeof newChild === "string" || typeof newChild === "number") {
710
- const textNode = element.childNodes[i];
711
- if (textNode && textNode.nodeType === Node.TEXT_NODE) {
712
- textNode.textContent = String(newChild);
762
+ const oldText = String(oldChild);
763
+ const newText = String(newChild);
764
+ const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
765
+ if (!needsUpdate) {
766
+ continue;
767
+ }
768
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
769
+ oldNode.textContent = newText;
713
770
  } else {
714
- const newTextNode = document.createTextNode(String(newChild));
715
- if (textNode) {
716
- element.replaceChild(newTextNode, textNode);
771
+ const newTextNode = document.createTextNode(newText);
772
+ if (oldNode && !shouldPreserveElement(oldNode)) {
773
+ element.replaceChild(newTextNode, oldNode);
717
774
  } else {
718
- element.appendChild(newTextNode);
775
+ element.insertBefore(newTextNode, oldNode || null);
719
776
  }
720
777
  }
721
778
  } else {
722
- const textNode = element.childNodes[i];
723
- if (textNode) {
724
- if (!shouldPreserveElement(textNode)) {
725
- element.removeChild(textNode);
726
- }
779
+ if (oldNode && !shouldPreserveElement(oldNode)) {
780
+ element.removeChild(oldNode);
727
781
  }
728
- if (typeof newChild === "string" || typeof newChild === "number") {
729
- element.appendChild(document.createTextNode(String(newChild)));
730
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
731
- element.appendChild(newChild);
782
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
783
+ if (newChild.parentNode !== element) {
784
+ element.insertBefore(newChild, oldNode || null);
785
+ }
732
786
  } else if (newChild instanceof DocumentFragment) {
733
- element.appendChild(newChild);
787
+ element.insertBefore(newChild, oldNode || null);
734
788
  }
735
789
  }
736
790
  } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
791
+ if (oldNode && shouldPreserveElement(oldNode)) {
792
+ continue;
793
+ }
737
794
  if (newChild === oldChild) {
738
795
  continue;
739
796
  } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
740
- const oldNode = element.childNodes[i];
797
+ const oldCacheKey = oldNode && (oldNode instanceof HTMLElement || oldNode instanceof SVGElement) ? getElementCacheKey(oldNode) : null;
798
+ const newCacheKey = getElementCacheKey(newChild);
799
+ const hasSameCacheKey = oldCacheKey && newCacheKey && oldCacheKey === newCacheKey;
741
800
  if (oldNode) {
742
801
  if (!shouldPreserveElement(oldNode)) {
743
802
  if (oldNode !== newChild) {
744
- element.replaceChild(newChild, oldNode);
803
+ if (newChild.parentNode === element) {
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
+ }
745
818
  }
746
819
  } else {
747
820
  if (newChild.parentNode !== element) {
748
- element.appendChild(newChild);
821
+ if (newChild.parentNode) {
822
+ newChild.parentNode.removeChild(newChild);
823
+ }
824
+ element.insertBefore(newChild, oldNode.nextSibling);
749
825
  }
750
826
  }
751
827
  } else {
752
828
  if (newChild.parentNode !== element) {
829
+ if (newChild.parentNode) {
830
+ newChild.parentNode.removeChild(newChild);
831
+ }
753
832
  element.appendChild(newChild);
754
833
  }
755
834
  }
756
835
  } else {
757
- const oldNode = element.childNodes[i];
758
- if (oldNode) {
759
- if (!shouldPreserveElement(oldNode)) {
760
- element.removeChild(oldNode);
761
- }
836
+ if (oldNode && !shouldPreserveElement(oldNode)) {
837
+ element.removeChild(oldNode);
762
838
  }
763
839
  if (typeof newChild === "string" || typeof newChild === "number") {
764
- element.appendChild(document.createTextNode(String(newChild)));
840
+ const newTextNode = document.createTextNode(String(newChild));
841
+ element.insertBefore(newTextNode, oldNode?.nextSibling || null);
765
842
  } else if (newChild instanceof DocumentFragment) {
766
- element.appendChild(newChild);
843
+ element.insertBefore(newChild, oldNode?.nextSibling || null);
767
844
  }
768
845
  }
769
846
  }
@@ -776,20 +853,85 @@ function updateChildren(element, oldChildren, newChildren) {
776
853
  if (typeof newChild === "string" || typeof newChild === "number") {
777
854
  element.appendChild(document.createTextNode(String(newChild)));
778
855
  } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
779
- if (newChild.parentNode !== element) {
780
- element.appendChild(newChild);
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);
781
866
  }
867
+ element.appendChild(newChild);
782
868
  } else if (newChild instanceof DocumentFragment) {
783
869
  element.appendChild(newChild);
784
870
  }
785
871
  }
786
872
  const nodesToRemove = [];
787
- for (let i = flatNew.length; i < element.childNodes.length; i++) {
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--) {
788
895
  const child = element.childNodes[i];
789
- if (!shouldPreserveElement(child)) {
790
- nodesToRemove.push(child);
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
+ }
791
913
  }
792
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
+ }
793
935
  for (let i = nodesToRemove.length - 1; i >= 0; i--) {
794
936
  const node = nodesToRemove[i];
795
937
  if (node.parentNode === element) {
@@ -801,12 +943,12 @@ function updateElement(element, newProps, newChildren, tag, cacheManager) {
801
943
  const oldMetadata = cacheManager.getMetadata(element);
802
944
  const oldProps = oldMetadata?.props || null;
803
945
  const oldChildren = oldMetadata?.children || [];
804
- updateProps(element, oldProps, newProps, tag);
805
- updateChildren(element, oldChildren, newChildren);
806
946
  cacheManager.setMetadata(element, {
807
947
  props: newProps || {},
808
948
  children: newChildren
809
949
  });
950
+ updateProps(element, oldProps, newProps, tag);
951
+ updateChildren(element, oldChildren, newChildren);
810
952
  }
811
953
 
812
954
  // src/jsx-factory.ts
@@ -820,7 +962,36 @@ function h(tag, props = {}, ...children) {
820
962
  if (context && cacheManager) {
821
963
  return tryUseCacheOrCreate(tag, props, children, context, cacheManager);
822
964
  }
823
- return createElementWithPropsAndChildren(tag, props, children);
965
+ try {
966
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
967
+ globalThis.process.env?.NODE_ENV;
968
+ if (nodeEnv === "development") {
969
+ if (!context) {
970
+ logger3.debug(
971
+ `h() called without render context. Tag: "${tag}", ComponentId: "${getComponentId()}"`,
972
+ {
973
+ tag,
974
+ props: props ? Object.keys(props) : [],
975
+ hasCacheManager: !!cacheManager
976
+ }
977
+ );
978
+ } else if (!cacheManager) {
979
+ logger3.debug(
980
+ `h() called with context but no cache manager. Tag: "${tag}", Component: "${context.constructor.name}"`,
981
+ {
982
+ tag,
983
+ component: context.constructor.name
984
+ }
985
+ );
986
+ }
987
+ }
988
+ } catch {
989
+ }
990
+ const element = createElementWithPropsAndChildren(tag, props, children);
991
+ const componentId = getComponentId();
992
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
993
+ markElement(element, cacheKey);
994
+ return element;
824
995
  }
825
996
  function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
826
997
  try {
@@ -830,6 +1001,14 @@ function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
830
1001
  if (cachedElement) {
831
1002
  const element2 = cachedElement;
832
1003
  updateElement(element2, props, children, tag, cacheManager);
1004
+ const isCustomElement = tag.includes("-") && customElements.get(tag);
1005
+ if (isCustomElement && element2.isConnected) {
1006
+ const parent = element2.parentNode;
1007
+ if (parent) {
1008
+ parent.removeChild(element2);
1009
+ parent.appendChild(element2);
1010
+ }
1011
+ }
833
1012
  return element2;
834
1013
  }
835
1014
  const element = createElementWithPropsAndChildren(tag, props, children);
@@ -853,7 +1032,12 @@ function handleCacheError(error, tag, props, children) {
853
1032
  }
854
1033
  } catch {
855
1034
  }
856
- return createElementWithPropsAndChildren(tag, props, children);
1035
+ const element = createElementWithPropsAndChildren(tag, props, children);
1036
+ const context = RenderContext.getCurrentComponent();
1037
+ const componentId = getComponentId();
1038
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1039
+ markElement(element, cacheKey);
1040
+ return element;
857
1041
  }
858
1042
  function Fragment(_props, children) {
859
1043
  const fragment = document.createDocumentFragment();
@@ -898,6 +1082,7 @@ function jsxs(tag, props) {
898
1082
 
899
1083
  export {
900
1084
  RenderContext,
1085
+ shouldPreserveElement,
901
1086
  createLogger,
902
1087
  h,
903
1088
  Fragment,