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,22 +1,20 @@
1
- import { track } from 'ripple';
1
+ import { Dynamic, track } from 'ripple';
2
2
  import type { Component, PropsWithChildren, PropsWithExtras } from 'ripple';
3
3
 
4
4
  describe('SVG namespace handling', () => {
5
5
  it('should render static SVG elements with correct namespace', () => {
6
- function App() {
7
- return <>
8
- <svg
9
- xmlns="http://www.w3.org/2000/svg"
10
- width="24"
11
- height="24"
12
- fill="none"
13
- stroke="currentColor"
14
- >
15
- <path d="m14 12 4 4 4-4" />
16
- <circle cx="12" cy="12" r="4" />
17
- <rect x="4" y="4" width="16" height="16" />
18
- </svg>
19
- </>;
6
+ function App() @{
7
+ <svg
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ width="24"
10
+ height="24"
11
+ fill="none"
12
+ stroke="currentColor"
13
+ >
14
+ <path d="m14 12 4 4 4-4" />
15
+ <circle cx="12" cy="12" r="4" />
16
+ <rect x="4" y="4" width="16" height="16" />
17
+ </svg>
20
18
  }
21
19
 
22
20
  render(App);
@@ -42,26 +40,24 @@ describe('SVG namespace handling', () => {
42
40
  });
43
41
 
44
42
  it('should render dynamic SVG paths with for loop (original issue)', () => {
45
- function App() {
46
- return <>
47
- const d = [
48
- 'm14 12 4 4 4-4',
49
- 'M18 16V7',
50
- 'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
51
- 'M3.304 13h6.392',
52
- ];
53
- <svg
54
- xmlns="http://www.w3.org/2000/svg"
55
- width="24"
56
- height="24"
57
- fill="none"
58
- stroke="currentColor"
59
- >
60
- for (const pathData of d) {
61
- <path d={pathData} />
62
- }
63
- </svg>
64
- </>;
43
+ function App() @{
44
+ const d = [
45
+ 'm14 12 4 4 4-4',
46
+ 'M18 16V7',
47
+ 'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
48
+ 'M3.304 13h6.392',
49
+ ];
50
+ <svg
51
+ xmlns="http://www.w3.org/2000/svg"
52
+ width="24"
53
+ height="24"
54
+ fill="none"
55
+ stroke="currentColor"
56
+ >
57
+ @for (const pathData of d) {
58
+ <path d={pathData} />
59
+ }
60
+ </svg>
65
61
  }
66
62
 
67
63
  render(App);
@@ -95,23 +91,21 @@ describe('SVG namespace handling', () => {
95
91
  });
96
92
 
97
93
  it('should handle mixed static and dynamic SVG elements', () => {
98
- function App() {
99
- return <>
100
- const dynamicPaths = ['M12 2L2 7v10c0 5.55 3.84 10 9 11 5.16-1 9-5.45 9-11V7l-10-5z'];
101
- <svg
102
- xmlns="http://www.w3.org/2000/svg"
103
- width="24"
104
- height="24"
105
- fill="none"
106
- stroke="currentColor"
107
- >
108
- <circle cx="12" cy="12" r="10" />
109
- for (const pathData of dynamicPaths) {
110
- <path d={pathData} />
111
- }
112
- <rect x="4" y="4" width="16" height="16" />
113
- </svg>
114
- </>;
94
+ function App() @{
95
+ const dynamicPaths = ['M12 2L2 7v10c0 5.55 3.84 10 9 11 5.16-1 9-5.45 9-11V7l-10-5z'];
96
+ <svg
97
+ xmlns="http://www.w3.org/2000/svg"
98
+ width="24"
99
+ height="24"
100
+ fill="none"
101
+ stroke="currentColor"
102
+ >
103
+ <circle cx="12" cy="12" r="10" />
104
+ @for (const pathData of dynamicPaths) {
105
+ <path d={pathData} />
106
+ }
107
+ <rect x="4" y="4" width="16" height="16" />
108
+ </svg>
115
109
  }
116
110
 
117
111
  render(App);
@@ -134,20 +128,18 @@ describe('SVG namespace handling', () => {
134
128
  });
135
129
 
136
130
  it('should handle nested SVG groups with for loops', () => {
137
- function App() {
138
- return <>
139
- const items = [
140
- { x: '10', y: '10', width: '20', height: '20' },
141
- { x: '40', y: '40', width: '20', height: '20' },
142
- ];
143
- <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
144
- <g fill="blue">
145
- for (const item of items) {
146
- <rect x={item.x} y={item.y} width={item.width} height={item.height} />
147
- }
148
- </g>
149
- </svg>
150
- </>;
131
+ function App() @{
132
+ const items = [
133
+ { x: '10', y: '10', width: '20', height: '20' },
134
+ { x: '40', y: '40', width: '20', height: '20' },
135
+ ];
136
+ <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
137
+ <g fill="blue">
138
+ @for (const item of items) {
139
+ <rect x={item.x} y={item.y} width={item.width} height={item.height} />
140
+ }
141
+ </g>
142
+ </svg>
151
143
  }
152
144
 
153
145
  render(App);
@@ -173,17 +165,15 @@ describe('SVG namespace handling', () => {
173
165
  });
174
166
 
175
167
  it('should handle SVG class attributes correctly', () => {
176
- function App() {
177
- return <>
178
- let className = 'svg-element';
179
- const paths = ['M10 10 L20 20'];
180
- <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" class={className}>
181
- for (const pathData of paths) {
182
- <path d={pathData} class="dynamic-path" />
183
- }
184
- <circle cx="50" cy="50" r="10" class={className} />
185
- </svg>
186
- </>;
168
+ function App() @{
169
+ let className = 'svg-element';
170
+ const paths = ['M10 10 L20 20'];
171
+ <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" class={className}>
172
+ @for (const pathData of paths) {
173
+ <path d={pathData} class="dynamic-path" />
174
+ }
175
+ <circle cx="50" cy="50" r="10" class={className} />
176
+ </svg>
187
177
  }
188
178
 
189
179
  render(App);
@@ -208,16 +198,14 @@ describe('SVG namespace handling', () => {
208
198
  });
209
199
 
210
200
  it('should handle namespace transitions with foreignObject', () => {
211
- function App() {
212
- return <>
213
- <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
214
- <rect x="10" y="10" width="50" height="50" fill="red" />
215
- <foreignObject x="100" y="100" width="80" height="80">
216
- <div class="html-content">{'HTML inside SVG'}</div>
217
- </foreignObject>
218
- <circle cx="50" cy="150" r="20" fill="blue" />
219
- </svg>
220
- </>;
201
+ function App() @{
202
+ <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
203
+ <rect x="10" y="10" width="50" height="50" fill="red" />
204
+ <foreignObject x="100" y="100" width="80" height="80">
205
+ <div class="html-content">{'HTML inside SVG'}</div>
206
+ </foreignObject>
207
+ <circle cx="50" cy="150" r="20" fill="blue" />
208
+ </svg>
221
209
  }
222
210
 
223
211
  render(App);
@@ -240,25 +228,25 @@ describe('SVG namespace handling', () => {
240
228
  });
241
229
 
242
230
  it('should render SVG with children as svg elements', () => {
243
- function SVG({ children }: PropsWithChildren<{}>) {
244
- return <>
245
- <svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
246
- {children}
247
- </svg>
248
- </>;
231
+ function SVG({ children }: PropsWithChildren<{}>) @{
232
+ <svg
233
+ width={20}
234
+ height={20}
235
+ fill="blue"
236
+ viewBox="0 0 30 10"
237
+ preserveAspectRatio="none"
238
+ >{children}</svg>
249
239
  }
250
240
 
251
- function App() {
252
- return <>
253
- let isDiamond = true;
254
- <SVG>
255
- if (isDiamond) {
256
- <polygon points="0,0 30,0 15,10" />
257
- } else {
258
- <polygon points="0,0 30,0 15,10" />
259
- }
260
- </SVG>
261
- </>;
241
+ function App() @{
242
+ let isDiamond = true;
243
+ <SVG>
244
+ @if (isDiamond) {
245
+ <polygon points="0,0 30,0 15,10" />
246
+ } @else {
247
+ <polygon points="0,0 30,0 15,10" />
248
+ }
249
+ </SVG>
262
250
  }
263
251
 
264
252
  render(App);
@@ -271,20 +259,18 @@ describe('SVG namespace handling', () => {
271
259
  });
272
260
 
273
261
  it('should render SVG with props as svg elements', () => {
274
- function SVG({ Polygon }: PropsWithExtras<{ Polygon: Component }>) {
275
- return <>
276
- <svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
277
- <Polygon />
278
- </svg>
279
- </>;
262
+ function SVG({ Polygon }: PropsWithExtras<{ Polygon: Component }>) @{
263
+ <svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
264
+ <Polygon />
265
+ </svg>
280
266
  }
281
267
 
282
- function App() {
283
- return <><SVG {Polygon} /></>;
268
+ function App() @{
269
+ <SVG {Polygon} />
284
270
  }
285
271
 
286
- function Polygon() {
287
- return <><polygon points="0,0 30,0 15,10" /></>;
272
+ function Polygon() @{
273
+ <polygon points="0,0 30,0 15,10" />
288
274
  }
289
275
 
290
276
  render(App);
@@ -297,21 +283,21 @@ describe('SVG namespace handling', () => {
297
283
  });
298
284
 
299
285
  it('should render SVG with children as dynamic elements', () => {
300
- function SVG({ children }: PropsWithChildren<{}>) {
301
- return <>
302
- <svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
303
- {children}
304
- </svg>
305
- </>;
286
+ function SVG({ children }: PropsWithChildren<{}>) @{
287
+ <svg
288
+ width={20}
289
+ height={20}
290
+ fill="blue"
291
+ viewBox="0 0 30 10"
292
+ preserveAspectRatio="none"
293
+ >{children}</svg>
306
294
  }
307
295
 
308
- function App() {
309
- return <>
310
- let &[dynTag] = track('polygon');
311
- <SVG>
312
- <@dynTag points="0,0 30,0 15,10" />
313
- </SVG>
314
- </>;
296
+ function App() @{
297
+ let &[dynTag] = track('polygon');
298
+ <SVG>
299
+ <Dynamic is={dynTag} points="0,0 30,0 15,10" />
300
+ </SVG>
315
301
  }
316
302
 
317
303
  render(App);
@@ -324,25 +310,25 @@ describe('SVG namespace handling', () => {
324
310
  });
325
311
 
326
312
  it('should render SVG with children as dynamic components', () => {
327
- function SVG({ children }: PropsWithChildren<{}>) {
328
- return <>
329
- <svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
330
- {children}
331
- </svg>
332
- </>;
313
+ function SVG({ children }: PropsWithChildren<{}>) @{
314
+ <svg
315
+ width={20}
316
+ height={20}
317
+ fill="blue"
318
+ viewBox="0 0 30 10"
319
+ preserveAspectRatio="none"
320
+ >{children}</svg>
333
321
  }
334
322
 
335
- function Polygon({ points }: PropsWithExtras<{ points: string }>) {
336
- return <><polygon {points} /></>;
323
+ function Polygon({ points }: PropsWithExtras<{ points: string }>) @{
324
+ <polygon {points} />
337
325
  }
338
326
 
339
- function App() {
340
- return <>
341
- let &[Component] = track(() => Polygon);
342
- <SVG>
343
- <@Component points="0,0 30,0 15,10" />
344
- </SVG>
345
- </>;
327
+ function App() @{
328
+ let &[Component] = track(() => Polygon);
329
+ <SVG>
330
+ <Dynamic is={Component} points="0,0 30,0 15,10" />
331
+ </SVG>
346
332
  }
347
333
 
348
334
  render(App);
@@ -355,29 +341,28 @@ describe('SVG namespace handling', () => {
355
341
  });
356
342
 
357
343
  it('should render SVG as a dynamic top element with any dynamic children elements', () => {
358
- function SVG({ children }: PropsWithChildren<{}>) {
359
- return <>
360
- let &[tag] = track('svg');
361
- <@tag width={100} height={50} fill="red" viewBox="0 0 30 10" preserveAspectRatio="none">
362
- {children}
363
- </@tag>
364
- </>;
344
+ function SVG({ children }: PropsWithChildren<{}>) @{
345
+ let &[tag] = track('svg');
346
+ <Dynamic
347
+ is={tag}
348
+ width={100}
349
+ height={50}
350
+ fill="red"
351
+ viewBox="0 0 30 10"
352
+ preserveAspectRatio="none"
353
+ >{children}</Dynamic>
365
354
  }
366
355
 
367
- function Polygon({ points }: PropsWithExtras<{ points: string }>) {
368
- return <>
369
- let &[dynTag] = track('polygon');
370
- <@dynTag {points} />
371
- </>;
356
+ function Polygon({ points }: PropsWithExtras<{ points: string }>) @{
357
+ let &[dynTag] = track('polygon');
358
+ <Dynamic is={dynTag} {points} />
372
359
  }
373
360
 
374
- function App() {
375
- return <>
376
- let &[Component] = track(() => Polygon);
377
- <SVG>
378
- <@Component points="0,0 30,0 15,10" />
379
- </SVG>
380
- </>;
361
+ function App() @{
362
+ let &[Component] = track(() => Polygon);
363
+ <SVG>
364
+ <Dynamic is={Component} points="0,0 30,0 15,10" />
365
+ </SVG>
381
366
  }
382
367
 
383
368
  render(App);
@@ -390,43 +375,41 @@ describe('SVG namespace handling', () => {
390
375
  });
391
376
 
392
377
  it('should compare static vs dynamic SVG rendering (original problem case)', () => {
393
- function App() {
394
- return <>
395
- const d = [
396
- 'm14 12 4 4 4-4',
397
- 'M18 16V7',
398
- 'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
399
- 'M3.304 13h6.392',
400
- ];
401
- <div class="container">
402
- <svg
403
- xmlns="http://www.w3.org/2000/svg"
404
- width="24"
405
- height="24"
406
- fill="none"
407
- stroke="currentColor"
408
- class="dynamic-svg"
409
- >
410
- for (const path of d) {
411
- <path d={path} />
412
- }
413
- </svg>
414
-
415
- <svg
416
- xmlns="http://www.w3.org/2000/svg"
417
- width="24"
418
- height="24"
419
- fill="none"
420
- stroke="currentColor"
421
- class="static-svg"
422
- >
423
- <path d="m14 12 4 4 4-4" />
424
- <path d="M18 16V7" />
425
- <path d="m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" />
426
- <path d="M3.304 13h6.392" />
427
- </svg>
428
- </div>
429
- </>;
378
+ function App() @{
379
+ const d = [
380
+ 'm14 12 4 4 4-4',
381
+ 'M18 16V7',
382
+ 'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
383
+ 'M3.304 13h6.392',
384
+ ];
385
+ <div class="container">
386
+ <svg
387
+ xmlns="http://www.w3.org/2000/svg"
388
+ width="24"
389
+ height="24"
390
+ fill="none"
391
+ stroke="currentColor"
392
+ class="dynamic-svg"
393
+ >
394
+ @for (const path of d) {
395
+ <path d={path} />
396
+ }
397
+ </svg>
398
+
399
+ <svg
400
+ xmlns="http://www.w3.org/2000/svg"
401
+ width="24"
402
+ height="24"
403
+ fill="none"
404
+ stroke="currentColor"
405
+ class="static-svg"
406
+ >
407
+ <path d="m14 12 4 4 4-4" />
408
+ <path d="M18 16V7" />
409
+ <path d="m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" />
410
+ <path d="M3.304 13h6.392" />
411
+ </svg>
412
+ </div>
430
413
  }
431
414
 
432
415
  render(App);
@@ -469,26 +452,24 @@ describe('SVG namespace handling', () => {
469
452
  });
470
453
 
471
454
  it('should render dynamic SVG elements dispatched via a switch inside a for loop', () => {
472
- function App() {
473
- return <>
474
- const iconNodes: [string, Record<string, string>][] = [
475
- ['path', { d: 'm14 12 4 4 4-4' }],
476
- ['circle', { cx: '12', cy: '12', r: '4' }],
477
- ['path', { d: 'M18 16V7' }],
478
- ];
479
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
480
- for (const [tag, attrs] of iconNodes) {
481
- switch (tag) {
482
- case 'path':
483
- <path {...attrs} />
484
- break;
485
- case 'circle':
486
- <circle {...attrs} />
487
- break;
455
+ function App() @{
456
+ const iconNodes: [string, Record<string, string>][] = [
457
+ ['path', { d: 'm14 12 4 4 4-4' }],
458
+ ['circle', { cx: '12', cy: '12', r: '4' }],
459
+ ['path', { d: 'M18 16V7' }],
460
+ ];
461
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
462
+ @for (const [tag, attrs] of iconNodes) {
463
+ @switch (tag) {
464
+ @case 'path': {
465
+ <path {...attrs} />
466
+ }
467
+ @case 'circle': {
468
+ <circle {...attrs} />
488
469
  }
489
470
  }
490
- </svg>
491
- </>;
471
+ }
472
+ </svg>
492
473
  }
493
474
 
494
475
  render(App);