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.
Files changed (108) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +2 -1
  3. package/package.json +2 -6
  4. package/shims/rollup-estree-types.d.ts +1 -1
  5. package/src/compiler/index.d.ts +1 -0
  6. package/src/compiler/index.js +7 -1
  7. package/src/compiler/phases/1-parse/index.js +15 -6
  8. package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
  9. package/src/compiler/phases/2-analyze/index.js +215 -2
  10. package/src/compiler/phases/3-transform/client/index.js +388 -50
  11. package/src/compiler/phases/3-transform/segments.js +123 -39
  12. package/src/compiler/phases/3-transform/server/index.js +266 -13
  13. package/src/compiler/types/index.d.ts +16 -3
  14. package/src/compiler/utils.js +1 -15
  15. package/src/constants.js +0 -2
  16. package/src/helpers.d.ts +4 -0
  17. package/src/html-tree-validation.js +211 -0
  18. package/src/jsx-runtime.d.ts +260 -259
  19. package/src/jsx-runtime.js +12 -12
  20. package/src/runtime/array.js +17 -17
  21. package/src/runtime/create-subscriber.js +1 -1
  22. package/src/runtime/index-client.js +1 -5
  23. package/src/runtime/index-server.js +15 -0
  24. package/src/runtime/internal/client/compat.js +3 -3
  25. package/src/runtime/internal/client/composite.js +6 -1
  26. package/src/runtime/internal/client/head.js +50 -4
  27. package/src/runtime/internal/client/html.js +73 -12
  28. package/src/runtime/internal/client/hydration.js +12 -0
  29. package/src/runtime/internal/client/index.js +1 -1
  30. package/src/runtime/internal/client/portal.js +54 -29
  31. package/src/runtime/internal/client/rpc.js +3 -1
  32. package/src/runtime/internal/client/switch.js +5 -0
  33. package/src/runtime/internal/client/template.js +117 -11
  34. package/src/runtime/internal/client/try.js +1 -0
  35. package/src/runtime/internal/server/index.js +113 -1
  36. package/src/runtime/internal/server/rpc.js +4 -4
  37. package/src/runtime/map.js +2 -2
  38. package/src/runtime/object.js +6 -6
  39. package/src/runtime/proxy.js +12 -11
  40. package/src/runtime/reactive-value.js +9 -1
  41. package/src/runtime/set.js +12 -7
  42. package/src/runtime/url-search-params.js +0 -1
  43. package/src/server/index.js +4 -0
  44. package/src/utils/hashing.js +15 -0
  45. package/src/utils/normalize_css_property_name.js +1 -1
  46. package/tests/client/array/array.mutations.test.ripple +8 -8
  47. package/tests/client/basic/basic.errors.test.ripple +28 -0
  48. package/tests/client/basic/basic.events.test.ripple +6 -3
  49. package/tests/client/basic/basic.utilities.test.ripple +1 -1
  50. package/tests/client/compiler/compiler.regex.test.ripple +10 -8
  51. package/tests/client/composite/composite.generics.test.ripple +5 -2
  52. package/tests/client/dynamic-elements.test.ripple +30 -1
  53. package/tests/client/function-overload-import.ripple +6 -7
  54. package/tests/client/html.test.ripple +0 -1
  55. package/tests/client/object.test.ripple +2 -2
  56. package/tests/client/portal.test.ripple +3 -3
  57. package/tests/client/return.test.ripple +2500 -0
  58. package/tests/client/try.test.ripple +69 -0
  59. package/tests/client/typescript-generics.test.ripple +1 -1
  60. package/tests/client/url/url.derived.test.ripple +1 -1
  61. package/tests/client/url/url.parsing.test.ripple +3 -3
  62. package/tests/client/url/url.partial-removal.test.ripple +7 -7
  63. package/tests/client/url/url.reactivity.test.ripple +15 -15
  64. package/tests/client/url/url.serialization.test.ripple +2 -2
  65. package/tests/hydration/basic.test.js +23 -0
  66. package/tests/hydration/build-components.js +10 -4
  67. package/tests/hydration/compiled/client/basic.js +165 -3
  68. package/tests/hydration/compiled/client/for.js +1140 -23
  69. package/tests/hydration/compiled/client/head.js +234 -0
  70. package/tests/hydration/compiled/client/html.js +135 -0
  71. package/tests/hydration/compiled/client/portal.js +172 -0
  72. package/tests/hydration/compiled/client/reactivity.js +3 -1
  73. package/tests/hydration/compiled/client/return.js +1976 -0
  74. package/tests/hydration/compiled/client/switch.js +162 -0
  75. package/tests/hydration/compiled/server/basic.js +249 -0
  76. package/tests/hydration/compiled/server/events.js +1 -1
  77. package/tests/hydration/compiled/server/for.js +891 -1
  78. package/tests/hydration/compiled/server/head.js +291 -0
  79. package/tests/hydration/compiled/server/html.js +133 -0
  80. package/tests/hydration/compiled/server/if.js +1 -1
  81. package/tests/hydration/compiled/server/portal.js +250 -0
  82. package/tests/hydration/compiled/server/reactivity.js +1 -1
  83. package/tests/hydration/compiled/server/return.js +1969 -0
  84. package/tests/hydration/compiled/server/switch.js +130 -0
  85. package/tests/hydration/components/basic.ripple +55 -0
  86. package/tests/hydration/components/for.ripple +403 -0
  87. package/tests/hydration/components/head.ripple +111 -0
  88. package/tests/hydration/components/html.ripple +38 -0
  89. package/tests/hydration/components/portal.ripple +49 -0
  90. package/tests/hydration/components/return.ripple +564 -0
  91. package/tests/hydration/components/switch.ripple +51 -0
  92. package/tests/hydration/for.test.js +363 -0
  93. package/tests/hydration/head.test.js +105 -0
  94. package/tests/hydration/html.test.js +46 -0
  95. package/tests/hydration/portal.test.js +71 -0
  96. package/tests/hydration/return.test.js +544 -0
  97. package/tests/hydration/switch.test.js +42 -0
  98. package/tests/server/basic.attributes.test.ripple +1 -1
  99. package/tests/server/compiler.test.ripple +22 -0
  100. package/tests/server/composite.test.ripple +5 -2
  101. package/tests/server/html-nesting-validation.test.ripple +237 -0
  102. package/tests/server/return.test.ripple +1379 -0
  103. package/tests/setup-hydration.js +6 -1
  104. package/tests/utils/escaping.test.js +3 -1
  105. package/tests/utils/normalize_css_property_name.test.js +0 -1
  106. package/tests/utils/patterns.test.js +6 -2
  107. package/tests/utils/sanitize_template_string.test.js +3 -2
  108. 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
+ }