@wsxjs/wsx-core 0.0.20 → 0.0.21

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,170 @@ __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 isCreatedByH(element) {
175
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
176
+ return false;
177
+ }
178
+ return element[CACHE_KEY_PROP] !== void 0;
179
+ }
180
+ function shouldPreserveElement(element) {
181
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
182
+ return true;
183
+ }
184
+ if (!isCreatedByH(element)) {
185
+ return true;
186
+ }
187
+ if (element.hasAttribute("data-wsx-preserve")) {
188
+ return true;
189
+ }
190
+ return false;
191
+ }
192
+
29
193
  // src/utils/svg-utils.ts
30
194
  var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
31
195
  var SVG_ONLY_ELEMENTS = /* @__PURE__ */ new Set([
@@ -138,21 +302,63 @@ function getSVGAttributeName(attributeName) {
138
302
  return SVG_ATTRIBUTE_MAP.get(attributeName) || attributeName;
139
303
  }
140
304
 
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 || "";
305
+ // src/utils/logger.ts
306
+ var WSXLogger = class {
307
+ constructor(prefix = "[WSX]", enabled = true, level = "info") {
308
+ this.prefix = prefix;
309
+ this.enabled = enabled;
310
+ this.level = level;
311
+ }
312
+ shouldLog(level) {
313
+ if (!this.enabled) return false;
314
+ const levels = ["debug", "info", "warn", "error"];
315
+ const currentLevelIndex = levels.indexOf(this.level);
316
+ const messageLevelIndex = levels.indexOf(level);
317
+ return messageLevelIndex >= currentLevelIndex;
318
+ }
319
+ debug(message, ...args) {
320
+ if (this.shouldLog("debug")) {
321
+ console.debug(`${this.prefix} ${message}`, ...args);
151
322
  }
152
- });
323
+ }
324
+ info(message, ...args) {
325
+ if (this.shouldLog("info")) {
326
+ console.info(`${this.prefix} ${message}`, ...args);
327
+ }
328
+ }
329
+ warn(message, ...args) {
330
+ if (this.shouldLog("warn")) {
331
+ console.warn(`${this.prefix} ${message}`, ...args);
332
+ }
333
+ }
334
+ error(message, ...args) {
335
+ if (this.shouldLog("error")) {
336
+ console.error(`${this.prefix} ${message}`, ...args);
337
+ }
338
+ }
339
+ };
340
+ var logger = new WSXLogger();
341
+ function createLogger(componentName) {
342
+ return new WSXLogger(`[WSX:${componentName}]`);
153
343
  }
154
344
 
155
- // src/jsx-factory.ts
345
+ // src/utils/props-utils.ts
346
+ var logger2 = createLogger("Props Utilities");
347
+ function isFrameworkInternalProp(key) {
348
+ if (key === "key") {
349
+ return true;
350
+ }
351
+ if (key === "__wsxPositionId" || key === "__wsxIndex") {
352
+ return true;
353
+ }
354
+ if (key === "__testId") {
355
+ return true;
356
+ }
357
+ if (key === "ref") {
358
+ return true;
359
+ }
360
+ return false;
361
+ }
156
362
  function isStandardHTMLAttribute(key) {
157
363
  const standardAttributes = /* @__PURE__ */ new Set([
158
364
  // 全局属性
@@ -235,7 +441,8 @@ function isStandardHTMLAttribute(key) {
235
441
  function isSpecialProperty(key, value) {
236
442
  return key === "ref" || key === "className" || key === "class" || key === "style" || key.startsWith("on") && typeof value === "function" || typeof value === "boolean" || key === "value";
237
443
  }
238
- function setSmartProperty(element, key, value, isSVG = false) {
444
+ function setSmartProperty(element, key, value, tag) {
445
+ const isSVG = shouldUseSVGNamespace(tag);
239
446
  if (isSpecialProperty(key, value)) {
240
447
  return;
241
448
  }
@@ -245,13 +452,13 @@ function setSmartProperty(element, key, value, isSVG = false) {
245
452
  try {
246
453
  const serialized = JSON.stringify(value);
247
454
  if (serialized.length > 1024 * 1024) {
248
- console.warn(
455
+ logger2.warn(
249
456
  `[WSX] Attribute "${key}" value too large, consider using a non-standard property name instead`
250
457
  );
251
458
  }
252
459
  element.setAttribute(attributeName, serialized);
253
460
  } catch (error) {
254
- console.warn(`[WSX] Cannot serialize attribute "${key}":`, error);
461
+ logger2.warn(`Cannot serialize attribute "${key}":`, error);
255
462
  }
256
463
  } else {
257
464
  element.setAttribute(attributeName, String(value));
@@ -265,7 +472,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
265
472
  const serialized = JSON.stringify(value);
266
473
  element.setAttribute(attributeName, serialized);
267
474
  } catch (error) {
268
- console.warn(`[WSX] Cannot serialize SVG attribute "${key}":`, error);
475
+ logger2.warn(`Cannot serialize SVG attribute "${key}":`, error);
269
476
  }
270
477
  } else {
271
478
  element.setAttribute(attributeName, String(value));
@@ -289,7 +496,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
289
496
  const serialized = JSON.stringify(value);
290
497
  element.setAttribute(attributeName, serialized);
291
498
  } catch (error) {
292
- console.warn(`[WSX] Cannot serialize readonly property "${key}":`, error);
499
+ logger2.warn(`Cannot serialize readonly property "${key}":`, error);
293
500
  }
294
501
  } else {
295
502
  element.setAttribute(attributeName, String(value));
@@ -304,7 +511,7 @@ function setSmartProperty(element, key, value, isSVG = false) {
304
511
  const serialized = JSON.stringify(value);
305
512
  element.setAttribute(attributeName, serialized);
306
513
  } catch (error) {
307
- console.warn(
514
+ logger2.warn(
308
515
  `[WSX] Cannot serialize property "${key}" for attribute:`,
309
516
  error
310
517
  );
@@ -320,59 +527,76 @@ function setSmartProperty(element, key, value, isSVG = false) {
320
527
  try {
321
528
  const serialized = JSON.stringify(value);
322
529
  if (serialized.length > 1024 * 1024) {
323
- console.warn(
530
+ logger2.warn(
324
531
  `[WSX] Property "${key}" value too large for attribute, consider using a JavaScript property instead`
325
532
  );
326
533
  }
327
534
  element.setAttribute(attributeName, serialized);
328
535
  } catch (error) {
329
- console.warn(`[WSX] Cannot serialize property "${key}" for attribute:`, error);
536
+ logger2.warn(`Cannot serialize property "${key}" for attribute:`, error);
330
537
  }
331
538
  } else {
332
539
  element.setAttribute(attributeName, String(value));
333
540
  }
334
541
  }
335
542
  }
336
- function h(tag, props = {}, ...children) {
337
- if (typeof tag === "function") {
338
- return tag(props, children);
543
+
544
+ // src/utils/element-creation.ts
545
+ function applySingleProp(element, key, value, tag, isSVG) {
546
+ if (value === null || value === void 0 || value === false) {
547
+ return;
339
548
  }
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
- });
549
+ if (key === "ref" && typeof value === "function") {
550
+ value(element);
551
+ return;
375
552
  }
553
+ if (key === "className" || key === "class") {
554
+ if (isSVG) {
555
+ element.setAttribute("class", value);
556
+ } else {
557
+ element.className = value;
558
+ }
559
+ return;
560
+ }
561
+ if (key === "style" && typeof value === "string") {
562
+ element.setAttribute("style", value);
563
+ return;
564
+ }
565
+ if (key.startsWith("on") && typeof value === "function") {
566
+ const eventName = key.slice(2).toLowerCase();
567
+ element.addEventListener(eventName, value);
568
+ return;
569
+ }
570
+ if (typeof value === "boolean") {
571
+ if (value) {
572
+ element.setAttribute(key, "");
573
+ }
574
+ return;
575
+ }
576
+ if (key === "value") {
577
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
578
+ element.value = String(value);
579
+ } else {
580
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
581
+ element.setAttribute(attributeName, String(value));
582
+ }
583
+ return;
584
+ }
585
+ if (isFrameworkInternalProp(key)) {
586
+ return;
587
+ }
588
+ setSmartProperty(element, key, value, tag);
589
+ }
590
+ function applyPropsToElement(element, props, tag) {
591
+ if (!props) {
592
+ return;
593
+ }
594
+ const isSVG = shouldUseSVGNamespace(tag);
595
+ Object.entries(props).forEach(([key, value]) => {
596
+ applySingleProp(element, key, value, tag, isSVG);
597
+ });
598
+ }
599
+ function appendChildrenToElement(element, children) {
376
600
  const flatChildren = flattenChildren(children);
377
601
  flatChildren.forEach((child) => {
378
602
  if (child === null || child === void 0 || child === false) {
@@ -386,60 +610,278 @@ function h(tag, props = {}, ...children) {
386
610
  element.appendChild(child);
387
611
  }
388
612
  });
613
+ }
614
+ function createElementWithPropsAndChildren(tag, props, children) {
615
+ const element = createElement(tag);
616
+ applyPropsToElement(element, props, tag);
617
+ appendChildrenToElement(element, children);
389
618
  return element;
390
619
  }
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);
620
+
621
+ // src/utils/element-update.ts
622
+ function removeProp(element, key, oldValue, tag) {
623
+ const isSVG = shouldUseSVGNamespace(tag);
624
+ if (key === "ref") {
625
+ return;
626
+ }
627
+ if (key === "className" || key === "class") {
628
+ if (isSVG) {
629
+ element.removeAttribute("class");
630
+ } else {
631
+ element.className = "";
632
+ }
633
+ return;
634
+ }
635
+ if (key === "style") {
636
+ element.removeAttribute("style");
637
+ return;
638
+ }
639
+ if (key.startsWith("on") && typeof oldValue === "function") {
640
+ return;
641
+ }
642
+ if (key === "value") {
643
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
644
+ element.value = "";
645
+ } else {
646
+ const attributeName2 = isSVG ? getSVGAttributeName(key) : key;
647
+ element.removeAttribute(attributeName2);
648
+ }
649
+ return;
650
+ }
651
+ if (isFrameworkInternalProp(key)) {
652
+ return;
653
+ }
654
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
655
+ element.removeAttribute(attributeName);
656
+ try {
657
+ delete element[key];
658
+ } catch {
659
+ }
398
660
  }
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
- );
661
+ function applySingleProp2(element, key, value, tag, isSVG) {
662
+ if (value === null || value === void 0 || value === false) {
663
+ return;
407
664
  }
408
- const result = [];
409
- for (const child of children) {
410
- if (child === null || child === void 0 || child === false) {
665
+ if (key === "ref" && typeof value === "function") {
666
+ value(element);
667
+ return;
668
+ }
669
+ if (key === "className" || key === "class") {
670
+ if (isSVG) {
671
+ element.setAttribute("class", value);
672
+ } else {
673
+ element.className = value;
674
+ }
675
+ return;
676
+ }
677
+ if (key === "style" && typeof value === "string") {
678
+ element.setAttribute("style", value);
679
+ return;
680
+ }
681
+ if (key.startsWith("on") && typeof value === "function") {
682
+ const eventName = key.slice(2).toLowerCase();
683
+ element.addEventListener(eventName, value);
684
+ return;
685
+ }
686
+ if (typeof value === "boolean") {
687
+ if (value) {
688
+ element.setAttribute(key, "");
689
+ }
690
+ return;
691
+ }
692
+ if (key === "value") {
693
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
694
+ element.value = String(value);
695
+ } else {
696
+ const attributeName = isSVG ? getSVGAttributeName(key) : key;
697
+ element.setAttribute(attributeName, String(value));
698
+ }
699
+ return;
700
+ }
701
+ if (isFrameworkInternalProp(key)) {
702
+ return;
703
+ }
704
+ setSmartProperty(element, key, value, tag);
705
+ }
706
+ function updateProps(element, oldProps, newProps, tag) {
707
+ const isSVG = shouldUseSVGNamespace(tag);
708
+ const old = oldProps || {};
709
+ const new_ = newProps || {};
710
+ for (const key in old) {
711
+ if (!(key in new_)) {
712
+ removeProp(element, key, old[key], tag);
713
+ }
714
+ }
715
+ for (const key in new_) {
716
+ const oldValue = old[key];
717
+ const newValue = new_[key];
718
+ if (oldValue === newValue) {
411
719
  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);
424
- } else {
425
- result.push(node);
426
- }
720
+ }
721
+ if (typeof oldValue === "object" && oldValue !== null && typeof newValue === "object" && newValue !== null) {
722
+ if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
723
+ continue;
724
+ }
725
+ }
726
+ applySingleProp2(element, key, newValue, tag, isSVG);
727
+ }
728
+ }
729
+ function updateChildren(element, oldChildren, newChildren) {
730
+ const flatOld = flattenChildren(oldChildren);
731
+ const flatNew = flattenChildren(newChildren);
732
+ const minLength = Math.min(flatOld.length, flatNew.length);
733
+ for (let i = 0; i < minLength; i++) {
734
+ const oldChild = flatOld[i];
735
+ const newChild = flatNew[i];
736
+ if (typeof oldChild === "string" || typeof oldChild === "number") {
737
+ 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
+ }
748
+ }
749
+ } 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);
760
+ } else if (newChild instanceof DocumentFragment) {
761
+ element.appendChild(newChild);
762
+ }
763
+ }
764
+ } else if (oldChild instanceof HTMLElement || oldChild instanceof SVGElement) {
765
+ if (newChild === oldChild) {
766
+ 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);
427
773
  }
428
774
  } else {
429
- result.push(child);
775
+ if (newChild.parentNode !== element) {
776
+ element.appendChild(newChild);
777
+ }
778
+ }
779
+ } else {
780
+ if (newChild.parentNode !== element) {
781
+ element.appendChild(newChild);
430
782
  }
431
- } catch (error) {
432
- console.warn("[WSX] Failed to parse HTML string, treating as text:", error);
433
- result.push(child);
434
783
  }
435
784
  } else {
436
- result.push(child);
785
+ const oldNode = element.childNodes[i];
786
+ if (oldNode) {
787
+ if (!shouldPreserveElement(oldNode)) {
788
+ element.removeChild(oldNode);
789
+ }
790
+ }
791
+ if (typeof newChild === "string" || typeof newChild === "number") {
792
+ element.appendChild(document.createTextNode(String(newChild)));
793
+ } else if (newChild instanceof DocumentFragment) {
794
+ element.appendChild(newChild);
795
+ }
437
796
  }
438
- } else {
439
- result.push(child);
440
797
  }
441
798
  }
442
- return result;
799
+ 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
+ }
826
+ }
827
+ }
828
+ function updateElement(element, newProps, newChildren, tag, cacheManager) {
829
+ const oldMetadata = cacheManager.getMetadata(element);
830
+ const oldProps = oldMetadata?.props || null;
831
+ const oldChildren = oldMetadata?.children || [];
832
+ updateProps(element, oldProps, newProps, tag);
833
+ updateChildren(element, oldChildren, newChildren);
834
+ cacheManager.setMetadata(element, {
835
+ props: newProps || {},
836
+ children: newChildren
837
+ });
838
+ }
839
+
840
+ // src/jsx-factory.ts
841
+ var logger3 = createLogger("JSX Factory");
842
+ function h(tag, props = {}, ...children) {
843
+ if (typeof tag === "function") {
844
+ return tag(props, children);
845
+ }
846
+ const context = RenderContext.getCurrentComponent();
847
+ const cacheManager = context ? RenderContext.getDOMCache() : null;
848
+ if (context && cacheManager) {
849
+ return tryUseCacheOrCreate(tag, props, children, context, cacheManager);
850
+ }
851
+ return createElementWithPropsAndChildren(tag, props, children);
852
+ }
853
+ function tryUseCacheOrCreate(tag, props, children, context, cacheManager) {
854
+ try {
855
+ const componentId = getComponentId();
856
+ const cacheKey = generateCacheKey(tag, props, componentId, context);
857
+ const cachedElement = cacheManager.get(cacheKey);
858
+ if (cachedElement) {
859
+ const element2 = cachedElement;
860
+ updateElement(element2, props, children, tag, cacheManager);
861
+ return element2;
862
+ }
863
+ const element = createElementWithPropsAndChildren(tag, props, children);
864
+ cacheManager.set(cacheKey, element);
865
+ markElement(element, cacheKey);
866
+ cacheManager.setMetadata(element, {
867
+ props: props || {},
868
+ children
869
+ });
870
+ return element;
871
+ } catch (error) {
872
+ return handleCacheError(error, tag, props, children);
873
+ }
874
+ }
875
+ function handleCacheError(error, tag, props, children) {
876
+ try {
877
+ const nodeEnv = typeof globalThis.process !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
878
+ globalThis.process.env?.NODE_ENV;
879
+ if (nodeEnv === "development") {
880
+ logger3.warn("[WSX DOM Cache] Cache error, falling back to create new element:", error);
881
+ }
882
+ } catch {
883
+ }
884
+ return createElementWithPropsAndChildren(tag, props, children);
443
885
  }
444
886
  function Fragment(_props, children) {
445
887
  const fragment = document.createDocumentFragment();