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
@@ -3,8 +3,8 @@ import { RippleArray, RippleObject, flushSync, track } from 'ripple';
3
3
 
4
4
  describe('basic client > attribute rendering', () => {
5
5
  it('render static attributes', () => {
6
- function Basic() {
7
- return <><div class="foo" id="bar" style="color: red;">{'Hello World'}</div></>;
6
+ function Basic() @{
7
+ <div class="foo" id="bar" style="color: red;">{'Hello World'}</div>
8
8
  }
9
9
 
10
10
  render(Basic);
@@ -13,23 +13,21 @@ describe('basic client > attribute rendering', () => {
13
13
  });
14
14
 
15
15
  it('render dynamic class attribute', () => {
16
- function Basic() {
17
- return <>
18
- let &[active] = track(false);
16
+ function Basic() @{
17
+ let &[active] = track(false);
18
+ <>
19
19
  <button
20
20
  onClick={() => {
21
21
  active = !active;
22
22
  }}
23
- >
24
- {'Toggle'}
25
- </button>
23
+ >{'Toggle'}</button>
26
24
  <div class={active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
27
25
  <style>
28
26
  .active {
29
27
  color: green;
30
28
  }
31
29
  </style>
32
- </>;
30
+ </>
33
31
  }
34
32
 
35
33
  render(Basic);
@@ -51,8 +49,8 @@ describe('basic client > attribute rendering', () => {
51
49
  });
52
50
 
53
51
  it('render class attribute with array, nested array, nested object', () => {
54
- function Basic() {
55
- return <>
52
+ function Basic() @{
53
+ <>
56
54
  <div
57
55
  class={[
58
56
  'foo',
@@ -66,15 +64,13 @@ describe('basic client > attribute rendering', () => {
66
64
  { eee: true, fff: false },
67
65
  ],
68
66
  ]}
69
- >
70
- {'Class Array'}
71
- </div>
67
+ >{'Class Array'}</div>
72
68
  <style>
73
69
  .foo {
74
70
  color: red;
75
71
  }
76
72
  </style>
77
- </>;
73
+ </>
78
74
  }
79
75
 
80
76
  render(Basic);
@@ -94,23 +90,21 @@ describe('basic client > attribute rendering', () => {
94
90
  });
95
91
 
96
92
  it('render dynamic class object', () => {
97
- function Basic() {
98
- return <>
99
- let &[active] = track(false);
93
+ function Basic() @{
94
+ let &[active] = track(false);
95
+ <>
100
96
  <button
101
97
  onClick={() => {
102
98
  active = !active;
103
99
  }}
104
- >
105
- {'Toggle'}
106
- </button>
100
+ >{'Toggle'}</button>
107
101
  <div class={{ active: active, inactive: !active }}>{'Dynamic Class'}</div>
108
102
  <style>
109
103
  .active {
110
104
  color: green;
111
105
  }
112
106
  </style>
113
- </>;
107
+ </>
114
108
  }
115
109
 
116
110
  render(Basic);
@@ -135,9 +129,9 @@ describe('basic client > attribute rendering', () => {
135
129
  });
136
130
 
137
131
  it('applies scoped ripple class to multiple elements with dynamic class expressions', () => {
138
- function Basic() {
139
- return <>
140
- let &[selected] = track(1);
132
+ function Basic() @{
133
+ let &[selected] = track(1);
134
+ <>
141
135
  <div class={selected === 0 ? 'selected' : ''}>{`div 1`}</div>
142
136
  <div class={selected === 0 ? 'selected' : ''}>{`div 2`}</div>
143
137
  <style>
@@ -149,7 +143,7 @@ describe('basic client > attribute rendering', () => {
149
143
  background: indigo;
150
144
  }
151
145
  </style>
152
- </>;
146
+ </>
153
147
  }
154
148
 
155
149
  render(Basic);
@@ -164,18 +158,16 @@ describe('basic client > attribute rendering', () => {
164
158
  });
165
159
 
166
160
  it('render dynamic id attribute', () => {
167
- function Basic() {
168
- return <>
169
- let &[count] = track(0);
161
+ function Basic() @{
162
+ let &[count] = track(0);
163
+ <>
170
164
  <button
171
165
  onClick={() => {
172
166
  count++;
173
167
  }}
174
- >
175
- {'Increment'}
176
- </button>
168
+ >{'Increment'}</button>
177
169
  <div id={`item-${count}`}>{'Dynamic ID'}</div>
178
- </>;
170
+ </>
179
171
  }
180
172
 
181
173
  render(Basic);
@@ -197,18 +189,16 @@ describe('basic client > attribute rendering', () => {
197
189
  });
198
190
 
199
191
  it('render dynamic style attribute', () => {
200
- function Basic() {
201
- return <>
202
- let &[color] = track('red');
192
+ function Basic() @{
193
+ let &[color] = track('red');
194
+ <>
203
195
  <button
204
196
  onClick={() => {
205
197
  color = color === 'red' ? 'blue' : 'red';
206
198
  }}
207
- >
208
- {'Change Color'}
209
- </button>
199
+ >{'Change Color'}</button>
210
200
  <div style={`color: ${color}; font-weight: bold;`}>{'Dynamic Style'}</div>
211
- </>;
201
+ </>
212
202
  }
213
203
 
214
204
  render(Basic);
@@ -227,18 +217,16 @@ describe('basic client > attribute rendering', () => {
227
217
  });
228
218
 
229
219
  it('render style attribute as dynamic object', () => {
230
- function Basic() {
231
- return <>
232
- let &[color] = track('red');
220
+ function Basic() @{
221
+ let &[color] = track('red');
222
+ <>
233
223
  <button
234
224
  onClick={() => {
235
225
  color = color === 'red' ? 'blue' : 'red';
236
226
  }}
237
- >
238
- {'Change Color'}
239
- </button>
227
+ >{'Change Color'}</button>
240
228
  <div style={{ color: color, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
241
- </>;
229
+ </>
242
230
  }
243
231
 
244
232
  render(Basic);
@@ -257,15 +245,15 @@ describe('basic client > attribute rendering', () => {
257
245
  });
258
246
 
259
247
  it('render tracked variable as style attribute', () => {
260
- function Basic() {
261
- return <>
262
- let &[style] = track({ color: 'red', fontWeight: 'bold' });
263
- function toggleColor() {
264
- style = { ...style, color: style.color === 'red' ? 'blue' : 'red' };
265
- }
248
+ function Basic() @{
249
+ let &[style] = track({ color: 'red', fontWeight: 'bold' });
250
+ function toggleColor() {
251
+ style = { ...style, color: style.color === 'red' ? 'blue' : 'red' };
252
+ }
253
+ <>
266
254
  <button onClick={toggleColor}>{'Change Color'}</button>
267
255
  <div {style}>{'Dynamic Style'}</div>
268
- </>;
256
+ </>
269
257
  }
270
258
 
271
259
  render(Basic);
@@ -284,15 +272,15 @@ describe('basic client > attribute rendering', () => {
284
272
  });
285
273
 
286
274
  it('render tracked object as style attribute', () => {
287
- function Basic() {
288
- return <>
289
- let style = new RippleObject({ color: 'red', fontWeight: 'bold' });
290
- function toggleColor() {
291
- style.color = style.color === 'red' ? 'blue' : 'red';
292
- }
275
+ function Basic() @{
276
+ let style = new RippleObject({ color: 'red', fontWeight: 'bold' });
277
+ function toggleColor() {
278
+ style.color = style.color === 'red' ? 'blue' : 'red';
279
+ }
280
+ <>
293
281
  <button onClick={toggleColor}>{'Change Color'}</button>
294
282
  <div style={{ color: style.color, fontWeight: style.fontWeight }}>{'Dynamic Style'}</div>
295
- </>;
283
+ </>
296
284
  }
297
285
 
298
286
  render(Basic);
@@ -311,14 +299,12 @@ describe('basic client > attribute rendering', () => {
311
299
  });
312
300
 
313
301
  it('render spread attributes with style and class', () => {
314
- function Basic() {
315
- return <>
316
- const attributes = {
317
- style: { color: 'red', fontWeight: 'bold' },
318
- class: ['foo', false && 'bar'],
319
- };
320
- <div {...attributes}>{'Attributes with style and class'}</div>
321
- </>;
302
+ function Basic() @{
303
+ const attributes = {
304
+ style: { color: 'red', fontWeight: 'bold' },
305
+ class: ['foo', false && 'bar'],
306
+ };
307
+ <div {...attributes}>{'Attributes with style and class'}</div>
322
308
  }
323
309
 
324
310
  render(Basic);
@@ -333,13 +319,11 @@ describe('basic client > attribute rendering', () => {
333
319
  });
334
320
 
335
321
  it('render spread props without duplication', () => {
336
- function App() {
337
- return <>
338
- const checkBoxProp = { name: 'car' };
339
- <div>
340
- <input {...checkBoxProp} type="checkbox" id="vehicle1" value="Bike" />
341
- </div>
342
- </>;
322
+ function App() @{
323
+ const checkBoxProp = { name: 'car' };
324
+ <div>
325
+ <input {...checkBoxProp} type="checkbox" id="vehicle1" value="Bike" />
326
+ </div>
343
327
  }
344
328
 
345
329
  render(App);
@@ -359,20 +343,18 @@ describe('basic client > attribute rendering', () => {
359
343
  });
360
344
 
361
345
  it('render dynamic boolean attributes', () => {
362
- function Basic() {
363
- return <>
364
- let &[disabled] = track(false);
365
- let &[checked] = track(false);
346
+ function Basic() @{
347
+ let &[disabled] = track(false);
348
+ let &[checked] = track(false);
349
+ <>
366
350
  <button
367
351
  onClick={() => {
368
352
  disabled = !disabled;
369
353
  checked = !checked;
370
354
  }}
371
- >
372
- {'Toggle'}
373
- </button>
355
+ >{'Toggle'}</button>
374
356
  <input type="checkbox" {disabled} {checked} />
375
- </>;
357
+ </>
376
358
  }
377
359
 
378
360
  render(Basic);
@@ -391,22 +373,22 @@ describe('basic client > attribute rendering', () => {
391
373
  });
392
374
 
393
375
  it('render multiple dynamic attributes', () => {
394
- function Basic() {
395
- return <>
396
- let &[theme] = track('light');
397
- let &[size] = track('medium');
376
+ function Basic() @{
377
+ let &[theme] = track('light');
378
+ let &[size] = track('medium');
379
+ <>
398
380
  <button
399
381
  onClick={() => {
400
382
  theme = theme === 'light' ? 'dark' : 'light';
401
383
  size = size === 'medium' ? 'large' : 'medium';
402
384
  }}
403
- >
404
- {'Toggle Theme & Size'}
405
- </button>
406
- <div class={`theme-${theme} size-${size}`} data-theme={theme} data-size={size}>
407
- {'Multiple Dynamic Attributes'}
408
- </div>
409
- </>;
385
+ >{'Toggle Theme & Size'}</button>
386
+ <div
387
+ class={`theme-${theme} size-${size}`}
388
+ data-theme={theme}
389
+ data-size={size}
390
+ >{'Multiple Dynamic Attributes'}</div>
391
+ </>
410
392
  }
411
393
 
412
394
  render(Basic);
@@ -427,25 +409,21 @@ describe('basic client > attribute rendering', () => {
427
409
  });
428
410
 
429
411
  it('render conditional attributes', () => {
430
- function Basic() {
431
- return <>
432
- let &[showTitle] = track(false);
433
- let &[showAria] = track(false);
412
+ function Basic() @{
413
+ let &[showTitle] = track(false);
414
+ let &[showAria] = track(false);
415
+ <>
434
416
  <button
435
417
  onClick={() => {
436
418
  showTitle = !showTitle;
437
419
  showAria = !showAria;
438
420
  }}
439
- >
440
- {'Toggle Attributes'}
441
- </button>
421
+ >{'Toggle Attributes'}</button>
442
422
  <div
443
423
  title={showTitle ? 'This is a title' : undefined}
444
424
  aria-label={showAria ? 'Accessible label' : undefined}
445
- >
446
- {'Conditional Attributes'}
447
- </div>
448
- </>;
425
+ >{'Conditional Attributes'}</div>
426
+ </>
449
427
  }
450
428
 
451
429
  render(Basic);
@@ -470,12 +448,12 @@ describe('basic client > attribute rendering', () => {
470
448
  });
471
449
 
472
450
  it('render spread attributes', () => {
473
- function Basic() {
474
- return <>
475
- let &[attrs] = track<TestAttributes>({
476
- class: 'initial',
477
- id: 'test-1',
478
- });
451
+ function Basic() @{
452
+ let &[attrs] = track<TestAttributes>({
453
+ class: 'initial',
454
+ id: 'test-1',
455
+ });
456
+ <>
479
457
  <button
480
458
  onClick={() => {
481
459
  attrs = {
@@ -484,11 +462,9 @@ describe('basic client > attribute rendering', () => {
484
462
  'data-extra': 'value',
485
463
  };
486
464
  }}
487
- >
488
- {'Update Attributes'}
489
- </button>
465
+ >{'Update Attributes'}</button>
490
466
  <div {...attrs}>{'Spread Attributes'}</div>
491
- </>;
467
+ </>
492
468
  }
493
469
 
494
470
  render(Basic);
@@ -509,16 +485,15 @@ describe('basic client > attribute rendering', () => {
509
485
  });
510
486
 
511
487
  it('renders with reactive attributes with nested reactive attributes', () => {
512
- function App() {
513
- return <>
514
- let &[value] = track('parent-class');
488
+ function App() @{
489
+ let &[value] = track('parent-class');
490
+ let &[nested] = track('nested-class');
491
+ <>
515
492
  <p class={value}>{'Colored parent value'}</p>
516
493
  <div>
517
- let &[nested] = track('nested-class');
518
-
519
494
  <p class={nested}>{'Colored nested value'}</p>
520
495
  </div>
521
- </>;
496
+ </>
522
497
  }
523
498
 
524
499
  render(App);
@@ -530,13 +505,11 @@ describe('basic client > attribute rendering', () => {
530
505
  });
531
506
 
532
507
  it('handles boolean attributes with no prop value provides', () => {
533
- function App() {
534
- return <>
535
- <div class="container">
536
- <button onClick={() => console.log('clicked!')} disabled>{'Button'}</button>
537
- <input type="checkbox" checked />
538
- </div>
539
- </>;
508
+ function App() @{
509
+ <div class="container">
510
+ <button onClick={() => console.log('clicked!')} disabled>{'Button'}</button>
511
+ <input type="checkbox" checked />
512
+ </div>
540
513
  }
541
514
 
542
515
  render(App);
@@ -544,15 +517,15 @@ describe('basic client > attribute rendering', () => {
544
517
  });
545
518
 
546
519
  it('handles boolean props correctly', () => {
547
- function App() {
548
- return <>
520
+ function App() @{
521
+ <>
549
522
  <div data-disabled />
550
523
  <Child isDisabled />
551
- </>;
524
+ </>
552
525
  }
553
526
 
554
- function Child({ isDisabled }: { isDisabled: boolean }) {
555
- return <><input disabled={isDisabled} /></>;
527
+ function Child({ isDisabled }: { isDisabled: boolean }) @{
528
+ <input disabled={isDisabled} />
556
529
  }
557
530
 
558
531
  render(App);
@@ -560,29 +533,27 @@ describe('basic client > attribute rendering', () => {
560
533
  });
561
534
 
562
535
  it('handles reactive event handler changes', () => {
563
- function Basic() {
564
- return <>
565
- let &[count] = track(0);
566
- let &[mode] = track<'increment' | 'decrement'>('increment');
567
- const incrementHandler = () => {
568
- count++;
569
- };
570
- const decrementHandler = () => {
571
- count--;
572
- };
536
+ function Basic() @{
537
+ let &[count] = track(0);
538
+ let &[mode] = track<'increment' | 'decrement'>('increment');
539
+ const incrementHandler = () => {
540
+ count++;
541
+ };
542
+ const decrementHandler = () => {
543
+ count--;
544
+ };
545
+ <>
573
546
  <button
574
547
  onClick={() => {
575
548
  mode = mode === 'increment' ? 'decrement' : 'increment';
576
549
  }}
577
550
  class="toggle-mode"
578
- >
579
- {'Toggle Mode'}
580
- </button>
551
+ >{'Toggle Mode'}</button>
581
552
  <button onClick={mode === 'increment' ? incrementHandler : decrementHandler} class="action">
582
553
  {mode === 'increment' ? '+' : '-'}
583
554
  </button>
584
555
  <div class="count">{count}</div>
585
- </>;
556
+ </>
586
557
  }
587
558
 
588
559
  render(Basic);
@@ -616,23 +587,21 @@ describe('basic client > attribute rendering', () => {
616
587
  });
617
588
 
618
589
  it('handles events with capture option', () => {
619
- function Basic() {
620
- return <>
621
- let captureOrder: RippleArray<string> = new RippleArray();
622
- const handleCaptureClick = {
623
- handleEvent() {
624
- captureOrder.push('capture');
625
- },
626
- capture: true,
627
- };
628
- const handleBubbleClick = () => {
629
- captureOrder.push('bubble');
630
- };
631
- <div onClick={handleCaptureClick} class="outer">
632
- <button onClick={handleBubbleClick} class="inner">{'Click'}</button>
633
- <div class="order">{captureOrder.join(' -> ')}</div>
634
- </div>
635
- </>;
590
+ function Basic() @{
591
+ let captureOrder: RippleArray<string> = new RippleArray();
592
+ const handleCaptureClick = {
593
+ handleEvent() {
594
+ captureOrder.push('capture');
595
+ },
596
+ capture: true,
597
+ };
598
+ const handleBubbleClick = () => {
599
+ captureOrder.push('bubble');
600
+ };
601
+ <div onClick={handleCaptureClick} class="outer">
602
+ <button onClick={handleBubbleClick} class="inner">{'Click'}</button>
603
+ <div class="order">{captureOrder.join(' -> ')}</div>
604
+ </div>
636
605
  }
637
606
 
638
607
  render(Basic);
@@ -649,20 +618,18 @@ describe('basic client > attribute rendering', () => {
649
618
  });
650
619
 
651
620
  it('handles events with Capture suffix in the name', () => {
652
- function Basic() {
653
- return <>
654
- let captureOrder: RippleArray<string> = new RippleArray();
655
- const handleCaptureClick = () => {
656
- captureOrder.push('capture');
657
- };
658
- const handleBubbleClick = () => {
659
- captureOrder.push('bubble');
660
- };
661
- <div onClickCapture={handleCaptureClick} class="outer">
662
- <button onClick={handleBubbleClick} class="inner">{'Click'}</button>
663
- <div class="order">{captureOrder.join(' -> ')}</div>
664
- </div>
665
- </>;
621
+ function Basic() @{
622
+ let captureOrder: RippleArray<string> = new RippleArray();
623
+ const handleCaptureClick = () => {
624
+ captureOrder.push('capture');
625
+ };
626
+ const handleBubbleClick = () => {
627
+ captureOrder.push('bubble');
628
+ };
629
+ <div onClickCapture={handleCaptureClick} class="outer">
630
+ <button onClick={handleBubbleClick} class="inner">{'Click'}</button>
631
+ <div class="order">{captureOrder.join(' -> ')}</div>
632
+ </div>
666
633
  }
667
634
 
668
635
  render(Basic);
@@ -679,20 +646,18 @@ describe('basic client > attribute rendering', () => {
679
646
  });
680
647
 
681
648
  it('handles custom events with customName option', () => {
682
- function Basic() {
683
- return <>
684
- let &[customEventCount] = track(0);
685
- const handleCustom = {
686
- handleEvent(event: CustomEvent) {
687
- customEventCount += event.detail.value;
688
- },
689
- customName: 'MyCustomEvent',
690
- };
691
- <div>
692
- <div onMyCustomEvent={handleCustom} class="custom-target">{'Custom'}</div>
693
- <div class="custom-count">{customEventCount}</div>
694
- </div>
695
- </>;
649
+ function Basic() @{
650
+ let &[customEventCount] = track(0);
651
+ const handleCustom = {
652
+ handleEvent(event: CustomEvent) {
653
+ customEventCount += event.detail.value;
654
+ },
655
+ customName: 'MyCustomEvent',
656
+ };
657
+ <div>
658
+ <div onMyCustomEvent={handleCustom} class="custom-target">{'Custom'}</div>
659
+ <div class="custom-count">{customEventCount}</div>
660
+ </div>
696
661
  }
697
662
 
698
663
  render(Basic);
@@ -714,26 +679,24 @@ describe('basic client > attribute rendering', () => {
714
679
  });
715
680
 
716
681
  it('handles events with delegated: false option to bypass delegation', () => {
717
- function Basic() {
718
- return <>
719
- let &[delegatedCount] = track(0);
720
- let &[nonDelegatedCount] = track(0);
721
- const delegatedHandler = () => {
722
- delegatedCount++;
723
- };
724
- const nonDelegatedHandler = {
725
- handleEvent() {
726
- nonDelegatedCount++;
727
- },
728
- delegated: false,
729
- };
730
- <div>
731
- <button onClick={delegatedHandler} class="delegated-btn">{'Delegated'}</button>
732
- <button onClick={nonDelegatedHandler} class="non-delegated-btn">{'Non-Delegated'}</button>
733
- <div class="delegated-count">{delegatedCount}</div>
734
- <div class="non-delegated-count">{nonDelegatedCount}</div>
735
- </div>
736
- </>;
682
+ function Basic() @{
683
+ let &[delegatedCount] = track(0);
684
+ let &[nonDelegatedCount] = track(0);
685
+ const delegatedHandler = () => {
686
+ delegatedCount++;
687
+ };
688
+ const nonDelegatedHandler = {
689
+ handleEvent() {
690
+ nonDelegatedCount++;
691
+ },
692
+ delegated: false,
693
+ };
694
+ <div>
695
+ <button onClick={delegatedHandler} class="delegated-btn">{'Delegated'}</button>
696
+ <button onClick={nonDelegatedHandler} class="non-delegated-btn">{'Non-Delegated'}</button>
697
+ <div class="delegated-count">{delegatedCount}</div>
698
+ <div class="non-delegated-count">{nonDelegatedCount}</div>
699
+ </div>
737
700
  }
738
701
 
739
702
  render(Basic);
@@ -762,33 +725,32 @@ describe('basic client > attribute rendering', () => {
762
725
  const delegatedClicks: number[] = [];
763
726
  const nonDelegatedClicks: number[] = [];
764
727
 
765
- function Basic() {
766
- return <>
767
- const makeDelegatedHandler = (id: number) => () => {
768
- delegatedClicks.push(id);
769
- };
770
- const makeNonDelegatedHandler = (id: number) => ({
771
- handleEvent() {
772
- nonDelegatedClicks.push(id);
773
- },
774
- delegated: false,
775
- });
776
- const buttonIds = [0, 1, 2, 3, 4];
777
- <div>
778
- <div class="delegated-buttons">
779
- for (const i of buttonIds) {
780
- <button onClick={makeDelegatedHandler(i)} class={`delegated-${i}`}>{`D${i}`}</button>
781
- }
782
- </div>
783
- <div class="non-delegated-buttons">
784
- for (const i of buttonIds) {
785
- <button onClick={makeNonDelegatedHandler(i)} class={`non-delegated-${i}`}>
786
- {`ND${i}`}
787
- </button>
788
- }
789
- </div>
728
+ function Basic() @{
729
+ const makeDelegatedHandler = (id: number) => () => {
730
+ delegatedClicks.push(id);
731
+ };
732
+ const makeNonDelegatedHandler = (id: number) => ({
733
+ handleEvent() {
734
+ nonDelegatedClicks.push(id);
735
+ },
736
+ delegated: false,
737
+ });
738
+ const buttonIds = [0, 1, 2, 3, 4];
739
+ <div>
740
+ <div class="delegated-buttons">
741
+ @for (const i of buttonIds) {
742
+ <button onClick={makeDelegatedHandler(i)} class={`delegated-${i}`}>{`D${i}`}</button>
743
+ }
744
+ </div>
745
+ <div class="non-delegated-buttons">
746
+ @for (const i of buttonIds) {
747
+ <button
748
+ onClick={makeNonDelegatedHandler(i)}
749
+ class={`non-delegated-${i}`}
750
+ >{`ND${i}`}</button>
751
+ }
790
752
  </div>
791
- </>;
753
+ </div>
792
754
  }
793
755
 
794
756
  render(Basic);
@@ -826,25 +788,23 @@ describe('basic client > attribute rendering', () => {
826
788
  });
827
789
 
828
790
  it('handles events defined as function directly vs as object', () => {
829
- function Basic() {
830
- return <>
831
- let &[functionCount] = track(0);
832
- let &[objectCount] = track(0);
833
- const functionHandler = () => {
834
- functionCount++;
835
- };
836
- const objectHandler = {
837
- handleEvent() {
838
- objectCount++;
839
- },
840
- };
841
- <div>
842
- <button onClick={functionHandler} class="function-btn">{'Function'}</button>
843
- <button onClick={objectHandler} class="object-btn">{'Object'}</button>
844
- <div class="function-count">{functionCount}</div>
845
- <div class="object-count">{objectCount}</div>
846
- </div>
847
- </>;
791
+ function Basic() @{
792
+ let &[functionCount] = track(0);
793
+ let &[objectCount] = track(0);
794
+ const functionHandler = () => {
795
+ functionCount++;
796
+ };
797
+ const objectHandler = {
798
+ handleEvent() {
799
+ objectCount++;
800
+ },
801
+ };
802
+ <div>
803
+ <button onClick={functionHandler} class="function-btn">{'Function'}</button>
804
+ <button onClick={objectHandler} class="object-btn">{'Object'}</button>
805
+ <div class="function-count">{functionCount}</div>
806
+ <div class="object-count">{objectCount}</div>
807
+ </div>
848
808
  }
849
809
 
850
810
  render(Basic);
@@ -878,46 +838,44 @@ describe('basic client > attribute rendering', () => {
878
838
  });
879
839
 
880
840
  it('handles passive event option', () => {
881
- function Basic() {
882
- return <>
883
- let &[passiveDefaultPrevented] = track<boolean | null>(null);
884
- let &[nonPassiveDefaultPrevented] = track<boolean | null>(null);
885
- const passiveHandler = {
886
- handleEvent(event: Event) {
887
- event.preventDefault();
888
- // In passive listeners, preventDefault() is ignored
889
- passiveDefaultPrevented = event.defaultPrevented;
890
- },
891
- passive: true,
892
- delegated: false, // Need to ensure it's not delegated to test passive properly
893
- };
894
- const nonPassiveHandler = {
895
- handleEvent(event: Event) {
896
- event.preventDefault();
897
- // In non-passive listeners, preventDefault() works
898
- nonPassiveDefaultPrevented = event.defaultPrevented;
899
- },
900
- delegated: false,
901
- };
902
- <div>
903
- <div onWheel={passiveHandler} class="passive-target">{'Passive'}</div>
904
- <div onWheel={nonPassiveHandler} class="non-passive-target">{'Non-Passive'}</div>
905
- <div class="passive-result">
906
- {passiveDefaultPrevented === null
907
- ? 'not-tested'
908
- : passiveDefaultPrevented
909
- ? 'prevented'
910
- : 'not-prevented'}
911
- </div>
912
- <div class="non-passive-result">
913
- {nonPassiveDefaultPrevented === null
914
- ? 'not-tested'
915
- : nonPassiveDefaultPrevented
916
- ? 'prevented'
917
- : 'not-prevented'}
918
- </div>
841
+ function Basic() @{
842
+ let &[passiveDefaultPrevented] = track<boolean | null>(null);
843
+ let &[nonPassiveDefaultPrevented] = track<boolean | null>(null);
844
+ const passiveHandler = {
845
+ handleEvent(event: Event) {
846
+ event.preventDefault();
847
+ // In passive listeners, preventDefault() is ignored
848
+ passiveDefaultPrevented = event.defaultPrevented;
849
+ },
850
+ passive: true,
851
+ delegated: false, // Need to ensure it's not delegated to test passive properly
852
+ };
853
+ const nonPassiveHandler = {
854
+ handleEvent(event: Event) {
855
+ event.preventDefault();
856
+ // In non-passive listeners, preventDefault() works
857
+ nonPassiveDefaultPrevented = event.defaultPrevented;
858
+ },
859
+ delegated: false,
860
+ };
861
+ <div>
862
+ <div onWheel={passiveHandler} class="passive-target">{'Passive'}</div>
863
+ <div onWheel={nonPassiveHandler} class="non-passive-target">{'Non-Passive'}</div>
864
+ <div class="passive-result">
865
+ {passiveDefaultPrevented === null
866
+ ? 'not-tested'
867
+ : passiveDefaultPrevented
868
+ ? 'prevented'
869
+ : 'not-prevented'}
870
+ </div>
871
+ <div class="non-passive-result">
872
+ {nonPassiveDefaultPrevented === null
873
+ ? 'not-tested'
874
+ : nonPassiveDefaultPrevented
875
+ ? 'prevented'
876
+ : 'not-prevented'}
919
877
  </div>
920
- </>;
878
+ </div>
921
879
  }
922
880
 
923
881
  render(Basic);
@@ -942,26 +900,24 @@ describe('basic client > attribute rendering', () => {
942
900
  });
943
901
 
944
902
  it('handles once option to fire event only once', () => {
945
- function Basic() {
946
- return <>
947
- let &[onceCount] = track(0);
948
- let &[regularCount] = track(0);
949
- const onceHandler = {
950
- handleEvent() {
951
- onceCount++;
952
- },
953
- once: true,
954
- };
955
- const regularHandler = () => {
956
- regularCount++;
957
- };
958
- <div>
959
- <button onClick={onceHandler} class="once-btn">{'Once'}</button>
960
- <button onClick={regularHandler} class="regular-btn">{'Regular'}</button>
961
- <div class="once-count">{onceCount}</div>
962
- <div class="regular-count">{regularCount}</div>
963
- </div>
964
- </>;
903
+ function Basic() @{
904
+ let &[onceCount] = track(0);
905
+ let &[regularCount] = track(0);
906
+ const onceHandler = {
907
+ handleEvent() {
908
+ onceCount++;
909
+ },
910
+ once: true,
911
+ };
912
+ const regularHandler = () => {
913
+ regularCount++;
914
+ };
915
+ <div>
916
+ <button onClick={onceHandler} class="once-btn">{'Once'}</button>
917
+ <button onClick={regularHandler} class="regular-btn">{'Regular'}</button>
918
+ <div class="once-count">{onceCount}</div>
919
+ <div class="regular-count">{regularCount}</div>
920
+ </div>
965
921
  }
966
922
 
967
923
  render(Basic);