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