ripple 0.3.71 → 0.3.74

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 (165) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -8
  4. package/src/runtime/index-client.js +3 -13
  5. package/src/runtime/internal/client/blocks.js +3 -25
  6. package/src/runtime/internal/client/for.js +80 -5
  7. package/src/runtime/internal/client/index.js +0 -2
  8. package/src/runtime/internal/client/types.d.ts +0 -10
  9. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  10. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  11. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  12. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  13. package/tests/client/array/array.derived.test.tsrx +97 -109
  14. package/tests/client/array/array.iteration.test.tsrx +28 -28
  15. package/tests/client/array/array.mutations.test.tsrx +68 -68
  16. package/tests/client/array/array.static.test.tsrx +82 -92
  17. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  18. package/tests/client/async-suspend.test.tsrx +180 -179
  19. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  20. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  21. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  22. package/tests/client/basic/basic.collections.test.tsrx +59 -71
  23. package/tests/client/basic/basic.components.test.tsrx +196 -222
  24. package/tests/client/basic/basic.errors.test.tsrx +72 -78
  25. package/tests/client/basic/basic.events.test.tsrx +80 -85
  26. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  27. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  28. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  29. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  30. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  31. package/tests/client/boundaries.test.tsrx +18 -18
  32. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  33. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  34. package/tests/client/compiler/compiler.basic.test.tsrx +364 -296
  35. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  36. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  37. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  38. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  39. package/tests/client/composite/composite.dynamic-components.test.tsrx +41 -44
  40. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  41. package/tests/client/composite/composite.props.test.tsrx +66 -74
  42. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  43. package/tests/client/composite/composite.render.test.tsrx +92 -101
  44. package/tests/client/computed-properties.test.tsrx +14 -18
  45. package/tests/client/context.test.tsrx +14 -18
  46. package/tests/client/css/global-additional-cases.test.tsrx +491 -437
  47. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  48. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  49. package/tests/client/css/global-basic.test.tsrx +105 -98
  50. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  51. package/tests/client/css/global-combinators.test.tsrx +83 -78
  52. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  53. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  54. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  55. package/tests/client/css/global-nested.test.tsrx +88 -78
  56. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  57. package/tests/client/css/global-scoping.test.tsrx +145 -125
  58. package/tests/client/css/style-identifier.test.tsrx +62 -69
  59. package/tests/client/date.test.tsrx +83 -83
  60. package/tests/client/dynamic-elements.test.tsrx +227 -283
  61. package/tests/client/events.test.tsrx +252 -266
  62. package/tests/client/for.test.tsrx +120 -127
  63. package/tests/client/head.test.tsrx +40 -48
  64. package/tests/client/html.test.tsrx +37 -49
  65. package/tests/client/input-value.test.tsrx +1125 -1354
  66. package/tests/client/lazy-array.test.tsrx +10 -16
  67. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  68. package/tests/client/map.test.tsrx +39 -41
  69. package/tests/client/media-query.test.tsrx +15 -19
  70. package/tests/client/object.test.tsrx +46 -56
  71. package/tests/client/portal.test.tsrx +31 -37
  72. package/tests/client/ref.test.tsrx +173 -193
  73. package/tests/client/return.test.tsrx +62 -37
  74. package/tests/client/set.test.tsrx +33 -33
  75. package/tests/client/svg.test.tsrx +195 -215
  76. package/tests/client/switch.test.tsrx +201 -191
  77. package/tests/client/track-async-hydration.test.tsrx +14 -18
  78. package/tests/client/tracked-index-access.test.tsrx +18 -28
  79. package/tests/client/try.test.tsrx +494 -619
  80. package/tests/client/tsx.test.tsrx +290 -371
  81. package/tests/client/typescript-generics.test.tsrx +121 -129
  82. package/tests/client/url/url.derived.test.tsrx +21 -25
  83. package/tests/client/url/url.parsing.test.tsrx +35 -35
  84. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  85. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  86. package/tests/client/url/url.serialization.test.tsrx +8 -8
  87. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  88. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  89. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  90. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  91. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  92. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  93. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  94. package/tests/hydration/compiled/client/basic.js +396 -325
  95. package/tests/hydration/compiled/client/composite.js +52 -44
  96. package/tests/hydration/compiled/client/for.js +734 -604
  97. package/tests/hydration/compiled/client/head.js +183 -103
  98. package/tests/hydration/compiled/client/html.js +93 -86
  99. package/tests/hydration/compiled/client/if-children.js +95 -71
  100. package/tests/hydration/compiled/client/if.js +113 -89
  101. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  102. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  103. package/tests/hydration/compiled/client/reactivity.js +26 -24
  104. package/tests/hydration/compiled/client/return.js +8 -42
  105. package/tests/hydration/compiled/client/switch.js +208 -173
  106. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  107. package/tests/hydration/compiled/client/try.js +29 -21
  108. package/tests/hydration/compiled/server/basic.js +210 -221
  109. package/tests/hydration/compiled/server/composite.js +13 -14
  110. package/tests/hydration/compiled/server/for.js +427 -444
  111. package/tests/hydration/compiled/server/head.js +199 -189
  112. package/tests/hydration/compiled/server/html.js +33 -41
  113. package/tests/hydration/compiled/server/if-children.js +114 -117
  114. package/tests/hydration/compiled/server/if.js +77 -83
  115. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  116. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  117. package/tests/hydration/compiled/server/reactivity.js +24 -22
  118. package/tests/hydration/compiled/server/return.js +6 -18
  119. package/tests/hydration/compiled/server/switch.js +179 -176
  120. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  121. package/tests/hydration/compiled/server/try.js +31 -35
  122. package/tests/hydration/components/basic.tsrx +216 -286
  123. package/tests/hydration/components/composite.tsrx +32 -42
  124. package/tests/hydration/components/events.tsrx +81 -101
  125. package/tests/hydration/components/for.tsrx +270 -336
  126. package/tests/hydration/components/head.tsrx +43 -39
  127. package/tests/hydration/components/hmr.tsrx +16 -22
  128. package/tests/hydration/components/html-in-template.tsrx +15 -21
  129. package/tests/hydration/components/html.tsrx +442 -526
  130. package/tests/hydration/components/if-children.tsrx +107 -125
  131. package/tests/hydration/components/if.tsrx +68 -90
  132. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  133. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  134. package/tests/hydration/components/portal.tsrx +33 -41
  135. package/tests/hydration/components/reactivity.tsrx +26 -34
  136. package/tests/hydration/components/return.tsrx +4 -6
  137. package/tests/hydration/components/switch.tsrx +73 -78
  138. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  139. package/tests/hydration/components/try.tsrx +37 -51
  140. package/tests/hydration/switch.test.js +8 -8
  141. package/tests/server/await.test.tsrx +3 -3
  142. package/tests/server/basic.attributes.test.tsrx +120 -167
  143. package/tests/server/basic.components.test.tsrx +163 -197
  144. package/tests/server/basic.test.tsrx +298 -220
  145. package/tests/server/compiler.test.tsrx +142 -72
  146. package/tests/server/composite.props.test.tsrx +54 -58
  147. package/tests/server/composite.test.tsrx +165 -167
  148. package/tests/server/context.test.tsrx +13 -17
  149. package/tests/server/dynamic-elements.test.tsrx +103 -135
  150. package/tests/server/for.test.tsrx +115 -84
  151. package/tests/server/head.test.tsrx +31 -31
  152. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  153. package/tests/server/if.test.tsrx +49 -59
  154. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  155. package/tests/server/return.test.tsrx +58 -36
  156. package/tests/server/streaming-ssr.test.tsrx +4 -4
  157. package/tests/server/style-identifier.test.tsrx +58 -66
  158. package/tests/server/switch.test.tsrx +89 -97
  159. package/tests/server/track-async-serialization.test.tsrx +85 -103
  160. package/tests/server/try.test.tsrx +275 -360
  161. package/tests/utils/ref-types.test.js +72 -0
  162. package/tests/utils/vite-plugin-config.test.js +41 -74
  163. package/types/index.d.ts +1 -0
  164. package/src/runtime/internal/client/compat.js +0 -40
  165. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -1,56 +1,52 @@
1
1
  import { flushSync, track } from 'ripple';
2
2
 
3
3
  describe('tsx expression', () => {
4
- it('renders an empty <tsx></tsx> element', () => {
5
- function App() {
6
- return <>
7
- <tsx></tsx>
8
- </>;
4
+ it('renders an empty <></> element', () => {
5
+ function App() @{
6
+ <></>
9
7
  }
10
8
  render(App);
11
9
  expect(container.textContent).toBe('');
12
10
  });
13
11
 
14
12
  it('renders an empty <></> fragment shorthand', () => {
15
- function App() {
16
- return <>
17
- <></>
18
- </>;
13
+ function App() @{
14
+ <></>
19
15
  }
20
16
  render(App);
21
17
  expect(container.textContent).toBe('');
22
18
  });
23
19
 
24
- it('renders an empty <tsx></tsx> assigned to a variable', () => {
25
- function App() {
26
- return <>
27
- const el = <tsx></tsx>;
20
+ it('renders an empty <></> assigned to a variable', () => {
21
+ function App() @{
22
+ const el = <></>;
23
+ <>
28
24
  {el}
29
- </>;
25
+ </>
30
26
  }
31
27
  render(App);
32
28
  expect(container.textContent).toBe('');
33
29
  });
34
30
 
35
31
  it('renders an empty <></> fragment assigned to a variable', () => {
36
- function App() {
37
- return <>
38
- const el = <></>;
32
+ function App() @{
33
+ const el = <></>;
34
+ <>
39
35
  {el}
40
- </>;
36
+ </>
41
37
  }
42
38
  render(App);
43
39
  expect(container.textContent).toBe('');
44
40
  });
45
41
 
46
42
  it('renders a basic fragment shorthand element', () => {
47
- function App() {
48
- return <>
49
- const el = <tsx>
50
- <div>hello world</div>
51
- </tsx>;
52
- {el}
43
+ function App() @{
44
+ const el = <>
45
+ <div>{'hello world'}</div>
53
46
  </>;
47
+ <>
48
+ {el}
49
+ </>
54
50
  }
55
51
  render(App);
56
52
  expect(container.textContent).toBe('hello world');
@@ -58,15 +54,13 @@ describe('tsx expression', () => {
58
54
  });
59
55
 
60
56
  it('applies scoped classes inside tsx blocks and fragment shorthand', () => {
61
- function App() {
62
- return <>
63
- <tsx>
57
+ function App() @{
58
+ <>
59
+ <>
64
60
  <div class="card">
65
- <h2>
66
- {'tsx block'}
67
- </h2>
61
+ <h2>{'tsx block'}</h2>
68
62
  </div>
69
- </tsx>
63
+ </>
70
64
  <>
71
65
  <div class="card">
72
66
  <h2>{'fragment shorthand'}</h2>
@@ -81,7 +75,7 @@ describe('tsx expression', () => {
81
75
  color: red;
82
76
  }
83
77
  </style>
84
- </>;
78
+ </>
85
79
  }
86
80
 
87
81
  render(App);
@@ -106,13 +100,11 @@ describe('tsx expression', () => {
106
100
  });
107
101
 
108
102
  it('renders a tsx element assigned to a variable', () => {
109
- function App() {
110
- return <>
111
- const el = <tsx>
112
- <span class="test">content</span>
113
- </tsx>;
103
+ function App() @{
104
+ const el = <span class="test">{'content'}</span>;
105
+ <>
114
106
  {el}
115
- </>;
107
+ </>
116
108
  }
117
109
  render(App);
118
110
  const span = container.querySelector('span.test');
@@ -121,14 +113,14 @@ describe('tsx expression', () => {
121
113
  });
122
114
 
123
115
  it('renders a tsx element with multiple children', () => {
124
- function App() {
125
- return <>
126
- const el = <tsx>
127
- <div>first</div>
128
- <div>second</div>
129
- </tsx>;
130
- {el}
116
+ function App() @{
117
+ const el = <>
118
+ <div>first</div>
119
+ <div>second</div>
131
120
  </>;
121
+ <>
122
+ {el}
123
+ </>
132
124
  }
133
125
  render(App);
134
126
  const divs = container.querySelectorAll('div');
@@ -138,15 +130,15 @@ describe('tsx expression', () => {
138
130
  });
139
131
 
140
132
  it('renders a tsx element with nested elements', () => {
141
- function App() {
142
- return <>
143
- const el = <tsx>
144
- <div class="outer">
145
- <span class="inner">nested</span>
146
- </div>
147
- </tsx>;
148
- {el}
133
+ function App() @{
134
+ const el = <>
135
+ <div class="outer">
136
+ <span class="inner">nested</span>
137
+ </div>
149
138
  </>;
139
+ <>
140
+ {el}
141
+ </>
150
142
  }
151
143
  render(App);
152
144
  const outer = container.querySelector('div.outer');
@@ -157,13 +149,9 @@ describe('tsx expression', () => {
157
149
  });
158
150
 
159
151
  it('renders a tsx element inline in a parent element', () => {
160
- function App() {
161
- return <>
162
- const el = <tsx>
163
- <span>inline</span>
164
- </tsx>;
165
- <div class="parent">{el}</div>
166
- </>;
152
+ function App() @{
153
+ const el = <span>{'inline'}</span>;
154
+ <div class="parent">{el}</div>
167
155
  }
168
156
  render(App);
169
157
  const parent = container.querySelector('div.parent');
@@ -173,17 +161,17 @@ describe('tsx expression', () => {
173
161
  });
174
162
 
175
163
  it('renders a tsx element with reactive expressions', () => {
176
- function App() {
177
- return <>
178
- let &[count] = track(0);
179
- const el = <tsx>
180
- <div>
181
- {'count: ' + count}
182
- </div>
183
- </tsx>;
164
+ function App() @{
165
+ let &[count] = track(0);
166
+ const el = <>
167
+ <div>
168
+ {'count: ' + count}
169
+ </div>
170
+ </>;
171
+ <>
184
172
  {el}
185
173
  <button onClick={() => count++}>{'increment'}</button>
186
- </>;
174
+ </>
187
175
  }
188
176
  render(App);
189
177
  expect(container.querySelector('div').textContent).toBe('count: 0');
@@ -194,17 +182,17 @@ describe('tsx expression', () => {
194
182
  });
195
183
 
196
184
  it('conditionally renders tsx elements', () => {
197
- function App() {
198
- return <>
199
- let &[show] = track(true);
200
- const el = <tsx>
201
- <div class="tsx-content">visible</div>
202
- </tsx>;
203
- if (show) {
204
- {el}
185
+ function App() @{
186
+ let &[show] = track(true);
187
+ const el = <div class="tsx-content">{'content'}</div>;
188
+ <>
189
+ @if (show) {
190
+ <>
191
+ {el}
192
+ </>
205
193
  }
206
194
  <button onClick={() => (show = !show)}>{'toggle'}</button>
207
- </>;
195
+ </>
208
196
  }
209
197
  render(App);
210
198
  expect(container.querySelector('.tsx-content')).toBeTruthy();
@@ -219,17 +207,13 @@ describe('tsx expression', () => {
219
207
  });
220
208
 
221
209
  it('renders tsx element passed as children prop', () => {
222
- function Child(&{ children }: { children: any }) {
223
- return <><div class="wrapper">{children}</div></>;
210
+ function Child(&{ children }) @{
211
+ <div class="wrapper">{children}</div>
224
212
  }
225
213
 
226
- function App() {
227
- return <>
228
- const el = <tsx>
229
- <span>from tsx</span>
230
- </tsx>;
231
- <Child children={el} />
232
- </>;
214
+ function App() @{
215
+ const el = <span>{'from tsx'}</span>;
216
+ <Child children={el} />
233
217
  }
234
218
  render(App);
235
219
  const wrapper = container.querySelector('.wrapper');
@@ -239,13 +223,11 @@ describe('tsx expression', () => {
239
223
  });
240
224
 
241
225
  it('renders tsx element with text content only', () => {
242
- function App() {
243
- return <>
244
- const el = <tsx>
245
- just text
246
- </tsx>;
226
+ function App() @{
227
+ const el = <>just text</>;
228
+ <>
247
229
  {el}
248
- </>;
230
+ </>
249
231
  }
250
232
 
251
233
  render(App);
@@ -253,13 +235,13 @@ describe('tsx expression', () => {
253
235
  });
254
236
 
255
237
  it('renders tsx element with static attributes', () => {
256
- function App() {
257
- return <>
258
- const el = <tsx>
259
- <div id="my-id" class="my-class" data-testid="test" aria-label="label">content</div>
260
- </tsx>;
238
+ function App() @{
239
+ const el = <div id="my-id" class="my-class" data-testid="test" aria-label="label">
240
+ content
241
+ </div>;
242
+ <>
261
243
  {el}
262
- </>;
244
+ </>
263
245
  }
264
246
 
265
247
  render(App);
@@ -271,15 +253,13 @@ describe('tsx expression', () => {
271
253
  });
272
254
 
273
255
  it('renders tsx element with dynamic attribute values', () => {
274
- function App() {
275
- return <>
276
- let &[name] = track('initial');
277
- const el = <tsx>
278
- <div id={name} class={'cls-' + name}>content</div>
279
- </tsx>;
256
+ function App() @{
257
+ let &[name] = track('initial');
258
+ const el = <div id={name} class={'cls-' + name}>{'content'}</div>;
259
+ <>
280
260
  {el}
281
261
  <button onClick={() => (name = 'updated')}>{'update'}</button>
282
- </>;
262
+ </>
283
263
  }
284
264
 
285
265
  render(App);
@@ -294,17 +274,15 @@ describe('tsx expression', () => {
294
274
  });
295
275
 
296
276
  it('renders tsx element with event handlers', () => {
297
- function App() {
298
- return <>
299
- let &[clicked] = track(false);
300
- const el = <tsx>
301
- <button onClick={() => (clicked = true)}>
302
- {'click me'}
303
- </button>
304
- </tsx>;
277
+ function App() @{
278
+ let &[clicked] = track(false);
279
+ const el = <button onClick={() => (clicked = true)}>{'click'}</button>;
280
+ <>
305
281
  {el}
306
- <div class="status">{clicked ? 'clicked' : 'not clicked'}</div>
307
- </>;
282
+ <div class="status">
283
+ {clicked ? 'clicked' : 'not clicked'}
284
+ </div>
285
+ </>
308
286
  }
309
287
 
310
288
  render(App);
@@ -316,17 +294,13 @@ describe('tsx expression', () => {
316
294
  });
317
295
 
318
296
  it('renders tsx element with boolean attributes', () => {
319
- function App() {
320
- return <>
321
- let &[isDisabled] = track(true);
322
- const el = <tsx>
323
- <button disabled={isDisabled}>
324
- {'btn'}
325
- </button>
326
- </tsx>;
297
+ function App() @{
298
+ let &[isDisabled] = track(true);
299
+ const el = <button disabled={isDisabled}>{'submit'}</button>;
300
+ <>
327
301
  {el}
328
302
  <button class="toggle" onClick={() => (isDisabled = !isDisabled)}>{'toggle'}</button>
329
- </>;
303
+ </>
330
304
  }
331
305
 
332
306
  render(App);
@@ -338,15 +312,13 @@ describe('tsx expression', () => {
338
312
  });
339
313
 
340
314
  it('renders tsx element with style attribute', () => {
341
- function App() {
342
- return <>
343
- let &[color] = track('red');
344
- const el = <tsx>
345
- <div style={'color: ' + color}>styled</div>
346
- </tsx>;
315
+ function App() @{
316
+ let &[color] = track('red');
317
+ const el = <div style={{ color }}>{'content'}</div>;
318
+ <>
347
319
  {el}
348
320
  <button onClick={() => (color = 'blue')}>{'change color'}</button>
349
- </>;
321
+ </>
350
322
  }
351
323
 
352
324
  render(App);
@@ -358,22 +330,20 @@ describe('tsx expression', () => {
358
330
  });
359
331
 
360
332
  it('renders tsx element with multiple dynamic attributes', () => {
361
- function App() {
362
- return <>
363
- let &[index] = track(0);
364
- const el = <tsx>
365
- <div
366
- id={'item-' + index}
367
- class={'item pos-' + index}
368
- data-index={index}
369
- title={'Item ' + index}
370
- >
371
- {'Item ' + index}
372
- </div>
373
- </tsx>;
333
+ function App() @{
334
+ let &[index] = track(0);
335
+ const el = <div
336
+ id={'item-' + index}
337
+ class={'item pos-' + index}
338
+ data-index={index}
339
+ title={'Item ' + index}
340
+ >
341
+ {'Item ' + index}
342
+ </div>;
343
+ <>
374
344
  {el}
375
345
  <button onClick={() => index++}>{'next'}</button>
376
- </>;
346
+ </>
377
347
  }
378
348
 
379
349
  render(App);
@@ -392,18 +362,12 @@ describe('tsx expression', () => {
392
362
  });
393
363
 
394
364
  it('renders fragment shorthand passed directly as component prop', () => {
395
- function Wrapper(&{ content }: { content: any }) {
396
- return <><div class="wrapper">{content}</div></>;
365
+ function Wrapper(&{ content }) @{
366
+ <div class="wrapper">{content}</div>
397
367
  }
398
368
 
399
- function App() {
400
- return <>
401
- <Wrapper
402
- content={<tsx>
403
- <span class="inner">direct prop</span>
404
- </tsx>}
405
- />
406
- </>;
369
+ function App() @{
370
+ <Wrapper content={<><span class="inner">direct prop</span></>} />
407
371
  }
408
372
 
409
373
  render(App);
@@ -414,26 +378,15 @@ describe('tsx expression', () => {
414
378
  });
415
379
 
416
380
  it('renders fragment shorthand passed directly as children prop', () => {
417
- function Card(&{ title, children }: { title: any; children: any }) {
418
- return <>
419
- <div class="card">
420
- <h2 class="card-title">{title}</h2>
421
- <div class="card-body">{children}</div>
422
- </div>
423
- </>;
381
+ function Card(&{ title, children }) @{
382
+ <div class="card">
383
+ <h2 class="card-title">{title}</h2>
384
+ <div class="card-body">{children}</div>
385
+ </div>
424
386
  }
425
387
 
426
- function App() {
427
- return <>
428
- <Card
429
- title={<tsx>
430
- <span class="bold">Title</span>
431
- </tsx>}
432
- children={<tsx>
433
- <p>Card content here</p>
434
- </tsx>}
435
- />
436
- </>;
388
+ function App() @{
389
+ <Card title={<><span class="bold">Title</span></>} children={<><p>Card content here</p></>} />
437
390
  }
438
391
 
439
392
  render(App);
@@ -443,17 +396,15 @@ describe('tsx expression', () => {
443
396
  });
444
397
 
445
398
  it('renders tsx from function defined outside component', () => {
446
- function createBadge(label: string) {
447
- return <tsx>
448
- <span class="badge">{label}</span>
449
- </tsx>;
399
+ function createBadge(label) @{
400
+ <span class="badge">{label}</span>
450
401
  }
451
402
 
452
- function App() {
453
- return <>
454
- const badge = createBadge('New');
403
+ function App() @{
404
+ const badge = createBadge('New');
405
+ <>
455
406
  {badge}
456
- </>;
407
+ </>
457
408
  }
458
409
 
459
410
  render(App);
@@ -462,21 +413,19 @@ describe('tsx expression', () => {
462
413
  });
463
414
 
464
415
  it('renders tsx from function with multiple elements', () => {
465
- function createListItem(item: string) {
466
- return <tsx>
467
- <li class="list-item">{item}</li>
468
- </tsx>;
416
+ function createListItem(item) @{
417
+ <li class="list-item">{item}</li>
469
418
  }
470
419
 
471
- function App() {
472
- return <>
473
- const items = ['Apple', 'Banana', 'Cherry'];
474
- <ul>
475
- for (const item of items) {
420
+ function App() @{
421
+ const items = ['Apple', 'Banana', 'Cherry'];
422
+ <ul>
423
+ @for (const item of items) {
424
+ <>
476
425
  {createListItem(item)}
477
- }
478
- </ul>
479
- </>;
426
+ </>
427
+ }
428
+ </ul>
480
429
  }
481
430
 
482
431
  render(App);
@@ -488,26 +437,24 @@ describe('tsx expression', () => {
488
437
  });
489
438
 
490
439
  it('renders tsx from factory function passed to component', () => {
491
- function List(&{ renderItem, items }: { renderItem: (item: string) => any; items: string[] }) {
492
- return <>
493
- <ul class="list">
494
- for (const item of items) {
440
+ function List(&{ renderItem, items }) @{
441
+ <ul class="list">
442
+ @for (const item of items) {
443
+ <>
495
444
  {renderItem(item)}
496
- }
497
- </ul>
498
- </>;
445
+ </>
446
+ }
447
+ </ul>
499
448
  }
500
449
 
501
- function itemRenderer(item: string) {
502
- return <tsx>
503
- <li>
504
- <span class="item-content">{item}</span>
505
- </li>
506
- </tsx>;
450
+ function itemRenderer(item) @{
451
+ <li>
452
+ <span class="item-content">{item}</span>
453
+ </li>
507
454
  }
508
455
 
509
- function App() {
510
- return <><List items={['One', 'Two', 'Three']} renderItem={itemRenderer} /></>;
456
+ function App() @{
457
+ <List items={['One', 'Two', 'Three']} renderItem={itemRenderer} />
511
458
  }
512
459
 
513
460
  render(App);
@@ -519,24 +466,20 @@ describe('tsx expression', () => {
519
466
  });
520
467
 
521
468
  it('renders tsx from function with reactive state', () => {
522
- function createCounter(label: string, getCount: () => number) {
523
- return <tsx>
524
- <div class="counter-display">
525
- <span class="label">{label}</span>
526
- <span class="count">
527
- {getCount()}
528
- </span>
529
- </div>
530
- </tsx>;
469
+ function createCounter(label, getCount) @{
470
+ <div class="counter-display">
471
+ <span class="label">{label}</span>
472
+ <span class="count">{getCount()}</span>
473
+ </div>
531
474
  }
532
475
 
533
- function App() {
534
- return <>
535
- let &[count] = track(0);
536
- const counterElement = createCounter('Count:', () => count);
476
+ function App() @{
477
+ let &[count] = track(0);
478
+ const counterElement = createCounter('Count:', () => count);
479
+ <>
537
480
  {counterElement}
538
481
  <button onClick={() => count++}>{'increment'}</button>
539
- </>;
482
+ </>
540
483
  }
541
484
 
542
485
  render(App);
@@ -549,26 +492,22 @@ describe('tsx expression', () => {
549
492
  });
550
493
 
551
494
  it('renders nested tsx from multiple functions', () => {
552
- function createIcon(name: string) {
553
- return <tsx>
554
- <i class={'icon icon-' + name}></i>
555
- </tsx>;
495
+ function createIcon(name) @{
496
+ <i class={'icon icon-' + name} />
556
497
  }
557
498
 
558
- function createButton(icon: string, label: string) {
559
- return <tsx>
560
- <button class="icon-button">
561
- {createIcon(icon)}
562
- <span class="btn-label">{label}</span>
563
- </button>
564
- </tsx>;
499
+ function createButton(icon, label) @{
500
+ <button class="icon-button">
501
+ {createIcon(icon)}
502
+ <span class="btn-label">{label}</span>
503
+ </button>
565
504
  }
566
505
 
567
- function App() {
568
- return <>
569
- const btn = createButton('save', 'Save');
506
+ function App() @{
507
+ const btn = createButton('save', 'Save');
508
+ <>
570
509
  {btn}
571
- </>;
510
+ </>
572
511
  }
573
512
 
574
513
  render(App);
@@ -579,31 +518,31 @@ describe('tsx expression', () => {
579
518
  });
580
519
 
581
520
  it('renders deeply nested tsx and tsrx expression values', () => {
582
- function HelperItem({ item }: { item: number }) {
583
- return <><div class="helper-item">{item}</div></>;
521
+ function HelperItem({ item }) @{
522
+ <div class="helper-item">{item}</div>
584
523
  }
585
524
 
586
- function MakeFragment({ label }: { label: string }) {
587
- return <>
525
+ function MakeFragment({ label }) @{
526
+ const test = <>
527
+ {[1, 2, 3, 4].map(
528
+ (item) => @{
529
+ <HelperItem {item} />
530
+ },
531
+ )}
532
+ </>;
533
+ <>
588
534
  <span class="label">{label}</span>
589
- const test = <tsx>
590
- {[1, 2, 3, 4].map(
591
- (item) => <tsx>
592
- <HelperItem item={item} />
593
- </tsx>,
594
- )}
595
- </tsx>;
596
535
  {test}
597
- </>;
536
+ </>
598
537
  }
599
538
 
600
- function App() {
601
- return <>
602
- {<tsx>
539
+ function App() @{
540
+ <>
541
+ <>
603
542
  {[1, 2, 3].map((item) => <div class="app-item">{item}</div>)}
604
- </tsx>}
543
+ </>
605
544
  <MakeFragment label="from helper" />
606
- </>;
545
+ </>
607
546
  }
608
547
 
609
548
  render(App);
@@ -622,19 +561,15 @@ describe('tsx expression', () => {
622
561
  });
623
562
 
624
563
  it('renders tsrx nested directly inside a top-level tsx expression value', () => {
625
- function App() {
626
- return <>
627
- const content = <tsx>
628
- <section class="outer">
629
- {<>
630
- <div class="inner">
631
- {'from tsrx'}
632
- </div>
633
- </>}
634
- </section>
635
- </tsx>;
636
- {content}
564
+ function App() @{
565
+ const content = <>
566
+ <section class="outer">
567
+ {<><div class="inner">{'from tsrx'}</div></>}
568
+ </section>
637
569
  </>;
570
+ <>
571
+ {content}
572
+ </>
638
573
  }
639
574
 
640
575
  render(App);
@@ -645,21 +580,19 @@ describe('tsx expression', () => {
645
580
  });
646
581
 
647
582
  it('renders nested elements from tsrx inside a top-level tsx value', () => {
648
- function App() {
649
- return <>
650
- const content = <tsx>
651
- <div class="wrapper">
652
- {<>
653
- <section class="native">
654
- <span class="nested-tsrx">
655
- {'inside nested tsrx'}
656
- </span>
657
- </section>
658
- </>}
659
- </div>
660
- </tsx>;
661
- {content}
583
+ function App() @{
584
+ const content = <>
585
+ <div class="wrapper">
586
+ {<>
587
+ <section class="native">
588
+ <span class="nested-tsrx">{'inside nested tsrx'}</span>
589
+ </section>
590
+ </>}
591
+ </div>
662
592
  </>;
593
+ <>
594
+ {content}
595
+ </>
663
596
  }
664
597
 
665
598
  render(App);
@@ -670,18 +603,12 @@ describe('tsx expression', () => {
670
603
  });
671
604
 
672
605
  it('renders tsx declared before a top-level tsx value', () => {
673
- function App() {
674
- return <>
675
- const nested = <tsx>
676
- <span class="nested-tsx">
677
- {'inside nested tsx'}
678
- </span>
679
- </tsx>;
680
- const content = <tsx>
681
- <div class="native">{nested}</div>
682
- </tsx>;
606
+ function App() @{
607
+ const nested = <span class="nested-tsx">{'inside nested tsx'}</span>;
608
+ const content = <><div class="native">{nested}</div></>;
609
+ <>
683
610
  {content}
684
- </>;
611
+ </>
685
612
  }
686
613
 
687
614
  render(App);
@@ -692,25 +619,18 @@ describe('tsx expression', () => {
692
619
  });
693
620
 
694
621
  it('renders tsx as prop with fallback in component', () => {
695
- function Alert(&{ icon, message }: { icon?: any; message: string }) {
696
- return <>
697
- <div class="alert">
698
- {icon}
699
- <span class="message">{message}</span>
700
- </div>
701
- </>;
622
+ function Alert(&{ icon, message }) @{
623
+ <div class="alert">
624
+ {icon}
625
+ <span class="message">{message}</span>
626
+ </div>
702
627
  }
703
628
 
704
- function App() {
705
- return <>
629
+ function App() @{
630
+ <>
706
631
  <Alert message="No icon" />
707
- <Alert
708
- icon={<tsx>
709
- <span class="custom-icon">✓</span>
710
- </tsx>}
711
- message="Custom icon"
712
- />
713
- </>;
632
+ <Alert icon={<><span class="custom-icon">{'✓'}</span></>} message="Custom icon" />
633
+ </>
714
634
  }
715
635
 
716
636
  render(App);
@@ -721,25 +641,23 @@ describe('tsx expression', () => {
721
641
  });
722
642
 
723
643
  it('renders tsx stored in array via function', () => {
724
- function createItem(className: string, content: string) {
725
- return <tsx>
726
- <div class={className}>{content}</div>
727
- </tsx>;
728
- }
729
-
730
- function App() {
731
- return <>
732
- const items = [
733
- { className: 'item-a', content: 'A' },
734
- { className: 'item-b', content: 'B' },
735
- { className: 'item-c', content: 'C' },
736
- ];
737
- <div class="container">
738
- for (const item of items) {
644
+ function createItem(className, content) @{
645
+ <div class={className}>{content}</div>
646
+ }
647
+
648
+ function App() @{
649
+ const items = [
650
+ { className: 'item-a', content: 'A' },
651
+ { className: 'item-b', content: 'B' },
652
+ { className: 'item-c', content: 'C' },
653
+ ];
654
+ <div class="container">
655
+ @for (const item of items) {
656
+ <>
739
657
  {createItem(item.className, item.content)}
740
- }
741
- </div>
742
- </>;
658
+ </>
659
+ }
660
+ </div>
743
661
  }
744
662
 
745
663
  render(App);
@@ -750,28 +668,23 @@ describe('tsx expression', () => {
750
668
  });
751
669
 
752
670
  it('renders tsx conditionally from function', () => {
753
- function createContent(type: string) {
754
- if (type === 'success') {
755
- return <tsx>
756
- <div class="success">Success!</div>
757
- </tsx>;
758
- } else if (type === 'error') {
759
- return <tsx>
760
- <div class="error">Error!</div>
761
- </tsx>;
762
- }
763
- return <tsx>
671
+ function createContent(type) @{
672
+ @if (type === 'success') {
673
+ <div class="success">Success!</div>
674
+ } @else if (type === 'error') {
675
+ <div class="error">Error!</div>
676
+ } @else {
764
677
  <div class="default">Default</div>
765
- </tsx>;
678
+ }
766
679
  }
767
680
 
768
- function App() {
769
- return <>
770
- let &[status] = track('default');
681
+ function App() @{
682
+ let &[status] = track('default');
683
+ <>
771
684
  {createContent(status)}
772
685
  <button class="set-success" onClick={() => (status = 'success')}>{'Success'}</button>
773
686
  <button class="set-error" onClick={() => (status = 'error')}>{'Error'}</button>
774
- </>;
687
+ </>
775
688
  }
776
689
 
777
690
  render(App);
@@ -790,12 +703,14 @@ describe('tsx expression', () => {
790
703
  });
791
704
 
792
705
  describe('tsrx expression', () => {
793
- it('renders native double-quoted text in an assigned fragment', () => {
794
- function App() {
795
- return <>
796
- const el = <><div>"Hello world"</div></>;
797
- {el}
706
+ it('renders native JSX text in an assigned fragment', () => {
707
+ function App() @{
708
+ const el = <>
709
+ <div>Hello world</div>
798
710
  </>;
711
+ <>
712
+ {el}
713
+ </>
799
714
  }
800
715
 
801
716
  render(App);
@@ -806,14 +721,14 @@ describe('tsrx expression', () => {
806
721
  });
807
722
 
808
723
  it('runs setup statements before native template output', () => {
809
- function App() {
810
- return <>
811
- const el = <>
812
- const label = 'from setup';
813
- <div>{label}</div>
814
- </>;
815
- {el}
724
+ function App() @{
725
+ const label = 'from setup';
726
+ const el = <>
727
+ <div>{label}</div>
816
728
  </>;
729
+ <>
730
+ {el}
731
+ </>
817
732
  }
818
733
 
819
734
  render(App);
@@ -822,13 +737,17 @@ describe('tsrx expression', () => {
822
737
  });
823
738
 
824
739
  it('updates reactive expressions inside native fragments', () => {
825
- function App() {
826
- return <>
827
- let &[count] = track(0);
828
- const el = <><div>{'count: ' + count}</div></>;
740
+ function App() @{
741
+ let &[count] = track(0);
742
+ const el = <>
743
+ <div>
744
+ {'count: ' + count}
745
+ </div>
746
+ </>;
747
+ <>
829
748
  {el}
830
749
  <button onClick={() => count++}>{'increment'}</button>
831
- </>;
750
+ </>
832
751
  }
833
752
 
834
753
  render(App);
@@ -840,15 +759,15 @@ describe('tsrx expression', () => {
840
759
  });
841
760
 
842
761
  it('renders native control flow inside an assigned fragment', () => {
843
- function App() {
844
- return <>
845
- const el = <>
846
- if (true) {
847
- <span>"visible"</span>
848
- }
849
- </>;
850
- {el}
762
+ function App() @{
763
+ const el = <>
764
+ @if (true) {
765
+ <span>visible</span>
766
+ }
851
767
  </>;
768
+ <>
769
+ {el}
770
+ </>
852
771
  }
853
772
 
854
773
  render(App);
@@ -857,12 +776,12 @@ describe('tsrx expression', () => {
857
776
  });
858
777
 
859
778
  it('renders fragments returned from component functions outside components', () => {
860
- function MakeFragment({ label }: { label: string }) {
861
- return <><span>{label}</span></>;
779
+ function MakeFragment({ label }) @{
780
+ <span>{label}</span>
862
781
  }
863
782
 
864
- function App() {
865
- return <><MakeFragment label="from helper" /></>;
783
+ function App() @{
784
+ <MakeFragment label="from helper" />
866
785
  }
867
786
 
868
787
  render(App);