ripple 0.3.127 → 0.4.0
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 +293 -0
- package/package.json +10 -4
- package/src/runtime/element.js +23 -6
- package/src/runtime/index-client.js +81 -41
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/blocks.js +192 -114
- package/src/runtime/internal/client/component.js +4 -30
- package/src/runtime/internal/client/composite.js +12 -13
- package/src/runtime/internal/client/constants.js +14 -5
- package/src/runtime/internal/client/context.js +12 -19
- package/src/runtime/internal/client/css.js +7 -9
- package/src/runtime/internal/client/events.js +178 -90
- package/src/runtime/internal/client/expression.js +185 -124
- package/src/runtime/internal/client/for.js +616 -264
- package/src/runtime/internal/client/head.js +10 -5
- package/src/runtime/internal/client/html.js +1 -0
- package/src/runtime/internal/client/hydration.js +152 -10
- package/src/runtime/internal/client/if.js +239 -50
- package/src/runtime/internal/client/index.js +9 -13
- package/src/runtime/internal/client/operations.js +44 -51
- package/src/runtime/internal/client/portal.js +163 -85
- package/src/runtime/internal/client/render.js +44 -25
- package/src/runtime/internal/client/rpc.js +3 -3
- package/src/runtime/internal/client/runtime.js +799 -576
- package/src/runtime/internal/client/selector.js +77 -0
- package/src/runtime/internal/client/template.js +133 -158
- package/src/runtime/internal/client/transport.js +38 -0
- package/src/runtime/internal/client/try.js +465 -426
- package/src/runtime/internal/client/types.d.ts +65 -21
- package/src/runtime/internal/client/utils.js +1 -3
- package/src/runtime/internal/server/dynamic.js +20 -21
- package/src/runtime/internal/server/index.js +327 -275
- package/src/runtime/internal/server/rpc.js +3 -2
- package/src/runtime/internal/server/transport.js +16 -0
- package/src/runtime/transport.js +21 -0
- package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
- package/tests/client/array/array.copy-within.test.tsrx +12 -12
- package/tests/client/array/array.derived.test.tsrx +46 -46
- package/tests/client/array/array.iteration.test.tsrx +10 -10
- package/tests/client/array/array.mutations.test.tsrx +20 -20
- package/tests/client/array/array.static.test.tsrx +11 -11
- package/tests/client/array/array.to-methods.test.tsrx +6 -6
- package/tests/client/async-suspend.test.tsrx +74 -75
- package/tests/client/basic/basic.attributes.test.tsrx +86 -83
- package/tests/client/basic/basic.collections.test.tsrx +12 -12
- package/tests/client/basic/basic.components.test.tsrx +99 -25
- package/tests/client/basic/basic.errors.test.tsrx +18 -18
- package/tests/client/basic/basic.events.test.tsrx +42 -42
- package/tests/client/basic/basic.get-set.test.tsrx +8 -8
- package/tests/client/basic/basic.reactivity.test.tsrx +97 -29
- package/tests/client/basic/basic.rendering.test.tsrx +25 -25
- package/tests/client/basic/basic.utilities.test.tsrx +3 -3
- package/tests/client/boundaries.test.tsrx +8 -8
- package/tests/client/boxed-locals.test.tsrx +452 -0
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
- package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
- package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
- package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
- package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
- package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
- package/tests/client/composite/composite.props.test.tsrx +149 -12
- package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
- package/tests/client/composite/composite.render.test.tsrx +26 -9
- package/tests/client/css/scoped-styles.test.tsrx +8 -8
- package/tests/client/date.test.tsrx +42 -42
- package/tests/client/derived-release.test.tsrx +370 -0
- package/tests/client/dynamic-elements.test.tsrx +45 -45
- package/tests/client/events.test.tsrx +97 -71
- package/tests/client/for-selector.test.tsrx +221 -0
- package/tests/client/for-single-root-items.test.tsrx +118 -3
- package/tests/client/for.test.tsrx +332 -31
- package/tests/client/head.test.tsrx +19 -19
- package/tests/client/html.test.tsrx +11 -9
- package/tests/client/if-block.test.tsrx +80 -0
- package/tests/client/map.test.tsrx +16 -16
- package/tests/client/media-query.test.tsrx +7 -7
- package/tests/client/portal.test.tsrx +224 -26
- package/tests/client/primitive-text.test.tsrx +50 -0
- package/tests/client/prop-kind-switch.test.tsrx +141 -0
- package/tests/client/ref.test.tsrx +17 -17
- package/tests/client/return.test.tsrx +26 -3
- package/tests/client/root-boundary.test.tsrx +42 -0
- package/tests/client/scoped-flush.test.tsrx +8 -8
- package/tests/client/set.test.tsrx +6 -6
- package/tests/client/svg.test.tsrx +11 -11
- package/tests/client/switch.test.tsrx +44 -44
- package/tests/client/track-async-hydration.test.tsrx +4 -4
- package/tests/client/try.test.tsrx +151 -83
- package/tests/client/tsx.test.tsrx +43 -40
- package/tests/client/url/url.derived.test.tsrx +6 -6
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
- package/tests/hydration/basic.test.js +74 -1
- package/tests/hydration/build-components.js +22 -1
- package/tests/hydration/compiled/client/basic.js +1142 -713
- package/tests/hydration/compiled/client/composite.js +151 -100
- package/tests/hydration/compiled/client/events.js +190 -150
- package/tests/hydration/compiled/client/for.js +1472 -1126
- package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
- package/tests/hydration/compiled/client/head.js +255 -199
- package/tests/hydration/compiled/client/hmr.js +54 -41
- package/tests/hydration/compiled/client/html-in-template.js +54 -39
- package/tests/hydration/compiled/client/html.js +1633 -1263
- package/tests/hydration/compiled/client/if-children.js +420 -270
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
- package/tests/hydration/compiled/client/if.js +229 -219
- package/tests/hydration/compiled/client/mixed-control-flow.js +420 -400
- package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1255
- package/tests/hydration/compiled/client/portal.js +87 -95
- package/tests/hydration/compiled/client/reactivity.js +140 -83
- package/tests/hydration/compiled/client/return.js +28 -19
- package/tests/hydration/compiled/client/streaming.js +390 -306
- package/tests/hydration/compiled/client/switch.js +258 -266
- package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
- package/tests/hydration/compiled/client/try.js +173 -129
- package/tests/hydration/compiled/client/typed-text.js +71 -0
- package/tests/hydration/compiled/fixtures/money.js +10 -0
- package/tests/hydration/compiled/server/basic.js +123 -6
- package/tests/hydration/compiled/server/composite.js +16 -30
- package/tests/hydration/compiled/server/events.js +19 -19
- package/tests/hydration/compiled/server/for.js +109 -49
- package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
- package/tests/hydration/compiled/server/head.js +20 -28
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +71 -247
- package/tests/hydration/compiled/server/if-children.js +107 -15
- package/tests/hydration/compiled/server/if.js +11 -15
- package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
- package/tests/hydration/compiled/server/portal.js +14 -22
- package/tests/hydration/compiled/server/reactivity.js +14 -46
- package/tests/hydration/compiled/server/streaming.js +19 -19
- package/tests/hydration/compiled/server/switch.js +8 -8
- package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
- package/tests/hydration/compiled/server/try.js +8 -8
- package/tests/hydration/compiled/server/typed-text.js +17 -0
- package/tests/hydration/components/basic.tsrx +44 -8
- package/tests/hydration/components/composite.tsrx +2 -2
- package/tests/hydration/components/events.tsrx +25 -25
- package/tests/hydration/components/for.tsrx +115 -67
- package/tests/hydration/components/fragment-cursor.tsrx +650 -0
- package/tests/hydration/components/head.tsrx +16 -16
- package/tests/hydration/components/hmr.tsrx +2 -2
- package/tests/hydration/components/html.tsrx +7 -7
- package/tests/hydration/components/if-children.tsrx +72 -25
- package/tests/hydration/components/if.tsrx +18 -18
- package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
- package/tests/hydration/components/portal.tsrx +3 -3
- package/tests/hydration/components/reactivity.tsrx +16 -16
- package/tests/hydration/components/streaming.tsrx +20 -20
- package/tests/hydration/components/switch.tsrx +20 -20
- package/tests/hydration/components/text-types.ts +4 -0
- package/tests/hydration/components/track-async-serialization.tsrx +80 -26
- package/tests/hydration/components/try.tsrx +8 -8
- package/tests/hydration/components/typed-text.tsrx +22 -0
- package/tests/hydration/fixtures/money.js +10 -0
- package/tests/hydration/for.test.js +36 -0
- package/tests/hydration/fragment-cursor.test.js +111 -0
- package/tests/hydration/if-children.test.js +24 -0
- package/tests/hydration/streaming.test.js +19 -0
- package/tests/hydration/track-async-serialization.test.js +87 -2
- package/tests/hydration/tsconfig.text-types.json +10 -0
- package/tests/hydration/typed-text.test.js +34 -0
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +42 -42
- package/tests/server/basic.components.test.tsrx +64 -8
- package/tests/server/basic.test.tsrx +34 -32
- package/tests/server/compiler.test.tsrx +1 -70
- package/tests/server/composite.props.test.tsrx +6 -6
- package/tests/server/dynamic-elements.test.tsrx +31 -8
- package/tests/server/for.test.tsrx +94 -0
- package/tests/server/head.test.tsrx +11 -11
- package/tests/server/scoped-styles.test.tsrx +2 -2
- package/tests/server/streaming-ssr.test.tsrx +48 -43
- package/tests/server/track-async-serialization.test.tsrx +204 -21
- package/tests/server/try.test.tsrx +48 -48
- package/tests/types/transport.ts +40 -0
- package/tests/utils/vite-plugin-config.test.js +23 -0
- package/types/index.d.ts +48 -7
- package/types/server.d.ts +3 -0
- package/types/transport.d.ts +15 -0
- package/src/runtime/internal/client/switch.js +0 -113
- package/src/utils/errors.js +0 -13
- package/tests/client/lazy-array.test.tsrx +0 -31
- package/tests/client/lazy-destructuring.test.tsrx +0 -438
- package/tests/client/tracked-index-access.test.tsrx +0 -113
- package/tests/server/lazy-destructuring.test.tsrx +0 -595
- package/tests/server/tracked-index-access.test.tsrx +0 -76
|
@@ -3,79 +3,79 @@ import { track } from 'ripple';
|
|
|
3
3
|
// Event handling components for hydration testing
|
|
4
4
|
|
|
5
5
|
export function ClickCounter() @{
|
|
6
|
-
|
|
6
|
+
const count = track(0);
|
|
7
7
|
<div>
|
|
8
8
|
<button
|
|
9
9
|
class="increment"
|
|
10
10
|
onClick={() => {
|
|
11
|
-
count++;
|
|
11
|
+
count.value++;
|
|
12
12
|
}}
|
|
13
13
|
>{'Increment'}</button>
|
|
14
|
-
<span class="count">{count}</span>
|
|
14
|
+
<span class="count">{count.value}</span>
|
|
15
15
|
</div>
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function IncrementDecrement() @{
|
|
19
|
-
|
|
19
|
+
const count = track(0);
|
|
20
20
|
<div>
|
|
21
21
|
<button
|
|
22
22
|
class="decrement"
|
|
23
23
|
onClick={() => {
|
|
24
|
-
count--;
|
|
24
|
+
count.value--;
|
|
25
25
|
}}
|
|
26
26
|
>{'-'}</button>
|
|
27
|
-
<span class="count">{count}</span>
|
|
27
|
+
<span class="count">{count.value}</span>
|
|
28
28
|
<button
|
|
29
29
|
class="increment"
|
|
30
30
|
onClick={() => {
|
|
31
|
-
count++;
|
|
31
|
+
count.value++;
|
|
32
32
|
}}
|
|
33
33
|
>{'+'}</button>
|
|
34
34
|
</div>
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export function MultipleEvents() @{
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const clicks = track(0);
|
|
39
|
+
const hovers = track(0);
|
|
40
40
|
<div>
|
|
41
41
|
<button
|
|
42
42
|
class="target"
|
|
43
43
|
onClick={() => {
|
|
44
|
-
clicks++;
|
|
44
|
+
clicks.value++;
|
|
45
45
|
}}
|
|
46
46
|
onMouseEnter={() => {
|
|
47
|
-
hovers++;
|
|
47
|
+
hovers.value++;
|
|
48
48
|
}}
|
|
49
49
|
>{'Target'}</button>
|
|
50
|
-
<span class="clicks">{clicks}</span>
|
|
51
|
-
<span class="hovers">{hovers}</span>
|
|
50
|
+
<span class="clicks">{clicks.value}</span>
|
|
51
|
+
<span class="hovers">{hovers.value}</span>
|
|
52
52
|
</div>
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export function MultiStateUpdate() @{
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
const count = track(0);
|
|
57
|
+
const lastAction = track('none');
|
|
58
58
|
const handleClick = () => {
|
|
59
|
-
count++;
|
|
60
|
-
lastAction = 'increment';
|
|
59
|
+
count.value++;
|
|
60
|
+
lastAction.value = 'increment';
|
|
61
61
|
};
|
|
62
62
|
<div>
|
|
63
63
|
<button class="btn" onClick={handleClick}>{'Click'}</button>
|
|
64
|
-
<span class="count">{count}</span>
|
|
65
|
-
<span class="action">{lastAction}</span>
|
|
64
|
+
<span class="count">{count.value}</span>
|
|
65
|
+
<span class="action">{lastAction.value}</span>
|
|
66
66
|
</div>
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export function ToggleButton() @{
|
|
70
|
-
|
|
70
|
+
const isOn = track(false);
|
|
71
71
|
<div>
|
|
72
72
|
<button
|
|
73
73
|
class="toggle"
|
|
74
74
|
onClick={() => {
|
|
75
|
-
isOn = !isOn;
|
|
75
|
+
isOn.value = !isOn.value;
|
|
76
76
|
}}
|
|
77
77
|
>
|
|
78
|
-
{isOn ? 'ON' : 'OFF'}
|
|
78
|
+
{isOn.value ? 'ON' : 'OFF'}
|
|
79
79
|
</button>
|
|
80
80
|
</div>
|
|
81
81
|
}
|
|
@@ -85,14 +85,14 @@ export function ChildButton(props: { onClick: () => void; label: string }) @{
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export function ParentWithChildButton() @{
|
|
88
|
-
|
|
88
|
+
const count = track(0);
|
|
89
89
|
<div>
|
|
90
90
|
<ChildButton
|
|
91
91
|
onClick={() => {
|
|
92
|
-
count++;
|
|
92
|
+
count.value++;
|
|
93
93
|
}}
|
|
94
94
|
label="Click me"
|
|
95
95
|
/>
|
|
96
|
-
<span class="count">{count}</span>
|
|
96
|
+
<span class="count">{count.value}</span>
|
|
97
97
|
</div>
|
|
98
98
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { track } from 'ripple';
|
|
1
|
+
import { track, type Tracked } from 'ripple';
|
|
2
2
|
|
|
3
3
|
// For loop components for hydration testing
|
|
4
4
|
|
|
@@ -34,16 +34,16 @@ export function KeyedForLoop() @{
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function ReactiveForLoopAdd() @{
|
|
37
|
-
|
|
37
|
+
const items = track(['A', 'B']);
|
|
38
38
|
<>
|
|
39
39
|
<button
|
|
40
40
|
class="add"
|
|
41
41
|
onClick={() => {
|
|
42
|
-
items = [...items, 'C'];
|
|
42
|
+
items.value = [...items.value, 'C'];
|
|
43
43
|
}}
|
|
44
44
|
>{'Add'}</button>
|
|
45
45
|
<ul>
|
|
46
|
-
@for (const item of items) {
|
|
46
|
+
@for (const item of items.value) {
|
|
47
47
|
<li>{item}</li>
|
|
48
48
|
}
|
|
49
49
|
</ul>
|
|
@@ -51,16 +51,16 @@ export function ReactiveForLoopAdd() @{
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function ReactiveForLoopRemove() @{
|
|
54
|
-
|
|
54
|
+
const items = track(['A', 'B', 'C']);
|
|
55
55
|
<>
|
|
56
56
|
<button
|
|
57
57
|
class="remove"
|
|
58
58
|
onClick={() => {
|
|
59
|
-
items = items.slice(0, -1);
|
|
59
|
+
items.value = items.value.slice(0, -1);
|
|
60
60
|
}}
|
|
61
61
|
>{'Remove'}</button>
|
|
62
62
|
<ul>
|
|
63
|
-
@for (const item of items) {
|
|
63
|
+
@for (const item of items.value) {
|
|
64
64
|
<li>{item}</li>
|
|
65
65
|
}
|
|
66
66
|
</ul>
|
|
@@ -68,17 +68,17 @@ export function ReactiveForLoopRemove() @{
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export function ForLoopInteractive() @{
|
|
71
|
-
|
|
71
|
+
const counts = track([0, 0, 0]);
|
|
72
72
|
<div>
|
|
73
|
-
@for (const count of counts; index i) {
|
|
73
|
+
@for (const count of counts.value; index i) {
|
|
74
74
|
<div class={`item-${i}`}>
|
|
75
75
|
<span class="value">{count}</span>
|
|
76
76
|
<button
|
|
77
77
|
class="increment"
|
|
78
78
|
onClick={() => {
|
|
79
|
-
const newCounts = [...counts];
|
|
79
|
+
const newCounts = [...counts.value];
|
|
80
80
|
newCounts[i]++;
|
|
81
|
-
counts = newCounts;
|
|
81
|
+
counts.value = newCounts;
|
|
82
82
|
}}
|
|
83
83
|
>{'+'}</button>
|
|
84
84
|
</div>
|
|
@@ -128,7 +128,7 @@ export function ForLoopComplexObjects() @{
|
|
|
128
128
|
|
|
129
129
|
// Test reordering items in a keyed for loop
|
|
130
130
|
export function KeyedForLoopReorder() @{
|
|
131
|
-
|
|
131
|
+
const items = track([
|
|
132
132
|
{ id: 1, name: 'First' },
|
|
133
133
|
{ id: 2, name: 'Second' },
|
|
134
134
|
{ id: 3, name: 'Third' },
|
|
@@ -137,11 +137,11 @@ export function KeyedForLoopReorder() @{
|
|
|
137
137
|
<button
|
|
138
138
|
class="reorder"
|
|
139
139
|
onClick={() => {
|
|
140
|
-
items = [items[2], items[0], items[1]];
|
|
140
|
+
items.value = [items.value[2], items.value[0], items.value[1]];
|
|
141
141
|
}}
|
|
142
142
|
>{'Reorder'}</button>
|
|
143
143
|
<ul>
|
|
144
|
-
@for (const item of items; key item.id) {
|
|
144
|
+
@for (const item of items.value; key item.id) {
|
|
145
145
|
<li class={`item-${item.id}`}>{item.name}</li>
|
|
146
146
|
}
|
|
147
147
|
</ul>
|
|
@@ -150,7 +150,7 @@ export function KeyedForLoopReorder() @{
|
|
|
150
150
|
|
|
151
151
|
// Test for loop with item property updates (keyed)
|
|
152
152
|
export function KeyedForLoopUpdate() @{
|
|
153
|
-
|
|
153
|
+
const items = track([
|
|
154
154
|
{ id: 1, name: 'Item 1' },
|
|
155
155
|
{ id: 2, name: 'Item 2' },
|
|
156
156
|
]);
|
|
@@ -158,11 +158,13 @@ export function KeyedForLoopUpdate() @{
|
|
|
158
158
|
<button
|
|
159
159
|
class="update"
|
|
160
160
|
onClick={() => {
|
|
161
|
-
items = items.map(
|
|
161
|
+
items.value = items.value.map(
|
|
162
|
+
(item) => (item.id === 1 ? { ...item, name: 'Updated' } : item),
|
|
163
|
+
);
|
|
162
164
|
}}
|
|
163
165
|
>{'Update'}</button>
|
|
164
166
|
<ul>
|
|
165
|
-
@for (const item of items; key item.id) {
|
|
167
|
+
@for (const item of items.value; key item.id) {
|
|
166
168
|
<li class={`item-${item.id}`}>{item.name}</li>
|
|
167
169
|
}
|
|
168
170
|
</ul>
|
|
@@ -171,17 +173,17 @@ export function KeyedForLoopUpdate() @{
|
|
|
171
173
|
|
|
172
174
|
// Test for loop with combined add/remove/reorder
|
|
173
175
|
export function ForLoopMixedOperations() @{
|
|
174
|
-
|
|
176
|
+
const items = track(['A', 'B', 'C', 'D']);
|
|
175
177
|
<>
|
|
176
178
|
<button
|
|
177
179
|
class="shuffle"
|
|
178
180
|
onClick={() => {
|
|
179
181
|
// Remove B, add E, reorder to D, C, A, E
|
|
180
|
-
items = ['D', 'C', 'A', 'E'];
|
|
182
|
+
items.value = ['D', 'C', 'A', 'E'];
|
|
181
183
|
}}
|
|
182
184
|
>{'Shuffle'}</button>
|
|
183
185
|
<ul>
|
|
184
|
-
@for (const item of items) {
|
|
186
|
+
@for (const item of items.value) {
|
|
185
187
|
<li class={`item-${item}`}>{item}</li>
|
|
186
188
|
}
|
|
187
189
|
</ul>
|
|
@@ -190,24 +192,24 @@ export function ForLoopMixedOperations() @{
|
|
|
190
192
|
|
|
191
193
|
// Test for loop inside if block (combined control flow)
|
|
192
194
|
export function ForLoopInsideIf() @{
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
const showList = track(true);
|
|
196
|
+
const items = track(['X', 'Y', 'Z']);
|
|
195
197
|
<>
|
|
196
198
|
<button
|
|
197
199
|
class="toggle"
|
|
198
200
|
onClick={() => {
|
|
199
|
-
showList = !showList;
|
|
201
|
+
showList.value = !showList.value;
|
|
200
202
|
}}
|
|
201
203
|
>{'Toggle List'}</button>
|
|
202
204
|
<button
|
|
203
205
|
class="add"
|
|
204
206
|
onClick={() => {
|
|
205
|
-
items = [...items, 'W'];
|
|
207
|
+
items.value = [...items.value, 'W'];
|
|
206
208
|
}}
|
|
207
209
|
>{'Add Item'}</button>
|
|
208
|
-
@if (showList) {
|
|
210
|
+
@if (showList.value) {
|
|
209
211
|
<ul class="list">
|
|
210
|
-
@for (const item of items) {
|
|
212
|
+
@for (const item of items.value) {
|
|
211
213
|
<li>{item}</li>
|
|
212
214
|
}
|
|
213
215
|
</ul>
|
|
@@ -217,16 +219,16 @@ export function ForLoopInsideIf() @{
|
|
|
217
219
|
|
|
218
220
|
// Test for loop that transitions from empty to populated
|
|
219
221
|
export function ForLoopEmptyToPopulated() @{
|
|
220
|
-
|
|
222
|
+
const items = track<string[]>([]);
|
|
221
223
|
<>
|
|
222
224
|
<button
|
|
223
225
|
class="populate"
|
|
224
226
|
onClick={() => {
|
|
225
|
-
items = ['One', 'Two', 'Three'];
|
|
227
|
+
items.value = ['One', 'Two', 'Three'];
|
|
226
228
|
}}
|
|
227
229
|
>{'Populate'}</button>
|
|
228
230
|
<ul class="list">
|
|
229
|
-
@for (const item of items) {
|
|
231
|
+
@for (const item of items.value) {
|
|
230
232
|
<li>{item}</li>
|
|
231
233
|
}
|
|
232
234
|
</ul>
|
|
@@ -235,16 +237,16 @@ export function ForLoopEmptyToPopulated() @{
|
|
|
235
237
|
|
|
236
238
|
// Test for loop that transitions from populated to empty
|
|
237
239
|
export function ForLoopPopulatedToEmpty() @{
|
|
238
|
-
|
|
240
|
+
const items = track(['One', 'Two', 'Three']);
|
|
239
241
|
<>
|
|
240
242
|
<button
|
|
241
243
|
class="clear"
|
|
242
244
|
onClick={() => {
|
|
243
|
-
items = [];
|
|
245
|
+
items.value = [];
|
|
244
246
|
}}
|
|
245
247
|
>{'Clear'}</button>
|
|
246
248
|
<ul class="list">
|
|
247
|
-
@for (const item of items) {
|
|
249
|
+
@for (const item of items.value) {
|
|
248
250
|
<li>{item}</li>
|
|
249
251
|
}
|
|
250
252
|
</ul>
|
|
@@ -253,7 +255,7 @@ export function ForLoopPopulatedToEmpty() @{
|
|
|
253
255
|
|
|
254
256
|
// Test nested for loops with reactivity
|
|
255
257
|
export function NestedForLoopReactive() @{
|
|
256
|
-
|
|
258
|
+
const grid = track([
|
|
257
259
|
[1, 2],
|
|
258
260
|
[3, 4],
|
|
259
261
|
]);
|
|
@@ -261,19 +263,19 @@ export function NestedForLoopReactive() @{
|
|
|
261
263
|
<button
|
|
262
264
|
class="add-row"
|
|
263
265
|
onClick={() => {
|
|
264
|
-
grid = [...grid, [5, 6]];
|
|
266
|
+
grid.value = [...grid.value, [5, 6]];
|
|
265
267
|
}}
|
|
266
268
|
>{'Add Row'}</button>
|
|
267
269
|
<button
|
|
268
270
|
class="update-cell"
|
|
269
271
|
onClick={() => {
|
|
270
|
-
const newGrid = grid.map((row) => [...row]);
|
|
272
|
+
const newGrid = grid.value.map((row) => [...row]);
|
|
271
273
|
newGrid[0][0] = 99;
|
|
272
|
-
grid = newGrid;
|
|
274
|
+
grid.value = newGrid;
|
|
273
275
|
}}
|
|
274
276
|
>{'Update Cell'}</button>
|
|
275
277
|
<div class="grid">
|
|
276
|
-
@for (const row of grid; index rowIndex) {
|
|
278
|
+
@for (const row of grid.value; index rowIndex) {
|
|
277
279
|
<div class={`row-${rowIndex}`}>
|
|
278
280
|
@for (const cell of row; index colIndex) {
|
|
279
281
|
<span class={`cell-${rowIndex}-${colIndex}`}>{cell}</span>
|
|
@@ -324,16 +326,16 @@ export function ForLoopDeeplyNested() @{
|
|
|
324
326
|
|
|
325
327
|
// Test for loop with index that gets updated
|
|
326
328
|
export function ForLoopIndexUpdate() @{
|
|
327
|
-
|
|
329
|
+
const items = track(['First', 'Second', 'Third']);
|
|
328
330
|
<>
|
|
329
331
|
<button
|
|
330
332
|
class="prepend"
|
|
331
333
|
onClick={() => {
|
|
332
|
-
items = ['Zeroth', ...items];
|
|
334
|
+
items.value = ['Zeroth', ...items.value];
|
|
333
335
|
}}
|
|
334
336
|
>{'Prepend'}</button>
|
|
335
337
|
<ul>
|
|
336
|
-
@for (const item of items; index i) {
|
|
338
|
+
@for (const item of items.value; index i) {
|
|
337
339
|
<li class={`item-${i}`}>{`[${i}] ${item}`}</li>
|
|
338
340
|
}
|
|
339
341
|
</ul>
|
|
@@ -342,7 +344,7 @@ export function ForLoopIndexUpdate() @{
|
|
|
342
344
|
|
|
343
345
|
// Test keyed for loop with index
|
|
344
346
|
export function KeyedForLoopWithIndex() @{
|
|
345
|
-
|
|
347
|
+
const items = track([
|
|
346
348
|
{ id: 'a', value: 'Alpha' },
|
|
347
349
|
{ id: 'b', value: 'Beta' },
|
|
348
350
|
{ id: 'c', value: 'Gamma' },
|
|
@@ -351,11 +353,11 @@ export function KeyedForLoopWithIndex() @{
|
|
|
351
353
|
<button
|
|
352
354
|
class="reorder"
|
|
353
355
|
onClick={() => {
|
|
354
|
-
items = [items[1], items[2], items[0]];
|
|
356
|
+
items.value = [items.value[1], items.value[2], items.value[0]];
|
|
355
357
|
}}
|
|
356
358
|
>{'Rotate'}</button>
|
|
357
359
|
<ul>
|
|
358
|
-
@for (const item of items; index i; key item.id) {
|
|
360
|
+
@for (const item of items.value; index i; key item.id) {
|
|
359
361
|
<li class={`item-${item.id}`} data-index={i}>{`[${i}] ${item.id}: ${item.value}`}</li>
|
|
360
362
|
}
|
|
361
363
|
</ul>
|
|
@@ -364,11 +366,11 @@ export function KeyedForLoopWithIndex() @{
|
|
|
364
366
|
|
|
365
367
|
// Test for loop with sibling elements
|
|
366
368
|
export function ForLoopWithSiblings() @{
|
|
367
|
-
|
|
369
|
+
const items = track(['A', 'B']);
|
|
368
370
|
<>
|
|
369
371
|
<div class="wrapper">
|
|
370
372
|
<header class="before">{'Before'}</header>
|
|
371
|
-
@for (const item of items) {
|
|
373
|
+
@for (const item of items.value) {
|
|
372
374
|
<div class={`item-${item}`}>{item}</div>
|
|
373
375
|
}
|
|
374
376
|
<footer class="after">{'After'}</footer>
|
|
@@ -376,7 +378,7 @@ export function ForLoopWithSiblings() @{
|
|
|
376
378
|
<button
|
|
377
379
|
class="add"
|
|
378
380
|
onClick={() => {
|
|
379
|
-
items = [...items, 'C'];
|
|
381
|
+
items.value = [...items.value, 'C'];
|
|
380
382
|
}}
|
|
381
383
|
>{'Add'}</button>
|
|
382
384
|
</>
|
|
@@ -397,17 +399,17 @@ export function ForLoopItemState() @{
|
|
|
397
399
|
}
|
|
398
400
|
|
|
399
401
|
function TodoItem(props: { id: number; text: string }) @{
|
|
400
|
-
|
|
402
|
+
const done = track(false);
|
|
401
403
|
<div class={`todo-${props.id}`}>
|
|
402
404
|
<input
|
|
403
405
|
type="checkbox"
|
|
404
406
|
class="checkbox"
|
|
405
|
-
checked={done}
|
|
407
|
+
checked={done.value}
|
|
406
408
|
onChange={(e) => {
|
|
407
|
-
done = (e.target as HTMLInputElement).checked;
|
|
409
|
+
done.value = (e.target as HTMLInputElement).checked;
|
|
408
410
|
}}
|
|
409
411
|
/>
|
|
410
|
-
<span class={done ? 'completed' : 'pending'}>{props.text}</span>
|
|
412
|
+
<span class={done.value ? 'completed' : 'pending'}>{props.text}</span>
|
|
411
413
|
</div>
|
|
412
414
|
}
|
|
413
415
|
|
|
@@ -423,16 +425,16 @@ export function ForLoopSingleItem() @{
|
|
|
423
425
|
|
|
424
426
|
// Test for loop adding at beginning
|
|
425
427
|
export function ForLoopAddAtBeginning() @{
|
|
426
|
-
|
|
428
|
+
const items = track(['B', 'C']);
|
|
427
429
|
<>
|
|
428
430
|
<button
|
|
429
431
|
class="prepend"
|
|
430
432
|
onClick={() => {
|
|
431
|
-
items = ['A', ...items];
|
|
433
|
+
items.value = ['A', ...items.value];
|
|
432
434
|
}}
|
|
433
435
|
>{'Prepend A'}</button>
|
|
434
436
|
<ul>
|
|
435
|
-
@for (const item of items) {
|
|
437
|
+
@for (const item of items.value) {
|
|
436
438
|
<li class={`item-${item}`}>{item}</li>
|
|
437
439
|
}
|
|
438
440
|
</ul>
|
|
@@ -441,18 +443,18 @@ export function ForLoopAddAtBeginning() @{
|
|
|
441
443
|
|
|
442
444
|
// Test for loop adding in the middle
|
|
443
445
|
export function ForLoopAddInMiddle() @{
|
|
444
|
-
|
|
446
|
+
const items = track(['A', 'C']);
|
|
445
447
|
<>
|
|
446
448
|
<button
|
|
447
449
|
class="insert"
|
|
448
450
|
onClick={() => {
|
|
449
|
-
const copy = [...items];
|
|
451
|
+
const copy = [...items.value];
|
|
450
452
|
copy.splice(1, 0, 'B');
|
|
451
|
-
items = copy;
|
|
453
|
+
items.value = copy;
|
|
452
454
|
}}
|
|
453
455
|
>{'Insert B'}</button>
|
|
454
456
|
<ul>
|
|
455
|
-
@for (const item of items) {
|
|
457
|
+
@for (const item of items.value) {
|
|
456
458
|
<li class={`item-${item}`}>{item}</li>
|
|
457
459
|
}
|
|
458
460
|
</ul>
|
|
@@ -461,16 +463,16 @@ export function ForLoopAddInMiddle() @{
|
|
|
461
463
|
|
|
462
464
|
// Test for loop removing from the middle
|
|
463
465
|
export function ForLoopRemoveFromMiddle() @{
|
|
464
|
-
|
|
466
|
+
const items = track(['A', 'B', 'C']);
|
|
465
467
|
<>
|
|
466
468
|
<button
|
|
467
469
|
class="remove-middle"
|
|
468
470
|
onClick={() => {
|
|
469
|
-
items = items.filter((item) => item !== 'B');
|
|
471
|
+
items.value = items.value.filter((item) => item !== 'B');
|
|
470
472
|
}}
|
|
471
473
|
>{'Remove B'}</button>
|
|
472
474
|
<ul>
|
|
473
|
-
@for (const item of items) {
|
|
475
|
+
@for (const item of items.value) {
|
|
474
476
|
<li class={`item-${item}`}>{item}</li>
|
|
475
477
|
}
|
|
476
478
|
</ul>
|
|
@@ -489,18 +491,18 @@ export function ForLoopLargeList() @{
|
|
|
489
491
|
|
|
490
492
|
// Test for loop with swap operation
|
|
491
493
|
export function ForLoopSwap() @{
|
|
492
|
-
|
|
494
|
+
const items = track(['A', 'B', 'C', 'D']);
|
|
493
495
|
<>
|
|
494
496
|
<button
|
|
495
497
|
class="swap"
|
|
496
498
|
onClick={() => {
|
|
497
|
-
const copy = [...items];
|
|
499
|
+
const copy = [...items.value];
|
|
498
500
|
[copy[0], copy[3]] = [copy[3], copy[0]];
|
|
499
|
-
items = copy;
|
|
501
|
+
items.value = copy;
|
|
500
502
|
}}
|
|
501
503
|
>{'Swap First and Last'}</button>
|
|
502
504
|
<ul>
|
|
503
|
-
@for (const item of items) {
|
|
505
|
+
@for (const item of items.value) {
|
|
504
506
|
<li class={`item-${item}`}>{item}</li>
|
|
505
507
|
}
|
|
506
508
|
</ul>
|
|
@@ -509,18 +511,64 @@ export function ForLoopSwap() @{
|
|
|
509
511
|
|
|
510
512
|
// Test for loop with reverse operation
|
|
511
513
|
export function ForLoopReverse() @{
|
|
512
|
-
|
|
514
|
+
const items = track(['A', 'B', 'C', 'D']);
|
|
513
515
|
<>
|
|
514
516
|
<button
|
|
515
517
|
class="reverse"
|
|
516
518
|
onClick={() => {
|
|
517
|
-
items = [...items].reverse();
|
|
519
|
+
items.value = [...items.value].reverse();
|
|
518
520
|
}}
|
|
519
521
|
>{'Reverse'}</button>
|
|
520
522
|
<ul>
|
|
521
|
-
@for (const item of items) {
|
|
523
|
+
@for (const item of items.value) {
|
|
522
524
|
<li class={`item-${item}`}>{item}</li>
|
|
523
525
|
}
|
|
524
526
|
</ul>
|
|
525
527
|
</>
|
|
526
528
|
}
|
|
529
|
+
|
|
530
|
+
// Inserting at or moving to the end of a hydrated keyed list must land after
|
|
531
|
+
// the hydrated items, before the following sibling.
|
|
532
|
+
export function KeyedForLoopAppendAndRotate() @{
|
|
533
|
+
const items = track([1, 2, 3]);
|
|
534
|
+
<div class="wrapper">
|
|
535
|
+
<div class="host">
|
|
536
|
+
@for (const item of items.value; key item) {
|
|
537
|
+
<span class="item">{item}</span>
|
|
538
|
+
}
|
|
539
|
+
<p class="tail">{'p'}</p>
|
|
540
|
+
</div>
|
|
541
|
+
<button
|
|
542
|
+
class="push"
|
|
543
|
+
onClick={() => (items.value = [...items.value, items.value.length + 1])}
|
|
544
|
+
>{'Push'}</button>
|
|
545
|
+
<button
|
|
546
|
+
class="rotate"
|
|
547
|
+
onClick={() => (items.value = [...items.value.slice(1), items.value[0]])}
|
|
548
|
+
>{'Rotate'}</button>
|
|
549
|
+
</div>
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function RootKeyedList(props: { items: Tracked<number[]> }) @{
|
|
553
|
+
@for (const item of props.items.value; key item) {
|
|
554
|
+
<span class="item">{item}</span>
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function RootKeyedForLoopAppendAndRotate() @{
|
|
559
|
+
const items = track([1, 2, 3]);
|
|
560
|
+
<div class="wrapper">
|
|
561
|
+
<div class="host">
|
|
562
|
+
<RootKeyedList {items} />
|
|
563
|
+
<p class="tail">{'p'}</p>
|
|
564
|
+
</div>
|
|
565
|
+
<button
|
|
566
|
+
class="push"
|
|
567
|
+
onClick={() => (items.value = [...items.value, items.value.length + 1])}
|
|
568
|
+
>{'Push'}</button>
|
|
569
|
+
<button
|
|
570
|
+
class="rotate"
|
|
571
|
+
onClick={() => (items.value = [...items.value.slice(1), items.value[0]])}
|
|
572
|
+
>{'Rotate'}</button>
|
|
573
|
+
</div>
|
|
574
|
+
}
|