ripple 0.3.128 → 0.4.1

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 (197) hide show
  1. package/CHANGELOG.md +294 -0
  2. package/package.json +11 -4
  3. package/src/jsx-runtime.d.ts +12 -2
  4. package/src/runtime/element.js +23 -6
  5. package/src/runtime/index-client.js +81 -41
  6. package/src/runtime/index-server.js +1 -0
  7. package/src/runtime/internal/client/blocks.js +173 -91
  8. package/src/runtime/internal/client/component.js +4 -30
  9. package/src/runtime/internal/client/composite.js +12 -13
  10. package/src/runtime/internal/client/constants.js +9 -0
  11. package/src/runtime/internal/client/context.js +12 -19
  12. package/src/runtime/internal/client/css.js +7 -9
  13. package/src/runtime/internal/client/events.js +178 -90
  14. package/src/runtime/internal/client/expression.js +45 -25
  15. package/src/runtime/internal/client/for.js +409 -129
  16. package/src/runtime/internal/client/head.js +10 -5
  17. package/src/runtime/internal/client/html.js +1 -0
  18. package/src/runtime/internal/client/hydration.js +152 -10
  19. package/src/runtime/internal/client/if.js +239 -50
  20. package/src/runtime/internal/client/index.js +4 -12
  21. package/src/runtime/internal/client/operations.js +40 -61
  22. package/src/runtime/internal/client/portal.js +163 -85
  23. package/src/runtime/internal/client/render.js +44 -43
  24. package/src/runtime/internal/client/rpc.js +3 -3
  25. package/src/runtime/internal/client/runtime.js +592 -433
  26. package/src/runtime/internal/client/selector.js +5 -2
  27. package/src/runtime/internal/client/template.js +133 -158
  28. package/src/runtime/internal/client/transport.js +38 -0
  29. package/src/runtime/internal/client/try.js +465 -426
  30. package/src/runtime/internal/client/types.d.ts +56 -23
  31. package/src/runtime/internal/client/utils.js +1 -3
  32. package/src/runtime/internal/server/dynamic.js +20 -21
  33. package/src/runtime/internal/server/index.js +329 -277
  34. package/src/runtime/internal/server/rpc.js +3 -2
  35. package/src/runtime/internal/server/transport.js +16 -0
  36. package/src/runtime/transport.js +21 -0
  37. package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
  38. package/tests/client/array/array.copy-within.test.tsrx +12 -12
  39. package/tests/client/array/array.derived.test.tsrx +46 -46
  40. package/tests/client/array/array.iteration.test.tsrx +10 -10
  41. package/tests/client/array/array.mutations.test.tsrx +20 -20
  42. package/tests/client/array/array.static.test.tsrx +11 -11
  43. package/tests/client/array/array.to-methods.test.tsrx +6 -6
  44. package/tests/client/async-suspend.test.tsrx +74 -75
  45. package/tests/client/basic/basic.attributes.test.tsrx +123 -83
  46. package/tests/client/basic/basic.collections.test.tsrx +12 -12
  47. package/tests/client/basic/basic.components.test.tsrx +99 -25
  48. package/tests/client/basic/basic.errors.test.tsrx +18 -18
  49. package/tests/client/basic/basic.events.test.tsrx +42 -42
  50. package/tests/client/basic/basic.get-set.test.tsrx +8 -8
  51. package/tests/client/basic/basic.reactivity.test.tsrx +73 -38
  52. package/tests/client/basic/basic.rendering.test.tsrx +25 -25
  53. package/tests/client/basic/basic.utilities.test.tsrx +3 -3
  54. package/tests/client/boundaries.test.tsrx +8 -8
  55. package/tests/client/boxed-locals.test.tsrx +452 -0
  56. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
  57. package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
  58. package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
  59. package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
  60. package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
  61. package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
  62. package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
  63. package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
  64. package/tests/client/composite/composite.props.test.tsrx +149 -12
  65. package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
  66. package/tests/client/composite/composite.render.test.tsrx +26 -9
  67. package/tests/client/css/scoped-styles.test.tsrx +8 -8
  68. package/tests/client/date.test.tsrx +42 -42
  69. package/tests/client/derived-release.test.tsrx +370 -0
  70. package/tests/client/dynamic-elements.test.tsrx +45 -45
  71. package/tests/client/events.test.tsrx +97 -71
  72. package/tests/client/for-selector.test.tsrx +14 -14
  73. package/tests/client/for-single-root-items.test.tsrx +118 -3
  74. package/tests/client/for.test.tsrx +332 -31
  75. package/tests/client/head.test.tsrx +19 -19
  76. package/tests/client/html.test.tsrx +11 -9
  77. package/tests/client/if-block.test.tsrx +80 -0
  78. package/tests/client/map.test.tsrx +16 -16
  79. package/tests/client/media-query.test.tsrx +7 -7
  80. package/tests/client/portal.test.tsrx +224 -26
  81. package/tests/client/primitive-text.test.tsrx +50 -0
  82. package/tests/client/prop-kind-switch.test.tsrx +141 -0
  83. package/tests/client/ref.test.tsrx +17 -17
  84. package/tests/client/return.test.tsrx +26 -3
  85. package/tests/client/root-boundary.test.tsrx +42 -0
  86. package/tests/client/scoped-flush.test.tsrx +8 -8
  87. package/tests/client/set.test.tsrx +6 -6
  88. package/tests/client/svg.test.tsrx +11 -11
  89. package/tests/client/switch.test.tsrx +44 -44
  90. package/tests/client/track-async-hydration.test.tsrx +4 -4
  91. package/tests/client/try.test.tsrx +151 -83
  92. package/tests/client/tsx.test.tsrx +43 -40
  93. package/tests/client/url/url.derived.test.tsrx +6 -6
  94. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
  95. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
  96. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
  97. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
  98. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
  99. package/tests/hydration/basic.test.js +74 -1
  100. package/tests/hydration/build-components.js +22 -1
  101. package/tests/hydration/compiled/client/basic.js +1142 -713
  102. package/tests/hydration/compiled/client/composite.js +151 -100
  103. package/tests/hydration/compiled/client/events.js +184 -171
  104. package/tests/hydration/compiled/client/for.js +1472 -1132
  105. package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
  106. package/tests/hydration/compiled/client/head.js +254 -201
  107. package/tests/hydration/compiled/client/hmr.js +54 -41
  108. package/tests/hydration/compiled/client/html-in-template.js +54 -39
  109. package/tests/hydration/compiled/client/html.js +1633 -1263
  110. package/tests/hydration/compiled/client/if-children.js +420 -270
  111. package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
  112. package/tests/hydration/compiled/client/if.js +229 -219
  113. package/tests/hydration/compiled/client/mixed-control-flow.js +420 -404
  114. package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
  115. package/tests/hydration/compiled/client/portal.js +87 -95
  116. package/tests/hydration/compiled/client/reactivity.js +135 -101
  117. package/tests/hydration/compiled/client/return.js +28 -19
  118. package/tests/hydration/compiled/client/streaming.js +390 -306
  119. package/tests/hydration/compiled/client/switch.js +258 -266
  120. package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
  121. package/tests/hydration/compiled/client/try.js +173 -129
  122. package/tests/hydration/compiled/client/typed-text.js +71 -0
  123. package/tests/hydration/compiled/fixtures/money.js +10 -0
  124. package/tests/hydration/compiled/server/basic.js +123 -6
  125. package/tests/hydration/compiled/server/composite.js +16 -30
  126. package/tests/hydration/compiled/server/events.js +66 -18
  127. package/tests/hydration/compiled/server/for.js +117 -41
  128. package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
  129. package/tests/hydration/compiled/server/head.js +20 -20
  130. package/tests/hydration/compiled/server/hmr.js +2 -2
  131. package/tests/hydration/compiled/server/html.js +70 -238
  132. package/tests/hydration/compiled/server/if-children.js +107 -15
  133. package/tests/hydration/compiled/server/if.js +11 -15
  134. package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
  135. package/tests/hydration/compiled/server/portal.js +14 -22
  136. package/tests/hydration/compiled/server/reactivity.js +14 -14
  137. package/tests/hydration/compiled/server/streaming.js +19 -19
  138. package/tests/hydration/compiled/server/switch.js +8 -8
  139. package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
  140. package/tests/hydration/compiled/server/try.js +8 -8
  141. package/tests/hydration/compiled/server/typed-text.js +17 -0
  142. package/tests/hydration/components/basic.tsrx +44 -8
  143. package/tests/hydration/components/composite.tsrx +2 -2
  144. package/tests/hydration/components/events.tsrx +25 -25
  145. package/tests/hydration/components/for.tsrx +115 -67
  146. package/tests/hydration/components/fragment-cursor.tsrx +650 -0
  147. package/tests/hydration/components/head.tsrx +16 -16
  148. package/tests/hydration/components/hmr.tsrx +2 -2
  149. package/tests/hydration/components/html.tsrx +7 -7
  150. package/tests/hydration/components/if-children.tsrx +72 -25
  151. package/tests/hydration/components/if.tsrx +18 -18
  152. package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
  153. package/tests/hydration/components/portal.tsrx +3 -3
  154. package/tests/hydration/components/reactivity.tsrx +16 -16
  155. package/tests/hydration/components/streaming.tsrx +20 -20
  156. package/tests/hydration/components/switch.tsrx +20 -20
  157. package/tests/hydration/components/text-types.ts +4 -0
  158. package/tests/hydration/components/track-async-serialization.tsrx +80 -26
  159. package/tests/hydration/components/try.tsrx +8 -8
  160. package/tests/hydration/components/typed-text.tsrx +22 -0
  161. package/tests/hydration/fixtures/money.js +10 -0
  162. package/tests/hydration/for.test.js +36 -0
  163. package/tests/hydration/fragment-cursor.test.js +111 -0
  164. package/tests/hydration/if-children.test.js +24 -0
  165. package/tests/hydration/streaming.test.js +19 -0
  166. package/tests/hydration/track-async-serialization.test.js +87 -2
  167. package/tests/hydration/tsconfig.text-types.json +10 -0
  168. package/tests/hydration/typed-text.test.js +34 -0
  169. package/tests/server/await.test.tsrx +3 -3
  170. package/tests/server/basic.attributes.test.tsrx +70 -42
  171. package/tests/server/basic.components.test.tsrx +64 -8
  172. package/tests/server/basic.test.tsrx +34 -32
  173. package/tests/server/compiler.test.tsrx +1 -70
  174. package/tests/server/composite.props.test.tsrx +6 -6
  175. package/tests/server/dynamic-elements.test.tsrx +31 -8
  176. package/tests/server/for.test.tsrx +94 -0
  177. package/tests/server/head.test.tsrx +11 -11
  178. package/tests/server/scoped-styles.test.tsrx +2 -2
  179. package/tests/server/streaming-ssr.test.tsrx +48 -43
  180. package/tests/server/track-async-serialization.test.tsrx +204 -21
  181. package/tests/server/try.test.tsrx +48 -48
  182. package/tests/types/transport.ts +40 -0
  183. package/tests/utils/jsx-runtime-types.test.js +67 -2
  184. package/tests/utils/tracked-types.test.js +117 -0
  185. package/tests/utils/vite-plugin-config.test.js +23 -0
  186. package/types/index.d.ts +49 -9
  187. package/types/server.d.ts +3 -0
  188. package/types/transport.d.ts +15 -0
  189. package/src/runtime/internal/client/switch.js +0 -113
  190. package/src/utils/errors.js +0 -13
  191. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +0 -12
  192. package/tests/client/compiler/__snapshots__/compiler.typescript.test.rsrx.snap +0 -46
  193. package/tests/client/lazy-array.test.tsrx +0 -31
  194. package/tests/client/lazy-destructuring.test.tsrx +0 -438
  195. package/tests/client/tracked-index-access.test.tsrx +0 -113
  196. package/tests/server/lazy-destructuring.test.tsrx +0 -595
  197. package/tests/server/tracked-index-access.test.tsrx +0 -76
@@ -14,14 +14,14 @@ describe('basic client > attribute rendering', () => {
14
14
 
15
15
  it('render dynamic class attribute', () => {
16
16
  function Basic() @{
17
- let &[active] = track(false);
17
+ const active = track(false);
18
18
  <>
19
19
  <button
20
20
  onClick={() => {
21
- active = !active;
21
+ active.value = !active.value;
22
22
  }}
23
23
  >{'Toggle'}</button>
24
- <div class={active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
24
+ <div class={active.value ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
25
25
  <style>
26
26
  .active {
27
27
  color: green;
@@ -91,14 +91,14 @@ describe('basic client > attribute rendering', () => {
91
91
 
92
92
  it('render dynamic class object', () => {
93
93
  function Basic() @{
94
- let &[active] = track(false);
94
+ const active = track(false);
95
95
  <>
96
96
  <button
97
97
  onClick={() => {
98
- active = !active;
98
+ active.value = !active.value;
99
99
  }}
100
100
  >{'Toggle'}</button>
101
- <div class={{ active: active, inactive: !active }}>{'Dynamic Class'}</div>
101
+ <div class={{ active: active.value, inactive: !active.value }}>{'Dynamic Class'}</div>
102
102
  <style>
103
103
  .active {
104
104
  color: green;
@@ -130,10 +130,10 @@ describe('basic client > attribute rendering', () => {
130
130
 
131
131
  it('applies scoped ripple class to multiple elements with dynamic class expressions', () => {
132
132
  function Basic() @{
133
- let &[selected] = track(1);
133
+ const selected = track(1);
134
134
  <>
135
- <div class={selected === 0 ? 'selected' : ''}>{`div 1`}</div>
136
- <div class={selected === 0 ? 'selected' : ''}>{`div 2`}</div>
135
+ <div class={selected.value === 0 ? 'selected' : ''}>{`div 1`}</div>
136
+ <div class={selected.value === 0 ? 'selected' : ''}>{`div 2`}</div>
137
137
  <style>
138
138
  div {
139
139
  background: green;
@@ -159,14 +159,14 @@ describe('basic client > attribute rendering', () => {
159
159
 
160
160
  it('render dynamic id attribute', () => {
161
161
  function Basic() @{
162
- let &[count] = track(0);
162
+ const count = track(0);
163
163
  <>
164
164
  <button
165
165
  onClick={() => {
166
- count++;
166
+ count.value++;
167
167
  }}
168
168
  >{'Increment'}</button>
169
- <div id={`item-${count}`}>{'Dynamic ID'}</div>
169
+ <div id={`item-${count.value}`}>{'Dynamic ID'}</div>
170
170
  </>
171
171
  }
172
172
 
@@ -190,14 +190,14 @@ describe('basic client > attribute rendering', () => {
190
190
 
191
191
  it('render dynamic style attribute', () => {
192
192
  function Basic() @{
193
- let &[color] = track('red');
193
+ const color = track('red');
194
194
  <>
195
195
  <button
196
196
  onClick={() => {
197
- color = color === 'red' ? 'blue' : 'red';
197
+ color.value = color.value === 'red' ? 'blue' : 'red';
198
198
  }}
199
199
  >{'Change Color'}</button>
200
- <div style={`color: ${color}; font-weight: bold;`}>{'Dynamic Style'}</div>
200
+ <div style={`color: ${color.value}; font-weight: bold;`}>{'Dynamic Style'}</div>
201
201
  </>
202
202
  }
203
203
 
@@ -218,14 +218,14 @@ describe('basic client > attribute rendering', () => {
218
218
 
219
219
  it('render style attribute as dynamic object', () => {
220
220
  function Basic() @{
221
- let &[color] = track('red');
221
+ const color = track('red');
222
222
  <>
223
223
  <button
224
224
  onClick={() => {
225
- color = color === 'red' ? 'blue' : 'red';
225
+ color.value = color.value === 'red' ? 'blue' : 'red';
226
226
  }}
227
227
  >{'Change Color'}</button>
228
- <div style={{ color: color, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
228
+ <div style={{ color: color.value, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
229
229
  </>
230
230
  }
231
231
 
@@ -244,15 +244,52 @@ describe('basic client > attribute rendering', () => {
244
244
  expect(div.style.fontWeight).toBe('bold');
245
245
  });
246
246
 
247
+ it.each([undefined, null])('omits %s styles and removes and restores conditional values', (
248
+ empty,
249
+ ) => {
250
+ function Basic() @{
251
+ const active = track(false);
252
+ <>
253
+ <button onClick={() => (active.value = !active.value)}>Toggle</button>
254
+ <div
255
+ style={{
256
+ width: active.value ? '400px' : empty,
257
+ '--scale': active.value ? 2 : empty,
258
+ margin: 0,
259
+ opacity: 0,
260
+ '--literal': 'undefined',
261
+ '--literal-null': 'null',
262
+ }}
263
+ />
264
+ </>
265
+ }
266
+
267
+ render(Basic);
268
+
269
+ const button = container.querySelector('button');
270
+ const div = container.querySelector('div');
271
+
272
+ for (const active of [false, true, false, true]) {
273
+ expect(div.style.width).toBe(active ? '400px' : '');
274
+ expect(div.style.getPropertyValue('--scale')).toBe(active ? '2' : '');
275
+ expect(div.style.margin).toBe('0px');
276
+ expect(div.style.opacity).toBe('0');
277
+ expect(div.style.getPropertyValue('--literal')).toBe('undefined');
278
+ expect(div.style.getPropertyValue('--literal-null')).toBe('null');
279
+ button.click();
280
+ flushSync();
281
+ }
282
+ });
283
+
247
284
  it('render tracked variable as style attribute', () => {
248
285
  function Basic() @{
249
- let &[style] = track({ color: 'red', fontWeight: 'bold' });
286
+ const style = track({ color: 'red', fontWeight: 'bold' });
250
287
  function toggleColor() {
251
- style = { ...style, color: style.color === 'red' ? 'blue' : 'red' };
288
+ style.value = { ...style.value, color: style.value.color === 'red' ? 'blue' : 'red' };
252
289
  }
253
290
  <>
254
291
  <button onClick={toggleColor}>{'Change Color'}</button>
255
- <div {style}>{'Dynamic Style'}</div>
292
+ <div style={style.value}>{'Dynamic Style'}</div>
256
293
  </>
257
294
  }
258
295
 
@@ -344,16 +381,16 @@ describe('basic client > attribute rendering', () => {
344
381
 
345
382
  it('render dynamic boolean attributes', () => {
346
383
  function Basic() @{
347
- let &[disabled] = track(false);
348
- let &[checked] = track(false);
384
+ const disabled = track(false);
385
+ const checked = track(false);
349
386
  <>
350
387
  <button
351
388
  onClick={() => {
352
- disabled = !disabled;
353
- checked = !checked;
389
+ disabled.value = !disabled.value;
390
+ checked.value = !checked.value;
354
391
  }}
355
392
  >{'Toggle'}</button>
356
- <input type="checkbox" {disabled} {checked} />
393
+ <input type="checkbox" disabled={disabled.value} checked={checked.value} />
357
394
  </>
358
395
  }
359
396
 
@@ -374,19 +411,19 @@ describe('basic client > attribute rendering', () => {
374
411
 
375
412
  it('render multiple dynamic attributes', () => {
376
413
  function Basic() @{
377
- let &[theme] = track('light');
378
- let &[size] = track('medium');
414
+ const theme = track('light');
415
+ const size = track('medium');
379
416
  <>
380
417
  <button
381
418
  onClick={() => {
382
- theme = theme === 'light' ? 'dark' : 'light';
383
- size = size === 'medium' ? 'large' : 'medium';
419
+ theme.value = theme.value === 'light' ? 'dark' : 'light';
420
+ size.value = size.value === 'medium' ? 'large' : 'medium';
384
421
  }}
385
422
  >{'Toggle Theme & Size'}</button>
386
423
  <div
387
- class={`theme-${theme} size-${size}`}
388
- data-theme={theme}
389
- data-size={size}
424
+ class={`theme-${theme.value} size-${size.value}`}
425
+ data-theme={theme.value}
426
+ data-size={size.value}
390
427
  >{'Multiple Dynamic Attributes'}</div>
391
428
  </>
392
429
  }
@@ -410,18 +447,18 @@ describe('basic client > attribute rendering', () => {
410
447
 
411
448
  it('render conditional attributes', () => {
412
449
  function Basic() @{
413
- let &[showTitle] = track(false);
414
- let &[showAria] = track(false);
450
+ const showTitle = track(false);
451
+ const showAria = track(false);
415
452
  <>
416
453
  <button
417
454
  onClick={() => {
418
- showTitle = !showTitle;
419
- showAria = !showAria;
455
+ showTitle.value = !showTitle.value;
456
+ showAria.value = !showAria.value;
420
457
  }}
421
458
  >{'Toggle Attributes'}</button>
422
459
  <div
423
- title={showTitle ? 'This is a title' : undefined}
424
- aria-label={showAria ? 'Accessible label' : undefined}
460
+ title={showTitle.value ? 'This is a title' : undefined}
461
+ aria-label={showAria.value ? 'Accessible label' : undefined}
425
462
  >{'Conditional Attributes'}</div>
426
463
  </>
427
464
  }
@@ -449,21 +486,21 @@ describe('basic client > attribute rendering', () => {
449
486
 
450
487
  it('render spread attributes', () => {
451
488
  function Basic() @{
452
- let &[attrs] = track<TestAttributes>({
489
+ const attrs = track<TestAttributes>({
453
490
  class: 'initial',
454
491
  id: 'test-1',
455
492
  });
456
493
  <>
457
494
  <button
458
495
  onClick={() => {
459
- attrs = {
496
+ attrs.value = {
460
497
  class: 'updated',
461
498
  id: 'test-2',
462
499
  'data-extra': 'value',
463
500
  };
464
501
  }}
465
502
  >{'Update Attributes'}</button>
466
- <div {...attrs}>{'Spread Attributes'}</div>
503
+ <div {...attrs.value}>{'Spread Attributes'}</div>
467
504
  </>
468
505
  }
469
506
 
@@ -486,12 +523,12 @@ describe('basic client > attribute rendering', () => {
486
523
 
487
524
  it('renders with reactive attributes with nested reactive attributes', () => {
488
525
  function App() @{
489
- let &[value] = track('parent-class');
490
- let &[nested] = track('nested-class');
526
+ const value = track('parent-class');
527
+ const nested = track('nested-class');
491
528
  <>
492
- <p class={value}>{'Colored parent value'}</p>
529
+ <p class={value.value}>{'Colored parent value'}</p>
493
530
  <div>
494
- <p class={nested}>{'Colored nested value'}</p>
531
+ <p class={nested.value}>{'Colored nested value'}</p>
495
532
  </div>
496
533
  </>
497
534
  }
@@ -534,25 +571,28 @@ describe('basic client > attribute rendering', () => {
534
571
 
535
572
  it('handles reactive event handler changes', () => {
536
573
  function Basic() @{
537
- let &[count] = track(0);
538
- let &[mode] = track<'increment' | 'decrement'>('increment');
574
+ const count = track(0);
575
+ const mode = track<'increment' | 'decrement'>('increment');
539
576
  const incrementHandler = () => {
540
- count++;
577
+ count.value++;
541
578
  };
542
579
  const decrementHandler = () => {
543
- count--;
580
+ count.value--;
544
581
  };
545
582
  <>
546
583
  <button
547
584
  onClick={() => {
548
- mode = mode === 'increment' ? 'decrement' : 'increment';
585
+ mode.value = mode.value === 'increment' ? 'decrement' : 'increment';
549
586
  }}
550
587
  class="toggle-mode"
551
588
  >{'Toggle Mode'}</button>
552
- <button onClick={mode === 'increment' ? incrementHandler : decrementHandler} class="action">
553
- {mode === 'increment' ? '+' : '-'}
589
+ <button
590
+ onClick={mode.value === 'increment' ? incrementHandler : decrementHandler}
591
+ class="action"
592
+ >
593
+ {mode.value === 'increment' ? '+' : '-'}
554
594
  </button>
555
- <div class="count">{count}</div>
595
+ <div class="count">{count.value}</div>
556
596
  </>
557
597
  }
558
598
 
@@ -647,16 +687,16 @@ describe('basic client > attribute rendering', () => {
647
687
 
648
688
  it('handles custom events with customName option', () => {
649
689
  function Basic() @{
650
- let &[customEventCount] = track(0);
690
+ const customEventCount = track(0);
651
691
  const handleCustom = {
652
692
  handleEvent(event: CustomEvent) {
653
- customEventCount += event.detail.value;
693
+ customEventCount.value += event.detail.value;
654
694
  },
655
695
  customName: 'MyCustomEvent',
656
696
  };
657
697
  <div>
658
698
  <div onMyCustomEvent={handleCustom} class="custom-target">{'Custom'}</div>
659
- <div class="custom-count">{customEventCount}</div>
699
+ <div class="custom-count">{customEventCount.value}</div>
660
700
  </div>
661
701
  }
662
702
 
@@ -680,22 +720,22 @@ describe('basic client > attribute rendering', () => {
680
720
 
681
721
  it('handles events with delegated: false option to bypass delegation', () => {
682
722
  function Basic() @{
683
- let &[delegatedCount] = track(0);
684
- let &[nonDelegatedCount] = track(0);
723
+ const delegatedCount = track(0);
724
+ const nonDelegatedCount = track(0);
685
725
  const delegatedHandler = () => {
686
- delegatedCount++;
726
+ delegatedCount.value++;
687
727
  };
688
728
  const nonDelegatedHandler = {
689
729
  handleEvent() {
690
- nonDelegatedCount++;
730
+ nonDelegatedCount.value++;
691
731
  },
692
732
  delegated: false,
693
733
  };
694
734
  <div>
695
735
  <button onClick={delegatedHandler} class="delegated-btn">{'Delegated'}</button>
696
736
  <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>
737
+ <div class="delegated-count">{delegatedCount.value}</div>
738
+ <div class="non-delegated-count">{nonDelegatedCount.value}</div>
699
739
  </div>
700
740
  }
701
741
 
@@ -789,21 +829,21 @@ describe('basic client > attribute rendering', () => {
789
829
 
790
830
  it('handles events defined as function directly vs as object', () => {
791
831
  function Basic() @{
792
- let &[functionCount] = track(0);
793
- let &[objectCount] = track(0);
832
+ const functionCount = track(0);
833
+ const objectCount = track(0);
794
834
  const functionHandler = () => {
795
- functionCount++;
835
+ functionCount.value++;
796
836
  };
797
837
  const objectHandler = {
798
838
  handleEvent() {
799
- objectCount++;
839
+ objectCount.value++;
800
840
  },
801
841
  };
802
842
  <div>
803
843
  <button onClick={functionHandler} class="function-btn">{'Function'}</button>
804
844
  <button onClick={objectHandler} class="object-btn">{'Object'}</button>
805
- <div class="function-count">{functionCount}</div>
806
- <div class="object-count">{objectCount}</div>
845
+ <div class="function-count">{functionCount.value}</div>
846
+ <div class="object-count">{objectCount.value}</div>
807
847
  </div>
808
848
  }
809
849
 
@@ -839,13 +879,13 @@ describe('basic client > attribute rendering', () => {
839
879
 
840
880
  it('handles passive event option', () => {
841
881
  function Basic() @{
842
- let &[passiveDefaultPrevented] = track<boolean | null>(null);
843
- let &[nonPassiveDefaultPrevented] = track<boolean | null>(null);
882
+ const passiveDefaultPrevented = track<boolean | null>(null);
883
+ const nonPassiveDefaultPrevented = track<boolean | null>(null);
844
884
  const passiveHandler = {
845
885
  handleEvent(event: Event) {
846
886
  event.preventDefault();
847
887
  // In passive listeners, preventDefault() is ignored
848
- passiveDefaultPrevented = event.defaultPrevented;
888
+ passiveDefaultPrevented.value = event.defaultPrevented;
849
889
  },
850
890
  passive: true,
851
891
  delegated: false, // Need to ensure it's not delegated to test passive properly
@@ -854,7 +894,7 @@ describe('basic client > attribute rendering', () => {
854
894
  handleEvent(event: Event) {
855
895
  event.preventDefault();
856
896
  // In non-passive listeners, preventDefault() works
857
- nonPassiveDefaultPrevented = event.defaultPrevented;
897
+ nonPassiveDefaultPrevented.value = event.defaultPrevented;
858
898
  },
859
899
  delegated: false,
860
900
  };
@@ -862,16 +902,16 @@ describe('basic client > attribute rendering', () => {
862
902
  <div onWheel={passiveHandler} class="passive-target">{'Passive'}</div>
863
903
  <div onWheel={nonPassiveHandler} class="non-passive-target">{'Non-Passive'}</div>
864
904
  <div class="passive-result">
865
- {passiveDefaultPrevented === null
905
+ {passiveDefaultPrevented.value === null
866
906
  ? 'not-tested'
867
- : passiveDefaultPrevented
907
+ : passiveDefaultPrevented.value
868
908
  ? 'prevented'
869
909
  : 'not-prevented'}
870
910
  </div>
871
911
  <div class="non-passive-result">
872
- {nonPassiveDefaultPrevented === null
912
+ {nonPassiveDefaultPrevented.value === null
873
913
  ? 'not-tested'
874
- : nonPassiveDefaultPrevented
914
+ : nonPassiveDefaultPrevented.value
875
915
  ? 'prevented'
876
916
  : 'not-prevented'}
877
917
  </div>
@@ -901,22 +941,22 @@ describe('basic client > attribute rendering', () => {
901
941
 
902
942
  it('handles once option to fire event only once', () => {
903
943
  function Basic() @{
904
- let &[onceCount] = track(0);
905
- let &[regularCount] = track(0);
944
+ const onceCount = track(0);
945
+ const regularCount = track(0);
906
946
  const onceHandler = {
907
947
  handleEvent() {
908
- onceCount++;
948
+ onceCount.value++;
909
949
  },
910
950
  once: true,
911
951
  };
912
952
  const regularHandler = () => {
913
- regularCount++;
953
+ regularCount.value++;
914
954
  };
915
955
  <div>
916
956
  <button onClick={onceHandler} class="once-btn">{'Once'}</button>
917
957
  <button onClick={regularHandler} class="regular-btn">{'Regular'}</button>
918
- <div class="once-count">{onceCount}</div>
919
- <div class="regular-count">{regularCount}</div>
958
+ <div class="once-count">{onceCount.value}</div>
959
+ <div class="regular-count">{regularCount.value}</div>
920
960
  </div>
921
961
  }
922
962
 
@@ -15,16 +15,16 @@ describe('basic client > collections', () => {
15
15
 
16
16
  it('renders with simple reactive objects', () => {
17
17
  function Basic() @{
18
- let &[user] = track({
18
+ const user = track({
19
19
  name: 'John',
20
20
  age: 25,
21
21
  });
22
22
  <>
23
- <div class="name">{user.name}</div>
24
- <div class="age">{user.age}</div>
23
+ <div class="name">{user.value.name}</div>
24
+ <div class="age">{user.value.age}</div>
25
25
  <button
26
26
  onClick={() => {
27
- user = { ...user, name: 'Jane', age: 30 };
27
+ user.value = { ...user.value, name: 'Jane', age: 30 };
28
28
  }}
29
29
  >{'Update User'}</button>
30
30
  </>
@@ -48,17 +48,17 @@ describe('basic client > collections', () => {
48
48
 
49
49
  it('renders with nested reactive objects', () => {
50
50
  function Basic() @{
51
- let &[user] = track({
51
+ const user = track({
52
52
  name: track('John'),
53
53
  age: track(25),
54
54
  });
55
55
  <>
56
- <div class="name">{user.name.value}</div>
57
- <div class="age">{user.age.value}</div>
56
+ <div class="name">{user.value.name.value}</div>
57
+ <div class="age">{user.value.age.value}</div>
58
58
  <button
59
59
  onClick={() => {
60
- user.name.value = 'Jane';
61
- user.age.value = 30;
60
+ user.value.name.value = 'Jane';
61
+ user.value.age.value = 30;
62
62
  }}
63
63
  >{'Update User'}</button>
64
64
  </>
@@ -116,11 +116,11 @@ describe('basic client > collections', () => {
116
116
 
117
117
  it('cleans up mixed tsrx collection sentinels and trailing text on rerender', () => {
118
118
  function App() @{
119
- let &[primary] = track(true);
119
+ const primary = track(true);
120
120
  <>
121
121
  <div class="frame">
122
122
  {<>
123
- {primary
123
+ {primary.value
124
124
  ? [
125
125
  'first:',
126
126
  <strong class="middle">{'one'}</strong>,
@@ -135,7 +135,7 @@ describe('basic client > collections', () => {
135
135
  </div>
136
136
  <button
137
137
  onClick={() => {
138
- primary = !primary;
138
+ primary.value = !primary.value;
139
139
  }}
140
140
  >{'toggle'}</button>
141
141
  </>