@estjs/template 0.0.14-beta.1 → 0.0.14-beta.12

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.
@@ -4,45 +4,40 @@ var shared = require('@estjs/shared');
4
4
  var signal = require('@estjs/signal');
5
5
 
6
6
  /**
7
- * @estjs/template v0.0.14-beta.1
7
+ * @estjs/template v0.0.14-beta.12
8
8
  * (c) 2023-Present jiangxd <jiangxd2016@gmail.com>
9
9
  * @license MIT
10
10
  **/
11
11
 
12
12
 
13
- // src/shared-config.ts
13
+ // src/sharedConfig.ts
14
14
  var EVENT_PREFIX = "on";
15
15
  var UPDATE_PREFIX = "update";
16
16
  var CHILDREN_PROP = "children";
17
17
  var EMPTY_TEMPLATE = "";
18
18
  var FRAGMENT_PROP_KEY = "0";
19
19
  var SINGLE_PROP_KEY = "1";
20
+ var REF_KEY = "ref";
20
21
  var PLACEHOLDER = " __PLACEHOLDER__ ";
21
22
  var RenderContext = class {
22
23
  constructor() {
23
24
  this.renderMode = 0 /* CLIENT */;
24
25
  }
25
- // Getter to check if the current mode is SSG
26
26
  get isSSG() {
27
27
  return this.renderMode === 1 /* SSG */;
28
28
  }
29
- // Getter to check if the current mode is SSR
30
29
  get isSSR() {
31
30
  return this.renderMode === 2 /* SSR */;
32
31
  }
33
- // Getter to check if the current mode is Client
34
32
  get isClient() {
35
33
  return this.renderMode === 0 /* CLIENT */;
36
34
  }
37
- // Set render mode to SSR
38
35
  setSSR() {
39
36
  this.renderMode = 2 /* SSR */;
40
37
  }
41
- // Set render mode to SSG
42
38
  setSSG() {
43
39
  this.renderMode = 1 /* SSG */;
44
40
  }
45
- // Set render mode to Client
46
41
  setClient() {
47
42
  this.renderMode = 0 /* CLIENT */;
48
43
  }
@@ -59,7 +54,7 @@ function getComponentIndex(temp) {
59
54
  return (_a = componentMap.get(temp)) == null ? void 0 : _a.index;
60
55
  }
61
56
 
62
- // src/lifecycle-context.ts
57
+ // src/lifecycleContext.ts
63
58
  var _LifecycleContext = class _LifecycleContext {
64
59
  constructor() {
65
60
  // Hooks for different lifecycle stages
@@ -85,11 +80,9 @@ var _LifecycleContext = class _LifecycleContext {
85
80
  setContext(context, value) {
86
81
  _LifecycleContext.context[context] = value;
87
82
  }
88
- // Initialize the static reference
89
83
  initRef() {
90
84
  _LifecycleContext.ref = this;
91
85
  }
92
- // Remove the static reference
93
86
  removeRef() {
94
87
  _LifecycleContext.ref = null;
95
88
  }
@@ -98,13 +91,11 @@ var _LifecycleContext = class _LifecycleContext {
98
91
  Object.values(this.hooks).forEach((set) => set.clear());
99
92
  }
100
93
  };
101
- // Static reference to the current context
102
94
  _LifecycleContext.ref = null;
103
- // Static context to store shared values
104
95
  _LifecycleContext.context = {};
105
96
  var LifecycleContext = _LifecycleContext;
106
97
 
107
- // src/ssg-node.ts
98
+ // src/ssgNode.ts
108
99
  function isSSGNode(node) {
109
100
  return node instanceof SSGNode;
110
101
  }
@@ -118,7 +109,6 @@ var SSGNode = class extends LifecycleContext {
118
109
  enterComponent(template, componentIndex);
119
110
  this.templates = this.processTemplate();
120
111
  }
121
- // Process the template and return an array of processed strings
122
112
  processTemplate() {
123
113
  if (shared.isArray(this.template)) {
124
114
  const htmlString = this.template.join(PLACEHOLDER);
@@ -127,7 +117,6 @@ var SSGNode = class extends LifecycleContext {
127
117
  }
128
118
  return [];
129
119
  }
130
- // Process HTML string by adding component index and handling text nodes
131
120
  processHtmlString(htmlString) {
132
121
  return htmlString.replaceAll(/(<[^>]+>)|([^<]+)/g, (match, p1, p2) => {
133
122
  if (p1) {
@@ -141,14 +130,12 @@ var SSGNode = class extends LifecycleContext {
141
130
  return match;
142
131
  });
143
132
  }
144
- // Mount the SSGNode and return the rendered string
145
133
  mount() {
146
134
  this.initRef();
147
135
  const output = this.render();
148
136
  this.removeRef();
149
137
  return output;
150
138
  }
151
- // Render the SSGNode
152
139
  render() {
153
140
  if (shared.isFunction(this.template)) {
154
141
  const root = this.template(this.props);
@@ -160,7 +147,6 @@ var SSGNode = class extends LifecycleContext {
160
147
  }
161
148
  return this.renderTemplate();
162
149
  }
163
- // Render the template by processing props and children
164
150
  renderTemplate() {
165
151
  Object.entries(this.props).forEach(([key, cur]) => {
166
152
  const children = cur.children;
@@ -176,10 +162,9 @@ var SSGNode = class extends LifecycleContext {
176
162
  });
177
163
  return this.templates.join("");
178
164
  }
179
- // Normalize props by removing children and handling signals
180
165
  normalizeProps(props) {
181
166
  Object.entries(props).forEach(([key, value]) => {
182
- if (key === "children") {
167
+ if (key === CHILDREN_PROP) {
183
168
  delete props[key];
184
169
  } else if (shared.isFunction(value)) {
185
170
  delete props[key];
@@ -188,11 +173,9 @@ var SSGNode = class extends LifecycleContext {
188
173
  }
189
174
  });
190
175
  }
191
- // Generate HTML attributes string from props
192
176
  generateAttributes(props) {
193
- return Object.entries(props).filter(([key, value]) => key !== "children" && !shared.isFunction(value)).map(([key, value]) => `${key}="${shared.escape(String(value))}"`).join(" ");
177
+ return Object.entries(props).filter(([key, value]) => key !== CHILDREN_PROP && !shared.isFunction(value)).map(([key, value]) => `${key}="${shared.escape(String(value))}"`).join(" ");
194
178
  }
195
- // Render children and append them to the template
196
179
  renderChildren(children, findIndex) {
197
180
  children.forEach(([child]) => {
198
181
  componentIndex++;
@@ -200,7 +183,6 @@ var SSGNode = class extends LifecycleContext {
200
183
  this.templates[findIndex] += renderedChild;
201
184
  });
202
185
  }
203
- // Render a single child node
204
186
  renderChild(child) {
205
187
  if (shared.isFunction(child)) {
206
188
  return this.renderChild(child(this.props));
@@ -217,9 +199,6 @@ var SSGNode = class extends LifecycleContext {
217
199
 
218
200
  // src/utils.ts
219
201
  var SELF_CLOSING_TAGS = "area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr".split(",");
220
- var HTML_TAGS = "a,abbr,acronym,address,applet,area,article,aside,audio,b,base,basefont,bdi,bdo,bgsound,big,blink,blockquote,body,br,button,canvas,caption,center,cite,code,col,colgroup,command,content,data,datalist,dd,del,details,dfn,dialog,dir,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,frame,frameset,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,i,iframe,image,img,input,ins,kbd,keygen,label,legend,li,link,listing,main,map,mark,marquee,menu,menuitem,meta,meter,nav,nobr,noframes,noscript,object,ol,optgroup,option,output,p,param,picture,plaintext,pre,progress,q,rb,rp,rt,rtc,ruby,s,samp,script,section,select,shadow,small,source,spacer,span,strike,strong,style,sub,summary,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,track,tt,u,ul,var,video,wbr,xmp".split(
221
- ","
222
- );
223
202
  function coerceNode(data) {
224
203
  if (isJsxElement(data) || data instanceof Node || isSSGNode(data)) {
225
204
  return data;
@@ -336,12 +315,14 @@ function bindNode(node, setter) {
336
315
  });
337
316
  }
338
317
  }
339
- Promise.resolve();
340
318
  function addEventListener(node, eventName, handler) {
341
319
  node.addEventListener(eventName, handler);
342
320
  return () => node.removeEventListener(eventName, handler);
343
321
  }
344
322
  function closeHtmlTags(input) {
323
+ if (!input) {
324
+ return input;
325
+ }
345
326
  const tagStack = [];
346
327
  const output = [];
347
328
  const tagPattern = /<\/?([\da-z-]+)([^>]*)>/gi;
@@ -377,17 +358,14 @@ function closeHtmlTags(input) {
377
358
  }
378
359
  return output.join("");
379
360
  }
380
- function isHtmlTagName(tagName) {
381
- return HTML_TAGS.includes(tagName);
382
- }
383
361
  function convertToHtmlTag(tagName) {
384
362
  return SELF_CLOSING_TAGS.includes(tagName) ? `<${tagName}/>` : `<${tagName}></${tagName}>`;
385
363
  }
386
- function extractSignal(signal$1) {
387
- if (signal.isSignal(signal$1)) {
388
- return signal$1.value;
364
+ function extractSignal(signal2) {
365
+ if (signal.isSignal(signal2)) {
366
+ return signal2.value;
389
367
  } else {
390
- return signal$1;
368
+ return signal2;
391
369
  }
392
370
  }
393
371
  var ComponentNode = class extends LifecycleContext {
@@ -399,28 +377,24 @@ var ComponentNode = class extends LifecycleContext {
399
377
  this.emitter = /* @__PURE__ */ new Set();
400
378
  this.rootNode = null;
401
379
  this.trackMap = /* @__PURE__ */ new Map();
402
- this.key || (this.key = props == null ? void 0 : props.key);
380
+ this.key || (this.key = props && props.key);
403
381
  this.proxyProps = this.createProxyProps(props);
404
382
  }
405
- // Create reactive props
406
383
  createProxyProps(props) {
407
384
  if (!props) return {};
408
- return signal.useReactive(
385
+ return signal.signalObject(
409
386
  props,
410
387
  (key) => shared.startsWith(key, EVENT_PREFIX) || shared.startsWith(key, UPDATE_PREFIX) || key === CHILDREN_PROP
411
388
  );
412
389
  }
413
- // Getter for the first child node
414
390
  get firstChild() {
415
391
  var _a, _b;
416
392
  return (_b = (_a = this.rootNode) == null ? void 0 : _a.firstChild) != null ? _b : null;
417
393
  }
418
- // Getter to check if the node is connected to the DOM
419
394
  get isConnected() {
420
395
  var _a, _b;
421
396
  return (_b = (_a = this.rootNode) == null ? void 0 : _a.isConnected) != null ? _b : false;
422
397
  }
423
- // Method to mount the component to the DOM
424
398
  mount(parent, before) {
425
399
  var _a, _b, _c, _d;
426
400
  if (!shared.isFunction(this.template)) {
@@ -430,14 +404,13 @@ var ComponentNode = class extends LifecycleContext {
430
404
  return (_b = (_a = this.rootNode) == null ? void 0 : _a.mount(parent, before)) != null ? _b : [];
431
405
  }
432
406
  this.initRef();
433
- this.rootNode = this.template(this.proxyProps);
407
+ this.rootNode = this.template(signal.reactive(this.proxyProps, [CHILDREN_PROP]));
434
408
  const mountedNode = (_d = (_c = this.rootNode) == null ? void 0 : _c.mount(parent, before)) != null ? _d : [];
435
409
  this.callMountHooks();
436
410
  this.patchProps(this.props);
437
411
  this.removeRef();
438
412
  return mountedNode;
439
413
  }
440
- // Method to unmount the component from the DOM
441
414
  unmount() {
442
415
  var _a;
443
416
  this.callDestroyHooks();
@@ -447,22 +420,18 @@ var ComponentNode = class extends LifecycleContext {
447
420
  this.proxyProps = {};
448
421
  this.clearEmitter();
449
422
  }
450
- // Private method to call mount hooks
451
423
  callMountHooks() {
452
424
  this.hooks.mounted.forEach((handler) => handler());
453
425
  }
454
- // Private method to call destroy hooks
455
426
  callDestroyHooks() {
456
427
  this.hooks.destroy.forEach((handler) => handler());
457
428
  }
458
- // Private method to clear the event emitter
459
429
  clearEmitter() {
460
430
  for (const cleanup of this.emitter) {
461
431
  cleanup();
462
432
  }
463
433
  this.emitter.clear();
464
434
  }
465
- // Method to inherit properties from another ComponentNode
466
435
  inheritNode(node) {
467
436
  Object.assign(this.proxyProps, node.proxyProps);
468
437
  this.rootNode = node.rootNode;
@@ -472,7 +441,6 @@ var ComponentNode = class extends LifecycleContext {
472
441
  this.props = node.props;
473
442
  this.patchProps(props);
474
443
  }
475
- // Private method to get or create a NodeTrack
476
444
  getNodeTrack(trackKey) {
477
445
  let track = this.trackMap.get(trackKey);
478
446
  if (!track) {
@@ -483,7 +451,6 @@ var ComponentNode = class extends LifecycleContext {
483
451
  track.cleanup();
484
452
  return track;
485
453
  }
486
- // Method to patch props onto the component
487
454
  patchProps(props) {
488
455
  var _a;
489
456
  if (!props) {
@@ -492,7 +459,7 @@ var ComponentNode = class extends LifecycleContext {
492
459
  for (const [key, prop] of Object.entries(props)) {
493
460
  if (shared.startsWith(key, EVENT_PREFIX) && ((_a = this.rootNode) == null ? void 0 : _a.firstChild)) {
494
461
  this.patchEventListener(key, prop);
495
- } else if (key === "ref") {
462
+ } else if (key === REF_KEY) {
496
463
  this.patchRef(prop);
497
464
  } else if (shared.startsWith(key, UPDATE_PREFIX)) {
498
465
  this.patchUpdateHandler(key, prop);
@@ -502,26 +469,24 @@ var ComponentNode = class extends LifecycleContext {
502
469
  }
503
470
  this.props = props;
504
471
  }
505
- // Private method to patch event listeners
506
472
  patchEventListener(key, prop) {
507
473
  const event = key.slice(2).toLowerCase();
508
474
  const cleanup = addEventListener(this.rootNode.nodes[0], event, prop);
509
475
  this.emitter.add(cleanup);
510
476
  }
511
- // Private method to patch ref
512
477
  patchRef(prop) {
513
478
  var _a, _b;
514
479
  prop.value = (_b = (_a = this.rootNode) == null ? void 0 : _a.firstChild) != null ? _b : null;
515
480
  }
516
- // Private method to patch update handlers
517
481
  patchUpdateHandler(key, prop) {
518
482
  this.props[key] = extractSignal(prop);
519
483
  }
520
- // Private method to patch normal props
521
484
  patchNormalProp(key, prop) {
485
+ var _a, _b;
486
+ const newValue = (_b = (_a = this.proxyProps)[key]) != null ? _b : _a[key] = signal.signal(prop);
522
487
  const track = this.getNodeTrack(key);
523
- track.cleanup = signal.useEffect(() => {
524
- this.proxyProps[key] = shared.isFunction(prop) ? prop() : prop;
488
+ track.cleanup = signal.effect(() => {
489
+ newValue.value = shared.isFunction(prop) ? prop() : prop;
525
490
  });
526
491
  }
527
492
  };
@@ -633,39 +598,33 @@ function getKey(node, index) {
633
598
  return `_$${index}$`;
634
599
  }
635
600
 
636
- // src/template-node.ts
601
+ // src/templateNode.ts
637
602
  var TemplateNode = class {
638
603
  constructor(template, props, key) {
639
604
  this.template = template;
640
605
  this.props = props;
641
606
  this.key = key;
642
- // Private properties for managing the node's state
643
607
  this.treeMap = /* @__PURE__ */ new Map();
644
608
  this.mounted = false;
645
609
  this.nodes = [];
646
610
  this.trackMap = /* @__PURE__ */ new Map();
647
611
  this.bindValueKeys = [];
648
612
  this.parent = null;
649
- this.key || (this.key = props == null ? void 0 : props.key);
650
613
  if (renderContext.isSSR) {
651
614
  this.componentIndex = getComponentIndex(this.template);
652
615
  }
653
616
  }
654
- // Getter for the first child node
655
617
  get firstChild() {
656
618
  var _a;
657
619
  return (_a = this.nodes[0]) != null ? _a : null;
658
620
  }
659
- // Getter to check if the node is connected to the DOM
660
621
  get isConnected() {
661
622
  return this.mounted;
662
623
  }
663
- // Placeholder methods for event handling
664
624
  addEventListener() {
665
625
  }
666
626
  removeEventListener() {
667
627
  }
668
- // Method to mount the node to the DOM
669
628
  mount(parent, before) {
670
629
  var _a;
671
630
  this.parent = parent;
@@ -680,7 +639,7 @@ var TemplateNode = class {
680
639
  const firstChild = cloneNode.firstChild;
681
640
  if ((_a = firstChild == null ? void 0 : firstChild.hasAttribute) == null ? void 0 : _a.call(firstChild, "_svg_")) {
682
641
  firstChild.remove();
683
- firstChild == null ? void 0 : firstChild.childNodes.forEach((node) => {
642
+ firstChild.childNodes.forEach((node) => {
684
643
  cloneNode.append(node);
685
644
  });
686
645
  }
@@ -695,45 +654,16 @@ var TemplateNode = class {
695
654
  this.mounted = true;
696
655
  return this.nodes;
697
656
  }
698
- // Method to unmount the node from the DOM
699
657
  unmount() {
700
- var _a, _b;
701
658
  this.trackMap.forEach((track) => {
702
- var _a2;
703
- (_a2 = track.cleanup) == null ? void 0 : _a2.call(track);
659
+ track.cleanup && track.cleanup();
704
660
  });
705
661
  this.trackMap.clear();
706
662
  this.treeMap.clear();
707
663
  this.nodes.forEach((node) => removeChild(node));
708
- if (!this.template.innerHTML && !this.nodes.length) {
709
- const children = (_b = (_a = this.props) == null ? void 0 : _a[FRAGMENT_PROP_KEY]) == null ? void 0 : _b.children;
710
- if (children) {
711
- if (shared.isArray(children)) {
712
- children.forEach((child) => {
713
- this.deleteFragmentTextNode(child);
714
- });
715
- } else {
716
- this.deleteFragmentTextNode(children);
717
- }
718
- }
719
- }
720
664
  this.nodes = [];
721
665
  this.mounted = false;
722
666
  }
723
- deleteFragmentTextNode(child) {
724
- var _a;
725
- if (shared.isPrimitive(child)) {
726
- (_a = this.parent) == null ? void 0 : _a.childNodes.forEach((node) => {
727
- var _a2;
728
- if (node.nodeType === Node.TEXT_NODE && node.textContent === `${child}`) {
729
- (_a2 = this.parent) == null ? void 0 : _a2.removeChild(node);
730
- }
731
- });
732
- } else {
733
- removeChild(child);
734
- }
735
- }
736
- // Method to inherit properties from another TemplateNode
737
667
  inheritNode(node) {
738
668
  this.mounted = node.mounted;
739
669
  this.nodes = node.nodes;
@@ -743,12 +673,11 @@ var TemplateNode = class {
743
673
  this.props = node.props;
744
674
  this.patchProps(props);
745
675
  }
746
- // Private method to map SSG node tree
747
676
  mapSSGNodeTree(parent) {
748
677
  this.treeMap.set(0, parent);
749
678
  this.walkNodeTree(parent, this.handleSSGNode.bind(this));
750
679
  }
751
- // Private method to map node tree
680
+ // protected method to map node tree
752
681
  mapNodeTree(parent, tree) {
753
682
  let index = 1;
754
683
  this.treeMap.set(0, parent);
@@ -759,7 +688,6 @@ var TemplateNode = class {
759
688
  };
760
689
  this.walkNodeTree(tree, handleNode);
761
690
  }
762
- // Private method to walk through the node tree
763
691
  walkNodeTree(node, handler) {
764
692
  if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
765
693
  handler(node);
@@ -770,7 +698,6 @@ var TemplateNode = class {
770
698
  child = child.nextSibling;
771
699
  }
772
700
  }
773
- // Private method to handle SSG nodes
774
701
  handleSSGNode(node) {
775
702
  var _a;
776
703
  if (node.nodeType === Node.COMMENT_NODE) {
@@ -786,7 +713,6 @@ var TemplateNode = class {
786
713
  }
787
714
  }
788
715
  }
789
- // Method to patch props onto the node
790
716
  patchProps(props) {
791
717
  if (!props) return;
792
718
  Object.entries(props).forEach(([key, value]) => {
@@ -798,15 +724,14 @@ var TemplateNode = class {
798
724
  });
799
725
  this.props = props;
800
726
  }
801
- // Private method to patch a single prop
802
727
  patchProp(key, node, props, isRoot) {
803
728
  if (!props) return;
804
729
  Object.entries(props).forEach(([attr, value]) => {
805
730
  if (attr === CHILDREN_PROP && value) {
806
731
  this.patchChildren(key, node, value, isRoot);
807
- } else if (attr === "ref") {
732
+ } else if (attr === REF_KEY) {
808
733
  props[attr].value = node;
809
- } else if (shared.startsWith(attr, "on")) {
734
+ } else if (shared.startsWith(attr, EVENT_PREFIX)) {
810
735
  this.patchEventListener(key, node, attr, value);
811
736
  } else {
812
737
  if (this.bindValueKeys.includes(attr)) return;
@@ -816,14 +741,12 @@ var TemplateNode = class {
816
741
  });
817
742
  }
818
743
  getBindUpdateValue(props, key, attr) {
819
- const UPDATE_PREFIX2 = "update";
820
- const updateKey = `${UPDATE_PREFIX2}${shared.capitalizeFirstLetter(attr)}`;
744
+ const updateKey = `${UPDATE_PREFIX}${shared.capitalize(attr)}`;
821
745
  if (updateKey && props[updateKey] && shared.isFunction(props[updateKey])) {
822
746
  this.bindValueKeys.push(updateKey);
823
747
  return props[updateKey];
824
748
  }
825
749
  }
826
- // Private method to patch children
827
750
  patchChildren(key, node, children, isRoot) {
828
751
  if (!shared.isArray(children)) {
829
752
  const trackKey = `${key}:${CHILDREN_PROP}:0`;
@@ -840,19 +763,21 @@ var TemplateNode = class {
840
763
  });
841
764
  }
842
765
  }
843
- // Private method to patch event listeners
844
766
  patchEventListener(key, node, attr, listener) {
845
767
  const eventName = attr.slice(2).toLowerCase();
846
768
  const track = this.getNodeTrack(`${key}:${attr}`);
847
769
  track.cleanup = addEventListener(node, eventName, listener);
848
770
  }
849
- // Private method to patch attributes
850
771
  patchAttribute(key, element, attr, value, updateFn) {
851
772
  const track = this.getNodeTrack(`${key}:${attr}`);
852
- const triggerValue = shared.isFunction(value) ? value() : signal.isSignal(value) ? value : signal.useSignal(value);
773
+ const val = shared.isFunction(value) ? value() : value;
774
+ const triggerValue = signal.isSignal(val) ? val : signal.shallowSignal(val);
853
775
  setAttribute(element, attr, triggerValue.value);
854
- const cleanup = signal.useEffect(() => {
855
- triggerValue.value = shared.isFunction(value) ? value() : signal.isSignal(value) ? value.value : value;
776
+ const cleanup = signal.effect(() => {
777
+ const val2 = shared.isFunction(value) ? value() : value;
778
+ if (shared.isPlainObject(val2) && shared.isPlainObject(triggerValue.peek()) && JSON.stringify(triggerValue.value) === JSON.stringify(val2))
779
+ return;
780
+ triggerValue.value = signal.isSignal(val2) ? val2.value : val2;
856
781
  setAttribute(element, attr, triggerValue.value);
857
782
  });
858
783
  let cleanupBind;
@@ -866,9 +791,7 @@ var TemplateNode = class {
866
791
  cleanupBind && cleanupBind();
867
792
  };
868
793
  }
869
- // Private method to get or create a NodeTrack
870
794
  getNodeTrack(trackKey, trackLastNodes, isRoot) {
871
- var _a;
872
795
  let track = this.trackMap.get(trackKey);
873
796
  if (!track) {
874
797
  track = { cleanup: () => {
@@ -881,13 +804,12 @@ var TemplateNode = class {
881
804
  }
882
805
  this.trackMap.set(trackKey, track);
883
806
  }
884
- (_a = track.cleanup) == null ? void 0 : _a.call(track);
807
+ track.cleanup && track.cleanup();
885
808
  return track;
886
809
  }
887
- // Private method to patch a child node
888
810
  patchChild(track, parent, child, before) {
889
811
  if (shared.isFunction(child)) {
890
- track.cleanup = signal.useEffect(() => {
812
+ track.cleanup = signal.effect(() => {
891
813
  const nextNodes = shared.coerceArray(child()).map(coerceNode);
892
814
  if (renderContext.isSSR) {
893
815
  track.lastNodes = this.reconcileChildren(parent, nextNodes, before);
@@ -908,7 +830,6 @@ var TemplateNode = class {
908
830
  });
909
831
  }
910
832
  }
911
- // Private method to reconcile children nodes
912
833
  reconcileChildren(parent, nextNodes, before) {
913
834
  const result = /* @__PURE__ */ new Map();
914
835
  const textNodes = Array.from(parent.childNodes).filter(
@@ -934,19 +855,41 @@ var TemplateNode = class {
934
855
  }
935
856
  };
936
857
 
937
- // src/jsx-renderer.ts
858
+ // src/fragmentNode.ts
859
+ var FragmentNode = class extends TemplateNode {
860
+ unmount() {
861
+ this.trackMap.forEach((track) => {
862
+ if (track.lastNodes) {
863
+ track.lastNodes.forEach((node) => {
864
+ removeChild(node);
865
+ });
866
+ }
867
+ track.cleanup && track.cleanup();
868
+ });
869
+ this.trackMap.clear();
870
+ this.treeMap.clear();
871
+ this.nodes.forEach((node) => {
872
+ removeChild(node);
873
+ });
874
+ this.nodes = [];
875
+ this.mounted = false;
876
+ }
877
+ };
878
+
879
+ // src/jsxRenderer.ts
938
880
  function h(template, props, key) {
881
+ if (template === EMPTY_TEMPLATE) {
882
+ return Fragment(template, props);
883
+ }
939
884
  if (shared.isString(template)) {
940
- if (isHtmlTagName(template)) {
941
- const htmlTemplate = convertToHtmlTag(template);
942
- props = { [SINGLE_PROP_KEY]: props };
943
- return new TemplateNode(createTemplate(htmlTemplate), props, key);
944
- } else if (template === EMPTY_TEMPLATE) {
945
- props = { [FRAGMENT_PROP_KEY]: props };
946
- return new TemplateNode(createTemplate(EMPTY_TEMPLATE), props, key);
947
- }
885
+ const htmlTemplate = convertToHtmlTag(template);
886
+ props = { [SINGLE_PROP_KEY]: props };
887
+ return new TemplateNode(createTemplate(htmlTemplate), props, key);
948
888
  }
949
- return shared.isFunction(template) ? new ComponentNode(template, props, key) : new TemplateNode(template, props, key);
889
+ if (shared.isFunction(template)) {
890
+ return new ComponentNode(template, props, key);
891
+ }
892
+ return new TemplateNode(template, props, key);
950
893
  }
951
894
  function isComponent(node) {
952
895
  return node instanceof ComponentNode;
@@ -959,10 +902,18 @@ function createTemplate(html) {
959
902
  template.innerHTML = closeHtmlTags(html);
960
903
  return template;
961
904
  }
962
- function Fragment(props) {
963
- return h(EMPTY_TEMPLATE, {
964
- children: shared.isArray(props.children) ? props.children.filter(Boolean) : [props.children]
965
- });
905
+ function Fragment(template, props) {
906
+ if (props.children) {
907
+ props = {
908
+ [FRAGMENT_PROP_KEY]: {
909
+ children: shared.isArray(props.children) ? props.children.filter(Boolean) : [props.children]
910
+ }
911
+ };
912
+ }
913
+ if (template === EMPTY_TEMPLATE) {
914
+ template = createTemplate(EMPTY_TEMPLATE);
915
+ }
916
+ return new FragmentNode(template, props);
966
917
  }
967
918
  function onMount(cb) {
968
919
  assertInsideComponent("onMounted");