@wsxjs/wsx-core 0.0.20 → 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.
@@ -26,6 +26,174 @@ __export(jsx_runtime_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(jsx_runtime_exports);
28
28
 
29
+ // src/utils/dom-utils.ts
30
+ function parseHTMLToNodes(html) {
31
+ if (!html) return [];
32
+ const temp = document.createElement("div");
33
+ temp.innerHTML = html;
34
+ return Array.from(temp.childNodes).map((node) => {
35
+ if (node instanceof HTMLElement || node instanceof SVGElement) {
36
+ return node;
37
+ } else {
38
+ return node.textContent || "";
39
+ }
40
+ });
41
+ }
42
+ function isHTMLString(str) {
43
+ const trimmed = str.trim();
44
+ if (!trimmed) return false;
45
+ const htmlTagPattern = /<[a-z][a-z0-9]*(\s[^>]*)?(\/>|>)/i;
46
+ const looksLikeMath = /^[^<]*<[^>]*>[^>]*$/.test(trimmed) && !htmlTagPattern.test(trimmed);
47
+ if (looksLikeMath) return false;
48
+ return htmlTagPattern.test(trimmed);
49
+ }
50
+ function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
51
+ if (depth > 10) {
52
+ console.warn(
53
+ "[WSX] flattenChildren: Maximum depth exceeded, treating remaining children as text"
54
+ );
55
+ return children.filter(
56
+ (child) => typeof child === "string" || typeof child === "number"
57
+ );
58
+ }
59
+ const result = [];
60
+ for (const child of children) {
61
+ if (child === null || child === void 0 || child === false) {
62
+ continue;
63
+ } else if (Array.isArray(child)) {
64
+ result.push(...flattenChildren(child, skipHTMLDetection, depth + 1));
65
+ } else if (typeof child === "string") {
66
+ if (skipHTMLDetection) {
67
+ result.push(child);
68
+ } else if (isHTMLString(child)) {
69
+ try {
70
+ const nodes = parseHTMLToNodes(child);
71
+ if (nodes.length > 0) {
72
+ for (const node of nodes) {
73
+ if (typeof node === "string") {
74
+ result.push(node);
75
+ } else {
76
+ result.push(node);
77
+ }
78
+ }
79
+ } else {
80
+ result.push(child);
81
+ }
82
+ } catch (error) {
83
+ console.warn("[WSX] Failed to parse HTML string, treating as text:", error);
84
+ result.push(child);
85
+ }
86
+ } else {
87
+ result.push(child);
88
+ }
89
+ } else {
90
+ result.push(child);
91
+ }
92
+ }
93
+ return result;
94
+ }
95
+
96
+ // src/render-context.ts
97
+ var _RenderContext = class _RenderContext {
98
+ /**
99
+ * Executes a function within the context of a component.
100
+ * @param component The component instance currently rendering.
101
+ * @param fn The function to execute (usually the render method).
102
+ */
103
+ static runInContext(component, fn) {
104
+ const prev = _RenderContext.current;
105
+ _RenderContext.current = component;
106
+ try {
107
+ return fn();
108
+ } finally {
109
+ _RenderContext.current = prev;
110
+ }
111
+ }
112
+ /**
113
+ * Gets the currently rendering component.
114
+ */
115
+ static getCurrentComponent() {
116
+ return _RenderContext.current;
117
+ }
118
+ /**
119
+ * Gets the current component's DOM cache.
120
+ */
121
+ static getDOMCache() {
122
+ return _RenderContext.current?.getDomCache();
123
+ }
124
+ };
125
+ _RenderContext.current = null;
126
+ var RenderContext = _RenderContext;
127
+
128
+ // src/utils/cache-key.ts
129
+ var POSITION_ID_KEY = "__wsxPositionId";
130
+ var INDEX_KEY = "__wsxIndex";
131
+ var componentElementCounters = /* @__PURE__ */ new WeakMap();
132
+ var componentIdCache = /* @__PURE__ */ new WeakMap();
133
+ function generateCacheKey(tag, props, componentId, component) {
134
+ const positionId = props?.[POSITION_ID_KEY];
135
+ const userKey = props?.key;
136
+ const index = props?.[INDEX_KEY];
137
+ if (userKey !== void 0 && userKey !== null) {
138
+ return `${componentId}:${tag}:key-${String(userKey)}`;
139
+ }
140
+ if (index !== void 0 && index !== null) {
141
+ return `${componentId}:${tag}:idx-${String(index)}`;
142
+ }
143
+ if (positionId !== void 0 && positionId !== null && positionId !== "no-id") {
144
+ return `${componentId}:${tag}:${String(positionId)}`;
145
+ }
146
+ if (component) {
147
+ let counter = componentElementCounters.get(component) || 0;
148
+ counter++;
149
+ componentElementCounters.set(component, counter);
150
+ return `${componentId}:${tag}:auto-${counter}`;
151
+ }
152
+ return `${componentId}:${tag}:fallback-${Date.now()}-${Math.random()}`;
153
+ }
154
+ function getComponentId() {
155
+ const component = RenderContext.getCurrentComponent();
156
+ if (component) {
157
+ let cachedId = componentIdCache.get(component);
158
+ if (cachedId) {
159
+ return cachedId;
160
+ }
161
+ const instanceId = component._instanceId || "default";
162
+ cachedId = `${component.constructor.name}:${instanceId}`;
163
+ componentIdCache.set(component, cachedId);
164
+ return cachedId;
165
+ }
166
+ return "unknown";
167
+ }
168
+
169
+ // src/utils/element-marking.ts
170
+ var CACHE_KEY_PROP = "__wsxCacheKey";
171
+ function markElement(element, cacheKey) {
172
+ element[CACHE_KEY_PROP] = cacheKey;
173
+ }
174
+ function getElementCacheKey(element) {
175
+ const key = element[CACHE_KEY_PROP];
176
+ return key !== void 0 ? String(key) : null;
177
+ }
178
+ function isCreatedByH(element) {
179
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
180
+ return false;
181
+ }
182
+ return element[CACHE_KEY_PROP] !== void 0;
183
+ }
184
+ function shouldPreserveElement(element) {
185
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
186
+ return true;
187
+ }
188
+ if (!isCreatedByH(element)) {
189
+ return true;
190
+ }
191
+ if (element.hasAttribute("data-wsx-preserve")) {
192
+ return true;
193
+ }
194
+ return false;
195
+ }
196
+
29
197
  // src/utils/svg-utils.ts
30
198
  var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
31
199
  var SVG_ONLY_ELEMENTS = /* @__PURE__ */ new Set([
@@ -138,21 +306,63 @@ function getSVGAttributeName(attributeName) {
138
306
  return SVG_ATTRIBUTE_MAP.get(attributeName) || attributeName;
139
307
  }
140
308
 
141
- // src/utils/dom-utils.ts
142
- function parseHTMLToNodes(html) {
143
- if (!html) return [];
144
- const temp = document.createElement("div");
145
- temp.innerHTML = html;
146
- return Array.from(temp.childNodes).map((node) => {
147
- if (node instanceof HTMLElement || node instanceof SVGElement) {
148
- return node;
149
- } else {
150
- return node.textContent || "";
309
+ // src/utils/logger.ts
310
+ var WSXLogger = class {
311
+ constructor(prefix = "[WSX]", enabled = true, level = "info") {
312
+ this.prefix = prefix;
313
+ this.enabled = enabled;
314
+ this.level = level;
315
+ }
316
+ shouldLog(level) {
317
+ if (!this.enabled) return false;
318
+ const levels = ["debug", "info", "warn", "error"];
319
+ const currentLevelIndex = levels.indexOf(this.level);
320
+ const messageLevelIndex = levels.indexOf(level);
321
+ return messageLevelIndex >= currentLevelIndex;
322
+ }
323
+ debug(message, ...args) {
324
+ if (this.shouldLog("debug")) {
325
+ console.debug(`${this.prefix} ${message}`, ...args);
151
326
  }
152
- });
327
+ }
328
+ info(message, ...args) {
329
+ if (this.shouldLog("info")) {
330
+ console.info(`${this.prefix} ${message}`, ...args);
331
+ }
332
+ }
333
+ warn(message, ...args) {
334
+ if (this.shouldLog("warn")) {
335
+ console.warn(`${this.prefix} ${message}`, ...args);
336
+ }
337
+ }
338
+ error(message, ...args) {
339
+ if (this.shouldLog("error")) {
340
+ console.error(`${this.prefix} ${message}`, ...args);
341
+ }
342
+ }
343
+ };
344
+ var logger = new WSXLogger();
345
+ function createLogger(componentName) {
346
+ return new WSXLogger(`[WSX:${componentName}]`);
153
347
  }
154
348
 
155
- // src/jsx-factory.ts
349
+ // src/utils/props-utils.ts
350
+ var logger2 = createLogger("Props Utilities");
351
+ function isFrameworkInternalProp(key) {
352
+ if (key === "key") {
353
+ return true;
354
+ }
355
+ if (key === "__wsxPositionId" || key === "__wsxIndex") {
356
+ return true;
357
+ }
358
+ if (key === "__testId") {
359
+ return true;
360
+ }
361
+ if (key === "ref") {
362
+ return true;
363
+ }
364
+ return false;
365
+ }
156
366
  function isStandardHTMLAttribute(key) {
157
367
  const standardAttributes = /* @__PURE__ */ new Set([
158
368
  // 全局属性
@@ -235,7 +445,8 @@ function isStandardHTMLAttribute(key) {
235
445
  function isSpecialProperty(key, value) {
236
446
  return key === "ref" || key === "className" || key === "class" || key === "style" || key.startsWith("on") && typeof value === "function" || typeof value === "boolean" || key === "value";
237
447
  }
238
- function setSmartProperty(element, key, value, isSVG = false) {
448
+ function setSmartProperty(element, key, value, tag) {
449
+ const isSVG = shouldUseSVGNamespace(tag);
239
450
  if (isSpecialProperty(key, value)) {
240
451
  return;
241
452
  }
@@ -245,13 +456,13 @@ function setSmartProperty(element, key, value, isSVG = false) {
245
456
  try {
246
457
  const serialized = JSON.stringify(value);
247
458
  if (serialized.length > 1024 * 1024) {
248
- console.warn(
459
+ logger2.warn(
249
460
  `[WSX] Attribute "${key}" value too large, consider using a non-standard property name instead`
250
461
  );
251
462
  }
252
463
  element.setAttribute(attributeName, serialized);
253
464
  } catch (error) {
254
- console.warn(`[WSX] Cannot serialize attribute "${key}":`, error);
465
+ logger2.warn(`Cannot serialize attribute "${key}":`, error);
255
466
  }
256
467
  } else {
257
468
  element.setAttribute(attributeName, String(value));
@@ -265,7 +476,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
265
476
  const serialized = JSON.stringify(value);
266
477
  element.setAttribute(attributeName, serialized);
267
478
  } catch (error) {
268
- console.warn(`[WSX] Cannot serialize SVG attribute "${key}":`, error);
479
+ logger2.warn(`Cannot serialize SVG attribute "${key}":`, error);
269
480
  }
270
481
  } else {
271
482
  element.setAttribute(attributeName, String(value));
@@ -289,7 +500,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
289
500
  const serialized = JSON.stringify(value);
290
501
  element.setAttribute(attributeName, serialized);
291
502
  } catch (error) {
292
- console.warn(`[WSX] Cannot serialize readonly property "${key}":`, error);
503
+ logger2.warn(`Cannot serialize readonly property "${key}":`, error);
293
504
  }
294
505
  } else {
295
506
  element.setAttribute(attributeName, String(value));
@@ -304,7 +515,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
304
515
  const serialized = JSON.stringify(value);
305
516
  element.setAttribute(attributeName, serialized);
306
517
  } catch (error) {
307
- console.warn(
518
+ logger2.warn(
308
519
  `[WSX] Cannot serialize property "${key}" for attribute:`,
309
520
  error
310
521
  );
@@ -320,59 +531,76 @@ function setSmartProperty(element, key, value, isSVG = false) {
320
531
  try {
321
532
  const serialized = JSON.stringify(value);
322
533
  if (serialized.length > 1024 * 1024) {
323
- console.warn(
534
+ logger2.warn(
324
535
  `[WSX] Property "${key}" value too large for attribute, consider using a JavaScript property instead`
325
536
  );
326
537
  }
327
538
  element.setAttribute(attributeName, serialized);
328
539
  } catch (error) {
329
- console.warn(`[WSX] Cannot serialize property "${key}" for attribute:`, error);
540
+ logger2.warn(`Cannot serialize property "${key}" for attribute:`, error);
330
541
  }
331
542
  } else {
332
543
  element.setAttribute(attributeName, String(value));
333
544
  }
334
545
  }
335
546
  }
336
- function h(tag, props = {}, ...children) {
337
- if (typeof tag === "function") {
338
- return tag(props, children);
547
+
548
+ // src/utils/element-creation.ts
549
+ function applySingleProp(element, key, value, tag, isSVG) {
550
+ if (value === null || value === void 0 || value === false) {
551
+ return;
339
552
  }
340
- const element = createElement(tag);
341
- if (props) {
342
- const isSVG = shouldUseSVGNamespace(tag);
343
- Object.entries(props).forEach(([key, value]) => {
344
- if (value === null || value === void 0 || value === false) {
345
- return;
346
- }
347
- if (key === "ref" && typeof value === "function") {
348
- value(element);
349
- } else if (key === "className" || key === "class") {
350
- if (isSVG) {
351
- element.setAttribute("class", value);
352
- } else {
353
- element.className = value;
354
- }
355
- } else if (key === "style" && typeof value === "string") {
356
- element.setAttribute("style", value);
357
- } else if (key.startsWith("on") && typeof value === "function") {
358
- const eventName = key.slice(2).toLowerCase();
359
- element.addEventListener(eventName, value);
360
- } else if (typeof value === "boolean") {
361
- if (value) {
362
- element.setAttribute(key, "");
363
- }
364
- } else if (key === "value") {
365
- if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
366
- element.value = String(value);
367
- } else {
368
- const attributeName = isSVG ? getSVGAttributeName(key) : key;
369
- element.setAttribute(attributeName, String(value));
370
- }
371
- } else {
372
- setSmartProperty(element, key, value, isSVG);
373
- }
374
- });
553
+ if (key === "ref" && typeof value === "function") {
554
+ value(element);
555
+ return;
556
+ }
557
+ if (key === "className" || key === "class") {
558
+ if (isSVG) {
559
+ element.setAttribute("class", value);
560
+ } else {
561
+ element.className = value;
562
+ }
563
+ return;
375
564
  }
565
+ if (key === "style" && typeof value === "string") {
566
+ element.setAttribute("style", value);
567
+ return;
568
+ }
569
+ if (key.startsWith("on") && typeof value === "function") {
570
+ const eventName = key.slice(2).toLowerCase();
571
+ element.addEventListener(eventName, value);
572
+ return;
573
+ }
574
+ if (typeof value === "boolean") {
575
+ if (value) {
576
+ element.setAttribute(key, "");
577
+ }
578
+ return;
579
+ }
580
+ if (key === "value") {
581
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
582
+ element.value = String(value);
583
+ } else {
584
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
585
+ element.setAttribute(attributeName, String(value));
586
+ }
587
+ return;
588
+ }
589
+ if (isFrameworkInternalProp(key)) {
590
+ return;
591
+ }
592
+ setSmartProperty(element, key, value, tag);
593
+ }
594
+ function applyPropsToElement(element, props, tag) {
595
+ if (!props) {
596
+ return;
597
+ }
598
+ const isSVG = shouldUseSVGNamespace(tag);
599
+ Object.entries(props).forEach(([key, value]) => {
600
+ applySingleProp(element, key, value, tag, isSVG);
601
+ });
602
+ }
603
+ function appendChildrenToElement(element, children) {
376
604
  const flatChildren = flattenChildren(children);
377
605
  flatChildren.forEach((child) => {
378
606
  if (child === null || child === void 0 || child === false) {
@@ -386,60 +614,458 @@ function h(tag, props = {}, ...children) {
386
614
  element.appendChild(child);
387
615
  }
388
616
  });
617
+ }
618
+ function createElementWithPropsAndChildren(tag, props, children) {
619
+ const element = createElement(tag);
620
+ applyPropsToElement(element, props, tag);
621
+ appendChildrenToElement(element, children);
389
622
  return element;
390
623
  }
391
- function isHTMLString(str) {
392
- const trimmed = str.trim();
393
- if (!trimmed) return false;
394
- const htmlTagPattern = /<[a-z][a-z0-9]*(\s[^>]*)?(\/>|>)/i;
395
- const looksLikeMath = /^[^<]*<[^>]*>[^>]*$/.test(trimmed) && !htmlTagPattern.test(trimmed);
396
- if (looksLikeMath) return false;
397
- return htmlTagPattern.test(trimmed);
624
+
625
+ // src/utils/element-update.ts
626
+ function removeProp(element, key, oldValue, tag) {
627
+ const isSVG = shouldUseSVGNamespace(tag);
628
+ if (key === "ref") {
629
+ return;
630
+ }
631
+ if (key === "className" || key === "class") {
632
+ if (isSVG) {
633
+ element.removeAttribute("class");
634
+ } else {
635
+ element.className = "";
636
+ }
637
+ return;
638
+ }
639
+ if (key === "style") {
640
+ element.removeAttribute("style");
641
+ return;
642
+ }
643
+ if (key.startsWith("on") && typeof oldValue === "function") {
644
+ return;
645
+ }
646
+ if (key === "value") {
647
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
648
+ element.value = "";
649
+ } else {
650
+ const attributeName2 = isSVG ? getSVGAttributeName(key) : key;
651
+ element.removeAttribute(attributeName2);
652
+ }
653
+ return;
654
+ }
655
+ if (isFrameworkInternalProp(key)) {
656
+ return;
657
+ }
658
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
659
+ element.removeAttribute(attributeName);
660
+ try {
661
+ delete element[key];
662
+ } catch {
663
+ }
398
664
  }
399
- function flattenChildren(children, skipHTMLDetection = false, depth = 0) {
400
- if (depth > 10) {
401
- console.warn(
402
- "[WSX] flattenChildren: Maximum depth exceeded, treating remaining children as text"
403
- );
404
- return children.filter(
405
- (child) => typeof child === "string" || typeof child === "number"
406
- );
665
+ function applySingleProp2(element, key, value, tag, isSVG) {
666
+ if (value === null || value === void 0 || value === false) {
667
+ return;
407
668
  }
408
- const result = [];
409
- for (const child of children) {
410
- if (child === null || child === void 0 || child === false) {
669
+ if (key === "ref" && typeof value === "function") {
670
+ value(element);
671
+ return;
672
+ }
673
+ if (key === "className" || key === "class") {
674
+ if (isSVG) {
675
+ element.setAttribute("class", value);
676
+ } else {
677
+ element.className = value;
678
+ }
679
+ return;
680
+ }
681
+ if (key === "style" && typeof value === "string") {
682
+ element.setAttribute("style", value);
683
+ return;
684
+ }
685
+ if (key.startsWith("on") && typeof value === "function") {
686
+ const eventName = key.slice(2).toLowerCase();
687
+ element.addEventListener(eventName, value);
688
+ return;
689
+ }
690
+ if (typeof value === "boolean") {
691
+ if (value) {
692
+ element.setAttribute(key, "");
693
+ }
694
+ return;
695
+ }
696
+ if (key === "value") {
697
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
698
+ element.value = String(value);
699
+ } else {
700
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
701
+ element.setAttribute(attributeName, String(value));
702
+ }
703
+ return;
704
+ }
705
+ if (isFrameworkInternalProp(key)) {
706
+ return;
707
+ }
708
+ setSmartProperty(element, key, value, tag);
709
+ }
710
+ function updateProps(element, oldProps, newProps, tag) {
711
+ const isSVG = shouldUseSVGNamespace(tag);
712
+ const old = oldProps || {};
713
+ const new_ = newProps || {};
714
+ for (const key in old) {
715
+ if (!(key in new_)) {
716
+ removeProp(element, key, old[key], tag);
717
+ }
718
+ }
719
+ for (const key in new_) {
720
+ const oldValue = old[key];
721
+ const newValue = new_[key];
722
+ if (oldValue === newValue) {
411
723
  continue;
412
- } else if (Array.isArray(child)) {
413
- result.push(...flattenChildren(child, skipHTMLDetection, depth + 1));
414
- } else if (typeof child === "string") {
415
- if (skipHTMLDetection) {
416
- result.push(child);
417
- } else if (isHTMLString(child)) {
418
- try {
419
- const nodes = parseHTMLToNodes(child);
420
- if (nodes.length > 0) {
421
- for (const node of nodes) {
422
- if (typeof node === "string") {
423
- result.push(node);
724
+ }
725
+ if (oldValue === void 0) {
726
+ applySingleProp2(element, key, newValue, tag, isSVG);
727
+ continue;
728
+ }
729
+ if (typeof oldValue === "object" && oldValue !== null && typeof newValue === "object" && newValue !== null) {
730
+ try {
731
+ const oldJson = JSON.stringify(oldValue);
732
+ const newJson = JSON.stringify(newValue);
733
+ if (oldJson === newJson) {
734
+ continue;
735
+ }
736
+ } catch {
737
+ }
738
+ }
739
+ applySingleProp2(element, key, newValue, tag, isSVG);
740
+ }
741
+ }
742
+ function updateChildren(element, oldChildren, newChildren) {
743
+ const flatOld = flattenChildren(oldChildren);
744
+ const flatNew = flattenChildren(newChildren);
745
+ const minLength = Math.min(flatOld.length, flatNew.length);
746
+ let domIndex = 0;
747
+ for (let i = 0; i < minLength; i++) {
748
+ const oldChild = flatOld[i];
749
+ const newChild = flatNew[i];
750
+ let oldNode = null;
751
+ if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
752
+ if (oldChild.parentNode === element) {
753
+ if (!shouldPreserveElement(oldChild)) {
754
+ oldNode = oldChild;
755
+ }
756
+ } else {
757
+ const oldCacheKey = getElementCacheKey(oldChild);
758
+ if (oldCacheKey) {
759
+ for (let j = 0; j < element.childNodes.length; j++) {
760
+ const domChild = element.childNodes[j];
761
+ if (domChild instanceof HTMLElement || domChild instanceof SVGElement) {
762
+ if (shouldPreserveElement(domChild)) {
763
+ continue;
764
+ }
765
+ const domCacheKey = getElementCacheKey(domChild);
766
+ if (domCacheKey === oldCacheKey) {
767
+ oldNode = domChild;
768
+ break;
769
+ }
770
+ }
771
+ }
772
+ }
773
+ }
774
+ } else if (typeof oldChild === "string" || typeof oldChild === "number") {
775
+ while (domIndex < element.childNodes.length) {
776
+ const node = element.childNodes[domIndex];
777
+ if (node.nodeType === Node.TEXT_NODE) {
778
+ oldNode = node;
779
+ domIndex++;
780
+ break;
781
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
782
+ domIndex++;
783
+ } else {
784
+ domIndex++;
785
+ }
786
+ }
787
+ }
788
+ if (typeof oldChild === "string" || typeof oldChild === "number") {
789
+ if (typeof newChild === "string" || typeof newChild === "number") {
790
+ const oldText = String(oldChild);
791
+ const newText = String(newChild);
792
+ const needsUpdate = oldText !== newText || oldNode && oldNode.nodeType === Node.TEXT_NODE && oldNode.textContent !== newText;
793
+ if (!needsUpdate) {
794
+ continue;
795
+ }
796
+ if (oldNode && oldNode.nodeType === Node.TEXT_NODE) {
797
+ oldNode.textContent = newText;
798
+ } else {
799
+ const newTextNode = document.createTextNode(newText);
800
+ if (oldNode && !shouldPreserveElement(oldNode)) {
801
+ element.replaceChild(newTextNode, oldNode);
802
+ } else {
803
+ element.insertBefore(newTextNode, oldNode || null);
804
+ }
805
+ }
806
+ } else {
807
+ if (oldNode && !shouldPreserveElement(oldNode)) {
808
+ element.removeChild(oldNode);
809
+ }
810
+ if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
811
+ if (newChild.parentNode !== element) {
812
+ element.insertBefore(newChild, oldNode || null);
813
+ }
814
+ } else if (newChild instanceof DocumentFragment) {
815
+ element.insertBefore(newChild, oldNode || null);
816
+ }
817
+ }
818
+ } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
819
+ if (oldNode && shouldPreserveElement(oldNode)) {
820
+ continue;
821
+ }
822
+ if (newChild === oldChild) {
823
+ continue;
824
+ } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
825
+ const oldCacheKey = oldNode && (oldNode instanceof HTMLElement || oldNode instanceof SVGElement) ? getElementCacheKey(oldNode) : null;
826
+ const newCacheKey = getElementCacheKey(newChild);
827
+ const hasSameCacheKey = oldCacheKey && newCacheKey && oldCacheKey === newCacheKey;
828
+ if (oldNode) {
829
+ if (!shouldPreserveElement(oldNode)) {
830
+ if (oldNode !== newChild) {
831
+ if (newChild.parentNode === element) {
832
+ if (hasSameCacheKey) {
833
+ if (newChild !== oldNode) {
834
+ element.replaceChild(newChild, oldNode);
835
+ }
836
+ } else {
837
+ element.removeChild(newChild);
838
+ element.replaceChild(newChild, oldNode);
839
+ }
840
+ } else if (newChild.parentNode) {
841
+ newChild.parentNode.removeChild(newChild);
842
+ element.replaceChild(newChild, oldNode);
424
843
  } else {
425
- result.push(node);
844
+ element.replaceChild(newChild, oldNode);
426
845
  }
427
846
  }
428
847
  } else {
429
- result.push(child);
848
+ if (newChild.parentNode !== element) {
849
+ if (newChild.parentNode) {
850
+ newChild.parentNode.removeChild(newChild);
851
+ }
852
+ element.insertBefore(newChild, oldNode.nextSibling);
853
+ }
854
+ }
855
+ } else {
856
+ if (newChild.parentNode !== element) {
857
+ if (newChild.parentNode) {
858
+ newChild.parentNode.removeChild(newChild);
859
+ }
860
+ element.appendChild(newChild);
430
861
  }
431
- } catch (error) {
432
- console.warn("[WSX] Failed to parse HTML string, treating as text:", error);
433
- result.push(child);
434
862
  }
435
863
  } else {
436
- result.push(child);
864
+ if (oldNode && !shouldPreserveElement(oldNode)) {
865
+ element.removeChild(oldNode);
866
+ }
867
+ if (typeof newChild === "string" || typeof newChild === "number") {
868
+ const newTextNode = document.createTextNode(String(newChild));
869
+ element.insertBefore(newTextNode, oldNode?.nextSibling || null);
870
+ } else if (newChild instanceof DocumentFragment) {
871
+ element.insertBefore(newChild, oldNode?.nextSibling || null);
872
+ }
437
873
  }
438
- } else {
439
- result.push(child);
440
874
  }
441
875
  }
442
- return result;
876
+ for (let i = minLength; i < flatNew.length; i++) {
877
+ const newChild = flatNew[i];
878
+ if (newChild === null || newChild === void 0 || newChild === false) {
879
+ continue;
880
+ }
881
+ if (typeof newChild === "string" || typeof newChild === "number") {
882
+ element.appendChild(document.createTextNode(String(newChild)));
883
+ } else if (newChild instanceof HTMLElement || newChild instanceof SVGElement) {
884
+ if (newChild.parentNode === element) {
885
+ const currentIndex = Array.from(element.childNodes).indexOf(newChild);
886
+ const expectedIndex = element.childNodes.length - 1;
887
+ if (currentIndex !== expectedIndex) {
888
+ element.removeChild(newChild);
889
+ element.appendChild(newChild);
890
+ }
891
+ continue;
892
+ } else if (newChild.parentNode) {
893
+ newChild.parentNode.removeChild(newChild);
894
+ }
895
+ element.appendChild(newChild);
896
+ } else if (newChild instanceof DocumentFragment) {
897
+ element.appendChild(newChild);
898
+ }
899
+ }
900
+ const nodesToRemove = [];
901
+ const newChildSet = /* @__PURE__ */ new Set();
902
+ const newChildCacheKeyMap = /* @__PURE__ */ new Map();
903
+ for (const child of flatNew) {
904
+ if (child instanceof HTMLElement || child instanceof SVGElement || child instanceof DocumentFragment) {
905
+ newChildSet.add(child);
906
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
907
+ const cacheKey = getElementCacheKey(child);
908
+ if (cacheKey) {
909
+ newChildCacheKeyMap.set(cacheKey, child);
910
+ }
911
+ }
912
+ }
913
+ }
914
+ const processedCacheKeys = /* @__PURE__ */ new Set();
915
+ const newChildToIndexMap = /* @__PURE__ */ new Map();
916
+ for (let i = 0; i < flatNew.length; i++) {
917
+ const child = flatNew[i];
918
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
919
+ newChildToIndexMap.set(child, i);
920
+ }
921
+ }
922
+ for (let i = element.childNodes.length - 1; i >= 0; i--) {
923
+ const child = element.childNodes[i];
924
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
925
+ if (shouldPreserveElement(child)) {
926
+ continue;
927
+ }
928
+ const cacheKey = getElementCacheKey(child);
929
+ if (cacheKey && newChildCacheKeyMap.has(cacheKey) && !processedCacheKeys.has(cacheKey)) {
930
+ processedCacheKeys.add(cacheKey);
931
+ const newChild = newChildCacheKeyMap.get(cacheKey);
932
+ if (child !== newChild) {
933
+ if (newChild.parentNode === element) {
934
+ element.replaceChild(newChild, child);
935
+ } else {
936
+ element.replaceChild(newChild, child);
937
+ }
938
+ } else {
939
+ }
940
+ }
941
+ }
942
+ }
943
+ for (let i = 0; i < element.childNodes.length; i++) {
944
+ const child = element.childNodes[i];
945
+ if (shouldPreserveElement(child)) {
946
+ continue;
947
+ }
948
+ if (child instanceof HTMLElement || child instanceof SVGElement) {
949
+ if (newChildSet.has(child)) {
950
+ continue;
951
+ }
952
+ const cacheKey = getElementCacheKey(child);
953
+ if (cacheKey && newChildCacheKeyMap.has(cacheKey)) {
954
+ continue;
955
+ }
956
+ } else if (child instanceof DocumentFragment) {
957
+ if (newChildSet.has(child)) {
958
+ continue;
959
+ }
960
+ }
961
+ nodesToRemove.push(child);
962
+ }
963
+ for (let i = nodesToRemove.length - 1; i >= 0; i--) {
964
+ const node = nodesToRemove[i];
965
+ if (node.parentNode === element) {
966
+ element.removeChild(node);
967
+ }
968
+ }
969
+ }
970
+ function updateElement(element, newProps, newChildren, tag, cacheManager) {
971
+ const oldMetadata = cacheManager.getMetadata(element);
972
+ const oldProps = oldMetadata?.props || null;
973
+ const oldChildren = oldMetadata?.children || [];
974
+ cacheManager.setMetadata(element, {
975
+ props: newProps || {},
976
+ children: newChildren
977
+ });
978
+ updateProps(element, oldProps, newProps, tag);
979
+ updateChildren(element, oldChildren, newChildren);
980
+ }
981
+
982
+ // src/jsx-factory.ts
983
+ var logger3 = createLogger("JSX Factory");
984
+ function h(tag, props = {}, ...children) {
985
+ if (typeof tag === "function") {
986
+ return tag(props, children);
987
+ }
988
+ const context = RenderContext.getCurrentComponent();
989
+ const cacheManager = context ? RenderContext.getDOMCache() : null;
990
+ if (context && cacheManager) {
991
+ return tryUseCacheOrCreate(tag, props, children, context, cacheManager);
992
+ }
993
+ try {
994
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
995
+ globalThis.process.env?.NODE_ENV;
996
+ if (nodeEnv === "development") {
997
+ if (!context) {
998
+ logger3.debug(
999
+ `h() called without render context. Tag: "${tag}", ComponentId: "${getComponentId()}"`,
1000
+ {
1001
+ tag,
1002
+ props: props ? Object.keys(props) : [],
1003
+ hasCacheManager: !!cacheManager
1004
+ }
1005
+ );
1006
+ } else if (!cacheManager) {
1007
+ logger3.debug(
1008
+ `h() called with context but no cache manager. Tag: "${tag}", Component: "${context.constructor.name}"`,
1009
+ {
1010
+ tag,
1011
+ component: context.constructor.name
1012
+ }
1013
+ );
1014
+ }
1015
+ }
1016
+ } catch {
1017
+ }
1018
+ const element = createElementWithPropsAndChildren(tag, props, children);
1019
+ const componentId = getComponentId();
1020
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1021
+ markElement(element, cacheKey);
1022
+ return element;
1023
+ }
1024
+ function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
1025
+ try {
1026
+ const componentId = getComponentId();
1027
+ const cacheKey = generateCacheKey(tag, props, componentId, context);
1028
+ const cachedElement = cacheManager.get(cacheKey);
1029
+ if (cachedElement) {
1030
+ const element2 = cachedElement;
1031
+ updateElement(element2, props, children, tag, cacheManager);
1032
+ const isCustomElement = tag.includes("-") && customElements.get(tag);
1033
+ if (isCustomElement && element2.isConnected) {
1034
+ const parent = element2.parentNode;
1035
+ if (parent) {
1036
+ parent.removeChild(element2);
1037
+ parent.appendChild(element2);
1038
+ }
1039
+ }
1040
+ return element2;
1041
+ }
1042
+ const element = createElementWithPropsAndChildren(tag, props, children);
1043
+ cacheManager.set(cacheKey, element);
1044
+ markElement(element, cacheKey);
1045
+ cacheManager.setMetadata(element, {
1046
+ props: props || {},
1047
+ children
1048
+ });
1049
+ return element;
1050
+ } catch (error) {
1051
+ return handleCacheError(error, tag, props, children);
1052
+ }
1053
+ }
1054
+ function handleCacheError(error, tag, props, children) {
1055
+ try {
1056
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
1057
+ globalThis.process.env?.NODE_ENV;
1058
+ if (nodeEnv === "development") {
1059
+ logger3.warn("[WSX DOM Cache] Cache error, falling back to create new element:", error);
1060
+ }
1061
+ } catch {
1062
+ }
1063
+ const element = createElementWithPropsAndChildren(tag, props, children);
1064
+ const context = RenderContext.getCurrentComponent();
1065
+ const componentId = getComponentId();
1066
+ const cacheKey = generateCacheKey(tag, props, componentId, context || void 0);
1067
+ markElement(element, cacheKey);
1068
+ return element;
443
1069
  }
444
1070
  function Fragment(_props, children) {
445
1071
  const fragment = document.createDocumentFragment();