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.
- package/CHANGELOG.md +57 -0
- package/package.json +3 -3
- package/src/jsx-runtime.d.ts +2 -2
- package/src/runtime/element.js +1 -1
- package/src/runtime/index-client.js +11 -11
- package/src/runtime/index-server.js +7 -4
- package/src/runtime/internal/client/bindings.js +1 -1
- package/src/runtime/internal/client/blocks.js +13 -4
- package/src/runtime/internal/client/component.js +55 -0
- package/src/runtime/internal/client/composite.js +4 -2
- package/src/runtime/internal/client/expression.js +65 -7
- package/src/runtime/internal/client/hmr.js +54 -43
- package/src/runtime/internal/client/index.js +5 -1
- package/src/runtime/internal/client/portal.js +70 -69
- package/src/runtime/internal/client/render.js +3 -0
- package/src/runtime/internal/server/index.js +92 -8
- package/tests/client/__snapshots__/html.test.tsrx.snap +3 -3
- package/tests/client/array/array.copy-within.test.tsrx +33 -31
- package/tests/client/array/array.derived.test.tsrx +186 -169
- package/tests/client/array/array.iteration.test.tsrx +40 -37
- package/tests/client/array/array.mutations.test.tsrx +113 -101
- package/tests/client/array/array.static.test.tsrx +119 -101
- package/tests/client/array/array.to-methods.test.tsrx +24 -21
- package/tests/client/async-suspend.test.tsrx +247 -246
- package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +0 -1
- package/tests/client/basic/basic.attributes.test.tsrx +428 -423
- package/tests/client/basic/basic.collections.test.tsrx +109 -102
- package/tests/client/basic/basic.components.test.tsrx +323 -205
- package/tests/client/basic/basic.errors.test.tsrx +91 -91
- package/tests/client/basic/basic.events.test.tsrx +114 -115
- package/tests/client/basic/basic.get-set.test.tsrx +97 -87
- package/tests/client/basic/basic.hmr.test.tsrx +19 -16
- package/tests/client/basic/basic.reactivity.test.tsrx +199 -191
- package/tests/client/basic/basic.rendering.test.tsrx +272 -182
- package/tests/client/basic/basic.styling.test.tsrx +23 -22
- package/tests/client/basic/basic.utilities.test.tsrx +10 -8
- package/tests/client/boundaries.test.tsrx +26 -26
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +5 -5
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +5 -5
- package/tests/client/compiler/compiler.assignments.test.tsrx +77 -81
- package/tests/client/compiler/compiler.attributes.test.tsrx +15 -15
- package/tests/client/compiler/compiler.basic.test.tsrx +322 -314
- package/tests/client/compiler/compiler.regex.test.tsrx +44 -47
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +38 -38
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
- package/tests/client/compiler/compiler.typescript.test.tsrx +2 -2
- package/tests/client/composite/composite.dynamic-components.test.tsrx +47 -48
- package/tests/client/composite/composite.generics.test.tsrx +168 -192
- package/tests/client/composite/composite.props.test.tsrx +97 -81
- package/tests/client/composite/composite.reactivity.test.tsrx +177 -147
- package/tests/client/composite/composite.render.test.tsrx +122 -105
- package/tests/client/computed-properties.test.tsrx +28 -28
- package/tests/client/context.test.tsrx +21 -21
- package/tests/client/css/global-additional-cases.test.tsrx +58 -58
- package/tests/client/css/global-advanced-selectors.test.tsrx +16 -16
- package/tests/client/css/global-at-rules.test.tsrx +10 -10
- package/tests/client/css/global-basic.test.tsrx +14 -14
- package/tests/client/css/global-classes-ids.test.tsrx +14 -14
- package/tests/client/css/global-combinators.test.tsrx +10 -10
- package/tests/client/css/global-complex-nesting.test.tsrx +14 -14
- package/tests/client/css/global-edge-cases.test.tsrx +18 -18
- package/tests/client/css/global-keyframes.test.tsrx +12 -12
- package/tests/client/css/global-nested.test.tsrx +10 -10
- package/tests/client/css/global-pseudo.test.tsrx +12 -12
- package/tests/client/css/global-scoping.test.tsrx +20 -20
- package/tests/client/css/style-identifier.test.tsrx +126 -259
- package/tests/client/date.test.tsrx +146 -133
- package/tests/client/dynamic-elements.test.tsrx +398 -365
- package/tests/client/events.test.tsrx +292 -290
- package/tests/client/for.test.tsrx +156 -153
- package/tests/client/head.test.tsrx +105 -96
- package/tests/client/html.test.tsrx +122 -26
- package/tests/client/input-value.test.tsrx +1361 -1314
- package/tests/client/lazy-array.test.tsrx +16 -13
- package/tests/client/lazy-destructuring.test.tsrx +257 -213
- package/tests/client/map.test.tsrx +65 -60
- package/tests/client/media-query.test.tsrx +22 -20
- package/tests/client/object.test.tsrx +87 -81
- package/tests/client/portal.test.tsrx +57 -51
- package/tests/client/ref.test.tsrx +233 -202
- package/tests/client/return.test.tsrx +71 -2560
- package/tests/client/set.test.tsrx +54 -45
- package/tests/client/svg.test.tsrx +216 -186
- package/tests/client/switch.test.tsrx +194 -193
- package/tests/client/track-async-hydration.test.tsrx +18 -14
- package/tests/client/tracked-index-access.test.tsrx +28 -18
- package/tests/client/try.test.tsrx +675 -548
- package/tests/client/tsx.test.tsrx +373 -311
- package/tests/client/typescript-generics.test.tsrx +145 -145
- package/tests/client/url/url.derived.test.tsrx +33 -28
- package/tests/client/url/url.parsing.test.tsrx +61 -51
- package/tests/client/url/url.partial-removal.test.tsrx +56 -48
- package/tests/client/url/url.reactivity.test.tsrx +142 -125
- package/tests/client/url/url.serialization.test.tsrx +13 -11
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +34 -29
- package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +25 -21
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +50 -45
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +111 -99
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +49 -43
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +14 -12
- package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +16 -14
- package/tests/hydration/basic.test.js +3 -3
- package/tests/hydration/compiled/client/basic.js +586 -651
- package/tests/hydration/compiled/client/composite.js +79 -104
- package/tests/hydration/compiled/client/events.js +140 -148
- package/tests/hydration/compiled/client/for.js +1005 -1018
- package/tests/hydration/compiled/client/head.js +124 -134
- package/tests/hydration/compiled/client/hmr.js +41 -48
- package/tests/hydration/compiled/client/html-in-template.js +38 -41
- package/tests/hydration/compiled/client/html.js +970 -1314
- package/tests/hydration/compiled/client/if-children.js +234 -249
- package/tests/hydration/compiled/client/if.js +182 -189
- package/tests/hydration/compiled/client/mixed-control-flow.js +347 -303
- package/tests/hydration/compiled/client/nested-control-flow.js +1084 -832
- package/tests/hydration/compiled/client/portal.js +65 -85
- package/tests/hydration/compiled/client/reactivity.js +84 -90
- package/tests/hydration/compiled/client/return.js +38 -1939
- package/tests/hydration/compiled/client/switch.js +218 -224
- package/tests/hydration/compiled/client/track-async-serialization.js +250 -259
- package/tests/hydration/compiled/client/try.js +123 -132
- package/tests/hydration/compiled/server/basic.js +773 -831
- package/tests/hydration/compiled/server/composite.js +166 -191
- package/tests/hydration/compiled/server/events.js +170 -184
- package/tests/hydration/compiled/server/for.js +851 -909
- package/tests/hydration/compiled/server/head.js +206 -216
- package/tests/hydration/compiled/server/hmr.js +64 -72
- package/tests/hydration/compiled/server/html-in-template.js +42 -76
- package/tests/hydration/compiled/server/html.js +1362 -1667
- package/tests/hydration/compiled/server/if-children.js +419 -445
- package/tests/hydration/compiled/server/if.js +194 -208
- package/tests/hydration/compiled/server/mixed-control-flow.js +249 -257
- package/tests/hydration/compiled/server/nested-control-flow.js +491 -515
- package/tests/hydration/compiled/server/portal.js +152 -160
- package/tests/hydration/compiled/server/reactivity.js +94 -106
- package/tests/hydration/compiled/server/return.js +28 -2172
- package/tests/hydration/compiled/server/switch.js +274 -286
- package/tests/hydration/compiled/server/track-async-serialization.js +340 -358
- package/tests/hydration/compiled/server/try.js +167 -185
- package/tests/hydration/components/basic.tsrx +320 -272
- package/tests/hydration/components/composite.tsrx +44 -32
- package/tests/hydration/components/events.tsrx +101 -91
- package/tests/hydration/components/for.tsrx +510 -452
- package/tests/hydration/components/head.tsrx +87 -80
- package/tests/hydration/components/hmr.tsrx +22 -17
- package/tests/hydration/components/html-in-template.tsrx +22 -17
- package/tests/hydration/components/html.tsrx +525 -443
- package/tests/hydration/components/if-children.tsrx +158 -148
- package/tests/hydration/components/if.tsrx +109 -95
- package/tests/hydration/components/mixed-control-flow.tsrx +100 -96
- package/tests/hydration/components/nested-control-flow.tsrx +215 -203
- package/tests/hydration/components/portal.tsrx +41 -34
- package/tests/hydration/components/reactivity.tsrx +37 -27
- package/tests/hydration/components/return.tsrx +12 -556
- package/tests/hydration/components/switch.tsrx +120 -114
- package/tests/hydration/components/track-async-serialization.tsrx +107 -91
- package/tests/hydration/components/try.tsrx +55 -40
- package/tests/hydration/html.test.js +4 -4
- package/tests/hydration/return.test.js +13 -532
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +264 -195
- package/tests/server/basic.components.test.tsrx +296 -169
- package/tests/server/basic.test.tsrx +300 -198
- package/tests/server/compiler.test.tsrx +62 -60
- package/tests/server/composite.props.test.tsrx +77 -63
- package/tests/server/composite.test.tsrx +168 -192
- package/tests/server/context.test.tsrx +18 -12
- package/tests/server/dynamic-elements.test.tsrx +197 -180
- package/tests/server/for.test.tsrx +85 -78
- package/tests/server/head.test.tsrx +50 -43
- package/tests/server/html-nesting-validation.test.tsrx +8 -8
- package/tests/server/if.test.tsrx +57 -51
- package/tests/server/lazy-destructuring.test.tsrx +366 -294
- package/tests/server/return.test.tsrx +76 -1355
- package/tests/server/streaming-ssr.test.tsrx +4 -75
- package/tests/server/style-identifier.test.tsrx +169 -131
- package/tests/server/switch.test.tsrx +91 -85
- package/tests/server/track-async-serialization.test.tsrx +105 -85
- package/tests/server/try.test.tsrx +374 -280
- package/tests/utils/compiler-compat-config.test.js +2 -2
- package/tests/utils/runtime-imports.test.js +10 -0
- package/types/index.d.ts +8 -0
- 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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
92
|
-
|
|
93
|
-
[
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
|
260
|
-
|
|
261
|
-
[
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
<
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
<
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
{
|
|
418
|
-
|
|
419
|
-
|
|
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
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
}
|