ripple 0.4.3 → 0.4.5

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/package.json +3 -3
  3. package/src/constants.js +6 -0
  4. package/src/runtime/internal/client/attributes.js +259 -126
  5. package/src/runtime/internal/client/blocks.js +16 -6
  6. package/src/runtime/internal/client/composite.js +292 -100
  7. package/src/runtime/internal/client/constants.js +8 -0
  8. package/src/runtime/internal/client/events.js +15 -1
  9. package/src/runtime/internal/client/expression.js +4 -4
  10. package/src/runtime/internal/client/for.js +13 -38
  11. package/src/runtime/internal/client/if.js +56 -1
  12. package/src/runtime/internal/client/index.js +8 -6
  13. package/src/runtime/internal/client/operations.js +9 -4
  14. package/src/runtime/internal/client/render.js +37 -0
  15. package/src/runtime/internal/client/runtime.js +94 -20
  16. package/src/runtime/internal/client/template-ns.js +45 -4
  17. package/src/runtime/internal/client/template.js +103 -0
  18. package/tests/client/composite/composite.dynamic-components.test.tsrx +40 -0
  19. package/tests/client/css/scoped-styles.test.tsrx +3 -1
  20. package/tests/client/svg.test.tsrx +273 -1
  21. package/tests/hydration/compiled/client/basic.js +79 -51
  22. package/tests/hydration/compiled/client/composite.js +13 -4
  23. package/tests/hydration/compiled/client/events.js +22 -7
  24. package/tests/hydration/compiled/client/for.js +110 -71
  25. package/tests/hydration/compiled/client/fragment-cursor.js +342 -156
  26. package/tests/hydration/compiled/client/head.js +13 -13
  27. package/tests/hydration/compiled/client/hmr.js +16 -4
  28. package/tests/hydration/compiled/client/html-in-template.js +1 -1
  29. package/tests/hydration/compiled/client/html.js +144 -87
  30. package/tests/hydration/compiled/client/if-children.js +118 -33
  31. package/tests/hydration/compiled/client/if-fragment-controlflow.js +41 -21
  32. package/tests/hydration/compiled/client/if.js +70 -18
  33. package/tests/hydration/compiled/client/mixed-control-flow.js +50 -20
  34. package/tests/hydration/compiled/client/nested-control-flow.js +191 -100
  35. package/tests/hydration/compiled/client/portal.js +29 -9
  36. package/tests/hydration/compiled/client/reactivity.js +9 -5
  37. package/tests/hydration/compiled/client/streaming.js +21 -18
  38. package/tests/hydration/compiled/client/switch.js +17 -17
  39. package/tests/hydration/compiled/client/track-async-serialization.js +29 -21
  40. package/tests/hydration/compiled/client/try.js +13 -10
  41. package/tests/hydration/compiled/client/typed-text.js +3 -2
  42. package/tests/utils/inline-drift.test.js +83 -0
@@ -1,7 +1,279 @@
1
- import { track } from 'ripple';
1
+ import { track, flushSync } from 'ripple';
2
2
  import type { Component, PropsWithChildren, PropsWithExtras } from 'ripple';
3
3
 
4
+ const SVG_NS = 'http://www.w3.org/2000/svg';
5
+ const HTML_NS = 'http://www.w3.org/1999/xhtml';
6
+
7
+ // The namespace is only known at runtime here: the component's children are
8
+ // compiled without it and rendered into an `<svg>` the component owns, so
9
+ // every block must keep the namespace it was created in when it reruns.
10
+ describe('SVG namespace in runtime-only contexts', () => {
11
+ function SVG({ children }: PropsWithChildren<{}>) @{
12
+ <svg>{children}</svg>
13
+ }
14
+
15
+ it('parses a nested template in the SVG namespace', () => {
16
+ function App() @{
17
+ <SVG>
18
+ <g class="group">
19
+ <circle r="1" />
20
+ </g>
21
+ </SVG>
22
+ }
23
+
24
+ render(App);
25
+ expect(container.querySelector('.group').namespaceURI).toBe(SVG_NS);
26
+ expect(container.querySelector('circle').namespaceURI).toBe(SVG_NS);
27
+ });
28
+
29
+ it('keeps the namespace when an @if in component children toggles', () => {
30
+ let setFlag: ((value: boolean) => void) | undefined;
31
+
32
+ function App() @{
33
+ const flag = track(true);
34
+ setFlag = (value) => {
35
+ flag.value = value;
36
+ };
37
+ <SVG>
38
+ @if (flag.value) {
39
+ <polygon class="a" points="0,0 1,1" />
40
+ } @else {
41
+ <g class="b">
42
+ <rect width="1" height="1" />
43
+ </g>
44
+ }
45
+ </SVG>
46
+ }
47
+
48
+ render(App);
49
+ expect(container.querySelector('.a').namespaceURI).toBe(SVG_NS);
50
+ flushSync(() => setFlag?.(false));
51
+ expect(container.querySelector('.b').namespaceURI).toBe(SVG_NS);
52
+ expect(container.querySelector('rect').namespaceURI).toBe(SVG_NS);
53
+ flushSync(() => setFlag?.(true));
54
+ expect(container.querySelector('.a').namespaceURI).toBe(SVG_NS);
55
+ });
56
+
57
+ it('keeps the namespace when an @if in a leaf component toggles', () => {
58
+ let setFlag: ((value: boolean) => void) | undefined;
59
+
60
+ function Shape() @{
61
+ const flag = track(true);
62
+ setFlag = (value) => {
63
+ flag.value = value;
64
+ };
65
+ @if (flag.value) {
66
+ <polygon class="a" points="0,0 1,1" />
67
+ } @else {
68
+ <rect class="b" width="1" height="1" />
69
+ }
70
+ }
71
+
72
+ function App() @{
73
+ <svg>
74
+ <Shape />
75
+ </svg>
76
+ }
77
+
78
+ render(App);
79
+ expect(container.querySelector('.a').namespaceURI).toBe(SVG_NS);
80
+ flushSync(() => setFlag?.(false));
81
+ expect(container.querySelector('.b').namespaceURI).toBe(SVG_NS);
82
+ });
83
+
84
+ it('keeps the namespace when a dynamic tag in component children changes', () => {
85
+ let setTag: ((value: string) => void) | undefined;
86
+
87
+ function App() @{
88
+ const tag = track('polygon');
89
+ setTag = (value) => {
90
+ tag.value = value;
91
+ };
92
+ <SVG>
93
+ <{tag.value} class="shape" />
94
+ </SVG>
95
+ }
96
+
97
+ render(App);
98
+ expect(container.querySelector('.shape').namespaceURI).toBe(SVG_NS);
99
+ flushSync(() => setTag?.('rect'));
100
+ const shape = container.querySelector('.shape');
101
+ expect(shape.localName).toBe('rect');
102
+ expect(shape.namespaceURI).toBe(SVG_NS);
103
+ });
104
+
105
+ it('keeps the namespace for items added to an @for in component children', () => {
106
+ let setItems: ((value: string[]) => void) | undefined;
107
+
108
+ function App() @{
109
+ const items = track(['a']);
110
+ setItems = (value) => {
111
+ items.value = value;
112
+ };
113
+ <SVG>
114
+ @for (const id of items.value) {
115
+ <circle data-id={id} r="1" />
116
+ }
117
+ </SVG>
118
+ }
119
+
120
+ render(App);
121
+ expect(container.querySelector('[data-id=a]').namespaceURI).toBe(SVG_NS);
122
+ flushSync(() => setItems?.(['a', 'b']));
123
+ expect(container.querySelector('[data-id=b]').namespaceURI).toBe(SVG_NS);
124
+ });
125
+
126
+ it('renders HTML inside a foreignObject in component children', () => {
127
+ let setTag: ((value: string) => void) | undefined;
128
+
129
+ function App() @{
130
+ const tag = track('div');
131
+ setTag = (value) => {
132
+ tag.value = value;
133
+ };
134
+ <SVG>
135
+ <foreignObject>
136
+ @if (tag.value !== 'none') {
137
+ <div class="static-label">
138
+ <span>hi</span>
139
+ </div>
140
+ }
141
+ <{tag.value} class="html-label">Label</{tag.value}>
142
+ </foreignObject>
143
+ <circle class="after" r="1" />
144
+ </SVG>
145
+ }
146
+
147
+ render(App);
148
+ expect(container.querySelector('.static-label').namespaceURI).toBe(HTML_NS);
149
+ expect(container.querySelector('span').namespaceURI).toBe(HTML_NS);
150
+ expect(container.querySelector('.html-label').namespaceURI).toBe(HTML_NS);
151
+ expect(container.querySelector('.after').namespaceURI).toBe(SVG_NS);
152
+ flushSync(() => setTag?.('span'));
153
+ const label = container.querySelector('.html-label');
154
+ expect(label.localName).toBe('span');
155
+ expect(label.namespaceURI).toBe(HTML_NS);
156
+ });
157
+
158
+ it('sets a dynamic class on SVG elements in component children', () => {
159
+ let setName: ((value: string) => void) | undefined;
160
+
161
+ function App() @{
162
+ const name = track('one');
163
+ setName = (value) => {
164
+ name.value = value;
165
+ };
166
+ <SVG>
167
+ <circle class={name.value} r="1" />
168
+ <a class={name.value} href="#link">
169
+ <text>link</text>
170
+ </a>
171
+ </SVG>
172
+ }
173
+
174
+ render(App);
175
+ expect(container.querySelector('circle').getAttribute('class')).toBe('one');
176
+ expect(container.querySelector('a').getAttribute('class')).toBe('one');
177
+ flushSync(() => setName?.('two'));
178
+ expect(container.querySelector('circle').getAttribute('class')).toBe('two');
179
+ expect(container.querySelector('a').getAttribute('class')).toBe('two');
180
+ });
181
+ });
182
+
183
+ describe('dynamic element namespace changes', () => {
184
+ it('switches a root between HTML and SVG with its children', () => {
185
+ let setTag: ((value: string) => void) | undefined;
186
+
187
+ function App() @{
188
+ const tag = track('div');
189
+ setTag = (value) => {
190
+ tag.value = value;
191
+ };
192
+ <{tag.value} class="root">
193
+ <g class="inner">
194
+ <title>t</title>
195
+ </g>
196
+ </{tag.value}>
197
+ }
198
+
199
+ render(App);
200
+ expect(container.querySelector('.root').namespaceURI).toBe(HTML_NS);
201
+ expect(container.querySelector('.inner').namespaceURI).toBe(HTML_NS);
202
+ flushSync(() => setTag?.('svg'));
203
+ expect(container.querySelector('.root').namespaceURI).toBe(SVG_NS);
204
+ expect(container.querySelector('.inner').namespaceURI).toBe(SVG_NS);
205
+ expect(container.querySelector('title').namespaceURI).toBe(SVG_NS);
206
+ flushSync(() => setTag?.('div'));
207
+ expect(container.querySelector('.root').namespaceURI).toBe(HTML_NS);
208
+ expect(container.querySelector('.inner').namespaceURI).toBe(HTML_NS);
209
+ });
210
+
211
+ it('renders HTML children once the tag becomes foreignObject', () => {
212
+ let setTag: ((value: string) => void) | undefined;
213
+
214
+ function App() @{
215
+ const tag = track('g');
216
+ setTag = (value) => {
217
+ tag.value = value;
218
+ };
219
+ <svg>
220
+ <{tag.value} class="host">
221
+ <a class="content">hi</a>
222
+ </{tag.value}>
223
+ </svg>
224
+ }
225
+
226
+ render(App);
227
+ expect(container.querySelector('.host').namespaceURI).toBe(SVG_NS);
228
+ expect(container.querySelector('.content').namespaceURI).toBe(SVG_NS);
229
+ flushSync(() => setTag?.('foreignObject'));
230
+ const host = container.querySelector('.host');
231
+ expect(host.localName).toBe('foreignObject');
232
+ expect(host.namespaceURI).toBe(SVG_NS);
233
+ expect(container.querySelector('.content').namespaceURI).toBe(HTML_NS);
234
+ flushSync(() => setTag?.('g'));
235
+ expect(container.querySelector('.content').namespaceURI).toBe(SVG_NS);
236
+ });
237
+ });
238
+
4
239
  describe('SVG namespace handling', () => {
240
+ it('preserves SVG and foreignObject namespaces when dynamic tags change', () => {
241
+ let setTags: ((svgTag: string, htmlTag: string) => void) | undefined;
242
+
243
+ function App() @{
244
+ const shape = track('circle');
245
+ const html = track('div');
246
+ setTags = (svgTag, htmlTag) => {
247
+ shape.value = svgTag;
248
+ html.value = htmlTag;
249
+ };
250
+ <svg>
251
+ <{shape.value} class="shape">
252
+ <title>Dynamic shape</title>
253
+ </{shape.value}>
254
+ <foreignObject>
255
+ <{html.value} class="html-label">Label</{html.value}>
256
+ </foreignObject>
257
+ </svg>
258
+ }
259
+
260
+ render(App);
261
+ for (const [svgTag, htmlTag] of [['circle', 'div'], ['path', 'span'], ['line', 'div']]) {
262
+ flushSync(() => {
263
+ setTags?.(svgTag, htmlTag);
264
+ });
265
+ const element = container.querySelector('.shape');
266
+ expect(element.localName).toBe(svgTag);
267
+ expect(element.namespaceURI).toBe('http://www.w3.org/2000/svg');
268
+ expect(element.querySelector('title').namespaceURI).toBe('http://www.w3.org/2000/svg');
269
+ expect(element.textContent).toBe('Dynamic shape');
270
+ const label = container.querySelector('.html-label');
271
+ expect(label.localName).toBe(htmlTag);
272
+ expect(label.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
273
+ expect(label.textContent).toBe('Label');
274
+ }
275
+ });
276
+
5
277
  it('should render static SVG elements with correct namespace', () => {
6
278
  function App() @{
7
279
  <svg
@@ -1,7 +1,7 @@
1
1
  // @ts-nocheck
2
2
  import * as _$_ from 'ripple/internal/client';
3
3
 
4
- var root = _$_.template(`<div>Hello World`);
4
+ var root = _$_.template_el('div', null, 'Hello World');
5
5
 
6
6
  function StaticText_render(__anchor, __block) {
7
7
  var div = root();
@@ -30,7 +30,13 @@ function MultipleElements_render(__anchor, __block) {
30
30
 
31
31
  MultipleElements[_$_.$r] = MultipleElements_render;
32
32
 
33
- var root_3 = _$_.template(`<div class=outer><div class=inner><span>Nested content`);
33
+ var root_3 = _$_.template_el('div', ['class', 'outer'], [
34
+ [
35
+ 'div',
36
+ ['class', 'inner'],
37
+ [['span', null, 'Nested content']]
38
+ ]
39
+ ]);
34
40
 
35
41
  function NestedElements_render(__anchor, __block) {
36
42
  var div_1 = root_3();
@@ -59,7 +65,7 @@ function WithAttributes_render(__anchor, __block) {
59
65
 
60
66
  WithAttributes[_$_.$r] = WithAttributes_render;
61
67
 
62
- var root_6 = _$_.template(`<span class=child>Child content`);
68
+ var root_6 = _$_.template_el('span', ['class', 'child'], 'Child content');
63
69
 
64
70
  function ChildComponent_render(__anchor, __block) {
65
71
  var span = root_6();
@@ -69,7 +75,7 @@ function ChildComponent_render(__anchor, __block) {
69
75
 
70
76
  ChildComponent[_$_.$r] = ChildComponent_render;
71
77
 
72
- var root_7 = _$_.template(`<div class=parent>`);
78
+ var root_7 = _$_.template_el('div', ['class', 'parent']);
73
79
 
74
80
  function ParentWithChild_render(__anchor, __block) {
75
81
  var div_2 = root_7();
@@ -86,7 +92,7 @@ function ParentWithChild_render(__anchor, __block) {
86
92
 
87
93
  ParentWithChild[_$_.$r] = ParentWithChild_render;
88
94
 
89
- var root_8 = _$_.template(`<div class=first>First`);
95
+ var root_8 = _$_.template_el('div', ['class', 'first'], 'First');
90
96
 
91
97
  function FirstSibling_render(__anchor, __block) {
92
98
  var div_3 = root_8();
@@ -96,7 +102,7 @@ function FirstSibling_render(__anchor, __block) {
96
102
 
97
103
  FirstSibling[_$_.$r] = FirstSibling_render;
98
104
 
99
- var root_9 = _$_.template(`<div class=second>Second`);
105
+ var root_9 = _$_.template_el('div', ['class', 'second'], 'Second');
100
106
 
101
107
  function SecondSibling_render(__anchor, __block) {
102
108
  var div_4 = root_9();
@@ -130,7 +136,7 @@ function SiblingComponents_render(__anchor, __block) {
130
136
 
131
137
  SiblingComponents[_$_.$r] = SiblingComponents_render;
132
138
 
133
- var root_12 = _$_.template(`<div>`);
139
+ var root_12 = _$_.template_el('div');
134
140
 
135
141
  function render(__prev) {
136
142
  var __a = 'Hello ' + __prev._a.name;
@@ -190,7 +196,7 @@ function ExpressionContent_render(__anchor, __block) {
190
196
 
191
197
  ExpressionContent[_$_.$r] = ExpressionContent_render;
192
198
 
193
- var root_15 = _$_.template(`<div class=helper-item>`);
199
+ var root_15 = _$_.template_el('div', ['class', 'helper-item']);
194
200
 
195
201
  function NestedHelperItem_render(__anchor, __block, { item }) {
196
202
  var div_7 = root_15();
@@ -238,8 +244,8 @@ function NestedTsxTsrxFragment_render(__anchor, __block, { label }) {
238
244
 
239
245
  NestedTsxTsrxFragment[_$_.$r] = NestedTsxTsrxFragment_render;
240
246
 
241
- var root_19 = _$_.template(`<div class=app-item> `);
242
- var root_18 = _$_.template(`<div class=nested-expression-values><!>`);
247
+ var root_19 = _$_.template_el('div', ['class', 'app-item'], ' ');
248
+ var root_18 = _$_.template_el('div', ['class', 'nested-expression-values'], [null]);
243
249
 
244
250
  function NestedTsxTsrxExpressionValues_render(__anchor, __block) {
245
251
  var div_8 = root_18();
@@ -276,10 +282,10 @@ function NestedTsxTsrxExpressionValues_render(__anchor, __block) {
276
282
 
277
283
  NestedTsxTsrxExpressionValues[_$_.$r] = NestedTsxTsrxExpressionValues_render;
278
284
 
279
- var root_20 = _$_.template(`<strong class=middle>beta`);
280
- var root_21 = _$_.template(`<em class=tail>epsilon`);
285
+ var root_20 = _$_.template_el('strong', ['class', 'middle'], 'beta');
286
+ var root_21 = _$_.template_el('em', ['class', 'tail'], 'epsilon');
281
287
  var root_22 = _$_.template(` `, 1, 1);
282
- var root_23 = _$_.template(`<div class=mixed-collection><!>`);
288
+ var root_23 = _$_.template_el('div', ['class', 'mixed-collection'], [null]);
283
289
 
284
290
  function MixedTsrxCollectionText_render(__anchor, __block) {
285
291
  const content = _$_.tsrx_element((__anchor, __block) => {
@@ -322,10 +328,10 @@ function MixedTsrxCollectionText_render(__anchor, __block) {
322
328
 
323
329
  MixedTsrxCollectionText[_$_.$r] = MixedTsrxCollectionText_render;
324
330
 
325
- var root_24 = _$_.template(`<strong class=middle>beta`);
326
- var root_25 = _$_.template(`<em class=tail>epsilon`);
331
+ var root_24 = _$_.template_el('strong', ['class', 'middle'], 'beta');
332
+ var root_25 = _$_.template_el('em', ['class', 'tail'], 'epsilon');
327
333
  var root_26 = _$_.template(` `, 1, 1);
328
- var root_27 = _$_.template(`<div class=mixed-collection-split><!>`);
334
+ var root_27 = _$_.template_el('div', ['class', 'mixed-collection-split'], [null]);
329
335
 
330
336
  function MixedTsrxCollectionSplitServerText_render(__anchor, __block) {
331
337
  const content = _$_.tsrx_element((__anchor, __block) => {
@@ -368,10 +374,10 @@ function MixedTsrxCollectionSplitServerText_render(__anchor, __block) {
368
374
 
369
375
  MixedTsrxCollectionSplitServerText[_$_.$r] = MixedTsrxCollectionSplitServerText_render;
370
376
 
371
- var root_28 = _$_.template(`<strong class=middle>beta`);
372
- var root_29 = _$_.template(`<em class=tail>epsilon`);
377
+ var root_28 = _$_.template_el('strong', ['class', 'middle'], 'beta');
378
+ var root_29 = _$_.template_el('em', ['class', 'tail'], 'epsilon');
373
379
  var root_30 = _$_.template(` `, 1, 1);
374
- var root_31 = _$_.template(`<div class=mixed-collection-split><!>`);
380
+ var root_31 = _$_.template_el('div', ['class', 'mixed-collection-split'], [null]);
375
381
 
376
382
  function MixedTsrxCollectionSplitClientText_render(__anchor, __block) {
377
383
  const content = _$_.tsrx_element((__anchor, __block) => {
@@ -414,9 +420,9 @@ function MixedTsrxCollectionSplitClientText_render(__anchor, __block) {
414
420
 
415
421
  MixedTsrxCollectionSplitClientText[_$_.$r] = MixedTsrxCollectionSplitClientText_render;
416
422
 
417
- var root_32 = _$_.template(`<span class=primitive-tail> ok`);
423
+ var root_32 = _$_.template_el('span', ['class', 'primitive-tail'], ' ok');
418
424
  var root_33 = _$_.template(` `, 1, 1);
419
- var root_34 = _$_.template(`<div class=mixed-collection-primitive><!>`);
425
+ var root_34 = _$_.template_el('div', ['class', 'mixed-collection-primitive'], [null]);
420
426
 
421
427
  function MixedTsrxCollectionPrimitiveServerText_render(__anchor, __block) {
422
428
  const content = _$_.tsrx_element((__anchor, __block) => {
@@ -452,9 +458,9 @@ function MixedTsrxCollectionPrimitiveServerText_render(__anchor, __block) {
452
458
 
453
459
  MixedTsrxCollectionPrimitiveServerText[_$_.$r] = MixedTsrxCollectionPrimitiveServerText_render;
454
460
 
455
- var root_35 = _$_.template(`<span class=primitive-tail> ok`);
461
+ var root_35 = _$_.template_el('span', ['class', 'primitive-tail'], ' ok');
456
462
  var root_36 = _$_.template(` `, 1, 1);
457
- var root_37 = _$_.template(`<div class=mixed-collection-primitive><!>`);
463
+ var root_37 = _$_.template_el('div', ['class', 'mixed-collection-primitive'], [null]);
458
464
 
459
465
  function MixedTsrxCollectionPrimitiveClientText_render(__anchor, __block) {
460
466
  const content = _$_.tsrx_element((__anchor, __block) => {
@@ -490,7 +496,7 @@ function MixedTsrxCollectionPrimitiveClientText_render(__anchor, __block) {
490
496
 
491
497
  MixedTsrxCollectionPrimitiveClientText[_$_.$r] = MixedTsrxCollectionPrimitiveClientText_render;
492
498
 
493
- var root_38 = _$_.template(`<div class=dynamic-array-call> `);
499
+ var root_38 = _$_.template_el('div', ['class', 'dynamic-array-call'], ' ');
494
500
 
495
501
  function DynamicArrayFromCall_render(__anchor, __block) {
496
502
  const items = _$_.with_scope(__block, createPrimitiveItems);
@@ -508,7 +514,7 @@ function DynamicArrayFromCall_render(__anchor, __block) {
508
514
 
509
515
  DynamicArrayFromCall[_$_.$r] = DynamicArrayFromCall_render;
510
516
 
511
- var root_39 = _$_.template(`<div class=dynamic-array-track> `);
517
+ var root_39 = _$_.template_el('div', ['class', 'dynamic-array-track'], ' ');
512
518
 
513
519
  function DynamicArrayFromTrack_render(__anchor, __block) {
514
520
  const items = _$_.track(['start:', ['one', 2], true, null, false, ':end'], __block, '1egmw3m');
@@ -526,7 +532,7 @@ function DynamicArrayFromTrack_render(__anchor, __block) {
526
532
 
527
533
  DynamicArrayFromTrack[_$_.$r] = DynamicArrayFromTrack_render;
528
534
 
529
- var root_40 = _$_.template(`<div class=dynamic-array-conditional> `);
535
+ var root_40 = _$_.template_el('div', ['class', 'dynamic-array-conditional'], ' ');
530
536
 
531
537
  function DynamicArrayFromConditional_render(__anchor, __block) {
532
538
  const condition = true;
@@ -549,7 +555,7 @@ function DynamicArrayFromConditional_render(__anchor, __block) {
549
555
 
550
556
  DynamicArrayFromConditional[_$_.$r] = DynamicArrayFromConditional_render;
551
557
 
552
- var root_41 = _$_.template(`<div class=dynamic-array-logical> `);
558
+ var root_41 = _$_.template_el('div', ['class', 'dynamic-array-logical'], ' ');
553
559
 
554
560
  function DynamicArrayFromLogical_render(__anchor, __block) {
555
561
  const condition = true;
@@ -568,7 +574,7 @@ function DynamicArrayFromLogical_render(__anchor, __block) {
568
574
 
569
575
  DynamicArrayFromLogical[_$_.$r] = DynamicArrayFromLogical_render;
570
576
 
571
- var root_42 = _$_.template(`<section class=outer><div class=inner>from tsrx`);
577
+ var root_42 = _$_.template_el('section', ['class', 'outer'], [['div', ['class', 'inner'], 'from tsrx']]);
572
578
  var root_44 = _$_.template(`<!>`, 1, 1);
573
579
  var root_43 = _$_.template(`<!>`, 1, 1);
574
580
 
@@ -595,7 +601,14 @@ function NestedTsrxInsideTopLevelTsxExpression_render(__anchor, __block) {
595
601
 
596
602
  NestedTsrxInsideTopLevelTsxExpression[_$_.$r] = NestedTsrxInsideTopLevelTsxExpression_render;
597
603
 
598
- var root_45 = _$_.template(`<div class=wrapper><section class=native><span class=nested-tsrx>inside nested tsrx`);
604
+ var root_45 = _$_.template_el('div', ['class', 'wrapper'], [
605
+ [
606
+ 'section',
607
+ ['class', 'native'],
608
+ [['span', ['class', 'nested-tsrx'], 'inside nested tsrx']]
609
+ ]
610
+ ]);
611
+
599
612
  var root_47 = _$_.template(`<!>`, 1, 1);
600
613
  var root_46 = _$_.template(`<!>`, 1, 1);
601
614
 
@@ -622,8 +635,8 @@ function NestedTsrxElementsInsideTopLevelTsxValue_render(__anchor, __block) {
622
635
 
623
636
  NestedTsrxElementsInsideTopLevelTsxValue[_$_.$r] = NestedTsrxElementsInsideTopLevelTsxValue_render;
624
637
 
625
- var root_48 = _$_.template(`<span class=nested-tsx>inside nested tsx`);
626
- var root_49 = _$_.template(`<div class=native> `);
638
+ var root_48 = _$_.template_el('span', ['class', 'nested-tsx'], 'inside nested tsx');
639
+ var root_49 = _$_.template_el('div', ['class', 'native'], ' ');
627
640
  var root_51 = _$_.template(`<!>`, 1, 1);
628
641
  var root_50 = _$_.template(`<!>`, 1, 1);
629
642
 
@@ -663,7 +676,7 @@ function TsxDeclaredBeforeTopLevelTsx_render(__anchor, __block) {
663
676
 
664
677
  TsxDeclaredBeforeTopLevelTsx[_$_.$r] = TsxDeclaredBeforeTopLevelTsx_render;
665
678
 
666
- var root_52 = _$_.template(`<div class=text-prop> `);
679
+ var root_52 = _$_.template_el('div', ['class', 'text-prop'], ' ');
667
680
 
668
681
  function TextProp_render(__anchor, __block, { children }) {
669
682
  var div_21 = root_52();
@@ -680,7 +693,7 @@ function TextProp_render(__anchor, __block, { children }) {
680
693
 
681
694
  TextProp[_$_.$r] = TextProp_render;
682
695
 
683
- var root_53 = _$_.template(`<div class=text-prop>`);
696
+ var root_53 = _$_.template_el('div', ['class', 'text-prop']);
684
697
 
685
698
  function render_1(__prev) {
686
699
  var __a = __prev._a.value;
@@ -826,8 +839,22 @@ function Header_render(__anchor, __block) {
826
839
 
827
840
  Header[_$_.$r] = Header_render;
828
841
 
829
- var root_65 = _$_.template(`<a href=/playground class=playground-link>Playground`);
830
- var root_64 = _$_.template(`<div class=social-links><a href=https://github.com class=github-link>GitHub</a><a href=https://discord.com class=discord-link>Discord</a><!>`);
842
+ var root_65 = _$_.template_el('a', ['href', '/playground', 'class', 'playground-link'], 'Playground');
843
+
844
+ var root_64 = _$_.template_el('div', ['class', 'social-links'], [
845
+ [
846
+ 'a',
847
+ ['href', 'https://github.com', 'class', 'github-link'],
848
+ 'GitHub'
849
+ ],
850
+
851
+ [
852
+ 'a',
853
+ ['href', 'https://discord.com', 'class', 'discord-link'],
854
+ 'Discord'
855
+ ],
856
+ null
857
+ ]);
831
858
 
832
859
  function Actions_render(__anchor, __block, { playgroundVisible = false }) {
833
860
  var div_23 = root_64();
@@ -853,7 +880,7 @@ function Actions_render(__anchor, __block, { playgroundVisible = false }) {
853
880
 
854
881
  Actions[_$_.$r] = Actions_render;
855
882
 
856
- var root_66 = _$_.template(`<main><div class=container><!>`);
883
+ var root_66 = _$_.template_el('main', null, [['div', ['class', 'container'], [null]]]);
857
884
 
858
885
  function Layout_render(__anchor, __block, { children }) {
859
886
  var main = root_66();
@@ -874,7 +901,7 @@ function Layout_render(__anchor, __block, { children }) {
874
901
 
875
902
  Layout[_$_.$r] = Layout_render;
876
903
 
877
- var root_67 = _$_.template(`<div class=content><p>Some content here`);
904
+ var root_67 = _$_.template_el('div', ['class', 'content'], [['p', null, 'Some content here']]);
878
905
 
879
906
  function Content_render(__anchor, __block) {
880
907
  var div_25 = root_67();
@@ -912,7 +939,7 @@ function WebsiteIndex_render(__anchor, __block) {
912
939
 
913
940
  WebsiteIndex[_$_.$r] = WebsiteIndex_render;
914
941
 
915
- var root_69 = _$_.template(`<footer class=last-child>I am the last child`);
942
+ var root_69 = _$_.template_el('footer', ['class', 'last-child'], 'I am the last child');
916
943
 
917
944
  function LastChild_render(__anchor, __block) {
918
945
  var footer = root_69();
@@ -922,7 +949,7 @@ function LastChild_render(__anchor, __block) {
922
949
 
923
950
  LastChild[_$_.$r] = LastChild_render;
924
951
 
925
- var root_70 = _$_.template(`<div class=wrapper><h1>Header</h1><p>Some content`);
952
+ var root_70 = _$_.template_el('div', ['class', 'wrapper'], [['h1', null, 'Header'], ['p', null, 'Some content']]);
926
953
 
927
954
  function ComponentAsLastSibling_render(__anchor, __block) {
928
955
  var div_26 = root_70();
@@ -941,7 +968,7 @@ function ComponentAsLastSibling_render(__anchor, __block) {
941
968
 
942
969
  ComponentAsLastSibling[_$_.$r] = ComponentAsLastSibling_render;
943
970
 
944
- var root_71 = _$_.template(`<div class=inner><span>Inner text`);
971
+ var root_71 = _$_.template_el('div', ['class', 'inner'], [['span', null, 'Inner text']]);
945
972
 
946
973
  function InnerContent_render(__anchor, __block) {
947
974
  var div_27 = root_71();
@@ -959,7 +986,7 @@ function InnerContent_render(__anchor, __block) {
959
986
 
960
987
  InnerContent[_$_.$r] = InnerContent_render;
961
988
 
962
- var root_72 = _$_.template(`<section class=outer><h2>Section title`);
989
+ var root_72 = _$_.template_el('section', ['class', 'outer'], [['h2', null, 'Section title']]);
963
990
 
964
991
  function NestedComponentAsLastSibling_render(__anchor, __block) {
965
992
  var section_1 = root_72();
@@ -977,7 +1004,7 @@ function NestedComponentAsLastSibling_render(__anchor, __block) {
977
1004
 
978
1005
  NestedComponentAsLastSibling[_$_.$r] = NestedComponentAsLastSibling_render;
979
1006
 
980
- var root_73 = _$_.template(`<div>`);
1007
+ var root_73 = _$_.template_el('div');
981
1008
 
982
1009
  function render_2(__prev) {
983
1010
  var __a = "label: " + String(_$_.with_scope(__prev._a, fetchLabel));
@@ -997,7 +1024,7 @@ function TextTailExpression_render(__anchor, __block) {
997
1024
 
998
1025
  TextTailExpression[_$_.$r] = TextTailExpression_render;
999
1026
 
1000
- var root_74 = _$_.template(`<div>`);
1027
+ var root_74 = _$_.template_el('div');
1001
1028
 
1002
1029
  function render_3(__prev) {
1003
1030
  var __a = 'frag-' + String(_$_.with_scope(__prev._a, fetchLabel));
@@ -1017,7 +1044,7 @@ function FragmentTailExpression_render(__anchor, __block) {
1017
1044
 
1018
1045
  FragmentTailExpression[_$_.$r] = FragmentTailExpression_render;
1019
1046
 
1020
- var root_75 = _$_.template(`<div>frag-<span>tail`);
1047
+ var root_75 = _$_.template_el('div', null, ['frag-', ['span', null, 'tail']]);
1021
1048
 
1022
1049
  function FragmentChildOnly_render(__anchor, __block) {
1023
1050
  var div_30 = root_75();
@@ -1052,7 +1079,7 @@ function OpaqueLead_render(__anchor, __block, props) {
1052
1079
 
1053
1080
  OpaqueLead[_$_.$r] = OpaqueLead_render;
1054
1081
 
1055
- var root_78 = _$_.template(`<div>`);
1082
+ var root_78 = _$_.template_el('div');
1056
1083
 
1057
1084
  function FragmentLeadsWithOpaqueValue_render(__anchor, __block) {
1058
1085
  var div_31 = root_78();
@@ -1099,7 +1126,7 @@ function PrimitiveCallLead_render(__anchor, __block) {
1099
1126
 
1100
1127
  PrimitiveCallLead[_$_.$r] = PrimitiveCallLead_render;
1101
1128
 
1102
- var root_81 = _$_.template(`<div>`);
1129
+ var root_81 = _$_.template_el('div');
1103
1130
 
1104
1131
  function FragmentLeadsWithPrimitiveCall_render(__anchor, __block) {
1105
1132
  var div_32 = root_81();
@@ -1119,7 +1146,8 @@ FragmentLeadsWithPrimitiveCall[_$_.$r] = FragmentLeadsWithPrimitiveCall_render;
1119
1146
  var root_83 = _$_.template(`<div class=primitive-calls></div><button>update`, 1, 2);
1120
1147
 
1121
1148
  function render_5(__prev) {
1122
- var __a = "sum: " + (String(Number(__prev._a.value) + Number(__prev._a.value) ?? '') + ("; big: " + String(_$_.with_scope(__prev._b, () => BigInt(__prev._a.value)) ?? '')));
1149
+ var __count_value = __prev._a.value;
1150
+ var __a = "sum: " + (String(Number(__count_value) + Number(__count_value) ?? '') + ("; big: " + String(_$_.with_scope(__prev._b, () => BigInt(__prev._a.value)) ?? '')));
1123
1151
 
1124
1152
  if (__prev.a !== __a) {
1125
1153
  _$_.set_text_content(__prev._c, __a, __prev.a);
@@ -1149,10 +1177,10 @@ function PrimitiveTextCalls_render(__anchor, __block) {
1149
1177
 
1150
1178
  PrimitiveTextCalls[_$_.$r] = PrimitiveTextCalls_render;
1151
1179
 
1152
- var root_84 = _$_.template(`<b>string`);
1153
- var root_85 = _$_.template(`<b>number`);
1154
- var root_86 = _$_.template(`<b>bigint`);
1155
- var root_87 = _$_.template(`<b>date`);
1180
+ var root_84 = _$_.template_el('b', null, 'string');
1181
+ var root_85 = _$_.template_el('b', null, 'number');
1182
+ var root_86 = _$_.template_el('b', null, 'bigint');
1183
+ var root_87 = _$_.template_el('b', null, 'date');
1156
1184
  var root_89 = _$_.template(`<p>before<!>after</p><p>before<!>after</p><p>before<!>after</p><p>before<!>after`, 1, 4);
1157
1185
  var root_88 = _$_.template(`<!>`, 1, 1);
1158
1186