ripple 0.3.68 → 0.3.70

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 (182) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -2
  4. package/src/runtime/element.js +1 -1
  5. package/src/runtime/index-client.js +11 -11
  6. package/src/runtime/index-server.js +7 -4
  7. package/src/runtime/internal/client/bindings.js +1 -1
  8. package/src/runtime/internal/client/blocks.js +13 -4
  9. package/src/runtime/internal/client/component.js +55 -0
  10. package/src/runtime/internal/client/composite.js +4 -2
  11. package/src/runtime/internal/client/expression.js +65 -7
  12. package/src/runtime/internal/client/hmr.js +54 -43
  13. package/src/runtime/internal/client/index.js +5 -1
  14. package/src/runtime/internal/client/portal.js +70 -69
  15. package/src/runtime/internal/client/render.js +3 -0
  16. package/src/runtime/internal/server/index.js +92 -8
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +3 -3
  18. package/tests/client/array/array.copy-within.test.tsrx +33 -31
  19. package/tests/client/array/array.derived.test.tsrx +186 -169
  20. package/tests/client/array/array.iteration.test.tsrx +40 -37
  21. package/tests/client/array/array.mutations.test.tsrx +113 -101
  22. package/tests/client/array/array.static.test.tsrx +119 -101
  23. package/tests/client/array/array.to-methods.test.tsrx +24 -21
  24. package/tests/client/async-suspend.test.tsrx +247 -246
  25. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +0 -1
  26. package/tests/client/basic/basic.attributes.test.tsrx +428 -423
  27. package/tests/client/basic/basic.collections.test.tsrx +109 -102
  28. package/tests/client/basic/basic.components.test.tsrx +323 -205
  29. package/tests/client/basic/basic.errors.test.tsrx +91 -91
  30. package/tests/client/basic/basic.events.test.tsrx +114 -115
  31. package/tests/client/basic/basic.get-set.test.tsrx +97 -87
  32. package/tests/client/basic/basic.hmr.test.tsrx +19 -16
  33. package/tests/client/basic/basic.reactivity.test.tsrx +199 -191
  34. package/tests/client/basic/basic.rendering.test.tsrx +272 -182
  35. package/tests/client/basic/basic.styling.test.tsrx +23 -22
  36. package/tests/client/basic/basic.utilities.test.tsrx +10 -8
  37. package/tests/client/boundaries.test.tsrx +26 -26
  38. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +5 -5
  39. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +5 -5
  40. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -81
  41. package/tests/client/compiler/compiler.attributes.test.tsrx +15 -15
  42. package/tests/client/compiler/compiler.basic.test.tsrx +322 -314
  43. package/tests/client/compiler/compiler.regex.test.tsrx +44 -47
  44. package/tests/client/compiler/compiler.tracked-access.test.tsrx +38 -38
  45. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  46. package/tests/client/compiler/compiler.typescript.test.tsrx +2 -2
  47. package/tests/client/composite/composite.dynamic-components.test.tsrx +47 -48
  48. package/tests/client/composite/composite.generics.test.tsrx +168 -192
  49. package/tests/client/composite/composite.props.test.tsrx +97 -81
  50. package/tests/client/composite/composite.reactivity.test.tsrx +177 -147
  51. package/tests/client/composite/composite.render.test.tsrx +122 -105
  52. package/tests/client/computed-properties.test.tsrx +28 -28
  53. package/tests/client/context.test.tsrx +21 -21
  54. package/tests/client/css/global-additional-cases.test.tsrx +58 -58
  55. package/tests/client/css/global-advanced-selectors.test.tsrx +16 -16
  56. package/tests/client/css/global-at-rules.test.tsrx +10 -10
  57. package/tests/client/css/global-basic.test.tsrx +14 -14
  58. package/tests/client/css/global-classes-ids.test.tsrx +14 -14
  59. package/tests/client/css/global-combinators.test.tsrx +10 -10
  60. package/tests/client/css/global-complex-nesting.test.tsrx +14 -14
  61. package/tests/client/css/global-edge-cases.test.tsrx +18 -18
  62. package/tests/client/css/global-keyframes.test.tsrx +12 -12
  63. package/tests/client/css/global-nested.test.tsrx +10 -10
  64. package/tests/client/css/global-pseudo.test.tsrx +12 -12
  65. package/tests/client/css/global-scoping.test.tsrx +20 -20
  66. package/tests/client/css/style-identifier.test.tsrx +126 -259
  67. package/tests/client/date.test.tsrx +146 -133
  68. package/tests/client/dynamic-elements.test.tsrx +398 -365
  69. package/tests/client/events.test.tsrx +292 -290
  70. package/tests/client/for.test.tsrx +156 -153
  71. package/tests/client/head.test.tsrx +105 -96
  72. package/tests/client/html.test.tsrx +122 -26
  73. package/tests/client/input-value.test.tsrx +1361 -1314
  74. package/tests/client/lazy-array.test.tsrx +16 -13
  75. package/tests/client/lazy-destructuring.test.tsrx +257 -213
  76. package/tests/client/map.test.tsrx +65 -60
  77. package/tests/client/media-query.test.tsrx +22 -20
  78. package/tests/client/object.test.tsrx +87 -81
  79. package/tests/client/portal.test.tsrx +57 -51
  80. package/tests/client/ref.test.tsrx +233 -202
  81. package/tests/client/return.test.tsrx +71 -2560
  82. package/tests/client/set.test.tsrx +54 -45
  83. package/tests/client/svg.test.tsrx +216 -186
  84. package/tests/client/switch.test.tsrx +194 -193
  85. package/tests/client/track-async-hydration.test.tsrx +18 -14
  86. package/tests/client/tracked-index-access.test.tsrx +28 -18
  87. package/tests/client/try.test.tsrx +675 -548
  88. package/tests/client/tsx.test.tsrx +373 -311
  89. package/tests/client/typescript-generics.test.tsrx +145 -145
  90. package/tests/client/url/url.derived.test.tsrx +33 -28
  91. package/tests/client/url/url.parsing.test.tsrx +61 -51
  92. package/tests/client/url/url.partial-removal.test.tsrx +56 -48
  93. package/tests/client/url/url.reactivity.test.tsrx +142 -125
  94. package/tests/client/url/url.serialization.test.tsrx +13 -11
  95. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +34 -29
  96. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +25 -21
  97. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +50 -45
  98. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +111 -99
  99. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +49 -43
  100. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +14 -12
  101. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +16 -14
  102. package/tests/hydration/basic.test.js +3 -3
  103. package/tests/hydration/compiled/client/basic.js +586 -651
  104. package/tests/hydration/compiled/client/composite.js +79 -104
  105. package/tests/hydration/compiled/client/events.js +140 -148
  106. package/tests/hydration/compiled/client/for.js +1005 -1018
  107. package/tests/hydration/compiled/client/head.js +124 -134
  108. package/tests/hydration/compiled/client/hmr.js +41 -48
  109. package/tests/hydration/compiled/client/html-in-template.js +38 -41
  110. package/tests/hydration/compiled/client/html.js +970 -1314
  111. package/tests/hydration/compiled/client/if-children.js +234 -249
  112. package/tests/hydration/compiled/client/if.js +182 -189
  113. package/tests/hydration/compiled/client/mixed-control-flow.js +347 -303
  114. package/tests/hydration/compiled/client/nested-control-flow.js +1084 -832
  115. package/tests/hydration/compiled/client/portal.js +65 -85
  116. package/tests/hydration/compiled/client/reactivity.js +84 -90
  117. package/tests/hydration/compiled/client/return.js +38 -1939
  118. package/tests/hydration/compiled/client/switch.js +218 -224
  119. package/tests/hydration/compiled/client/track-async-serialization.js +250 -259
  120. package/tests/hydration/compiled/client/try.js +123 -132
  121. package/tests/hydration/compiled/server/basic.js +773 -831
  122. package/tests/hydration/compiled/server/composite.js +166 -191
  123. package/tests/hydration/compiled/server/events.js +170 -184
  124. package/tests/hydration/compiled/server/for.js +851 -909
  125. package/tests/hydration/compiled/server/head.js +206 -216
  126. package/tests/hydration/compiled/server/hmr.js +64 -72
  127. package/tests/hydration/compiled/server/html-in-template.js +42 -76
  128. package/tests/hydration/compiled/server/html.js +1362 -1667
  129. package/tests/hydration/compiled/server/if-children.js +419 -445
  130. package/tests/hydration/compiled/server/if.js +194 -208
  131. package/tests/hydration/compiled/server/mixed-control-flow.js +249 -257
  132. package/tests/hydration/compiled/server/nested-control-flow.js +491 -515
  133. package/tests/hydration/compiled/server/portal.js +152 -160
  134. package/tests/hydration/compiled/server/reactivity.js +94 -106
  135. package/tests/hydration/compiled/server/return.js +28 -2172
  136. package/tests/hydration/compiled/server/switch.js +274 -286
  137. package/tests/hydration/compiled/server/track-async-serialization.js +340 -358
  138. package/tests/hydration/compiled/server/try.js +167 -185
  139. package/tests/hydration/components/basic.tsrx +320 -272
  140. package/tests/hydration/components/composite.tsrx +44 -32
  141. package/tests/hydration/components/events.tsrx +101 -91
  142. package/tests/hydration/components/for.tsrx +510 -452
  143. package/tests/hydration/components/head.tsrx +87 -80
  144. package/tests/hydration/components/hmr.tsrx +22 -17
  145. package/tests/hydration/components/html-in-template.tsrx +22 -17
  146. package/tests/hydration/components/html.tsrx +525 -443
  147. package/tests/hydration/components/if-children.tsrx +158 -148
  148. package/tests/hydration/components/if.tsrx +109 -95
  149. package/tests/hydration/components/mixed-control-flow.tsrx +100 -96
  150. package/tests/hydration/components/nested-control-flow.tsrx +215 -203
  151. package/tests/hydration/components/portal.tsrx +41 -34
  152. package/tests/hydration/components/reactivity.tsrx +37 -27
  153. package/tests/hydration/components/return.tsrx +12 -556
  154. package/tests/hydration/components/switch.tsrx +120 -114
  155. package/tests/hydration/components/track-async-serialization.tsrx +107 -91
  156. package/tests/hydration/components/try.tsrx +55 -40
  157. package/tests/hydration/html.test.js +4 -4
  158. package/tests/hydration/return.test.js +13 -532
  159. package/tests/server/await.test.tsrx +3 -3
  160. package/tests/server/basic.attributes.test.tsrx +264 -195
  161. package/tests/server/basic.components.test.tsrx +296 -169
  162. package/tests/server/basic.test.tsrx +300 -198
  163. package/tests/server/compiler.test.tsrx +62 -60
  164. package/tests/server/composite.props.test.tsrx +77 -63
  165. package/tests/server/composite.test.tsrx +168 -192
  166. package/tests/server/context.test.tsrx +18 -12
  167. package/tests/server/dynamic-elements.test.tsrx +197 -180
  168. package/tests/server/for.test.tsrx +85 -78
  169. package/tests/server/head.test.tsrx +50 -43
  170. package/tests/server/html-nesting-validation.test.tsrx +8 -8
  171. package/tests/server/if.test.tsrx +57 -51
  172. package/tests/server/lazy-destructuring.test.tsrx +366 -294
  173. package/tests/server/return.test.tsrx +76 -1355
  174. package/tests/server/streaming-ssr.test.tsrx +4 -75
  175. package/tests/server/style-identifier.test.tsrx +169 -131
  176. package/tests/server/switch.test.tsrx +91 -85
  177. package/tests/server/track-async-serialization.test.tsrx +105 -85
  178. package/tests/server/try.test.tsrx +374 -280
  179. package/tests/utils/compiler-compat-config.test.js +2 -2
  180. package/tests/utils/runtime-imports.test.js +10 -0
  181. package/types/index.d.ts +8 -0
  182. package/tests/client/__snapshots__/html.test.rsrx.snap +0 -40
@@ -2,533 +2,591 @@ import { track } from 'ripple';
2
2
 
3
3
  // For loop components for hydration testing
4
4
 
5
- export component StaticForLoop() {
6
- const items = ['Apple', 'Banana', 'Cherry'];
7
- <ul>
8
- for (const item of items) {
9
- <li>{item}</li>
10
- }
11
- </ul>
5
+ export function StaticForLoop() {
6
+ return <>
7
+ const items = ['Apple', 'Banana', 'Cherry'];
8
+ <ul>
9
+ for (const item of items) {
10
+ <li>{item}</li>
11
+ }
12
+ </ul>
13
+ </>;
12
14
  }
13
15
 
14
- export component ForLoopWithIndex() {
15
- const items = ['A', 'B', 'C'];
16
- <ul>
17
- for (const item of items; index i) {
18
- <li>{`${i}: ${item}`}</li>
19
- }
20
- </ul>
16
+ export function ForLoopWithIndex() {
17
+ return <>
18
+ const items = ['A', 'B', 'C'];
19
+ <ul>
20
+ for (const item of items; index i) {
21
+ <li>{`${i}: ${item}`}</li>
22
+ }
23
+ </ul>
24
+ </>;
21
25
  }
22
26
 
23
- export component KeyedForLoop() {
24
- const items = [
25
- { id: 1, name: 'First' },
26
- { id: 2, name: 'Second' },
27
- { id: 3, name: 'Third' },
28
- ];
29
- <ul>
30
- for (const item of items; key item.id) {
31
- <li>{item.name}</li>
32
- }
33
- </ul>
27
+ export function KeyedForLoop() {
28
+ return <>
29
+ const items = [
30
+ { id: 1, name: 'First' },
31
+ { id: 2, name: 'Second' },
32
+ { id: 3, name: 'Third' },
33
+ ];
34
+ <ul>
35
+ for (const item of items; key item.id) {
36
+ <li>{item.name}</li>
37
+ }
38
+ </ul>
39
+ </>;
34
40
  }
35
41
 
36
- export component ReactiveForLoopAdd() {
37
- let &[items] = track(['A', 'B']);
38
- <button
39
- class="add"
40
- onClick={() => {
41
- items = [...items, 'C'];
42
- }}
43
- >
44
- {'Add'}
45
- </button>
46
- <ul>
47
- for (const item of items) {
48
- <li>{item}</li>
49
- }
50
- </ul>
42
+ export function ReactiveForLoopAdd() {
43
+ return <>
44
+ let &[items] = track(['A', 'B']);
45
+ <button
46
+ class="add"
47
+ onClick={() => {
48
+ items = [...items, 'C'];
49
+ }}
50
+ >
51
+ {'Add'}
52
+ </button>
53
+ <ul>
54
+ for (const item of items) {
55
+ <li>{item}</li>
56
+ }
57
+ </ul>
58
+ </>;
51
59
  }
52
60
 
53
- export component ReactiveForLoopRemove() {
54
- let &[items] = track(['A', 'B', 'C']);
55
- <button
56
- class="remove"
57
- onClick={() => {
58
- items = items.slice(0, -1);
59
- }}
60
- >
61
- {'Remove'}
62
- </button>
63
- <ul>
64
- for (const item of items) {
65
- <li>{item}</li>
66
- }
67
- </ul>
61
+ export function ReactiveForLoopRemove() {
62
+ return <>
63
+ let &[items] = track(['A', 'B', 'C']);
64
+ <button
65
+ class="remove"
66
+ onClick={() => {
67
+ items = items.slice(0, -1);
68
+ }}
69
+ >
70
+ {'Remove'}
71
+ </button>
72
+ <ul>
73
+ for (const item of items) {
74
+ <li>{item}</li>
75
+ }
76
+ </ul>
77
+ </>;
68
78
  }
69
79
 
70
- export component ForLoopInteractive() {
71
- let &[counts] = track([0, 0, 0]);
72
- <div>
73
- for (const count of counts; index i) {
74
- <div class={`item-${i}`}>
75
- <span class="value">{count}</span>
76
- <button
77
- class="increment"
78
- onClick={() => {
79
- const newCounts = [...counts];
80
- newCounts[i]++;
81
- counts = newCounts;
82
- }}
83
- >
84
- {'+'}
85
- </button>
86
- </div>
87
- }
88
- </div>
80
+ export function ForLoopInteractive() {
81
+ return <>
82
+ let &[counts] = track([0, 0, 0]);
83
+ <div>
84
+ for (const count of counts; index i) {
85
+ <div class={`item-${i}`}>
86
+ <span class="value">{count}</span>
87
+ <button
88
+ class="increment"
89
+ onClick={() => {
90
+ const newCounts = [...counts];
91
+ newCounts[i]++;
92
+ counts = newCounts;
93
+ }}
94
+ >
95
+ {'+'}
96
+ </button>
97
+ </div>
98
+ }
99
+ </div>
100
+ </>;
89
101
  }
90
102
 
91
- export component NestedForLoop() {
92
- const grid = [
93
- [1, 2],
94
- [3, 4],
95
- ];
96
- <div class="grid">
97
- for (const row of grid; index rowIndex) {
98
- <div class={`row-${rowIndex}`}>
99
- for (const cell of row; index colIndex) {
100
- <span class={`cell-${rowIndex}-${colIndex}`}>{cell}</span>
101
- }
102
- </div>
103
- }
104
- </div>
103
+ export function NestedForLoop() {
104
+ return <>
105
+ const grid = [
106
+ [1, 2],
107
+ [3, 4],
108
+ ];
109
+ <div class="grid">
110
+ for (const row of grid; index rowIndex) {
111
+ <div class={`row-${rowIndex}`}>
112
+ for (const cell of row; index colIndex) {
113
+ <span class={`cell-${rowIndex}-${colIndex}`}>{cell}</span>
114
+ }
115
+ </div>
116
+ }
117
+ </div>
118
+ </>;
105
119
  }
106
120
 
107
- export component EmptyForLoop() {
108
- const items: string[] = [];
109
- <div class="container">
110
- for (const item of items) {
111
- <span>{item}</span>
112
- }
113
- </div>
121
+ export function EmptyForLoop() {
122
+ return <>
123
+ const items: string[] = [];
124
+ <div class="container">
125
+ for (const item of items) {
126
+ <span>{item}</span>
127
+ }
128
+ </div>
129
+ </>;
114
130
  }
115
131
 
116
- export component ForLoopComplexObjects() {
117
- const users = [
118
- { id: 1, name: 'Alice', role: 'Admin' },
119
- { id: 2, name: 'Bob', role: 'User' },
120
- ];
121
- <div>
122
- for (const user of users; key user.id) {
123
- <div class={`user-${user.id}`}>
124
- <span class="name">{user.name}</span>
125
- <span class="role">{user.role}</span>
126
- </div>
127
- }
128
- </div>
132
+ export function ForLoopComplexObjects() {
133
+ return <>
134
+ const users = [
135
+ { id: 1, name: 'Alice', role: 'Admin' },
136
+ { id: 2, name: 'Bob', role: 'User' },
137
+ ];
138
+ <div>
139
+ for (const user of users; key user.id) {
140
+ <div class={`user-${user.id}`}>
141
+ <span class="name">{user.name}</span>
142
+ <span class="role">{user.role}</span>
143
+ </div>
144
+ }
145
+ </div>
146
+ </>;
129
147
  }
130
148
 
131
149
  // Test reordering items in a keyed for loop
132
- export component KeyedForLoopReorder() {
133
- let &[items] = track([
134
- { id: 1, name: 'First' },
135
- { id: 2, name: 'Second' },
136
- { id: 3, name: 'Third' },
137
- ]);
138
- <button
139
- class="reorder"
140
- onClick={() => {
141
- items = [items[2], items[0], items[1]];
142
- }}
143
- >
144
- {'Reorder'}
145
- </button>
146
- <ul>
147
- for (const item of items; key item.id) {
148
- <li class={`item-${item.id}`}>{item.name}</li>
149
- }
150
- </ul>
150
+ export function KeyedForLoopReorder() {
151
+ return <>
152
+ let &[items] = track([
153
+ { id: 1, name: 'First' },
154
+ { id: 2, name: 'Second' },
155
+ { id: 3, name: 'Third' },
156
+ ]);
157
+ <button
158
+ class="reorder"
159
+ onClick={() => {
160
+ items = [items[2], items[0], items[1]];
161
+ }}
162
+ >
163
+ {'Reorder'}
164
+ </button>
165
+ <ul>
166
+ for (const item of items; key item.id) {
167
+ <li class={`item-${item.id}`}>{item.name}</li>
168
+ }
169
+ </ul>
170
+ </>;
151
171
  }
152
172
 
153
173
  // Test for loop with item property updates (keyed)
154
- export component KeyedForLoopUpdate() {
155
- let &[items] = track([
156
- { id: 1, name: 'Item 1' },
157
- { id: 2, name: 'Item 2' },
158
- ]);
159
- <button
160
- class="update"
161
- onClick={() => {
162
- items = items.map((item) => (item.id === 1 ? { ...item, name: 'Updated' } : item));
163
- }}
164
- >
165
- {'Update'}
166
- </button>
167
- <ul>
168
- for (const item of items; key item.id) {
169
- <li class={`item-${item.id}`}>{item.name}</li>
170
- }
171
- </ul>
174
+ export function KeyedForLoopUpdate() {
175
+ return <>
176
+ let &[items] = track([
177
+ { id: 1, name: 'Item 1' },
178
+ { id: 2, name: 'Item 2' },
179
+ ]);
180
+ <button
181
+ class="update"
182
+ onClick={() => {
183
+ items = items.map((item) => (item.id === 1 ? { ...item, name: 'Updated' } : item));
184
+ }}
185
+ >
186
+ {'Update'}
187
+ </button>
188
+ <ul>
189
+ for (const item of items; key item.id) {
190
+ <li class={`item-${item.id}`}>{item.name}</li>
191
+ }
192
+ </ul>
193
+ </>;
172
194
  }
173
195
 
174
196
  // Test for loop with combined add/remove/reorder
175
- export component ForLoopMixedOperations() {
176
- let &[items] = track(['A', 'B', 'C', 'D']);
177
- <button
178
- class="shuffle"
179
- onClick={() => {
180
- // Remove B, add E, reorder to D, C, A, E
181
- items = ['D', 'C', 'A', 'E'];
182
- }}
183
- >
184
- {'Shuffle'}
185
- </button>
186
- <ul>
187
- for (const item of items) {
188
- <li class={`item-${item}`}>{item}</li>
189
- }
190
- </ul>
197
+ export function ForLoopMixedOperations() {
198
+ return <>
199
+ let &[items] = track(['A', 'B', 'C', 'D']);
200
+ <button
201
+ class="shuffle"
202
+ onClick={() => {
203
+ // Remove B, add E, reorder to D, C, A, E
204
+ items = ['D', 'C', 'A', 'E'];
205
+ }}
206
+ >
207
+ {'Shuffle'}
208
+ </button>
209
+ <ul>
210
+ for (const item of items) {
211
+ <li class={`item-${item}`}>{item}</li>
212
+ }
213
+ </ul>
214
+ </>;
191
215
  }
192
216
 
193
217
  // Test for loop inside if block (combined control flow)
194
- export component ForLoopInsideIf() {
195
- let &[showList] = track(true);
196
- let &[items] = track(['X', 'Y', 'Z']);
197
- <button
198
- class="toggle"
199
- onClick={() => {
200
- showList = !showList;
201
- }}
202
- >
203
- {'Toggle List'}
204
- </button>
205
- <button
206
- class="add"
207
- onClick={() => {
208
- items = [...items, 'W'];
209
- }}
210
- >
211
- {'Add Item'}
212
- </button>
213
- if (showList) {
218
+ export function ForLoopInsideIf() {
219
+ return <>
220
+ let &[showList] = track(true);
221
+ let &[items] = track(['X', 'Y', 'Z']);
222
+ <button
223
+ class="toggle"
224
+ onClick={() => {
225
+ showList = !showList;
226
+ }}
227
+ >
228
+ {'Toggle List'}
229
+ </button>
230
+ <button
231
+ class="add"
232
+ onClick={() => {
233
+ items = [...items, 'W'];
234
+ }}
235
+ >
236
+ {'Add Item'}
237
+ </button>
238
+ if (showList) {
239
+ <ul class="list">
240
+ for (const item of items) {
241
+ <li>{item}</li>
242
+ }
243
+ </ul>
244
+ }
245
+ </>;
246
+ }
247
+
248
+ // Test for loop that transitions from empty to populated
249
+ export function ForLoopEmptyToPopulated() {
250
+ return <>
251
+ let &[items] = track<string[]>([]);
252
+ <button
253
+ class="populate"
254
+ onClick={() => {
255
+ items = ['One', 'Two', 'Three'];
256
+ }}
257
+ >
258
+ {'Populate'}
259
+ </button>
214
260
  <ul class="list">
215
261
  for (const item of items) {
216
262
  <li>{item}</li>
217
263
  }
218
264
  </ul>
219
- }
220
- }
221
-
222
- // Test for loop that transitions from empty to populated
223
- export component ForLoopEmptyToPopulated() {
224
- let &[items] = track<string[]>([]);
225
- <button
226
- class="populate"
227
- onClick={() => {
228
- items = ['One', 'Two', 'Three'];
229
- }}
230
- >
231
- {'Populate'}
232
- </button>
233
- <ul class="list">
234
- for (const item of items) {
235
- <li>{item}</li>
236
- }
237
- </ul>
265
+ </>;
238
266
  }
239
267
 
240
268
  // Test for loop that transitions from populated to empty
241
- export component ForLoopPopulatedToEmpty() {
242
- let &[items] = track(['One', 'Two', 'Three']);
243
- <button
244
- class="clear"
245
- onClick={() => {
246
- items = [];
247
- }}
248
- >
249
- {'Clear'}
250
- </button>
251
- <ul class="list">
252
- for (const item of items) {
253
- <li>{item}</li>
254
- }
255
- </ul>
269
+ export function ForLoopPopulatedToEmpty() {
270
+ return <>
271
+ let &[items] = track(['One', 'Two', 'Three']);
272
+ <button
273
+ class="clear"
274
+ onClick={() => {
275
+ items = [];
276
+ }}
277
+ >
278
+ {'Clear'}
279
+ </button>
280
+ <ul class="list">
281
+ for (const item of items) {
282
+ <li>{item}</li>
283
+ }
284
+ </ul>
285
+ </>;
256
286
  }
257
287
 
258
288
  // Test nested for loops with reactivity
259
- export component NestedForLoopReactive() {
260
- let &[grid] = track([
261
- [1, 2],
262
- [3, 4],
263
- ]);
264
- <button
265
- class="add-row"
266
- onClick={() => {
267
- grid = [...grid, [5, 6]];
268
- }}
269
- >
270
- {'Add Row'}
271
- </button>
272
- <button
273
- class="update-cell"
274
- onClick={() => {
275
- const newGrid = grid.map((row) => [...row]);
276
- newGrid[0][0] = 99;
277
- grid = newGrid;
278
- }}
279
- >
280
- {'Update Cell'}
281
- </button>
282
- <div class="grid">
283
- for (const row of grid; index rowIndex) {
284
- <div class={`row-${rowIndex}`}>
285
- for (const cell of row; index colIndex) {
286
- <span class={`cell-${rowIndex}-${colIndex}`}>{cell}</span>
287
- }
288
- </div>
289
- }
290
- </div>
289
+ export function NestedForLoopReactive() {
290
+ return <>
291
+ let &[grid] = track([
292
+ [1, 2],
293
+ [3, 4],
294
+ ]);
295
+ <button
296
+ class="add-row"
297
+ onClick={() => {
298
+ grid = [...grid, [5, 6]];
299
+ }}
300
+ >
301
+ {'Add Row'}
302
+ </button>
303
+ <button
304
+ class="update-cell"
305
+ onClick={() => {
306
+ const newGrid = grid.map((row) => [...row]);
307
+ newGrid[0][0] = 99;
308
+ grid = newGrid;
309
+ }}
310
+ >
311
+ {'Update Cell'}
312
+ </button>
313
+ <div class="grid">
314
+ for (const row of grid; index rowIndex) {
315
+ <div class={`row-${rowIndex}`}>
316
+ for (const cell of row; index colIndex) {
317
+ <span class={`cell-${rowIndex}-${colIndex}`}>{cell}</span>
318
+ }
319
+ </div>
320
+ }
321
+ </div>
322
+ </>;
291
323
  }
292
324
 
293
325
  // Test for loop with deeply nested data
294
- export component ForLoopDeeplyNested() {
295
- const departments = [
296
- {
297
- id: 'd1',
298
- name: 'Engineering',
299
- teams: [
300
- { id: 't1', name: 'Frontend', members: ['Alice', 'Bob'] },
301
- { id: 't2', name: 'Backend', members: ['Charlie'] },
302
- ],
303
- },
304
- {
305
- id: 'd2',
306
- name: 'Design',
307
- teams: [
308
- { id: 't3', name: 'UX', members: ['Diana', 'Eve', 'Frank'] },
309
- ],
310
- },
311
- ];
312
- <div class="org">
313
- for (const dept of departments; key dept.id) {
314
- <div class={`dept-${dept.id}`}>
315
- <h2 class="dept-name">{dept.name}</h2>
316
- for (const team of dept.teams; key team.id) {
317
- <div class={`team-${team.id}`}>
318
- <h3 class="team-name">{team.name}</h3>
319
- <ul>
320
- for (const member of team.members) {
321
- <li class="member">{member}</li>
322
- }
323
- </ul>
324
- </div>
325
- }
326
- </div>
327
- }
328
- </div>
326
+ export function ForLoopDeeplyNested() {
327
+ return <>
328
+ const departments = [
329
+ {
330
+ id: 'd1',
331
+ name: 'Engineering',
332
+ teams: [
333
+ { id: 't1', name: 'Frontend', members: ['Alice', 'Bob'] },
334
+ { id: 't2', name: 'Backend', members: ['Charlie'] },
335
+ ],
336
+ },
337
+ {
338
+ id: 'd2',
339
+ name: 'Design',
340
+ teams: [
341
+ { id: 't3', name: 'UX', members: ['Diana', 'Eve', 'Frank'] },
342
+ ],
343
+ },
344
+ ];
345
+ <div class="org">
346
+ for (const dept of departments; key dept.id) {
347
+ <div class={`dept-${dept.id}`}>
348
+ <h2 class="dept-name">{dept.name}</h2>
349
+ for (const team of dept.teams; key team.id) {
350
+ <div class={`team-${team.id}`}>
351
+ <h3 class="team-name">{team.name}</h3>
352
+ <ul>
353
+ for (const member of team.members) {
354
+ <li class="member">{member}</li>
355
+ }
356
+ </ul>
357
+ </div>
358
+ }
359
+ </div>
360
+ }
361
+ </div>
362
+ </>;
329
363
  }
330
364
 
331
365
  // Test for loop with index that gets updated
332
- export component ForLoopIndexUpdate() {
333
- let &[items] = track(['First', 'Second', 'Third']);
334
- <button
335
- class="prepend"
336
- onClick={() => {
337
- items = ['Zeroth', ...items];
338
- }}
339
- >
340
- {'Prepend'}
341
- </button>
342
- <ul>
343
- for (const item of items; index i) {
344
- <li class={`item-${i}`}>{`[${i}] ${item}`}</li>
345
- }
346
- </ul>
366
+ export function ForLoopIndexUpdate() {
367
+ return <>
368
+ let &[items] = track(['First', 'Second', 'Third']);
369
+ <button
370
+ class="prepend"
371
+ onClick={() => {
372
+ items = ['Zeroth', ...items];
373
+ }}
374
+ >
375
+ {'Prepend'}
376
+ </button>
377
+ <ul>
378
+ for (const item of items; index i) {
379
+ <li class={`item-${i}`}>{`[${i}] ${item}`}</li>
380
+ }
381
+ </ul>
382
+ </>;
347
383
  }
348
384
 
349
385
  // Test keyed for loop with index
350
- export component KeyedForLoopWithIndex() {
351
- let &[items] = track([
352
- { id: 'a', value: 'Alpha' },
353
- { id: 'b', value: 'Beta' },
354
- { id: 'c', value: 'Gamma' },
355
- ]);
356
- <button
357
- class="reorder"
358
- onClick={() => {
359
- items = [items[1], items[2], items[0]];
360
- }}
361
- >
362
- {'Rotate'}
363
- </button>
364
- <ul>
365
- for (const item of items; index i; key item.id) {
366
- <li class={`item-${item.id}`} data-index={i}>{`[${i}] ${item.id}: ${item.value}`}</li>
367
- }
368
- </ul>
386
+ export function KeyedForLoopWithIndex() {
387
+ return <>
388
+ let &[items] = track([
389
+ { id: 'a', value: 'Alpha' },
390
+ { id: 'b', value: 'Beta' },
391
+ { id: 'c', value: 'Gamma' },
392
+ ]);
393
+ <button
394
+ class="reorder"
395
+ onClick={() => {
396
+ items = [items[1], items[2], items[0]];
397
+ }}
398
+ >
399
+ {'Rotate'}
400
+ </button>
401
+ <ul>
402
+ for (const item of items; index i; key item.id) {
403
+ <li class={`item-${item.id}`} data-index={i}>{`[${i}] ${item.id}: ${item.value}`}</li>
404
+ }
405
+ </ul>
406
+ </>;
369
407
  }
370
408
 
371
409
  // Test for loop with sibling elements
372
- export component ForLoopWithSiblings() {
373
- let &[items] = track(['A', 'B']);
374
- <div class="wrapper">
375
- <header class="before">{'Before'}</header>
376
- for (const item of items) {
377
- <div class={`item-${item}`}>{item}</div>
378
- }
379
- <footer class="after">{'After'}</footer>
380
- </div>
381
- <button
382
- class="add"
383
- onClick={() => {
384
- items = [...items, 'C'];
385
- }}
386
- >
387
- {'Add'}
388
- </button>
410
+ export function ForLoopWithSiblings() {
411
+ return <>
412
+ let &[items] = track(['A', 'B']);
413
+ <div class="wrapper">
414
+ <header class="before">{'Before'}</header>
415
+ for (const item of items) {
416
+ <div class={`item-${item}`}>{item}</div>
417
+ }
418
+ <footer class="after">{'After'}</footer>
419
+ </div>
420
+ <button
421
+ class="add"
422
+ onClick={() => {
423
+ items = [...items, 'C'];
424
+ }}
425
+ >
426
+ {'Add'}
427
+ </button>
428
+ </>;
389
429
  }
390
430
 
391
431
  // Test for loop items with their own reactive state
392
- export component ForLoopItemState() {
393
- const initialItems = [
394
- { id: 1, text: 'Todo 1' },
395
- { id: 2, text: 'Todo 2' },
396
- { id: 3, text: 'Todo 3' },
397
- ];
398
- <div>
399
- for (const item of initialItems; key item.id) {
400
- <TodoItem id={item.id} text={item.text} />
401
- }
402
- </div>
432
+ export function ForLoopItemState() {
433
+ return <>
434
+ const initialItems = [
435
+ { id: 1, text: 'Todo 1' },
436
+ { id: 2, text: 'Todo 2' },
437
+ { id: 3, text: 'Todo 3' },
438
+ ];
439
+ <div>
440
+ for (const item of initialItems; key item.id) {
441
+ <TodoItem id={item.id} text={item.text} />
442
+ }
443
+ </div>
444
+ </>;
403
445
  }
404
446
 
405
- component TodoItem(props: { id: number; text: string }) {
406
- let &[done] = track(false);
407
- <div class={`todo-${props.id}`}>
408
- <input
409
- type="checkbox"
410
- class="checkbox"
411
- checked={done}
412
- onChange={(e) => {
413
- done = (e.target as HTMLInputElement).checked;
414
- }}
415
- />
416
- <span class={done ? 'completed' : 'pending'}>
417
- {props.text}
418
- </span>
419
- </div>
447
+ function TodoItem(props: { id: number; text: string }) {
448
+ return <>
449
+ let &[done] = track(false);
450
+ <div class={`todo-${props.id}`}>
451
+ <input
452
+ type="checkbox"
453
+ class="checkbox"
454
+ checked={done}
455
+ onChange={(e) => {
456
+ done = (e.target as HTMLInputElement).checked;
457
+ }}
458
+ />
459
+ <span class={done ? 'completed' : 'pending'}>
460
+ {props.text}
461
+ </span>
462
+ </div>
463
+ </>;
420
464
  }
421
465
 
422
466
  // Test for loop with single item
423
- export component ForLoopSingleItem() {
424
- const items = ['Only'];
425
- <ul>
426
- for (const item of items) {
427
- <li class="single">{item}</li>
428
- }
429
- </ul>
467
+ export function ForLoopSingleItem() {
468
+ return <>
469
+ const items = ['Only'];
470
+ <ul>
471
+ for (const item of items) {
472
+ <li class="single">{item}</li>
473
+ }
474
+ </ul>
475
+ </>;
430
476
  }
431
477
 
432
478
  // Test for loop adding at beginning
433
- export component ForLoopAddAtBeginning() {
434
- let &[items] = track(['B', 'C']);
435
- <button
436
- class="prepend"
437
- onClick={() => {
438
- items = ['A', ...items];
439
- }}
440
- >
441
- {'Prepend A'}
442
- </button>
443
- <ul>
444
- for (const item of items) {
445
- <li class={`item-${item}`}>{item}</li>
446
- }
447
- </ul>
479
+ export function ForLoopAddAtBeginning() {
480
+ return <>
481
+ let &[items] = track(['B', 'C']);
482
+ <button
483
+ class="prepend"
484
+ onClick={() => {
485
+ items = ['A', ...items];
486
+ }}
487
+ >
488
+ {'Prepend A'}
489
+ </button>
490
+ <ul>
491
+ for (const item of items) {
492
+ <li class={`item-${item}`}>{item}</li>
493
+ }
494
+ </ul>
495
+ </>;
448
496
  }
449
497
 
450
498
  // Test for loop adding in the middle
451
- export component ForLoopAddInMiddle() {
452
- let &[items] = track(['A', 'C']);
453
- <button
454
- class="insert"
455
- onClick={() => {
456
- const copy = [...items];
457
- copy.splice(1, 0, 'B');
458
- items = copy;
459
- }}
460
- >
461
- {'Insert B'}
462
- </button>
463
- <ul>
464
- for (const item of items) {
465
- <li class={`item-${item}`}>{item}</li>
466
- }
467
- </ul>
499
+ export function ForLoopAddInMiddle() {
500
+ return <>
501
+ let &[items] = track(['A', 'C']);
502
+ <button
503
+ class="insert"
504
+ onClick={() => {
505
+ const copy = [...items];
506
+ copy.splice(1, 0, 'B');
507
+ items = copy;
508
+ }}
509
+ >
510
+ {'Insert B'}
511
+ </button>
512
+ <ul>
513
+ for (const item of items) {
514
+ <li class={`item-${item}`}>{item}</li>
515
+ }
516
+ </ul>
517
+ </>;
468
518
  }
469
519
 
470
520
  // Test for loop removing from the middle
471
- export component ForLoopRemoveFromMiddle() {
472
- let &[items] = track(['A', 'B', 'C']);
473
- <button
474
- class="remove-middle"
475
- onClick={() => {
476
- items = items.filter((item) => item !== 'B');
477
- }}
478
- >
479
- {'Remove B'}
480
- </button>
481
- <ul>
482
- for (const item of items) {
483
- <li class={`item-${item}`}>{item}</li>
484
- }
485
- </ul>
521
+ export function ForLoopRemoveFromMiddle() {
522
+ return <>
523
+ let &[items] = track(['A', 'B', 'C']);
524
+ <button
525
+ class="remove-middle"
526
+ onClick={() => {
527
+ items = items.filter((item) => item !== 'B');
528
+ }}
529
+ >
530
+ {'Remove B'}
531
+ </button>
532
+ <ul>
533
+ for (const item of items) {
534
+ <li class={`item-${item}`}>{item}</li>
535
+ }
536
+ </ul>
537
+ </>;
486
538
  }
487
539
 
488
540
  // Test for loop with large list
489
- export component ForLoopLargeList() {
490
- const items = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
491
- <ul class="large-list">
492
- for (const item of items; index i) {
493
- <li class={`item-${i}`}>{item}</li>
494
- }
495
- </ul>
541
+ export function ForLoopLargeList() {
542
+ return <>
543
+ const items = Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`);
544
+ <ul class="large-list">
545
+ for (const item of items; index i) {
546
+ <li class={`item-${i}`}>{item}</li>
547
+ }
548
+ </ul>
549
+ </>;
496
550
  }
497
551
 
498
552
  // Test for loop with swap operation
499
- export component ForLoopSwap() {
500
- let &[items] = track(['A', 'B', 'C', 'D']);
501
- <button
502
- class="swap"
503
- onClick={() => {
504
- const copy = [...items];
505
- [copy[0], copy[3]] = [copy[3], copy[0]];
506
- items = copy;
507
- }}
508
- >
509
- {'Swap First and Last'}
510
- </button>
511
- <ul>
512
- for (const item of items) {
513
- <li class={`item-${item}`}>{item}</li>
514
- }
515
- </ul>
553
+ export function ForLoopSwap() {
554
+ return <>
555
+ let &[items] = track(['A', 'B', 'C', 'D']);
556
+ <button
557
+ class="swap"
558
+ onClick={() => {
559
+ const copy = [...items];
560
+ [copy[0], copy[3]] = [copy[3], copy[0]];
561
+ items = copy;
562
+ }}
563
+ >
564
+ {'Swap First and Last'}
565
+ </button>
566
+ <ul>
567
+ for (const item of items) {
568
+ <li class={`item-${item}`}>{item}</li>
569
+ }
570
+ </ul>
571
+ </>;
516
572
  }
517
573
 
518
574
  // Test for loop with reverse operation
519
- export component ForLoopReverse() {
520
- let &[items] = track(['A', 'B', 'C', 'D']);
521
- <button
522
- class="reverse"
523
- onClick={() => {
524
- items = [...items].reverse();
525
- }}
526
- >
527
- {'Reverse'}
528
- </button>
529
- <ul>
530
- for (const item of items) {
531
- <li class={`item-${item}`}>{item}</li>
532
- }
533
- </ul>
575
+ export function ForLoopReverse() {
576
+ return <>
577
+ let &[items] = track(['A', 'B', 'C', 'D']);
578
+ <button
579
+ class="reverse"
580
+ onClick={() => {
581
+ items = [...items].reverse();
582
+ }}
583
+ >
584
+ {'Reverse'}
585
+ </button>
586
+ <ul>
587
+ for (const item of items) {
588
+ <li class={`item-${item}`}>{item}</li>
589
+ }
590
+ </ul>
591
+ </>;
534
592
  }