ripple 0.2.208 → 0.2.210
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 +43 -0
- package/README.md +2 -1
- package/package.json +2 -6
- package/shims/rollup-estree-types.d.ts +1 -1
- package/src/compiler/index.d.ts +1 -0
- package/src/compiler/index.js +7 -1
- package/src/compiler/phases/1-parse/index.js +15 -6
- package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
- package/src/compiler/phases/2-analyze/index.js +215 -2
- package/src/compiler/phases/3-transform/client/index.js +388 -50
- package/src/compiler/phases/3-transform/segments.js +123 -39
- package/src/compiler/phases/3-transform/server/index.js +266 -13
- package/src/compiler/types/index.d.ts +16 -3
- package/src/compiler/utils.js +1 -15
- package/src/constants.js +0 -2
- package/src/helpers.d.ts +4 -0
- package/src/html-tree-validation.js +211 -0
- package/src/jsx-runtime.d.ts +260 -259
- package/src/jsx-runtime.js +12 -12
- package/src/runtime/array.js +17 -17
- package/src/runtime/create-subscriber.js +1 -1
- package/src/runtime/index-client.js +1 -5
- package/src/runtime/index-server.js +15 -0
- package/src/runtime/internal/client/compat.js +3 -3
- package/src/runtime/internal/client/composite.js +6 -1
- package/src/runtime/internal/client/head.js +50 -4
- package/src/runtime/internal/client/html.js +73 -12
- package/src/runtime/internal/client/hydration.js +12 -0
- package/src/runtime/internal/client/index.js +1 -1
- package/src/runtime/internal/client/portal.js +54 -29
- package/src/runtime/internal/client/rpc.js +3 -1
- package/src/runtime/internal/client/switch.js +5 -0
- package/src/runtime/internal/client/template.js +117 -11
- package/src/runtime/internal/client/try.js +1 -0
- package/src/runtime/internal/server/index.js +113 -1
- package/src/runtime/internal/server/rpc.js +4 -4
- package/src/runtime/map.js +2 -2
- package/src/runtime/object.js +6 -6
- package/src/runtime/proxy.js +12 -11
- package/src/runtime/reactive-value.js +9 -1
- package/src/runtime/set.js +12 -7
- package/src/runtime/url-search-params.js +0 -1
- package/src/server/index.js +4 -0
- package/src/utils/hashing.js +15 -0
- package/src/utils/normalize_css_property_name.js +1 -1
- package/tests/client/array/array.mutations.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +28 -0
- package/tests/client/basic/basic.events.test.ripple +6 -3
- package/tests/client/basic/basic.utilities.test.ripple +1 -1
- package/tests/client/compiler/compiler.regex.test.ripple +10 -8
- package/tests/client/composite/composite.generics.test.ripple +5 -2
- package/tests/client/dynamic-elements.test.ripple +30 -1
- package/tests/client/function-overload-import.ripple +6 -7
- package/tests/client/html.test.ripple +0 -1
- package/tests/client/object.test.ripple +2 -2
- package/tests/client/portal.test.ripple +3 -3
- package/tests/client/return.test.ripple +2500 -0
- package/tests/client/try.test.ripple +69 -0
- package/tests/client/typescript-generics.test.ripple +1 -1
- package/tests/client/url/url.derived.test.ripple +1 -1
- package/tests/client/url/url.parsing.test.ripple +3 -3
- package/tests/client/url/url.partial-removal.test.ripple +7 -7
- package/tests/client/url/url.reactivity.test.ripple +15 -15
- package/tests/client/url/url.serialization.test.ripple +2 -2
- package/tests/hydration/basic.test.js +23 -0
- package/tests/hydration/build-components.js +10 -4
- package/tests/hydration/compiled/client/basic.js +165 -3
- package/tests/hydration/compiled/client/for.js +1140 -23
- package/tests/hydration/compiled/client/head.js +234 -0
- package/tests/hydration/compiled/client/html.js +135 -0
- package/tests/hydration/compiled/client/portal.js +172 -0
- package/tests/hydration/compiled/client/reactivity.js +3 -1
- package/tests/hydration/compiled/client/return.js +1976 -0
- package/tests/hydration/compiled/client/switch.js +162 -0
- package/tests/hydration/compiled/server/basic.js +249 -0
- package/tests/hydration/compiled/server/events.js +1 -1
- package/tests/hydration/compiled/server/for.js +891 -1
- package/tests/hydration/compiled/server/head.js +291 -0
- package/tests/hydration/compiled/server/html.js +133 -0
- package/tests/hydration/compiled/server/if.js +1 -1
- package/tests/hydration/compiled/server/portal.js +250 -0
- package/tests/hydration/compiled/server/reactivity.js +1 -1
- package/tests/hydration/compiled/server/return.js +1969 -0
- package/tests/hydration/compiled/server/switch.js +130 -0
- package/tests/hydration/components/basic.ripple +55 -0
- package/tests/hydration/components/for.ripple +403 -0
- package/tests/hydration/components/head.ripple +111 -0
- package/tests/hydration/components/html.ripple +38 -0
- package/tests/hydration/components/portal.ripple +49 -0
- package/tests/hydration/components/return.ripple +564 -0
- package/tests/hydration/components/switch.ripple +51 -0
- package/tests/hydration/for.test.js +363 -0
- package/tests/hydration/head.test.js +105 -0
- package/tests/hydration/html.test.js +46 -0
- package/tests/hydration/portal.test.js +71 -0
- package/tests/hydration/return.test.js +544 -0
- package/tests/hydration/switch.test.js +42 -0
- package/tests/server/basic.attributes.test.ripple +1 -1
- package/tests/server/compiler.test.ripple +22 -0
- package/tests/server/composite.test.ripple +5 -2
- package/tests/server/html-nesting-validation.test.ripple +237 -0
- package/tests/server/return.test.ripple +1379 -0
- package/tests/setup-hydration.js +6 -1
- package/tests/utils/escaping.test.js +3 -1
- package/tests/utils/normalize_css_property_name.test.js +0 -1
- package/tests/utils/patterns.test.js +6 -2
- package/tests/utils/sanitize_template_string.test.js +3 -2
- package/types/server.d.ts +16 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// HTML tag hydration testing components
|
|
2
|
+
import { track } from 'ripple';
|
|
3
|
+
|
|
4
|
+
export component StaticHtml() {
|
|
5
|
+
const html = '<p><strong>Bold</strong> text</p>';
|
|
6
|
+
<div>{html html}</div>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export component DynamicHtml() {
|
|
10
|
+
const content = '<p>Dynamic <span>HTML</span> content</p>';
|
|
11
|
+
<div>{html content}</div>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export component EmptyHtml() {
|
|
15
|
+
const html = '';
|
|
16
|
+
<div>{html html}</div>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export component ComplexHtml() {
|
|
20
|
+
const html = '<div class="nested"><span>Nested <em>content</em></span></div>';
|
|
21
|
+
<section>{html html}</section>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export component MultipleHtml() {
|
|
25
|
+
const html1 = '<p>First paragraph</p>';
|
|
26
|
+
const html2 = '<p>Second paragraph</p>';
|
|
27
|
+
<div>
|
|
28
|
+
{html html1}
|
|
29
|
+
{html html2}
|
|
30
|
+
</div>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export component HtmlWithReactivity() {
|
|
34
|
+
<div>
|
|
35
|
+
{html '<p>Count: 0</p>'}
|
|
36
|
+
<button>{'Increment'}</button>
|
|
37
|
+
</div>
|
|
38
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Portal components for hydration testing
|
|
2
|
+
import { Portal } from 'ripple';
|
|
3
|
+
|
|
4
|
+
// Simple portal with static content
|
|
5
|
+
export component SimplePortal() {
|
|
6
|
+
<div class="container">
|
|
7
|
+
<h1>{'Main Content'}</h1>
|
|
8
|
+
<Portal target={typeof document !== 'undefined' ? document.body : null}>
|
|
9
|
+
<div class="portal-content">{'Portal content'}</div>
|
|
10
|
+
</Portal>
|
|
11
|
+
</div>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Portal with conditional rendering
|
|
15
|
+
export component ConditionalPortal() {
|
|
16
|
+
let show = @true;
|
|
17
|
+
|
|
18
|
+
<div class="container">
|
|
19
|
+
<button class="toggle" onClick={() => (@show = !@show)}>{'Toggle'}</button>
|
|
20
|
+
if (@show) {
|
|
21
|
+
<Portal target={typeof document !== 'undefined' ? document.body : null}>
|
|
22
|
+
<div class="portal-content">{'Portal is visible'}</div>
|
|
23
|
+
</Portal>
|
|
24
|
+
}
|
|
25
|
+
</div>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Component with portal that shouldn't break on initial load
|
|
29
|
+
export component PortalWithMainContent() {
|
|
30
|
+
<div>
|
|
31
|
+
<div class="main-content">{'Main page content'}</div>
|
|
32
|
+
<Portal target={typeof document !== 'undefined' ? document.body : null}>
|
|
33
|
+
<div class="portal-content">{'Modal content'}</div>
|
|
34
|
+
</Portal>
|
|
35
|
+
<div class="footer">{'Footer'}</div>
|
|
36
|
+
</div>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Nested portals scenario
|
|
40
|
+
export component NestedContentWithPortal() {
|
|
41
|
+
<div class="outer">
|
|
42
|
+
<div class="inner">
|
|
43
|
+
<span>{'Nested content'}</span>
|
|
44
|
+
</div>
|
|
45
|
+
<Portal target={typeof document !== 'undefined' ? document.body : null}>
|
|
46
|
+
<div class="portal-content">{'Portal content'}</div>
|
|
47
|
+
</Portal>
|
|
48
|
+
</div>
|
|
49
|
+
}
|
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
// Return statement components for hydration testing
|
|
2
|
+
import { track } from 'ripple';
|
|
3
|
+
|
|
4
|
+
// Basic return - skips content after direct return
|
|
5
|
+
export component DirectReturn() {
|
|
6
|
+
<div class="before">{'before'}</div>
|
|
7
|
+
return;
|
|
8
|
+
<div class="after">{'after'}</div>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Conditional return - condition is true, skips rest
|
|
12
|
+
export component ConditionalReturnTrue() {
|
|
13
|
+
let condition = true;
|
|
14
|
+
|
|
15
|
+
if (condition) {
|
|
16
|
+
<div class="guard">{'guard hit'}</div>
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
<div class="rest">{'rest'}</div>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Conditional return - condition is false, shows rest
|
|
23
|
+
export component ConditionalReturnFalse() {
|
|
24
|
+
let condition = false;
|
|
25
|
+
|
|
26
|
+
if (condition) {
|
|
27
|
+
<div class="guard">{'guard hit'}</div>
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
<div class="rest">{'rest'}</div>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Content before and after return guard
|
|
34
|
+
export component ContentBeforeAfterReturn() {
|
|
35
|
+
let shouldReturn = true;
|
|
36
|
+
|
|
37
|
+
<div class="before">{'before'}</div>
|
|
38
|
+
if (shouldReturn) {
|
|
39
|
+
<div class="guard">{'guard'}</div>
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
<div class="after">{'after'}</div>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Multiple elements after guard when condition is false
|
|
46
|
+
export component MultipleElementsAfterGuard() {
|
|
47
|
+
let shouldReturn = false;
|
|
48
|
+
|
|
49
|
+
if (shouldReturn) {
|
|
50
|
+
<div class="guard">{'guard'}</div>
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
<div class="first">{'first'}</div>
|
|
54
|
+
<div class="second">{'second'}</div>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Multiple sequential returns - first hits
|
|
58
|
+
export component MultipleReturnsFirstHits() {
|
|
59
|
+
let a = true;
|
|
60
|
+
let b = true;
|
|
61
|
+
|
|
62
|
+
if (a) {
|
|
63
|
+
<div class="first">{'first guard'}</div>
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (b) {
|
|
67
|
+
<div class="second">{'second guard'}</div>
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
<div class="rest">{'rest'}</div>
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Multiple sequential returns - second hits
|
|
74
|
+
export component MultipleReturnsSecondHits() {
|
|
75
|
+
let a = false;
|
|
76
|
+
let b = true;
|
|
77
|
+
|
|
78
|
+
if (a) {
|
|
79
|
+
<div class="first">{'first guard'}</div>
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (b) {
|
|
83
|
+
<div class="second">{'second guard'}</div>
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
<div class="rest">{'rest'}</div>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Multiple sequential returns - none hit
|
|
90
|
+
export component MultipleReturnsNoneHit() {
|
|
91
|
+
let a = false;
|
|
92
|
+
let b = false;
|
|
93
|
+
|
|
94
|
+
if (a) {
|
|
95
|
+
<div class="first">{'first guard'}</div>
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (b) {
|
|
99
|
+
<div class="second">{'second guard'}</div>
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
<div class="rest">{'rest'}</div>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Nested returns - both conditions true
|
|
106
|
+
export component NestedReturnsAllTrue() {
|
|
107
|
+
let a = true;
|
|
108
|
+
let b = true;
|
|
109
|
+
|
|
110
|
+
if (a) {
|
|
111
|
+
<div class="a">{'a is true'}</div>
|
|
112
|
+
if (b) {
|
|
113
|
+
<div class="b">{'b is true'}</div>
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
<div class="rest">{'rest'}</div>
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Nested returns - inner condition false
|
|
121
|
+
export component NestedReturnsInnerFalse() {
|
|
122
|
+
let a = true;
|
|
123
|
+
let b = false;
|
|
124
|
+
|
|
125
|
+
if (a) {
|
|
126
|
+
<div class="a">{'a is true'}</div>
|
|
127
|
+
if (b) {
|
|
128
|
+
<div class="b">{'b is true'}</div>
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
<div class="rest">{'rest'}</div>
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Nested returns - outer condition false
|
|
136
|
+
export component NestedReturnsOuterFalse() {
|
|
137
|
+
let a = false;
|
|
138
|
+
let b = true;
|
|
139
|
+
|
|
140
|
+
if (a) {
|
|
141
|
+
<div class="a">{'a is true'}</div>
|
|
142
|
+
if (b) {
|
|
143
|
+
<div class="b">{'b is true'}</div>
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
<div class="rest">{'rest'}</div>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Deeply nested returns (3 levels) - all true
|
|
151
|
+
export component DeeplyNestedReturnsAllTrue() {
|
|
152
|
+
let a = true;
|
|
153
|
+
let b = true;
|
|
154
|
+
let c = true;
|
|
155
|
+
|
|
156
|
+
if (a) {
|
|
157
|
+
<div class="a">{'a'}</div>
|
|
158
|
+
if (b) {
|
|
159
|
+
<div class="b">{'b'}</div>
|
|
160
|
+
if (c) {
|
|
161
|
+
<div class="c">{'c'}</div>
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
<div class="rest">{'rest'}</div>
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Deeply nested returns (3 levels) - innermost false
|
|
170
|
+
export component DeeplyNestedReturnsInnermostFalse() {
|
|
171
|
+
let a = true;
|
|
172
|
+
let b = true;
|
|
173
|
+
let c = false;
|
|
174
|
+
|
|
175
|
+
if (a) {
|
|
176
|
+
<div class="a">{'a'}</div>
|
|
177
|
+
if (b) {
|
|
178
|
+
<div class="b">{'b'}</div>
|
|
179
|
+
if (c) {
|
|
180
|
+
<div class="c">{'c'}</div>
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
<div class="rest">{'rest'}</div>
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Return with else-if chain - first condition
|
|
189
|
+
export component ElseIfChainFirst() {
|
|
190
|
+
let value = 1;
|
|
191
|
+
|
|
192
|
+
if (value === 1) {
|
|
193
|
+
<div class="one">{'one'}</div>
|
|
194
|
+
return;
|
|
195
|
+
} else if (value === 2) {
|
|
196
|
+
<div class="two">{'two'}</div>
|
|
197
|
+
return;
|
|
198
|
+
} else {
|
|
199
|
+
<div class="other">{'other'}</div>
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
<div class="never">{'never reached'}</div>
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Return with else-if chain - second condition
|
|
206
|
+
export component ElseIfChainSecond() {
|
|
207
|
+
let value = 2;
|
|
208
|
+
|
|
209
|
+
if (value === 1) {
|
|
210
|
+
<div class="one">{'one'}</div>
|
|
211
|
+
return;
|
|
212
|
+
} else if (value === 2) {
|
|
213
|
+
<div class="two">{'two'}</div>
|
|
214
|
+
return;
|
|
215
|
+
} else {
|
|
216
|
+
<div class="other">{'other'}</div>
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
<div class="never">{'never reached'}</div>
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Return with else-if chain - else condition
|
|
223
|
+
export component ElseIfChainElse() {
|
|
224
|
+
let value = 3;
|
|
225
|
+
|
|
226
|
+
if (value === 1) {
|
|
227
|
+
<div class="one">{'one'}</div>
|
|
228
|
+
return;
|
|
229
|
+
} else if (value === 2) {
|
|
230
|
+
<div class="two">{'two'}</div>
|
|
231
|
+
return;
|
|
232
|
+
} else {
|
|
233
|
+
<div class="other">{'other'}</div>
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
<div class="never">{'never reached'}</div>
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Return with else branch that does not return
|
|
240
|
+
export component ReturnWithElseNoReturn() {
|
|
241
|
+
let condition = false;
|
|
242
|
+
|
|
243
|
+
if (condition) {
|
|
244
|
+
<div class="true">{'condition true'}</div>
|
|
245
|
+
return;
|
|
246
|
+
} else {
|
|
247
|
+
<div class="false">{'condition false'}</div>
|
|
248
|
+
}
|
|
249
|
+
<div class="after">{'after if-else'}</div>
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Return with else branch that also returns
|
|
253
|
+
export component ReturnWithElseBothReturn() {
|
|
254
|
+
let condition = false;
|
|
255
|
+
|
|
256
|
+
if (condition) {
|
|
257
|
+
<div class="true">{'condition true'}</div>
|
|
258
|
+
return;
|
|
259
|
+
} else {
|
|
260
|
+
<div class="false">{'condition false'}</div>
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
<div class="never">{'never reached'}</div>
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Reactive return - starts true, can toggle to false
|
|
267
|
+
export component ReactiveReturnTrueToFalse() {
|
|
268
|
+
let condition = track(true);
|
|
269
|
+
|
|
270
|
+
<button
|
|
271
|
+
class="toggle"
|
|
272
|
+
onClick={() => {
|
|
273
|
+
@condition = !@condition;
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
{'Toggle'}
|
|
277
|
+
</button>
|
|
278
|
+
if (@condition) {
|
|
279
|
+
<div class="guard">{'guard hit'}</div>
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
<div class="rest">{'rest'}</div>
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Reactive return - starts false, can toggle to true
|
|
286
|
+
export component ReactiveReturnFalseToTrue() {
|
|
287
|
+
let condition = track(false);
|
|
288
|
+
|
|
289
|
+
<button
|
|
290
|
+
class="toggle"
|
|
291
|
+
onClick={() => {
|
|
292
|
+
@condition = !@condition;
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
{'Toggle'}
|
|
296
|
+
</button>
|
|
297
|
+
if (@condition) {
|
|
298
|
+
<div class="guard">{'guard hit'}</div>
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
<div class="rest">{'rest'}</div>
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Reactive nested return - only inner condition (b) is tracked
|
|
305
|
+
export component ReactiveNestedReturn() {
|
|
306
|
+
let a = true;
|
|
307
|
+
let b = track(true);
|
|
308
|
+
|
|
309
|
+
<button
|
|
310
|
+
class="toggle"
|
|
311
|
+
onClick={() => {
|
|
312
|
+
@b = !@b;
|
|
313
|
+
}}
|
|
314
|
+
>
|
|
315
|
+
{'Toggle'}
|
|
316
|
+
</button>
|
|
317
|
+
if (a) {
|
|
318
|
+
<div class="a">{'a'}</div>
|
|
319
|
+
if (@b) {
|
|
320
|
+
<div class="b">{'b'}</div>
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
<div class="rest">{'rest'}</div>
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Return inside nested element scope
|
|
328
|
+
export component ReturnInNestedElement() {
|
|
329
|
+
let show = true;
|
|
330
|
+
|
|
331
|
+
<div class="outer">
|
|
332
|
+
<span class="label">{'outer'}</span>
|
|
333
|
+
if (show) {
|
|
334
|
+
<p class="inner">{'inner'}</p>
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
</div>
|
|
338
|
+
<div class="after">{'after'}</div>
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Return with multiple elements before and after
|
|
342
|
+
export component ReturnWithMultipleElements() {
|
|
343
|
+
let shouldReturn = true;
|
|
344
|
+
|
|
345
|
+
<h1 class="title">{'title'}</h1>
|
|
346
|
+
<p class="desc">{'description'}</p>
|
|
347
|
+
if (shouldReturn) {
|
|
348
|
+
<div class="guard">{'guard'}</div>
|
|
349
|
+
<span class="guard-span">{'guard span'}</span>
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
<footer class="footer">{'footer'}</footer>
|
|
353
|
+
<nav class="nav">{'nav'}</nav>
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Return at the beginning of component
|
|
357
|
+
export component ReturnAtBeginning() {
|
|
358
|
+
if (true) {
|
|
359
|
+
<div class="early">{'early exit'}</div>
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
<div class="never1">{'never reached 1'}</div>
|
|
363
|
+
<div class="never2">{'never reached 2'}</div>
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Return at the end of component (after all content)
|
|
367
|
+
export component ReturnAtEnd() {
|
|
368
|
+
<div class="first">{'first'}</div>
|
|
369
|
+
<div class="second">{'second'}</div>
|
|
370
|
+
if (true) {
|
|
371
|
+
<div class="third">{'third'}</div>
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Multiple sibling returns at same level
|
|
377
|
+
export component MultipleSiblingReturns() {
|
|
378
|
+
let mode = 'b';
|
|
379
|
+
|
|
380
|
+
if (mode === 'a') {
|
|
381
|
+
<div class="mode-a">{'mode A'}</div>
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (mode === 'b') {
|
|
386
|
+
<div class="mode-b">{'mode B'}</div>
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (mode === 'c') {
|
|
391
|
+
<div class="mode-c">{'mode C'}</div>
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
<div class="default">{'default mode'}</div>
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Reactive sibling returns - cycles first -> second -> fallback
|
|
399
|
+
export component ReactiveSiblingReturns() {
|
|
400
|
+
let mode = track('first');
|
|
401
|
+
|
|
402
|
+
<button
|
|
403
|
+
class="toggle"
|
|
404
|
+
onClick={() => {
|
|
405
|
+
if (@mode === 'first') {
|
|
406
|
+
@mode = 'second';
|
|
407
|
+
} else if (@mode === 'second') {
|
|
408
|
+
@mode = 'none';
|
|
409
|
+
} else {
|
|
410
|
+
@mode = 'first';
|
|
411
|
+
}
|
|
412
|
+
}}
|
|
413
|
+
>
|
|
414
|
+
{'Toggle'}
|
|
415
|
+
</button>
|
|
416
|
+
|
|
417
|
+
if (@mode === 'first') {
|
|
418
|
+
<div class="first">{'first guard'}</div>
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (@mode === 'second') {
|
|
423
|
+
<div class="second">{'second guard'}</div>
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
<div class="rest">{'rest'}</div>
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Reactive nested returns with tracked outer and inner conditions
|
|
431
|
+
export component ReactiveOuterInnerReturns() {
|
|
432
|
+
let a = track(true);
|
|
433
|
+
let b = track(true);
|
|
434
|
+
|
|
435
|
+
<button
|
|
436
|
+
class="toggle-a"
|
|
437
|
+
onClick={() => {
|
|
438
|
+
@a = !@a;
|
|
439
|
+
}}
|
|
440
|
+
>
|
|
441
|
+
{'Toggle A'}
|
|
442
|
+
</button>
|
|
443
|
+
|
|
444
|
+
<button
|
|
445
|
+
class="toggle-b"
|
|
446
|
+
onClick={() => {
|
|
447
|
+
@b = !@b;
|
|
448
|
+
}}
|
|
449
|
+
>
|
|
450
|
+
{'Toggle B'}
|
|
451
|
+
</button>
|
|
452
|
+
|
|
453
|
+
if (@a) {
|
|
454
|
+
<div class="a">{'a'}</div>
|
|
455
|
+
if (@b) {
|
|
456
|
+
<div class="b">{'b'}</div>
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
<div class="rest">{@a ? 'a-on rest' : 'a-off rest'}</div>
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Reactive else-if return chain that transitions between return and non-return states
|
|
465
|
+
export component ReactiveElseIfReturns() {
|
|
466
|
+
let status = track(0);
|
|
467
|
+
|
|
468
|
+
<button
|
|
469
|
+
class="toggle"
|
|
470
|
+
onClick={() => {
|
|
471
|
+
@status = (@status + 1) % 3;
|
|
472
|
+
}}
|
|
473
|
+
>
|
|
474
|
+
{'Toggle'}
|
|
475
|
+
</button>
|
|
476
|
+
|
|
477
|
+
if (@status === 0) {
|
|
478
|
+
<div class="zero">{'zero'}</div>
|
|
479
|
+
return;
|
|
480
|
+
} else if (@status === 1) {
|
|
481
|
+
<div class="one">{'one'}</div>
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
<div class="rest">{'rest'}</div>
|
|
486
|
+
<div class="tail">{'tail'}</div>
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Deeply nested independent return guards with multiple root-level siblings
|
|
490
|
+
export component ReactiveDeepNestedIndependentReturns() {
|
|
491
|
+
let c1 = track(false);
|
|
492
|
+
let c2 = track(false);
|
|
493
|
+
let c3 = track(false);
|
|
494
|
+
let c4 = track(false);
|
|
495
|
+
|
|
496
|
+
<button
|
|
497
|
+
class="toggle-c1"
|
|
498
|
+
onClick={() => {
|
|
499
|
+
@c1 = !@c1;
|
|
500
|
+
}}
|
|
501
|
+
>
|
|
502
|
+
{'Toggle C1'}
|
|
503
|
+
</button>
|
|
504
|
+
<button
|
|
505
|
+
class="toggle-c2"
|
|
506
|
+
onClick={() => {
|
|
507
|
+
@c2 = !@c2;
|
|
508
|
+
}}
|
|
509
|
+
>
|
|
510
|
+
{'Toggle C2'}
|
|
511
|
+
</button>
|
|
512
|
+
<button
|
|
513
|
+
class="toggle-c3"
|
|
514
|
+
onClick={() => {
|
|
515
|
+
@c3 = !@c3;
|
|
516
|
+
}}
|
|
517
|
+
>
|
|
518
|
+
{'Toggle C3'}
|
|
519
|
+
</button>
|
|
520
|
+
<button
|
|
521
|
+
class="toggle-c4"
|
|
522
|
+
onClick={() => {
|
|
523
|
+
@c4 = !@c4;
|
|
524
|
+
}}
|
|
525
|
+
>
|
|
526
|
+
{'Toggle C4'}
|
|
527
|
+
</button>
|
|
528
|
+
|
|
529
|
+
<div class="top">{'top'}</div>
|
|
530
|
+
|
|
531
|
+
if (@c1) {
|
|
532
|
+
<div class="hit-1">{'hit-1'}</div>
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
<div class="middle">{'middle'}</div>
|
|
537
|
+
<section class="nest-1">
|
|
538
|
+
<div class="nest-1-a">{'nest-1-a'}</div>
|
|
539
|
+
if (@c2) {
|
|
540
|
+
<div class="hit-2">{'hit-2'}</div>
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
<div class="nest-1-b">{'nest-1-b'}</div>
|
|
545
|
+
<section class="nest-2">
|
|
546
|
+
<div class="nest-2-a">{'nest-2-a'}</div>
|
|
547
|
+
if (@c3) {
|
|
548
|
+
<div class="hit-3">{'hit-3'}</div>
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
<div class="nest-2-b">{'nest-2-b'}</div>
|
|
553
|
+
if (@c4) {
|
|
554
|
+
<div class="hit-4">{'hit-4'}</div>
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
</section>
|
|
558
|
+
</section>
|
|
559
|
+
|
|
560
|
+
<div class="root-1">{'root-1'}</div>
|
|
561
|
+
<div class="root-2">{'root-2'}</div>
|
|
562
|
+
<div class="root-3">{'root-3'}</div>
|
|
563
|
+
<div class="root-4">{'root-4'}</div>
|
|
564
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
3
|
+
export component SwitchStatic() {
|
|
4
|
+
const status = 'success';
|
|
5
|
+
switch (status) {
|
|
6
|
+
case 'success':
|
|
7
|
+
<div class="status-success">{'Success'}</div>
|
|
8
|
+
break;
|
|
9
|
+
case 'error':
|
|
10
|
+
<div class="status-error">{'Error'}</div>
|
|
11
|
+
break;
|
|
12
|
+
default:
|
|
13
|
+
<div class="status-unknown">{'Unknown'}</div>
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export component SwitchReactive() {
|
|
18
|
+
let status = track<'a' | 'b' | 'c'>('a');
|
|
19
|
+
<button
|
|
20
|
+
class="toggle"
|
|
21
|
+
onClick={() => {
|
|
22
|
+
if (@status === 'a') @status = 'b';
|
|
23
|
+
else if (@status === 'b') @status = 'c';
|
|
24
|
+
else @status = 'a';
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
{'Toggle'}
|
|
28
|
+
</button>
|
|
29
|
+
switch (@status) {
|
|
30
|
+
case 'a':
|
|
31
|
+
<div class="case-a">{'Case A'}</div>
|
|
32
|
+
break;
|
|
33
|
+
case 'b':
|
|
34
|
+
<div class="case-b">{'Case B'}</div>
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
<div class="case-c">{'Case C'}</div>
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export component SwitchFallthrough() {
|
|
42
|
+
const val = 1;
|
|
43
|
+
switch (val) {
|
|
44
|
+
case 1:
|
|
45
|
+
case 2:
|
|
46
|
+
<div class="case-1-2">{'1 or 2'}</div>
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
<div class="case-other">{'Other'}</div>
|
|
50
|
+
}
|
|
51
|
+
}
|