@wsxjs/wsx-core 0.0.21 → 0.0.23

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.
@@ -171,6 +171,10 @@ var CACHE_KEY_PROP = "__wsxCacheKey";
171
171
  function markElement(element, cacheKey) {
172
172
  element[CACHE_KEY_PROP] = cacheKey;
173
173
  }
174
+ function getElementCacheKey(element) {
175
+ const key = element[CACHE_KEY_PROP];
176
+ return key !== void 0 ? String(key) : null;
177
+ }
174
178
  function isCreatedByH(element) {
175
179
  if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
176
180
  return false;
@@ -618,6 +622,185 @@ function createElementWithPropsAndChildren(tag, props, children) {
618
622
  return element;
619
623
  }
620
624
 
625
+ // src/utils/update-children-helpers.ts
626
+ function collectPreservedElements(element) {
627
+ const preserved = [];
628
+ for (let i = 0; i < element.childNodes.length; i++) {
629
+ const child = element.childNodes[i];
630
+ if (shouldPreserveElement(child)) {
631
+ preserved.push(child);
632
+ }
633
+ }
634
+ return preserved;
635
+ }
636
+ function findDOMNodeByReference(oldChild, parent) {
637
+ if (oldChild.parentNode === parent && !shouldPreserveElement(oldChild)) {
638
+ return oldChild;
639
+ }
640
+ return null;
641
+ }
642
+ function findDOMNodeByCacheKey(cacheKey, parent) {
643
+ for (let i = 0; i < parent.childNodes.length; i++) {
644
+ const child = parent.childNodes[i];
645
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
646
+ if (shouldPreserveElement(child)) continue;
647
+ if (getElementCacheKey(child) === cacheKey) {
648
+ return child;
649
+ }
650
+ }
651
+ }
652
+ return null;
653
+ }
654
+ function findElementNode(oldChild, parent) {
655
+ const byRef = findDOMNodeByReference(oldChild, parent);
656
+ if (byRef) return byRef;
657
+ const cacheKey = getElementCacheKey(oldChild);
658
+ if (cacheKey) {
659
+ return findDOMNodeByCacheKey(cacheKey, parent);
660
+ }
661
+ return null;
662
+ }
663
+ function findTextNode(parent, domIndex) {
664
+ while (domIndex.value < parent.childNodes.length) {
665
+ const node = parent.childNodes[domIndex.value];
666
+ if (node.nodeType === Node.TEXT_NODE) {
667
+ const textNode = node;
668
+ domIndex.value++;
669
+ return textNode;
670
+ }
671
+ domIndex.value++;
672
+ }
673
+ return null;
674
+ }
675
+ function updateOrCreateTextNode(parent, oldNode, newText) {
676
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
677
+ if (oldNode.textContent !== newText) {
678
+ oldNode.textContent = newText;
679
+ }
680
+ } else {
681
+ const newTextNode = document.createTextNode(newText);
682
+ if (oldNode && !shouldPreserveElement(oldNode)) {
683
+ parent.replaceChild(newTextNode, oldNode);
684
+ } else {
685
+ parent.insertBefore(newTextNode, oldNode || null);
686
+ }
687
+ }
688
+ }
689
+ function removeNodeIfNotPreserved(parent, node) {
690
+ if (node && !shouldPreserveElement(node) && node.parentNode === parent) {
691
+ parent.removeChild(node);
692
+ }
693
+ }
694
+ function replaceOrInsertElement(parent, newChild, oldNode) {
695
+ if (newChild.parentNode && newChild.parentNode !== parent) {
696
+ newChild.parentNode.removeChild(newChild);
697
+ }
698
+ if (oldNode && !shouldPreserveElement(oldNode)) {
699
+ if (oldNode !== newChild) {
700
+ parent.replaceChild(newChild, oldNode);
701
+ }
702
+ } else if (newChild.parentNode !== parent) {
703
+ parent.insertBefore(newChild, oldNode || null);
704
+ }
705
+ }
706
+ function appendNewChild(parent, child) {
707
+ if (child === null || child === void 0 || child === false) {
708
+ return;
709
+ }
710
+ if (typeof child === "string" || typeof child === "number") {
711
+ parent.appendChild(document.createTextNode(String(child)));
712
+ } else if (child instanceof HTMLElement || child instanceof SVGElement) {
713
+ if (child.parentNode && child.parentNode !== parent) {
714
+ child.parentNode.removeChild(child);
715
+ }
716
+ if (child.parentNode !== parent) {
717
+ parent.appendChild(child);
718
+ }
719
+ } else if (child instanceof DocumentFragment) {
720
+ parent.appendChild(child);
721
+ }
722
+ }
723
+ function buildNewChildrenMaps(flatNew) {
724
+ const elementSet = /* @__PURE__ */ new Set();
725
+ const cacheKeyMap = /* @__PURE__ */ new Map();
726
+ for (const child of flatNew) {
727
+ if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
728
+ elementSet.add(child);
729
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
730
+ const cacheKey = getElementCacheKey(child);
731
+ if (cacheKey) {
732
+ cacheKeyMap.set(cacheKey, child);
733
+ }
734
+ }
735
+ }
736
+ }
737
+ return { elementSet, cacheKeyMap };
738
+ }
739
+ function shouldRemoveNode(node, elementSet, cacheKeyMap) {
740
+ if (shouldPreserveElement(node)) {
741
+ return false;
742
+ }
743
+ if (node instanceof HTMLElement || node instanceof SVGElement || node instanceof DocumentFragment) {
744
+ if (elementSet.has(node)) {
745
+ return false;
746
+ }
747
+ if (node instanceof HTMLElement || node instanceof SVGElement) {
748
+ const cacheKey = getElementCacheKey(node);
749
+ if (cacheKey && cacheKeyMap.has(cacheKey)) {
750
+ return false;
751
+ }
752
+ }
753
+ }
754
+ return true;
755
+ }
756
+ function deduplicateCacheKeys(parent, cacheKeyMap) {
757
+ const processedCacheKeys = /* @__PURE__ */ new Set();
758
+ for (let i = parent.childNodes.length - 1; i >= 0; i--) {
759
+ const child = parent.childNodes[i];
760
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
761
+ if (shouldPreserveElement(child)) {
762
+ continue;
763
+ }
764
+ const cacheKey = getElementCacheKey(child);
765
+ if (cacheKey && cacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
766
+ processedCacheKeys.add(cacheKey);
767
+ const newChild = cacheKeyMap.get(cacheKey);
768
+ if (child !== newChild) {
769
+ parent.replaceChild(newChild, child);
770
+ }
771
+ }
772
+ }
773
+ }
774
+ }
775
+ function collectNodesToRemove(parent, elementSet, cacheKeyMap) {
776
+ const nodesToRemove = [];
777
+ for (let i = 0; i < parent.childNodes.length; i++) {
778
+ const node = parent.childNodes[i];
779
+ if (shouldRemoveNode(node, elementSet, cacheKeyMap)) {
780
+ nodesToRemove.push(node);
781
+ }
782
+ }
783
+ return nodesToRemove;
784
+ }
785
+ function removeNodes(parent, nodes) {
786
+ for (let i = nodes.length - 1; i >= 0; i--) {
787
+ const node = nodes[i];
788
+ if (node.parentNode === parent) {
789
+ parent.removeChild(node);
790
+ }
791
+ }
792
+ }
793
+ function reinsertPreservedElements(parent, preservedElements) {
794
+ for (const element of preservedElements) {
795
+ if (element.parentNode !== parent) {
796
+ parent.appendChild(element);
797
+ }
798
+ }
799
+ }
800
+ function flattenChildrenSafe(children) {
801
+ return flattenChildren(children);
802
+ }
803
+
621
804
  // src/utils/element-update.ts
622
805
  function removeProp(element, key, oldValue, tag) {
623
806
  const isSVG = shouldUseSVGNamespace(tag);
@@ -718,123 +901,123 @@ function updateProps(element, oldProps, newProps, tag) {
718
901
  if (oldValue === newValue) {
719
902
  continue;
720
903
  }
904
+ if (oldValue === void 0) {
905
+ applySingleProp2(element, key, newValue, tag, isSVG);
906
+ continue;
907
+ }
721
908
  if (typeof oldValue === "object" && oldValue !== null && typeof newValue === "object" && newValue !== null) {
722
- if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
723
- continue;
909
+ try {
910
+ const oldJson = JSON.stringify(oldValue);
911
+ const newJson = JSON.stringify(newValue);
912
+ if (oldJson === newJson) {
913
+ continue;
914
+ }
915
+ } catch {
724
916
  }
725
917
  }
726
918
  applySingleProp2(element, key, newValue, tag, isSVG);
727
919
  }
728
920
  }
729
- function updateChildren(element, oldChildren, newChildren) {
730
- const flatOld = flattenChildren(oldChildren);
731
- const flatNew = flattenChildren(newChildren);
921
+ function updateChildren(element, oldChildren, newChildren, cacheManager) {
922
+ const flatOld = flattenChildrenSafe(oldChildren);
923
+ const flatNew = flattenChildrenSafe(newChildren);
924
+ const preservedElements = collectPreservedElements(element);
732
925
  const minLength = Math.min(flatOld.length, flatNew.length);
926
+ const domIndex = { value: 0 };
733
927
  for (let i = 0; i < minLength; i++) {
734
928
  const oldChild = flatOld[i];
735
929
  const newChild = flatNew[i];
930
+ let oldNode = null;
931
+ if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
932
+ oldNode = findElementNode(oldChild, element);
933
+ if (oldNode && oldNode.parentNode === element) {
934
+ const nodeIndex = Array.from(element.childNodes).indexOf(oldNode);
935
+ if (nodeIndex !== -1 && nodeIndex >= domIndex.value) {
936
+ domIndex.value = nodeIndex + 1;
937
+ }
938
+ }
939
+ } else if (typeof oldChild === "string" || typeof oldChild === "number") {
940
+ oldNode = findTextNode(element, domIndex);
941
+ if (!oldNode && element.childNodes.length > 0) {
942
+ for (let j = domIndex.value; j < element.childNodes.length; j++) {
943
+ const node = element.childNodes[j];
944
+ if (node.nodeType === Node.TEXT_NODE) {
945
+ oldNode = node;
946
+ domIndex.value = j + 1;
947
+ break;
948
+ }
949
+ }
950
+ }
951
+ }
736
952
  if (typeof oldChild === "string" || typeof oldChild === "number") {
737
953
  if (typeof newChild === "string" || typeof newChild === "number") {
738
- const textNode = element.childNodes[i];
739
- if (textNode && textNode.nodeType === Node.TEXT_NODE) {
740
- textNode.textContent = String(newChild);
741
- } else {
742
- const newTextNode = document.createTextNode(String(newChild));
743
- if (textNode) {
744
- element.replaceChild(newTextNode, textNode);
745
- } else {
746
- element.appendChild(newTextNode);
747
- }
954
+ const oldText = String(oldChild);
955
+ const newText = String(newChild);
956
+ const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
957
+ if (needsUpdate) {
958
+ updateOrCreateTextNode(element, oldNode, newText);
748
959
  }
749
960
  } else {
750
- const textNode = element.childNodes[i];
751
- if (textNode) {
752
- if (!shouldPreserveElement(textNode)) {
753
- element.removeChild(textNode);
754
- }
755
- }
756
- if (typeof newChild === "string" || typeof newChild === "number") {
757
- element.appendChild(document.createTextNode(String(newChild)));
758
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
759
- element.appendChild(newChild);
961
+ removeNodeIfNotPreserved(element, oldNode);
962
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
963
+ replaceOrInsertElement(element, newChild, oldNode);
760
964
  } else if (newChild instanceof DocumentFragment) {
761
- element.appendChild(newChild);
965
+ element.insertBefore(newChild, oldNode || null);
762
966
  }
763
967
  }
764
968
  } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
765
- if (newChild === oldChild) {
969
+ if (oldNode && shouldPreserveElement(oldNode)) {
766
970
  continue;
767
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
768
- const oldNode = element.childNodes[i];
769
- if (oldNode) {
770
- if (!shouldPreserveElement(oldNode)) {
771
- if (oldNode !== newChild) {
772
- element.replaceChild(newChild, oldNode);
773
- }
774
- } else {
775
- if (newChild.parentNode !== element) {
776
- element.appendChild(newChild);
971
+ }
972
+ if (newChild === oldChild && (newChild instanceof HTMLElement || newChild instanceof SVGElement)) {
973
+ if (cacheManager) {
974
+ const childMetadata = cacheManager.getMetadata(newChild);
975
+ if (childMetadata) {
976
+ if (oldNode === newChild && newChild.parentNode === element) {
977
+ continue;
777
978
  }
778
979
  }
779
980
  } else {
780
- if (newChild.parentNode !== element) {
781
- element.appendChild(newChild);
981
+ if (oldNode === newChild && newChild.parentNode === element) {
982
+ continue;
782
983
  }
783
984
  }
784
- } else {
785
- const oldNode = element.childNodes[i];
786
- if (oldNode) {
787
- if (!shouldPreserveElement(oldNode)) {
788
- element.removeChild(oldNode);
789
- }
985
+ }
986
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
987
+ if (newChild.parentNode === element && oldNode === newChild) {
988
+ continue;
790
989
  }
990
+ replaceOrInsertElement(element, newChild, oldNode);
991
+ } else {
992
+ removeNodeIfNotPreserved(element, oldNode);
791
993
  if (typeof newChild === "string" || typeof newChild === "number") {
792
- element.appendChild(document.createTextNode(String(newChild)));
994
+ const newTextNode = document.createTextNode(String(newChild));
995
+ element.insertBefore(newTextNode, oldNode?.nextSibling || null);
793
996
  } else if (newChild instanceof DocumentFragment) {
794
- element.appendChild(newChild);
997
+ element.insertBefore(newChild, oldNode?.nextSibling || null);
795
998
  }
796
999
  }
797
1000
  }
798
1001
  }
799
1002
  for (let i = minLength; i < flatNew.length; i++) {
800
- const newChild = flatNew[i];
801
- if (newChild === null || newChild === void 0 || newChild === false) {
802
- continue;
803
- }
804
- if (typeof newChild === "string" || typeof newChild === "number") {
805
- element.appendChild(document.createTextNode(String(newChild)));
806
- } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
807
- if (newChild.parentNode !== element) {
808
- element.appendChild(newChild);
809
- }
810
- } else if (newChild instanceof DocumentFragment) {
811
- element.appendChild(newChild);
812
- }
813
- }
814
- const nodesToRemove = [];
815
- for (let i = flatNew.length; i < element.childNodes.length; i++) {
816
- const child = element.childNodes[i];
817
- if (!shouldPreserveElement(child)) {
818
- nodesToRemove.push(child);
819
- }
820
- }
821
- for (let i = nodesToRemove.length - 1; i >= 0; i--) {
822
- const node = nodesToRemove[i];
823
- if (node.parentNode === element) {
824
- element.removeChild(node);
825
- }
1003
+ appendNewChild(element, flatNew[i]);
826
1004
  }
1005
+ const { elementSet, cacheKeyMap } = buildNewChildrenMaps(flatNew);
1006
+ deduplicateCacheKeys(element, cacheKeyMap);
1007
+ const nodesToRemove = collectNodesToRemove(element, elementSet, cacheKeyMap);
1008
+ removeNodes(element, nodesToRemove);
1009
+ reinsertPreservedElements(element, preservedElements);
827
1010
  }
828
1011
  function updateElement(element, newProps, newChildren, tag, cacheManager) {
829
1012
  const oldMetadata = cacheManager.getMetadata(element);
830
1013
  const oldProps = oldMetadata?.props || null;
831
1014
  const oldChildren = oldMetadata?.children || [];
832
- updateProps(element, oldProps, newProps, tag);
833
- updateChildren(element, oldChildren, newChildren);
834
1015
  cacheManager.setMetadata(element, {
835
1016
  props: newProps || {},
836
1017
  children: newChildren
837
1018
  });
1019
+ updateProps(element, oldProps, newProps, tag);
1020
+ updateChildren(element, oldChildren, newChildren, cacheManager);
838
1021
  }
839
1022
 
840
1023
  // src/jsx-factory.ts
@@ -848,7 +1031,36 @@ function h(tag, props = {}, ...children) {
848
1031
  if (context && cacheManager) {
849
1032
  return tryUseCacheOrCreate(tag, props, children, context, cacheManager);
850
1033
  }
851
- return createElementWithPropsAndChildren(tag, props, children);
1034
+ try {
1035
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
1036
+ globalThis.process.env?.NODE_ENV;
1037
+ if (nodeEnv === "development") {
1038
+ if (!context) {
1039
+ logger3.debug(
1040
+ `h() called without render context. Tag: "${tag}", ComponentId: "${getComponentId()}"`,
1041
+ {
1042
+ tag,
1043
+ props: props ? Object.keys(props) : [],
1044
+ hasCacheManager: !!cacheManager
1045
+ }
1046
+ );
1047
+ } else if (!cacheManager) {
1048
+ logger3.debug(
1049
+ `h() called with context but no cache manager. Tag: "${tag}", Component: "${context.constructor.name}"`,
1050
+ {
1051
+ tag,
1052
+ component: context.constructor.name
1053
+ }
1054
+ );
1055
+ }
1056
+ }
1057
+ } catch {
1058
+ }
1059
+ const element = createElementWithPropsAndChildren(tag, props, children);
1060
+ const componentId = getComponentId();
1061
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1062
+ markElement(element, cacheKey);
1063
+ return element;
852
1064
  }
853
1065
  function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
854
1066
  try {
@@ -858,6 +1070,14 @@ function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
858
1070
  if (cachedElement) {
859
1071
  const element2 = cachedElement;
860
1072
  updateElement(element2, props, children, tag, cacheManager);
1073
+ const isCustomElement = tag.includes("-") && customElements.get(tag);
1074
+ if (isCustomElement && element2.isConnected) {
1075
+ const parent = element2.parentNode;
1076
+ if (parent) {
1077
+ parent.removeChild(element2);
1078
+ parent.appendChild(element2);
1079
+ }
1080
+ }
861
1081
  return element2;
862
1082
  }
863
1083
  const element = createElementWithPropsAndChildren(tag, props, children);
@@ -881,7 +1101,12 @@ function handleCacheError(error, tag, props, children) {
881
1101
  }
882
1102
  } catch {
883
1103
  }
884
- return createElementWithPropsAndChildren(tag, props, children);
1104
+ const element = createElementWithPropsAndChildren(tag, props, children);
1105
+ const context = RenderContext.getCurrentComponent();
1106
+ const componentId = getComponentId();
1107
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1108
+ markElement(element, cacheKey);
1109
+ return element;
885
1110
  }
886
1111
  function Fragment(_props, children) {
887
1112
  const fragment = document.createDocumentFragment();
@@ -2,7 +2,7 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-AR3DIDLV.mjs";
5
+ } from "./chunk-ESZYREJK.mjs";
6
6
  export {
7
7
  Fragment,
8
8
  jsx,