ripple 0.3.72 → 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 +66 -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 +55 -61
  23. package/tests/client/basic/basic.components.test.tsrx +196 -218
  24. package/tests/client/basic/basic.errors.test.tsrx +70 -76
  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 +357 -288
  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 +286 -292
  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 +390 -319
  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 -258
  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 +117 -162
  143. package/tests/server/basic.components.test.tsrx +163 -193
  144. package/tests/server/basic.test.tsrx +298 -198
  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
@@ -3,20 +3,18 @@ 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
+ <@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
+ <@Component points="0,0 30,0 15,10" />
331
+ </SVG>
346
332
  }
347
333
 
348
334
  render(App);
@@ -355,29 +341,27 @@ 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
+ <@tag
347
+ width={100}
348
+ height={50}
349
+ fill="red"
350
+ viewBox="0 0 30 10"
351
+ preserveAspectRatio="none"
352
+ >{children}</@tag>
365
353
  }
366
354
 
367
- function Polygon({ points }: PropsWithExtras<{ points: string }>) {
368
- return <>
369
- let &[dynTag] = track('polygon');
370
- <@dynTag {points} />
371
- </>;
355
+ function Polygon({ points }: PropsWithExtras<{ points: string }>) @{
356
+ let &[dynTag] = track('polygon');
357
+ <@dynTag {points} />
372
358
  }
373
359
 
374
- function App() {
375
- return <>
376
- let &[Component] = track(() => Polygon);
377
- <SVG>
378
- <@Component points="0,0 30,0 15,10" />
379
- </SVG>
380
- </>;
360
+ function App() @{
361
+ let &[Component] = track(() => Polygon);
362
+ <SVG>
363
+ <@Component points="0,0 30,0 15,10" />
364
+ </SVG>
381
365
  }
382
366
 
383
367
  render(App);
@@ -390,43 +374,41 @@ describe('SVG namespace handling', () => {
390
374
  });
391
375
 
392
376
  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
- </>;
377
+ function App() @{
378
+ const d = [
379
+ 'm14 12 4 4 4-4',
380
+ 'M18 16V7',
381
+ 'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
382
+ 'M3.304 13h6.392',
383
+ ];
384
+ <div class="container">
385
+ <svg
386
+ xmlns="http://www.w3.org/2000/svg"
387
+ width="24"
388
+ height="24"
389
+ fill="none"
390
+ stroke="currentColor"
391
+ class="dynamic-svg"
392
+ >
393
+ @for (const path of d) {
394
+ <path d={path} />
395
+ }
396
+ </svg>
397
+
398
+ <svg
399
+ xmlns="http://www.w3.org/2000/svg"
400
+ width="24"
401
+ height="24"
402
+ fill="none"
403
+ stroke="currentColor"
404
+ class="static-svg"
405
+ >
406
+ <path d="m14 12 4 4 4-4" />
407
+ <path d="M18 16V7" />
408
+ <path d="m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" />
409
+ <path d="M3.304 13h6.392" />
410
+ </svg>
411
+ </div>
430
412
  }
431
413
 
432
414
  render(App);
@@ -469,26 +451,24 @@ describe('SVG namespace handling', () => {
469
451
  });
470
452
 
471
453
  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;
454
+ function App() @{
455
+ const iconNodes: [string, Record<string, string>][] = [
456
+ ['path', { d: 'm14 12 4 4 4-4' }],
457
+ ['circle', { cx: '12', cy: '12', r: '4' }],
458
+ ['path', { d: 'M18 16V7' }],
459
+ ];
460
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
461
+ @for (const [tag, attrs] of iconNodes) {
462
+ @switch (tag) {
463
+ @case 'path': {
464
+ <path {...attrs} />
465
+ }
466
+ @case 'circle': {
467
+ <circle {...attrs} />
488
468
  }
489
469
  }
490
- </svg>
491
- </>;
470
+ }
471
+ </svg>
492
472
  }
493
473
 
494
474
  render(App);