ripple 0.3.72 → 0.3.76

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 (172) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +4 -10
  4. package/src/runtime/dynamic-client.js +33 -0
  5. package/src/runtime/dynamic-server.js +80 -0
  6. package/src/runtime/index-client.js +5 -13
  7. package/src/runtime/index-server.js +2 -0
  8. package/src/runtime/internal/client/blocks.js +6 -27
  9. package/src/runtime/internal/client/composite.js +11 -6
  10. package/src/runtime/internal/client/for.js +80 -5
  11. package/src/runtime/internal/client/index.js +0 -2
  12. package/src/runtime/internal/client/render.js +5 -2
  13. package/src/runtime/internal/client/types.d.ts +0 -10
  14. package/src/runtime/internal/server/index.js +8 -1
  15. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  16. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  18. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  19. package/tests/client/array/array.derived.test.tsrx +97 -109
  20. package/tests/client/array/array.iteration.test.tsrx +28 -28
  21. package/tests/client/array/array.mutations.test.tsrx +68 -68
  22. package/tests/client/array/array.static.test.tsrx +82 -92
  23. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  24. package/tests/client/async-suspend.test.tsrx +180 -179
  25. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  26. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  27. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  28. package/tests/client/basic/basic.collections.test.tsrx +55 -61
  29. package/tests/client/basic/basic.components.test.tsrx +198 -220
  30. package/tests/client/basic/basic.errors.test.tsrx +70 -76
  31. package/tests/client/basic/basic.events.test.tsrx +80 -85
  32. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  33. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  34. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  35. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  36. package/tests/client/basic/basic.styling.test.tsrx +16 -14
  37. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  38. package/tests/client/boundaries.test.tsrx +18 -18
  39. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  40. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  41. package/tests/client/compiler/compiler.basic.test.tsrx +357 -288
  42. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  44. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  45. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  46. package/tests/client/composite/composite.dynamic-components.test.tsrx +62 -47
  47. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  48. package/tests/client/composite/composite.props.test.tsrx +66 -74
  49. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  50. package/tests/client/composite/composite.render.test.tsrx +92 -101
  51. package/tests/client/computed-properties.test.tsrx +14 -18
  52. package/tests/client/context.test.tsrx +14 -18
  53. package/tests/client/css/global-additional-cases.test.tsrx +493 -439
  54. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  55. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  56. package/tests/client/css/global-basic.test.tsrx +105 -98
  57. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  58. package/tests/client/css/global-combinators.test.tsrx +83 -78
  59. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  60. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  61. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  62. package/tests/client/css/global-nested.test.tsrx +88 -78
  63. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  64. package/tests/client/css/global-scoping.test.tsrx +145 -125
  65. package/tests/client/css/style-identifier.test.tsrx +65 -72
  66. package/tests/client/date.test.tsrx +83 -83
  67. package/tests/client/dynamic-elements.test.tsrx +318 -299
  68. package/tests/client/events.test.tsrx +252 -266
  69. package/tests/client/for.test.tsrx +120 -127
  70. package/tests/client/head.test.tsrx +74 -48
  71. package/tests/client/html.test.tsrx +37 -49
  72. package/tests/client/input-value.test.tsrx +1125 -1354
  73. package/tests/client/lazy-array.test.tsrx +10 -16
  74. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  75. package/tests/client/map.test.tsrx +39 -41
  76. package/tests/client/media-query.test.tsrx +15 -19
  77. package/tests/client/object.test.tsrx +46 -56
  78. package/tests/client/portal.test.tsrx +31 -37
  79. package/tests/client/ref.test.tsrx +173 -193
  80. package/tests/client/return.test.tsrx +62 -37
  81. package/tests/client/set.test.tsrx +33 -33
  82. package/tests/client/svg.test.tsrx +197 -216
  83. package/tests/client/switch.test.tsrx +201 -191
  84. package/tests/client/track-async-hydration.test.tsrx +14 -18
  85. package/tests/client/tracked-index-access.test.tsrx +18 -28
  86. package/tests/client/try.test.tsrx +494 -619
  87. package/tests/client/tsx.test.tsrx +286 -292
  88. package/tests/client/typescript-generics.test.tsrx +121 -129
  89. package/tests/client/url/url.derived.test.tsrx +21 -25
  90. package/tests/client/url/url.parsing.test.tsrx +35 -35
  91. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  92. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  93. package/tests/client/url/url.serialization.test.tsrx +8 -8
  94. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  95. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  96. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  97. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  98. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  99. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  100. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  101. package/tests/hydration/compiled/client/basic.js +390 -319
  102. package/tests/hydration/compiled/client/composite.js +52 -44
  103. package/tests/hydration/compiled/client/for.js +734 -604
  104. package/tests/hydration/compiled/client/head.js +183 -103
  105. package/tests/hydration/compiled/client/html.js +93 -86
  106. package/tests/hydration/compiled/client/if-children.js +95 -71
  107. package/tests/hydration/compiled/client/if.js +113 -89
  108. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  109. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  110. package/tests/hydration/compiled/client/reactivity.js +26 -24
  111. package/tests/hydration/compiled/client/return.js +8 -42
  112. package/tests/hydration/compiled/client/switch.js +208 -173
  113. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  114. package/tests/hydration/compiled/client/try.js +29 -21
  115. package/tests/hydration/compiled/server/basic.js +210 -221
  116. package/tests/hydration/compiled/server/composite.js +13 -14
  117. package/tests/hydration/compiled/server/for.js +427 -444
  118. package/tests/hydration/compiled/server/head.js +199 -189
  119. package/tests/hydration/compiled/server/html.js +33 -41
  120. package/tests/hydration/compiled/server/if-children.js +114 -117
  121. package/tests/hydration/compiled/server/if.js +77 -83
  122. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  123. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  124. package/tests/hydration/compiled/server/reactivity.js +24 -22
  125. package/tests/hydration/compiled/server/return.js +6 -18
  126. package/tests/hydration/compiled/server/switch.js +179 -176
  127. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  128. package/tests/hydration/compiled/server/try.js +31 -35
  129. package/tests/hydration/components/basic.tsrx +216 -258
  130. package/tests/hydration/components/composite.tsrx +32 -42
  131. package/tests/hydration/components/events.tsrx +81 -101
  132. package/tests/hydration/components/for.tsrx +270 -336
  133. package/tests/hydration/components/head.tsrx +43 -39
  134. package/tests/hydration/components/hmr.tsrx +16 -22
  135. package/tests/hydration/components/html-in-template.tsrx +15 -21
  136. package/tests/hydration/components/html.tsrx +442 -526
  137. package/tests/hydration/components/if-children.tsrx +107 -125
  138. package/tests/hydration/components/if.tsrx +68 -90
  139. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  140. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  141. package/tests/hydration/components/portal.tsrx +33 -41
  142. package/tests/hydration/components/reactivity.tsrx +26 -34
  143. package/tests/hydration/components/return.tsrx +4 -6
  144. package/tests/hydration/components/switch.tsrx +73 -78
  145. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  146. package/tests/hydration/components/try.tsrx +37 -51
  147. package/tests/hydration/switch.test.js +8 -8
  148. package/tests/server/await.test.tsrx +3 -3
  149. package/tests/server/basic.attributes.test.tsrx +117 -162
  150. package/tests/server/basic.components.test.tsrx +164 -194
  151. package/tests/server/basic.test.tsrx +299 -199
  152. package/tests/server/compiler.test.tsrx +142 -72
  153. package/tests/server/composite.props.test.tsrx +54 -58
  154. package/tests/server/composite.test.tsrx +165 -167
  155. package/tests/server/context.test.tsrx +13 -17
  156. package/tests/server/dynamic-elements.test.tsrx +147 -148
  157. package/tests/server/for.test.tsrx +115 -84
  158. package/tests/server/head.test.tsrx +54 -31
  159. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  160. package/tests/server/if.test.tsrx +49 -59
  161. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  162. package/tests/server/return.test.tsrx +58 -36
  163. package/tests/server/streaming-ssr.test.tsrx +4 -4
  164. package/tests/server/style-identifier.test.tsrx +61 -69
  165. package/tests/server/switch.test.tsrx +89 -97
  166. package/tests/server/track-async-serialization.test.tsrx +85 -103
  167. package/tests/server/try.test.tsrx +275 -360
  168. package/tests/utils/ref-types.test.js +72 -0
  169. package/tests/utils/vite-plugin-config.test.js +41 -74
  170. package/types/index.d.ts +29 -4
  171. package/src/runtime/internal/client/compat.js +0 -40
  172. 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);