ripple 0.3.71 → 0.3.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -8
  4. package/src/runtime/index-client.js +3 -13
  5. package/src/runtime/internal/client/blocks.js +3 -25
  6. package/src/runtime/internal/client/for.js +80 -5
  7. package/src/runtime/internal/client/index.js +0 -2
  8. package/src/runtime/internal/client/types.d.ts +0 -10
  9. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  10. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  11. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  12. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  13. package/tests/client/array/array.derived.test.tsrx +97 -109
  14. package/tests/client/array/array.iteration.test.tsrx +28 -28
  15. package/tests/client/array/array.mutations.test.tsrx +68 -68
  16. package/tests/client/array/array.static.test.tsrx +82 -92
  17. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  18. package/tests/client/async-suspend.test.tsrx +180 -179
  19. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  20. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  21. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  22. package/tests/client/basic/basic.collections.test.tsrx +59 -71
  23. package/tests/client/basic/basic.components.test.tsrx +196 -222
  24. package/tests/client/basic/basic.errors.test.tsrx +72 -78
  25. package/tests/client/basic/basic.events.test.tsrx +80 -85
  26. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  27. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  28. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  29. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  30. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  31. package/tests/client/boundaries.test.tsrx +18 -18
  32. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  33. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  34. package/tests/client/compiler/compiler.basic.test.tsrx +364 -296
  35. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  36. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  37. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  38. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  39. package/tests/client/composite/composite.dynamic-components.test.tsrx +41 -44
  40. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  41. package/tests/client/composite/composite.props.test.tsrx +66 -74
  42. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  43. package/tests/client/composite/composite.render.test.tsrx +92 -101
  44. package/tests/client/computed-properties.test.tsrx +14 -18
  45. package/tests/client/context.test.tsrx +14 -18
  46. package/tests/client/css/global-additional-cases.test.tsrx +491 -437
  47. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  48. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  49. package/tests/client/css/global-basic.test.tsrx +105 -98
  50. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  51. package/tests/client/css/global-combinators.test.tsrx +83 -78
  52. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  53. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  54. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  55. package/tests/client/css/global-nested.test.tsrx +88 -78
  56. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  57. package/tests/client/css/global-scoping.test.tsrx +145 -125
  58. package/tests/client/css/style-identifier.test.tsrx +62 -69
  59. package/tests/client/date.test.tsrx +83 -83
  60. package/tests/client/dynamic-elements.test.tsrx +227 -283
  61. package/tests/client/events.test.tsrx +252 -266
  62. package/tests/client/for.test.tsrx +120 -127
  63. package/tests/client/head.test.tsrx +40 -48
  64. package/tests/client/html.test.tsrx +37 -49
  65. package/tests/client/input-value.test.tsrx +1125 -1354
  66. package/tests/client/lazy-array.test.tsrx +10 -16
  67. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  68. package/tests/client/map.test.tsrx +39 -41
  69. package/tests/client/media-query.test.tsrx +15 -19
  70. package/tests/client/object.test.tsrx +46 -56
  71. package/tests/client/portal.test.tsrx +31 -37
  72. package/tests/client/ref.test.tsrx +173 -193
  73. package/tests/client/return.test.tsrx +62 -37
  74. package/tests/client/set.test.tsrx +33 -33
  75. package/tests/client/svg.test.tsrx +195 -215
  76. package/tests/client/switch.test.tsrx +201 -191
  77. package/tests/client/track-async-hydration.test.tsrx +14 -18
  78. package/tests/client/tracked-index-access.test.tsrx +18 -28
  79. package/tests/client/try.test.tsrx +494 -619
  80. package/tests/client/tsx.test.tsrx +290 -371
  81. package/tests/client/typescript-generics.test.tsrx +121 -129
  82. package/tests/client/url/url.derived.test.tsrx +21 -25
  83. package/tests/client/url/url.parsing.test.tsrx +35 -35
  84. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  85. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  86. package/tests/client/url/url.serialization.test.tsrx +8 -8
  87. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  88. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  89. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  90. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  91. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  92. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  93. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  94. package/tests/hydration/compiled/client/basic.js +396 -325
  95. package/tests/hydration/compiled/client/composite.js +52 -44
  96. package/tests/hydration/compiled/client/for.js +734 -604
  97. package/tests/hydration/compiled/client/head.js +183 -103
  98. package/tests/hydration/compiled/client/html.js +93 -86
  99. package/tests/hydration/compiled/client/if-children.js +95 -71
  100. package/tests/hydration/compiled/client/if.js +113 -89
  101. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  102. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  103. package/tests/hydration/compiled/client/reactivity.js +26 -24
  104. package/tests/hydration/compiled/client/return.js +8 -42
  105. package/tests/hydration/compiled/client/switch.js +208 -173
  106. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  107. package/tests/hydration/compiled/client/try.js +29 -21
  108. package/tests/hydration/compiled/server/basic.js +210 -221
  109. package/tests/hydration/compiled/server/composite.js +13 -14
  110. package/tests/hydration/compiled/server/for.js +427 -444
  111. package/tests/hydration/compiled/server/head.js +199 -189
  112. package/tests/hydration/compiled/server/html.js +33 -41
  113. package/tests/hydration/compiled/server/if-children.js +114 -117
  114. package/tests/hydration/compiled/server/if.js +77 -83
  115. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  116. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  117. package/tests/hydration/compiled/server/reactivity.js +24 -22
  118. package/tests/hydration/compiled/server/return.js +6 -18
  119. package/tests/hydration/compiled/server/switch.js +179 -176
  120. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  121. package/tests/hydration/compiled/server/try.js +31 -35
  122. package/tests/hydration/components/basic.tsrx +216 -286
  123. package/tests/hydration/components/composite.tsrx +32 -42
  124. package/tests/hydration/components/events.tsrx +81 -101
  125. package/tests/hydration/components/for.tsrx +270 -336
  126. package/tests/hydration/components/head.tsrx +43 -39
  127. package/tests/hydration/components/hmr.tsrx +16 -22
  128. package/tests/hydration/components/html-in-template.tsrx +15 -21
  129. package/tests/hydration/components/html.tsrx +442 -526
  130. package/tests/hydration/components/if-children.tsrx +107 -125
  131. package/tests/hydration/components/if.tsrx +68 -90
  132. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  133. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  134. package/tests/hydration/components/portal.tsrx +33 -41
  135. package/tests/hydration/components/reactivity.tsrx +26 -34
  136. package/tests/hydration/components/return.tsrx +4 -6
  137. package/tests/hydration/components/switch.tsrx +73 -78
  138. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  139. package/tests/hydration/components/try.tsrx +37 -51
  140. package/tests/hydration/switch.test.js +8 -8
  141. package/tests/server/await.test.tsrx +3 -3
  142. package/tests/server/basic.attributes.test.tsrx +120 -167
  143. package/tests/server/basic.components.test.tsrx +163 -197
  144. package/tests/server/basic.test.tsrx +298 -220
  145. package/tests/server/compiler.test.tsrx +142 -72
  146. package/tests/server/composite.props.test.tsrx +54 -58
  147. package/tests/server/composite.test.tsrx +165 -167
  148. package/tests/server/context.test.tsrx +13 -17
  149. package/tests/server/dynamic-elements.test.tsrx +103 -135
  150. package/tests/server/for.test.tsrx +115 -84
  151. package/tests/server/head.test.tsrx +31 -31
  152. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  153. package/tests/server/if.test.tsrx +49 -59
  154. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  155. package/tests/server/return.test.tsrx +58 -36
  156. package/tests/server/streaming-ssr.test.tsrx +4 -4
  157. package/tests/server/style-identifier.test.tsrx +58 -66
  158. package/tests/server/switch.test.tsrx +89 -97
  159. package/tests/server/track-async-serialization.test.tsrx +85 -103
  160. package/tests/server/try.test.tsrx +275 -360
  161. package/tests/utils/ref-types.test.js +72 -0
  162. package/tests/utils/vite-plugin-config.test.js +41 -74
  163. package/types/index.d.ts +1 -0
  164. package/src/runtime/internal/client/compat.js +0 -40
  165. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -1,4 +1,4 @@
1
- import type { PropsWithExtras } from 'ripple';
1
+ import type { PropsWithExtras, RefValue } from 'ripple';
2
2
  import { describe, it, expect } from 'vitest';
3
3
  import { RippleArray, createRefKey, effect, flushSync, isRefProp, track } from 'ripple';
4
4
  import type { Tracked } from 'ripple';
@@ -13,14 +13,12 @@ describe('refs', () => {
13
13
  it('captures a host element with ref={...}', () => {
14
14
  let captured: HTMLInputElement | null = null;
15
15
 
16
- function App() {
17
- return <>
18
- let input: HTMLInputElement | undefined;
19
- <input type="text" ref={input} />
20
- effect(() => {
21
- captured = input ?? null;
22
- });
23
- </>;
16
+ function App() @{
17
+ let input: HTMLInputElement | undefined;
18
+ effect(() => {
19
+ captured = input ?? null;
20
+ });
21
+ <input type="text" ref={input} />
24
22
  }
25
23
 
26
24
  render(App);
@@ -32,12 +30,16 @@ describe('refs', () => {
32
30
  it('forwards a named ref prop explicitly through a component', () => {
33
31
  let captured: HTMLInputElement | null = null;
34
32
 
35
- function Child(props: PropsWithExtras<{}>) {
36
- return <><input type="text" ref={props.input_ref} /></>;
33
+ function Child(props: PropsWithExtras<{ input_ref: RefValue<HTMLInputElement> }>) @{
34
+ <input type="text" ref={props.input_ref} />
37
35
  }
38
36
 
39
- function App() {
40
- return <><Child input_ref={(node: HTMLInputElement | null) => (captured = node)} /></>;
37
+ function App() @{
38
+ <Child
39
+ input_ref={(node: HTMLInputElement | null) => {
40
+ captured = node;
41
+ }}
42
+ />
41
43
  }
42
44
 
43
45
  render(App);
@@ -49,15 +51,17 @@ describe('refs', () => {
49
51
  it('forwards an ordinary named prop explicitly from a host spread', () => {
50
52
  let captured: HTMLInputElement | null = null;
51
53
 
52
- function Child(props: PropsWithExtras<{}>) {
53
- return <>
54
- const { input_ref, ...rest } = props;
55
- <input type="text" ref={input_ref} {...rest} />
56
- </>;
54
+ function Child(props: PropsWithExtras<{ input_ref: RefValue<HTMLInputElement> }>) @{
55
+ const { input_ref, ...rest } = props;
56
+ <input type="text" ref={input_ref} {...rest} />
57
57
  }
58
58
 
59
- function App() {
60
- return <><Child input_ref={(node: HTMLInputElement | null) => (captured = node)} /></>;
59
+ function App() @{
60
+ <Child
61
+ input_ref={(node: HTMLInputElement | null) => {
62
+ captured = node;
63
+ }}
64
+ />
61
65
  }
62
66
 
63
67
  render(App);
@@ -69,16 +73,12 @@ describe('refs', () => {
69
73
  it('capture a <div>', () => {
70
74
  let div: HTMLDivElement | undefined;
71
75
 
72
- function Component() {
73
- return <>
74
- <div
75
- ref={(node: HTMLDivElement) => {
76
- div = node;
77
- }}
78
- >
79
- {'Hello World'}
80
- </div>
81
- </>;
76
+ function Component() @{
77
+ <div
78
+ ref={(node: HTMLDivElement) => {
79
+ div = node;
80
+ }}
81
+ >{'Hello World'}</div>
82
82
  }
83
83
  render(Component);
84
84
  flushSync();
@@ -86,25 +86,27 @@ describe('refs', () => {
86
86
  });
87
87
 
88
88
  it('works with spreading from composite component', () => {
89
- type Child = typeof Child;
90
- let _node: Child | undefined;
89
+ let _node: HTMLPreElement | undefined;
91
90
 
92
- function Component() {
93
- return <>
94
- let items = RippleArray.from([1, 2, 3]);
95
- function componentRef(node: Child) {
91
+ function Component() @{
92
+ let items = RippleArray.from([1, 2, 3]);
93
+ function componentRef(node: HTMLPreElement | null) {
94
+ if (node !== null) {
96
95
  _node = node;
97
96
  }
98
- <Child ref={componentRef} {items} />
99
- </>;
97
+ }
98
+ <Child ref={componentRef} {items} />
100
99
  }
101
100
 
102
- function Child(props: { items: RippleArray<number> }) {
103
- return <>
104
- const { items, ...rest } = props;
101
+ function Child(props: PropsWithExtras<{
102
+ items: RippleArray<number>;
103
+ ref?: RefValue<HTMLPreElement>;
104
+ }>) @{
105
+ const { items, ...rest } = props;
106
+ <>
105
107
  <pre {...rest}>{JSON.stringify(items)}</pre>
106
108
  <pre>{items.length}</pre>
107
- </>;
109
+ </>
108
110
  }
109
111
 
110
112
  render(Component);
@@ -116,24 +118,24 @@ describe('refs', () => {
116
118
  it('should handle spreading into composite refs', () => {
117
119
  let logs: string[] = [];
118
120
 
119
- function App() {
120
- return <>
121
- let &[value] = track('test');
122
- function inputRef(node: HTMLInputElement) {
123
- logs.push('ref called');
124
- }
125
- const props = {
126
- id: 'example',
127
- value,
128
- [createRefKey()]: inputRef,
129
- };
121
+ function App() @{
122
+ let &[value] = track('test');
123
+ function inputRef(node: HTMLInputElement) {
124
+ logs.push('ref called');
125
+ }
126
+ const props = {
127
+ id: 'example',
128
+ value,
129
+ [createRefKey()]: inputRef,
130
+ };
131
+ <>
130
132
  <input type="text" {...props} />
131
133
  <Input {...props} />
132
- </>;
134
+ </>
133
135
  }
134
136
 
135
- function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) {
136
- return <><input type="text" {id} {value} {...rest} /></>;
137
+ function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) @{
138
+ <input type="text" {id} {value} {...rest} />
137
139
  }
138
140
 
139
141
  render(App);
@@ -145,12 +147,10 @@ describe('refs', () => {
145
147
  it('captures a host element into a Tracked via ref={tracker}', () => {
146
148
  let captured: Tracked<HTMLDivElement | null> | undefined;
147
149
 
148
- function Component() {
149
- return <>
150
- const tracker = track<HTMLDivElement | null>(null);
151
- captured = tracker;
152
- <div ref={tracker}>{'Hello World'}</div>
153
- </>;
150
+ function Component() @{
151
+ const tracker = track<HTMLDivElement | null>(null);
152
+ captured = tracker;
153
+ <div ref={tracker}>{'Hello World'}</div>
154
154
  }
155
155
 
156
156
  render(Component);
@@ -162,16 +162,14 @@ describe('refs', () => {
162
162
  it('forwards a Tracked through a composite component via prop destructuring + spread', () => {
163
163
  let captured: Tracked<HTMLInputElement | null> | undefined;
164
164
 
165
- function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) {
166
- return <><input type="text" {id} {...rest} /></>;
165
+ function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) @{
166
+ <input type="text" {id} {...rest} />
167
167
  }
168
168
 
169
- function App() {
170
- return <>
171
- const tracker = track<HTMLInputElement | null>(null);
172
- captured = tracker;
173
- <Child id="example" ref={tracker} />
174
- </>;
169
+ function App() @{
170
+ const tracker = track<HTMLInputElement | null>(null);
171
+ captured = tracker;
172
+ <Child id="example" ref={tracker} />
175
173
  }
176
174
 
177
175
  render(App);
@@ -183,17 +181,15 @@ describe('refs', () => {
183
181
  it('assigns a host element to a plain let variable via ref={var}', () => {
184
182
  let captured: HTMLDivElement | null = null;
185
183
 
186
- function App() {
187
- return <>
188
- let div: HTMLDivElement | undefined;
189
- <div ref={div}>{'Hello World'}</div>
190
- // Read the captured element through an effect so the assertion
191
- // observes the post-mount value (component setup runs before the
192
- // element is created).
193
- effect(() => {
194
- captured = div ?? null;
195
- });
196
- </>;
184
+ function App() @{
185
+ let div: HTMLDivElement | undefined;
186
+ // Read the captured element through an effect so the assertion
187
+ // observes the post-mount value (component setup runs before the
188
+ // element is created).
189
+ effect(() => {
190
+ captured = div ?? null;
191
+ });
192
+ <div ref={div}>{'Hello World'}</div>
197
193
  }
198
194
 
199
195
  render(App);
@@ -205,14 +201,12 @@ describe('refs', () => {
205
201
  it('assigns a host element to a plain let variable via ref={var}', () => {
206
202
  let captured: HTMLDivElement | null = null;
207
203
 
208
- function App() {
209
- return <>
210
- let div: HTMLDivElement | undefined;
211
- <div ref={div}>{'Hello ref attr'}</div>
212
- effect(() => {
213
- captured = div ?? null;
214
- });
215
- </>;
204
+ function App() @{
205
+ let div: HTMLDivElement | undefined;
206
+ effect(() => {
207
+ captured = div ?? null;
208
+ });
209
+ <div ref={div}>{'Hello ref attr'}</div>
216
210
  }
217
211
 
218
212
  render(App);
@@ -224,14 +218,14 @@ describe('refs', () => {
224
218
  it('clears a plain let variable via ref={var} when the host element unmounts', () => {
225
219
  let div: HTMLDivElement | null | undefined;
226
220
 
227
- function App() {
228
- return <>
229
- let &[show] = track(true);
230
- if (show) {
221
+ function App() @{
222
+ let &[show] = track(true);
223
+ <>
224
+ @if (show) {
231
225
  <div ref={div}>{'Hello cleanup'}</div>
232
226
  }
233
227
  <button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
234
- </>;
228
+ </>
235
229
  }
236
230
 
237
231
  render(App);
@@ -246,14 +240,12 @@ describe('refs', () => {
246
240
  it('assigns a host element to a member expression via ref={state.var}', () => {
247
241
  let captured: HTMLInputElement | null = null;
248
242
 
249
- function App() {
250
- return <>
251
- const state: { input?: HTMLInputElement } = {};
252
- <input type="text" ref={state.input} />
253
- effect(() => {
254
- captured = state.input ?? null;
255
- });
256
- </>;
243
+ function App() @{
244
+ const state: { input?: HTMLInputElement } = {};
245
+ effect(() => {
246
+ captured = state.input ?? null;
247
+ });
248
+ <input type="text" ref={state.input} />
257
249
  }
258
250
 
259
251
  render(App);
@@ -265,18 +257,18 @@ describe('refs', () => {
265
257
  let input: HTMLInputElement | null | undefined;
266
258
  let previous: HTMLInputElement | undefined;
267
259
 
268
- function Child(props: PropsWithExtras<{}>) {
269
- return <><input type="text" value="keep" {...props} /></>;
260
+ function Child(props: PropsWithExtras<{}>) @{
261
+ <input type="text" value="keep" {...props} />
270
262
  }
271
263
 
272
- function App() {
273
- return <>
274
- let &[show] = track(true);
275
- if (show) {
264
+ function App() @{
265
+ let &[show] = track(true);
266
+ <>
267
+ @if (show) {
276
268
  <Child ref={input} />
277
269
  }
278
270
  <button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
279
- </>;
271
+ </>
280
272
  }
281
273
 
282
274
  render(App);
@@ -296,13 +288,11 @@ describe('refs', () => {
296
288
  () => {
297
289
  let logs: string[] = [];
298
290
 
299
- function App() {
300
- return <>
301
- let cb = (node: HTMLDivElement) => {
302
- logs.push(`mount:${node.textContent}`);
303
- };
304
- <div ref={cb}>{'Hello'}</div>
305
- </>;
291
+ function App() @{
292
+ let cb = (node: HTMLDivElement) => {
293
+ logs.push(`mount:${node.textContent}`);
294
+ };
295
+ <div ref={cb}>{'Hello'}</div>
306
296
  }
307
297
 
308
298
  render(App);
@@ -316,13 +306,11 @@ describe('refs', () => {
316
306
  () => {
317
307
  let captured: Tracked<HTMLDivElement | null> | undefined;
318
308
 
319
- function App() {
320
- return <>
321
- const tracker = track<HTMLDivElement | null>(null);
322
- let slot = tracker;
323
- captured = tracker;
324
- <div ref={slot}>{'Hello'}</div>
325
- </>;
309
+ function App() @{
310
+ const tracker = track<HTMLDivElement | null>(null);
311
+ let slot = tracker;
312
+ captured = tracker;
313
+ <div ref={slot}>{'Hello'}</div>
326
314
  }
327
315
 
328
316
  render(App);
@@ -334,18 +322,16 @@ describe('refs', () => {
334
322
  it('propagates a plain let variable through a composite component via {...rest}', () => {
335
323
  let captured: HTMLInputElement | null = null;
336
324
 
337
- function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) {
338
- return <><input type="text" {id} {...rest} /></>;
325
+ function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) @{
326
+ <input type="text" {id} {...rest} />
339
327
  }
340
328
 
341
- function App() {
342
- return <>
343
- let input: HTMLInputElement | undefined;
344
- <Child id="example" ref={input} />
345
- effect(() => {
346
- captured = input ?? null;
347
- });
348
- </>;
329
+ function App() @{
330
+ let input: HTMLInputElement | undefined;
331
+ effect(() => {
332
+ captured = input ?? null;
333
+ });
334
+ <Child id="example" ref={input} />
349
335
  }
350
336
 
351
337
  render(App);
@@ -361,14 +347,14 @@ describe('refs', () => {
361
347
  let input: HTMLInputElement | null | undefined;
362
348
  let previous: HTMLInputElement | undefined;
363
349
 
364
- function Child(props: PropsWithExtras<{}>) {
365
- return <><input type="text" value="keep" {...props} /></>;
350
+ function Child(props: PropsWithExtras<{}>) @{
351
+ <input type="text" value="keep" {...props} />
366
352
  }
367
353
 
368
- function App() {
369
- return <>
370
- let &[show] = track(true);
371
- if (show) {
354
+ function App() @{
355
+ let &[show] = track(true);
356
+ <>
357
+ @if (show) {
372
358
  <Child
373
359
  ref={(node: HTMLInputElement | null) => {
374
360
  input = node;
@@ -379,7 +365,7 @@ describe('refs', () => {
379
365
  />
380
366
  }
381
367
  <button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
382
- </>;
368
+ </>
383
369
  }
384
370
 
385
371
  render(App);
@@ -399,29 +385,27 @@ describe('refs', () => {
399
385
  let input: HTMLInputElement | null | undefined;
400
386
  let previous: HTMLInputElement | undefined;
401
387
 
402
- function Child(props: PropsWithExtras<{}>) {
403
- return <>
404
- let &[as_ref] = track(true);
388
+ function Child(props: PropsWithExtras<{ ref: RefValue<HTMLInputElement> }>) @{
389
+ let &[as_ref] = track(true);
390
+ <>
405
391
  <input
406
392
  type="text"
407
393
  value="keep"
408
394
  {...(as_ref ? { ref: props.ref } : { input_ref: 'regular prop' })}
409
395
  />
410
396
  <button class="toggle" onClick={() => (as_ref = false)}>{'toggle'}</button>
411
- </>;
397
+ </>
412
398
  }
413
399
 
414
- function App() {
415
- return <>
416
- <Child
417
- ref={(node: HTMLInputElement | null) => {
418
- input = node;
419
- return () => {
420
- input = null;
421
- };
422
- }}
423
- />
424
- </>;
400
+ function App() @{
401
+ <Child
402
+ ref={(node: HTMLInputElement | null) => {
403
+ input = node;
404
+ return () => {
405
+ input = null;
406
+ };
407
+ }}
408
+ />
425
409
  }
426
410
 
427
411
  render(App);
@@ -442,29 +426,27 @@ describe('refs', () => {
442
426
  let input: HTMLInputElement | null | undefined;
443
427
  let previous: HTMLInputElement | undefined;
444
428
 
445
- function Child(props: PropsWithExtras<{}>) {
446
- return <>
447
- let &[as_ref] = track(false);
429
+ function Child(props: PropsWithExtras<{ ref: RefValue<HTMLInputElement> }>) @{
430
+ let &[as_ref] = track(false);
431
+ <>
448
432
  <input
449
433
  type="text"
450
434
  value="keep"
451
435
  {...(as_ref ? { ref: props.ref } : { input_ref: 'regular prop' })}
452
436
  />
453
437
  <button class="toggle" onClick={() => (as_ref = true)}>{'toggle'}</button>
454
- </>;
438
+ </>
455
439
  }
456
440
 
457
- function App() {
458
- return <>
459
- <Child
460
- ref={(node: HTMLInputElement | null) => {
461
- input = node;
462
- return () => {
463
- input = null;
464
- };
465
- }}
466
- />
467
- </>;
441
+ function App() @{
442
+ <Child
443
+ ref={(node: HTMLInputElement | null) => {
444
+ input = node;
445
+ return () => {
446
+ input = null;
447
+ };
448
+ }}
449
+ />
468
450
  }
469
451
 
470
452
  render(App);
@@ -485,16 +467,14 @@ describe('refs', () => {
485
467
  let captured: Tracked<HTMLDivElement | null> | undefined;
486
468
  let toggle: Tracked<boolean> | undefined;
487
469
 
488
- function Component() {
489
- return <>
490
- const tracker = track<HTMLDivElement | null>(null);
491
- const show = track(true);
492
- captured = tracker;
493
- toggle = show;
494
- if (show.value) {
495
- <div ref={tracker}>{'Hello World'}</div>
496
- }
497
- </>;
470
+ function Component() @{
471
+ const tracker = track<HTMLDivElement | null>(null);
472
+ const show = track(true);
473
+ captured = tracker;
474
+ toggle = show;
475
+ @if (show.value) {
476
+ <div ref={tracker}>{'Hello World'}</div>
477
+ }
498
478
  }
499
479
 
500
480
  render(Component);
@@ -509,23 +489,23 @@ describe('refs', () => {
509
489
  it('should handle spreading props with a static ref', () => {
510
490
  let logs: string[] = [];
511
491
 
512
- function App() {
513
- return <>
514
- let &[value] = track('test');
515
- function inputRef(node: HTMLInputElement) {
516
- logs.push('ref called');
517
- }
518
- const props = {
519
- id: 'example',
520
- value,
521
- };
492
+ function App() @{
493
+ let &[value] = track('test');
494
+ function inputRef(node: HTMLInputElement) {
495
+ logs.push('ref called');
496
+ }
497
+ const props = {
498
+ id: 'example',
499
+ value,
500
+ };
501
+ <>
522
502
  <input type="text" ref={inputRef} {...props} />
523
503
  <Input ref={inputRef} {...props} />
524
- </>;
504
+ </>
525
505
  }
526
506
 
527
- function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) {
528
- return <><input type="text" {id} {value} {...rest} /></>;
507
+ function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) @{
508
+ <input type="text" {id} {value} {...rest} />
529
509
  }
530
510
 
531
511
  render(App);