ripple 0.3.128 → 0.4.0

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 (192) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/package.json +10 -4
  3. package/src/runtime/element.js +23 -6
  4. package/src/runtime/index-client.js +81 -41
  5. package/src/runtime/index-server.js +1 -0
  6. package/src/runtime/internal/client/blocks.js +173 -91
  7. package/src/runtime/internal/client/component.js +4 -30
  8. package/src/runtime/internal/client/composite.js +12 -13
  9. package/src/runtime/internal/client/constants.js +9 -0
  10. package/src/runtime/internal/client/context.js +12 -19
  11. package/src/runtime/internal/client/css.js +7 -9
  12. package/src/runtime/internal/client/events.js +178 -90
  13. package/src/runtime/internal/client/expression.js +45 -25
  14. package/src/runtime/internal/client/for.js +409 -129
  15. package/src/runtime/internal/client/head.js +10 -5
  16. package/src/runtime/internal/client/html.js +1 -0
  17. package/src/runtime/internal/client/hydration.js +152 -10
  18. package/src/runtime/internal/client/if.js +239 -50
  19. package/src/runtime/internal/client/index.js +4 -12
  20. package/src/runtime/internal/client/operations.js +40 -61
  21. package/src/runtime/internal/client/portal.js +163 -85
  22. package/src/runtime/internal/client/render.js +39 -39
  23. package/src/runtime/internal/client/rpc.js +3 -3
  24. package/src/runtime/internal/client/runtime.js +592 -433
  25. package/src/runtime/internal/client/selector.js +5 -2
  26. package/src/runtime/internal/client/template.js +133 -158
  27. package/src/runtime/internal/client/transport.js +38 -0
  28. package/src/runtime/internal/client/try.js +465 -426
  29. package/src/runtime/internal/client/types.d.ts +56 -23
  30. package/src/runtime/internal/client/utils.js +1 -3
  31. package/src/runtime/internal/server/dynamic.js +20 -21
  32. package/src/runtime/internal/server/index.js +325 -275
  33. package/src/runtime/internal/server/rpc.js +3 -2
  34. package/src/runtime/internal/server/transport.js +16 -0
  35. package/src/runtime/transport.js +21 -0
  36. package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
  37. package/tests/client/array/array.copy-within.test.tsrx +12 -12
  38. package/tests/client/array/array.derived.test.tsrx +46 -46
  39. package/tests/client/array/array.iteration.test.tsrx +10 -10
  40. package/tests/client/array/array.mutations.test.tsrx +20 -20
  41. package/tests/client/array/array.static.test.tsrx +11 -11
  42. package/tests/client/array/array.to-methods.test.tsrx +6 -6
  43. package/tests/client/async-suspend.test.tsrx +74 -75
  44. package/tests/client/basic/basic.attributes.test.tsrx +86 -83
  45. package/tests/client/basic/basic.collections.test.tsrx +12 -12
  46. package/tests/client/basic/basic.components.test.tsrx +99 -25
  47. package/tests/client/basic/basic.errors.test.tsrx +18 -18
  48. package/tests/client/basic/basic.events.test.tsrx +42 -42
  49. package/tests/client/basic/basic.get-set.test.tsrx +8 -8
  50. package/tests/client/basic/basic.reactivity.test.tsrx +73 -38
  51. package/tests/client/basic/basic.rendering.test.tsrx +25 -25
  52. package/tests/client/basic/basic.utilities.test.tsrx +3 -3
  53. package/tests/client/boundaries.test.tsrx +8 -8
  54. package/tests/client/boxed-locals.test.tsrx +452 -0
  55. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
  56. package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
  57. package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
  58. package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
  59. package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
  60. package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
  61. package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
  62. package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
  63. package/tests/client/composite/composite.props.test.tsrx +149 -12
  64. package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
  65. package/tests/client/composite/composite.render.test.tsrx +26 -9
  66. package/tests/client/css/scoped-styles.test.tsrx +8 -8
  67. package/tests/client/date.test.tsrx +42 -42
  68. package/tests/client/derived-release.test.tsrx +370 -0
  69. package/tests/client/dynamic-elements.test.tsrx +45 -45
  70. package/tests/client/events.test.tsrx +97 -71
  71. package/tests/client/for-selector.test.tsrx +14 -14
  72. package/tests/client/for-single-root-items.test.tsrx +118 -3
  73. package/tests/client/for.test.tsrx +332 -31
  74. package/tests/client/head.test.tsrx +19 -19
  75. package/tests/client/html.test.tsrx +11 -9
  76. package/tests/client/if-block.test.tsrx +80 -0
  77. package/tests/client/map.test.tsrx +16 -16
  78. package/tests/client/media-query.test.tsrx +7 -7
  79. package/tests/client/portal.test.tsrx +224 -26
  80. package/tests/client/primitive-text.test.tsrx +50 -0
  81. package/tests/client/prop-kind-switch.test.tsrx +141 -0
  82. package/tests/client/ref.test.tsrx +17 -17
  83. package/tests/client/return.test.tsrx +26 -3
  84. package/tests/client/root-boundary.test.tsrx +42 -0
  85. package/tests/client/scoped-flush.test.tsrx +8 -8
  86. package/tests/client/set.test.tsrx +6 -6
  87. package/tests/client/svg.test.tsrx +11 -11
  88. package/tests/client/switch.test.tsrx +44 -44
  89. package/tests/client/track-async-hydration.test.tsrx +4 -4
  90. package/tests/client/try.test.tsrx +151 -83
  91. package/tests/client/tsx.test.tsrx +43 -40
  92. package/tests/client/url/url.derived.test.tsrx +6 -6
  93. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
  94. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
  95. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
  96. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
  97. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
  98. package/tests/hydration/basic.test.js +74 -1
  99. package/tests/hydration/build-components.js +22 -1
  100. package/tests/hydration/compiled/client/basic.js +1142 -713
  101. package/tests/hydration/compiled/client/composite.js +151 -100
  102. package/tests/hydration/compiled/client/events.js +184 -171
  103. package/tests/hydration/compiled/client/for.js +1472 -1132
  104. package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
  105. package/tests/hydration/compiled/client/head.js +254 -201
  106. package/tests/hydration/compiled/client/hmr.js +54 -41
  107. package/tests/hydration/compiled/client/html-in-template.js +54 -39
  108. package/tests/hydration/compiled/client/html.js +1633 -1263
  109. package/tests/hydration/compiled/client/if-children.js +420 -270
  110. package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
  111. package/tests/hydration/compiled/client/if.js +229 -219
  112. package/tests/hydration/compiled/client/mixed-control-flow.js +420 -404
  113. package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
  114. package/tests/hydration/compiled/client/portal.js +87 -95
  115. package/tests/hydration/compiled/client/reactivity.js +135 -101
  116. package/tests/hydration/compiled/client/return.js +28 -19
  117. package/tests/hydration/compiled/client/streaming.js +390 -306
  118. package/tests/hydration/compiled/client/switch.js +258 -266
  119. package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
  120. package/tests/hydration/compiled/client/try.js +173 -129
  121. package/tests/hydration/compiled/client/typed-text.js +71 -0
  122. package/tests/hydration/compiled/fixtures/money.js +10 -0
  123. package/tests/hydration/compiled/server/basic.js +123 -6
  124. package/tests/hydration/compiled/server/composite.js +16 -30
  125. package/tests/hydration/compiled/server/events.js +66 -18
  126. package/tests/hydration/compiled/server/for.js +117 -41
  127. package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
  128. package/tests/hydration/compiled/server/head.js +20 -20
  129. package/tests/hydration/compiled/server/hmr.js +2 -2
  130. package/tests/hydration/compiled/server/html.js +70 -238
  131. package/tests/hydration/compiled/server/if-children.js +107 -15
  132. package/tests/hydration/compiled/server/if.js +11 -15
  133. package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
  134. package/tests/hydration/compiled/server/portal.js +14 -22
  135. package/tests/hydration/compiled/server/reactivity.js +14 -14
  136. package/tests/hydration/compiled/server/streaming.js +19 -19
  137. package/tests/hydration/compiled/server/switch.js +8 -8
  138. package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
  139. package/tests/hydration/compiled/server/try.js +8 -8
  140. package/tests/hydration/compiled/server/typed-text.js +17 -0
  141. package/tests/hydration/components/basic.tsrx +44 -8
  142. package/tests/hydration/components/composite.tsrx +2 -2
  143. package/tests/hydration/components/events.tsrx +25 -25
  144. package/tests/hydration/components/for.tsrx +115 -67
  145. package/tests/hydration/components/fragment-cursor.tsrx +650 -0
  146. package/tests/hydration/components/head.tsrx +16 -16
  147. package/tests/hydration/components/hmr.tsrx +2 -2
  148. package/tests/hydration/components/html.tsrx +7 -7
  149. package/tests/hydration/components/if-children.tsrx +72 -25
  150. package/tests/hydration/components/if.tsrx +18 -18
  151. package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
  152. package/tests/hydration/components/portal.tsrx +3 -3
  153. package/tests/hydration/components/reactivity.tsrx +16 -16
  154. package/tests/hydration/components/streaming.tsrx +20 -20
  155. package/tests/hydration/components/switch.tsrx +20 -20
  156. package/tests/hydration/components/text-types.ts +4 -0
  157. package/tests/hydration/components/track-async-serialization.tsrx +80 -26
  158. package/tests/hydration/components/try.tsrx +8 -8
  159. package/tests/hydration/components/typed-text.tsrx +22 -0
  160. package/tests/hydration/fixtures/money.js +10 -0
  161. package/tests/hydration/for.test.js +36 -0
  162. package/tests/hydration/fragment-cursor.test.js +111 -0
  163. package/tests/hydration/if-children.test.js +24 -0
  164. package/tests/hydration/streaming.test.js +19 -0
  165. package/tests/hydration/track-async-serialization.test.js +87 -2
  166. package/tests/hydration/tsconfig.text-types.json +10 -0
  167. package/tests/hydration/typed-text.test.js +34 -0
  168. package/tests/server/await.test.tsrx +3 -3
  169. package/tests/server/basic.attributes.test.tsrx +42 -42
  170. package/tests/server/basic.components.test.tsrx +64 -8
  171. package/tests/server/basic.test.tsrx +34 -32
  172. package/tests/server/compiler.test.tsrx +1 -70
  173. package/tests/server/composite.props.test.tsrx +6 -6
  174. package/tests/server/dynamic-elements.test.tsrx +31 -8
  175. package/tests/server/for.test.tsrx +94 -0
  176. package/tests/server/head.test.tsrx +11 -11
  177. package/tests/server/scoped-styles.test.tsrx +2 -2
  178. package/tests/server/streaming-ssr.test.tsrx +48 -43
  179. package/tests/server/track-async-serialization.test.tsrx +204 -21
  180. package/tests/server/try.test.tsrx +48 -48
  181. package/tests/types/transport.ts +40 -0
  182. package/tests/utils/vite-plugin-config.test.js +23 -0
  183. package/types/index.d.ts +48 -7
  184. package/types/server.d.ts +3 -0
  185. package/types/transport.d.ts +15 -0
  186. package/src/runtime/internal/client/switch.js +0 -113
  187. package/src/utils/errors.js +0 -13
  188. package/tests/client/lazy-array.test.tsrx +0 -31
  189. package/tests/client/lazy-destructuring.test.tsrx +0 -438
  190. package/tests/client/tracked-index-access.test.tsrx +0 -113
  191. package/tests/server/lazy-destructuring.test.tsrx +0 -595
  192. package/tests/server/tracked-index-access.test.tsrx +0 -76
@@ -1,4 +1,4 @@
1
- import type { Props, Tracked } from 'ripple';
1
+ import type { Derived, Props, Tracked } from 'ripple';
2
2
  import { RippleObject, effect, flushSync, track } from 'ripple';
3
3
 
4
4
  describe('composite > reactivity', () => {
@@ -77,28 +77,28 @@ describe('composite > reactivity', () => {
77
77
  });
78
78
 
79
79
  it('parents and children have isolated state', () => {
80
- function Button(props: { count: number }) @{
81
- let &[count] = track(() => props.count);
80
+ function Button(props: { count: Tracked<number> }) @{
81
+ const count = track(() => props.count.value, undefined, true);
82
82
  <button
83
83
  onClick={() => {
84
- count++;
84
+ count.value++;
85
85
  }}
86
86
  >
87
- {'child: ' + count}
87
+ {'child: ' + count.value}
88
88
  </button>
89
89
  }
90
90
 
91
91
  function App() @{
92
- let &[count] = track(0);
92
+ const count = track(0);
93
93
  <div>
94
94
  <button
95
95
  onClick={() => {
96
- count++;
96
+ count.value++;
97
97
  }}
98
98
  >
99
- {'parent: ' + count}
99
+ {'parent: ' + count.value}
100
100
  </button>
101
- <Button {count} />
101
+ <Button count={count} />
102
102
  </div>
103
103
  }
104
104
 
@@ -123,28 +123,28 @@ describe('composite > reactivity', () => {
123
123
  });
124
124
 
125
125
  it('parents and children have isolated connected state (destructured props)', () => {
126
- function Button(&{ count }: { count: number }) @{
127
- let &[local_count] = track(() => count);
126
+ function Button({ count }: { count: Tracked<number> }) @{
127
+ const local_count = track(() => count.value, undefined, true);
128
128
  <button
129
129
  onClick={() => {
130
- local_count++;
130
+ local_count.value++;
131
131
  }}
132
132
  >
133
- {'child: ' + local_count}
133
+ {'child: ' + local_count.value}
134
134
  </button>
135
135
  }
136
136
 
137
137
  function App() @{
138
- let &[count] = track(0);
138
+ const count = track(0);
139
139
  <div>
140
140
  <button
141
141
  onClick={() => {
142
- count++;
142
+ count.value++;
143
143
  }}
144
144
  >
145
- {'parent: ' + count}
145
+ {'parent: ' + count.value}
146
146
  </button>
147
- <Button {count} />
147
+ <Button count={count} />
148
148
  </div>
149
149
  }
150
150
 
@@ -172,33 +172,27 @@ describe('composite > reactivity', () => {
172
172
  let logs: string[] = [];
173
173
 
174
174
  function App() @{
175
- let &[a] = track(1);
176
- let &[b] = track(2);
177
- let &[c] = track(3);
178
- let &[obj] = track(
179
- () => ({
180
- a,
181
- b,
182
- c,
183
- }),
184
- );
175
+ const a = track(1);
176
+ const b = track(2);
177
+ const c = track(3);
178
+ const obj = { a, b, c };
185
179
  <>
186
180
  <Child {...obj} />
187
181
  <button
188
182
  onClick={() => {
189
- a++;
190
- b++;
191
- c++;
183
+ a.value++;
184
+ b.value++;
185
+ c.value++;
192
186
  }}
193
187
  >{'Increment all'}</button>
194
188
  </>
195
189
  }
196
190
 
197
- function Child(&{ a, b, c }: { a: number; b: number; c: number }) @{
191
+ function Child({ a, b, c }: { a: Tracked<number>; b: Tracked<number>; c: Tracked<number> }) @{
198
192
  effect(() => {
199
- logs.push(`Child effect: ${a}, ${b}, ${c}`);
193
+ logs.push(`Child effect: ${a.value}, ${b.value}, ${c.value}`);
200
194
  });
201
- <div>{a + ' ' + b + ' ' + c}</div>
195
+ <div>{a.value + ' ' + b.value + ' ' + c.value}</div>
202
196
  }
203
197
 
204
198
  render(App);
@@ -215,10 +209,10 @@ describe('composite > reactivity', () => {
215
209
  expect(logs).toEqual(['Child effect: 1, 2, 3', 'Child effect: 2, 3, 4']);
216
210
  });
217
211
 
218
- it('keeps reactivity for spread props via intermediate components and lazy destructuring', () => {
212
+ it('keeps reactivity for spread props via intermediate components and destructured props', () => {
219
213
  function App() @{
220
- let &[count] = track(0);
221
- <CounterWrapper {count} up={() => count++} down={() => count--} />
214
+ const count = track(0);
215
+ <CounterWrapper count={count} up={() => count.value++} down={() => count.value--} />
222
216
  }
223
217
 
224
218
  function CounterWrapper(props: Props) @{
@@ -227,11 +221,11 @@ describe('composite > reactivity', () => {
227
221
  </div>
228
222
  }
229
223
 
230
- function Counter(&{ count, up, down, ...rest }: Props) @{
224
+ function Counter({ count, up, down, ...rest }: Props) @{
231
225
  <>
232
226
  <button onClick={() => up()}>{'UP'}</button>
233
227
  <button onClick={() => down()}>{'DOWN'}</button>
234
- <span {...rest}>{`Counter: ${count}`}</span>
228
+ <span {...rest}>{`Counter: ${count.value}`}</span>
235
229
  </>
236
230
  }
237
231
 
@@ -256,46 +250,51 @@ describe('composite > reactivity', () => {
256
250
 
257
251
  it('keeps reactivity on elements for element spreads and adds / removes dynamic props', () => {
258
252
  function App() @{
259
- let &[count] = track(0);
260
- <CounterWrapper {count} up={() => count++} />
253
+ const count = track(0);
254
+ <CounterWrapper count={count} up={() => count.value++} />
261
255
  }
262
256
 
263
- function CounterWrapper(props: { count: number; up: () => void }) @{
257
+ function CounterWrapper(props: { count: Tracked<number>; up: () => void }) @{
264
258
  const more: {
265
- double: Tracked<number>;
259
+ double: Derived<number>;
266
260
  another?: number;
267
261
  extra: number;
268
262
  } = new RippleObject({
269
- double: track(() => props.count * 2),
263
+ double: track(() => props.count.value * 2),
270
264
  another: 0,
271
265
  extra: 100,
272
266
  });
273
267
  effect(() => {
274
- props.count;
275
- if (props.count === 1) {
268
+ const count = props.count.value;
269
+ if (count === 1) {
276
270
  delete more.another;
277
- } else if (props.count === 2) {
271
+ } else if (count === 2) {
278
272
  more.another = 0;
279
273
  }
280
274
  });
281
275
  <div>
282
- <Counter {...props} double={more.double} another={more.another} extra={more.extra} />
276
+ <Counter
277
+ {...props}
278
+ double={more.double}
279
+ another={track(() => more.another)}
280
+ extra={more.extra}
281
+ />
283
282
  </div>
284
283
  }
285
284
 
286
- function Counter(&{
285
+ function Counter({
287
286
  count,
288
287
  up,
289
288
  ...rest
290
289
  }: {
291
- count: number;
290
+ count: Tracked<number>;
292
291
  up: () => void;
293
- double: Tracked<number>;
294
- another?: number;
292
+ double: Derived<number>;
293
+ another: Derived<number | undefined>;
295
294
  extra: number;
296
295
  }) @{
297
296
  <>
298
- <div {...rest}>{`Counter: ${count} Double: ${rest.double.value}`}</div>
297
+ <div {...rest}>{`Counter: ${count.value} Double: ${rest.double.value}`}</div>
299
298
  <button onClick={() => up()}>{'UP'}</button>
300
299
  </>
301
300
  }
@@ -1,16 +1,16 @@
1
- import { RippleArray, flushSync, track, type Component } from 'ripple';
1
+ import { RippleArray, flushSync, track, type Component, type Tracked } from 'ripple';
2
2
 
3
3
  describe('composite > render', () => {
4
4
  it('renders composite components', () => {
5
- function Button(&{ count }: { count: number }) @{
6
- <div>{count}</div>
5
+ function Button({ count }: { count: Tracked<number> }) @{
6
+ <div>{count.value}</div>
7
7
  }
8
8
 
9
9
  function App() @{
10
- let &[count] = track(0);
10
+ const count = track(0);
11
11
  <>
12
- <button onClick={() => count++}>{'Increment'}</button>
13
- <Button {count} />
12
+ <button onClick={() => count.value++}>{'Increment'}</button>
13
+ <Button count={count} />
14
14
  </>
15
15
  }
16
16
 
@@ -164,7 +164,7 @@ describe('composite > render', () => {
164
164
  });
165
165
 
166
166
  it('should not render <undefined> tag when a passed in component is undefined', () => {
167
- function Child(&{
167
+ function Child({
168
168
  children,
169
169
  NonExistent,
170
170
  ...props
@@ -176,8 +176,8 @@ describe('composite > render', () => {
176
176
  <div {...props}>
177
177
  {children}
178
178
 
179
- <NonExistent />
180
179
  // @ts-expect-error - intentionally testing behavior when a component is undefined
180
+ <NonExistent />
181
181
  </div>
182
182
  }
183
183
 
@@ -193,11 +193,28 @@ describe('composite > render', () => {
193
193
  expect(undefinedTag).toBeNull();
194
194
  expect(div.innerHTML).not.toContain('<undefined');
195
195
  });
196
+
197
+ it('renders nothing for a local or imported component value that is undefined', () => {
198
+ const pick = (): Component | undefined => undefined;
199
+
200
+ function App() @{
201
+ const Local = pick();
202
+ <div>
203
+ {'before'}
204
+ <Local />
205
+ {'after'}
206
+ </div>
207
+ }
208
+
209
+ render(App);
210
+
211
+ expect(container.querySelector('div').textContent).toBe('beforeafter');
212
+ });
196
213
  });
197
214
 
198
215
  describe('scoped styles with children', () => {
199
216
  it('generates correct CSS hashes for wrapper and child with empty style in App', () => {
200
- function Wrapper(&{ children }: { children?: Component }) @{
217
+ function Wrapper({ children }: { children?: Component }) @{
201
218
  <>
202
219
  <div class="green">
203
220
  {'Wrapper'}
@@ -51,9 +51,9 @@ const bundle = <style apply={[two, accent]} />;
51
51
  describe('sibling-scoped style blocks', () => {
52
52
  it('styles the items beside a block and everything below them, never the container', () => {
53
53
  function Status() @{
54
- let &[ready] = track(false);
54
+ const ready = track(false);
55
55
  <>
56
- <button onClick={() => (ready = !ready)}>{'toggle'}</button>
56
+ <button onClick={() => (ready.value = !ready.value)}>{'toggle'}</button>
57
57
  <style>
58
58
  .status {
59
59
  padding: 0.5rem;
@@ -69,7 +69,7 @@ describe('sibling-scoped style blocks', () => {
69
69
  }
70
70
  </style>
71
71
  <h2 id="title" class="title">{'Status'}</h2>
72
- @if (ready) {
72
+ @if (ready.value) {
73
73
  <>
74
74
  <style>
75
75
  .ok {
@@ -325,7 +325,7 @@ export function Status({ ready }: { ready: boolean }) @{
325
325
  );
326
326
 
327
327
  it('adds the scope classes of an element that spreads its props, one token per scope', () => {
328
- function Button(&{ ...rest }: { id: string; class?: string }) @{
328
+ function Button({ ...rest }: { id: string; class?: string }) @{
329
329
  <>
330
330
  <style>
331
331
  button {
@@ -356,7 +356,7 @@ export function Status({ ready }: { ready: boolean }) @{
356
356
  });
357
357
 
358
358
  it('keeps the scope classes of a static class when a spread brings its own class', () => {
359
- function Card(&{ ...rest }: { class?: string }) @{
359
+ function Card({ ...rest }: { class?: string }) @{
360
360
  <>
361
361
  <style apply={importedTheme}>
362
362
  .box {
@@ -387,15 +387,15 @@ export function Status({ ready }: { ready: boolean }) @{
387
387
 
388
388
  it('keeps the scope classes while a dynamic class value changes', () => {
389
389
  function App() @{
390
- let &[active] = track(false);
390
+ const active = track(false);
391
391
  <>
392
392
  <style>
393
393
  .on {
394
394
  color: green;
395
395
  }
396
396
  </style>
397
- <button id="toggle" onClick={() => (active = !active)}>{'toggle'}</button>
398
- <p id="p" class={active ? 'on' : 'off'}>{'p'}</p>
397
+ <button id="toggle" onClick={() => (active.value = !active.value)}>{'toggle'}</button>
398
+ <p id="p" class={active.value ? 'on' : 'off'}>{'p'}</p>
399
399
  </>
400
400
  }
401
401
 
@@ -4,10 +4,10 @@ describe('RippleDate', () => {
4
4
  it('handles getTime() with reactive updates', () => {
5
5
  function DateTest() @{
6
6
  let date = new RippleDate(2025, 0, 1);
7
- let &[time] = track(() => date.getTime());
7
+ const time = track(() => date.getTime());
8
8
  <>
9
9
  <button onClick={() => date.setFullYear(2026)}>{'Change Year'}</button>
10
- <pre>{time}</pre>
10
+ <pre>{time.value}</pre>
11
11
  </>
12
12
  }
13
13
 
@@ -27,10 +27,10 @@ describe('RippleDate', () => {
27
27
  it('handles getFullYear() with reactive updates', () => {
28
28
  function DateTest() @{
29
29
  let date = new RippleDate(2025, 5, 15);
30
- let &[year] = track(() => date.getFullYear());
30
+ const year = track(() => date.getFullYear());
31
31
  <>
32
32
  <button onClick={() => date.setFullYear(2030)}>{'Change Year'}</button>
33
- <pre>{year}</pre>
33
+ <pre>{year.value}</pre>
34
34
  </>
35
35
  }
36
36
 
@@ -49,10 +49,10 @@ describe('RippleDate', () => {
49
49
  it('handles getMonth() with reactive updates', () => {
50
50
  function DateTest() @{
51
51
  let date = new RippleDate(2025, 0, 15);
52
- let &[month] = track(() => date.getMonth());
52
+ const month = track(() => date.getMonth());
53
53
  <>
54
54
  <button onClick={() => date.setMonth(11)}>{'Change to December'}</button>
55
- <pre>{month}</pre>
55
+ <pre>{month.value}</pre>
56
56
  </>
57
57
  }
58
58
 
@@ -71,10 +71,10 @@ describe('RippleDate', () => {
71
71
  it('handles getDate() with reactive updates', () => {
72
72
  function DateTest() @{
73
73
  let date = new RippleDate(2025, 0, 1);
74
- let &[day] = track(() => date.getDate());
74
+ const day = track(() => date.getDate());
75
75
  <>
76
76
  <button onClick={() => date.setDate(15)}>{'Change Day'}</button>
77
- <pre>{day}</pre>
77
+ <pre>{day.value}</pre>
78
78
  </>
79
79
  }
80
80
 
@@ -93,10 +93,10 @@ describe('RippleDate', () => {
93
93
  it('handles getDay() with reactive updates', () => {
94
94
  function DateTest() @{
95
95
  let date = new RippleDate(2025, 0, 1);
96
- let &[dayOfWeek] = track(() => date.getDay());
96
+ const dayOfWeek = track(() => date.getDay());
97
97
  <>
98
98
  <button onClick={() => date.setDate(2)}>{'Next Day'}</button>
99
- <pre>{dayOfWeek}</pre>
99
+ <pre>{dayOfWeek.value}</pre>
100
100
  </>
101
101
  }
102
102
 
@@ -115,10 +115,10 @@ describe('RippleDate', () => {
115
115
  it('handles getHours() with reactive updates', () => {
116
116
  function DateTest() @{
117
117
  let date = new RippleDate(2025, 0, 1, 10, 30, 0);
118
- let &[hours] = track(() => date.getHours());
118
+ const hours = track(() => date.getHours());
119
119
  <>
120
120
  <button onClick={() => date.setHours(15)}>{'Change to 3 PM'}</button>
121
- <pre>{hours}</pre>
121
+ <pre>{hours.value}</pre>
122
122
  </>
123
123
  }
124
124
 
@@ -137,10 +137,10 @@ describe('RippleDate', () => {
137
137
  it('handles getMinutes() with reactive updates', () => {
138
138
  function DateTest() @{
139
139
  let date = new RippleDate(2025, 0, 1, 10, 15, 0);
140
- let &[minutes] = track(() => date.getMinutes());
140
+ const minutes = track(() => date.getMinutes());
141
141
  <>
142
142
  <button onClick={() => date.setMinutes(45)}>{'Change Minutes'}</button>
143
- <pre>{minutes}</pre>
143
+ <pre>{minutes.value}</pre>
144
144
  </>
145
145
  }
146
146
 
@@ -159,10 +159,10 @@ describe('RippleDate', () => {
159
159
  it('handles getSeconds() with reactive updates', () => {
160
160
  function DateTest() @{
161
161
  let date = new RippleDate(2025, 0, 1, 10, 15, 30);
162
- let &[seconds] = track(() => date.getSeconds());
162
+ const seconds = track(() => date.getSeconds());
163
163
  <>
164
164
  <button onClick={() => date.setSeconds(45)}>{'Change Seconds'}</button>
165
- <pre>{seconds}</pre>
165
+ <pre>{seconds.value}</pre>
166
166
  </>
167
167
  }
168
168
 
@@ -181,10 +181,10 @@ describe('RippleDate', () => {
181
181
  it('handles toISOString() with reactive updates', () => {
182
182
  function DateTest() @{
183
183
  let date = new RippleDate(2025, 0, 1, 12, 0, 0);
184
- let &[isoString] = track(() => date.toISOString());
184
+ const isoString = track(() => date.toISOString());
185
185
  <>
186
186
  <button onClick={() => date.setFullYear(2026)}>{'Change Year'}</button>
187
- <pre>{isoString}</pre>
187
+ <pre>{isoString.value}</pre>
188
188
  </>
189
189
  }
190
190
 
@@ -208,10 +208,10 @@ describe('RippleDate', () => {
208
208
  it('handles toDateString() with reactive updates', () => {
209
209
  function DateTest() @{
210
210
  let date = new RippleDate(2025, 0, 1);
211
- let &[dateString] = track(() => date.toDateString());
211
+ const dateString = track(() => date.toDateString());
212
212
  <>
213
213
  <button onClick={() => date.setMonth(11)}>{'Change to December'}</button>
214
- <pre>{dateString}</pre>
214
+ <pre>{dateString.value}</pre>
215
215
  </>
216
216
  }
217
217
 
@@ -233,10 +233,10 @@ describe('RippleDate', () => {
233
233
  it('handles valueOf() with reactive updates', () => {
234
234
  function DateTest() @{
235
235
  let date = new RippleDate(2025, 0, 1);
236
- let &[valueOf] = track(() => date.valueOf());
236
+ const valueOf = track(() => date.valueOf());
237
237
  <>
238
238
  <button onClick={() => date.setDate(2)}>{'Next Day'}</button>
239
- <pre>{valueOf}</pre>
239
+ <pre>{valueOf.value}</pre>
240
240
  </>
241
241
  }
242
242
 
@@ -256,29 +256,29 @@ describe('RippleDate', () => {
256
256
  it('handles multiple get methods reacting to same setTime change', () => {
257
257
  function DateTest() @{
258
258
  let date = new RippleDate(2025, 0, 1, 10, 30, 15);
259
- let &[year] = track(() => date.getFullYear());
260
- let &[month] = track(() => date.getMonth());
261
- let &[day] = track(() => date.getDate());
262
- let &[hours] = track(() => date.getHours());
259
+ const year = track(() => date.getFullYear());
260
+ const month = track(() => date.getMonth());
261
+ const day = track(() => date.getDate());
262
+ const hours = track(() => date.getHours());
263
263
  <>
264
264
  <button
265
265
  onClick={() => date.setTime(new Date(2026, 5, 15, 14, 45, 30).getTime())}
266
266
  >{'Change All'}</button>
267
267
  <div>
268
268
  {'Year: '}
269
- {year}
269
+ {year.value}
270
270
  </div>
271
271
  <div>
272
272
  {'Month: '}
273
- {month}
273
+ {month.value}
274
274
  </div>
275
275
  <div>
276
276
  {'Day: '}
277
- {day}
277
+ {day.value}
278
278
  </div>
279
279
  <div>
280
280
  {'Hours: '}
281
- {hours}
281
+ {hours.value}
282
282
  </div>
283
283
  </>
284
284
  }
@@ -308,26 +308,26 @@ describe('RippleDate', () => {
308
308
  let dateFromString = new RippleDate('2025-01-01');
309
309
  let dateFromNumbers = new RippleDate(2025, 0, 1);
310
310
  let dateFromTimestamp = new RippleDate(1735689600000);
311
- let &[nowYear] = track(() => dateNow.getFullYear());
312
- let &[stringYear] = track(() => dateFromString.getFullYear());
313
- let &[numbersYear] = track(() => dateFromNumbers.getFullYear());
314
- let &[timestampYear] = track(() => dateFromTimestamp.getFullYear());
311
+ const nowYear = track(() => dateNow.getFullYear());
312
+ const stringYear = track(() => dateFromString.getFullYear());
313
+ const numbersYear = track(() => dateFromNumbers.getFullYear());
314
+ const timestampYear = track(() => dateFromTimestamp.getFullYear());
315
315
  <>
316
316
  <div>
317
317
  {'Now: '}
318
- {nowYear}
318
+ {nowYear.value}
319
319
  </div>
320
320
  <div>
321
321
  {'String: '}
322
- {stringYear}
322
+ {stringYear.value}
323
323
  </div>
324
324
  <div>
325
325
  {'Numbers: '}
326
- {numbersYear}
326
+ {numbersYear.value}
327
327
  </div>
328
328
  <div>
329
329
  {'Timestamp: '}
330
- {timestampYear}
330
+ {timestampYear.value}
331
331
  </div>
332
332
  </>
333
333
  }
@@ -354,17 +354,17 @@ describe('RippleDate', () => {
354
354
  it('handles get methods with arguments non-memoized', () => {
355
355
  function DateTest() @{
356
356
  let date = new RippleDate();
357
- let &[localeDateString] = track(() => date.toLocaleDateString('en-US'));
358
- let &[localeTimeString] = track(() => date.toLocaleTimeString('en-US'));
357
+ const localeDateString = track(() => date.toLocaleDateString('en-US'));
358
+ const localeTimeString = track(() => date.toLocaleTimeString('en-US'));
359
359
  <>
360
360
  <button onClick={() => date.setFullYear(date.getFullYear() + 1)}>{'Next Year'}</button>
361
361
  <div>
362
362
  {'Date: '}
363
- {localeDateString}
363
+ {localeDateString.value}
364
364
  </div>
365
365
  <div>
366
366
  {'Time: '}
367
- {localeTimeString}
367
+ {localeTimeString.value}
368
368
  </div>
369
369
  </>
370
370
  }