ripple 0.3.7 → 0.3.9
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 +14 -0
- package/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +48 -349
- package/src/compiler/phases/2-analyze/index.js +343 -52
- package/src/compiler/phases/3-transform/client/index.js +28 -160
- package/src/compiler/phases/3-transform/segments.js +0 -7
- package/src/compiler/phases/3-transform/server/index.js +31 -154
- package/src/compiler/types/acorn.d.ts +1 -1
- package/src/compiler/types/estree.d.ts +1 -1
- package/src/compiler/types/import.d.ts +0 -2
- package/src/compiler/types/index.d.ts +5 -17
- package/src/compiler/types/parse.d.ts +1 -17
- package/src/compiler/utils.js +53 -20
- package/src/runtime/index-client.js +2 -13
- package/src/runtime/index-server.js +2 -2
- package/src/runtime/internal/client/bindings.js +3 -1
- package/src/runtime/internal/client/composite.js +3 -2
- package/src/runtime/internal/client/events.js +1 -1
- package/src/runtime/internal/client/head.js +3 -4
- package/src/runtime/internal/client/index.js +0 -1
- package/src/runtime/internal/client/runtime.js +0 -52
- package/src/runtime/internal/server/index.js +31 -55
- package/tests/client/array/array.copy-within.test.ripple +12 -12
- package/tests/client/array/array.derived.test.ripple +46 -46
- package/tests/client/array/array.iteration.test.ripple +10 -10
- package/tests/client/array/array.mutations.test.ripple +20 -20
- package/tests/client/array/array.to-methods.test.ripple +6 -6
- package/tests/client/async-suspend.test.ripple +5 -5
- package/tests/client/basic/basic.attributes.test.ripple +81 -81
- package/tests/client/basic/basic.collections.test.ripple +9 -9
- package/tests/client/basic/basic.components.test.ripple +28 -28
- package/tests/client/basic/basic.errors.test.ripple +46 -18
- package/tests/client/basic/basic.events.test.ripple +37 -37
- package/tests/client/basic/basic.get-set.test.ripple +6 -6
- package/tests/client/basic/basic.reactivity.test.ripple +58 -203
- package/tests/client/basic/basic.rendering.test.ripple +19 -19
- package/tests/client/basic/basic.utilities.test.ripple +3 -3
- package/tests/client/boundaries.test.ripple +12 -12
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +5 -5
- package/tests/client/compiler/compiler.assignments.test.ripple +19 -19
- package/tests/client/compiler/compiler.basic.test.ripple +46 -27
- package/tests/client/compiler/compiler.tracked-access.test.ripple +2 -2
- package/tests/client/composite/composite.dynamic-components.test.ripple +9 -9
- package/tests/client/composite/composite.props.test.ripple +14 -16
- package/tests/client/composite/composite.reactivity.test.ripple +69 -70
- package/tests/client/composite/composite.render.test.ripple +3 -3
- package/tests/client/computed-properties.test.ripple +4 -4
- package/tests/client/date.test.ripple +42 -42
- package/tests/client/dynamic-elements.test.ripple +44 -45
- package/tests/client/events.test.ripple +70 -70
- package/tests/client/for.test.ripple +25 -25
- package/tests/client/head.test.ripple +19 -19
- package/tests/client/html.test.ripple +3 -3
- package/tests/client/input-value.test.ripple +84 -84
- package/tests/client/lazy-destructuring.test.ripple +138 -26
- package/tests/client/map.test.ripple +16 -16
- package/tests/client/media-query.test.ripple +7 -7
- package/tests/client/portal.test.ripple +11 -11
- package/tests/client/ref.test.ripple +4 -4
- package/tests/client/return.test.ripple +52 -52
- package/tests/client/set.test.ripple +6 -6
- package/tests/client/svg.test.ripple +5 -5
- package/tests/client/switch.test.ripple +44 -44
- package/tests/client/try.test.ripple +5 -5
- package/tests/client/url/url.derived.test.ripple +6 -6
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +8 -8
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +10 -10
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +10 -10
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +18 -18
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +2 -2
- package/tests/hydration/compiled/client/events.js +25 -25
- package/tests/hydration/compiled/client/for.js +70 -66
- package/tests/hydration/compiled/client/head.js +25 -25
- package/tests/hydration/compiled/client/hmr.js +2 -2
- package/tests/hydration/compiled/client/html.js +3 -3
- package/tests/hydration/compiled/client/if-children.js +24 -24
- package/tests/hydration/compiled/client/if.js +18 -18
- package/tests/hydration/compiled/client/mixed-control-flow.js +9 -9
- package/tests/hydration/compiled/client/portal.js +3 -3
- package/tests/hydration/compiled/client/reactivity.js +16 -16
- package/tests/hydration/compiled/client/return.js +40 -40
- package/tests/hydration/compiled/client/switch.js +12 -12
- package/tests/hydration/compiled/server/events.js +19 -19
- package/tests/hydration/compiled/server/for.js +41 -41
- package/tests/hydration/compiled/server/head.js +26 -26
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +2 -2
- package/tests/hydration/compiled/server/if-children.js +16 -16
- package/tests/hydration/compiled/server/if.js +11 -11
- package/tests/hydration/compiled/server/mixed-control-flow.js +6 -6
- package/tests/hydration/compiled/server/portal.js +2 -2
- package/tests/hydration/compiled/server/reactivity.js +16 -16
- package/tests/hydration/compiled/server/return.js +25 -25
- package/tests/hydration/compiled/server/switch.js +8 -8
- package/tests/hydration/components/events.ripple +25 -25
- package/tests/hydration/components/for.ripple +66 -66
- package/tests/hydration/components/head.ripple +16 -16
- package/tests/hydration/components/hmr.ripple +2 -2
- package/tests/hydration/components/html.ripple +3 -3
- package/tests/hydration/components/if-children.ripple +24 -24
- package/tests/hydration/components/if.ripple +18 -18
- package/tests/hydration/components/mixed-control-flow.ripple +9 -9
- package/tests/hydration/components/portal.ripple +3 -3
- package/tests/hydration/components/reactivity.ripple +16 -16
- package/tests/hydration/components/return.ripple +40 -40
- package/tests/hydration/components/switch.ripple +20 -20
- package/tests/server/await.test.ripple +3 -3
- package/tests/server/basic.attributes.test.ripple +34 -34
- package/tests/server/basic.components.test.ripple +10 -10
- package/tests/server/basic.test.ripple +38 -40
- package/tests/server/compiler.test.ripple +22 -0
- package/tests/server/composite.props.test.ripple +12 -14
- package/tests/server/dynamic-elements.test.ripple +15 -15
- package/tests/server/head.test.ripple +11 -11
- package/tests/server/lazy-destructuring.test.ripple +92 -13
- package/tsconfig.typecheck.json +4 -0
- package/types/index.d.ts +0 -19
- package/tests/client/__snapshots__/tracked-expression.test.ripple.snap +0 -34
- package/tests/client/tracked-expression.test.ripple +0 -26
|
@@ -16,8 +16,8 @@ describe('compiler > assignments', () => {
|
|
|
16
16
|
|
|
17
17
|
logs.push(items[0]);
|
|
18
18
|
logs.push(items[i]);
|
|
19
|
-
logs.push(
|
|
20
|
-
logs.push(
|
|
19
|
+
logs.push(tracked_items.value[0]);
|
|
20
|
+
logs.push(tracked_items.value[i]);
|
|
21
21
|
logs.push(items2[0]);
|
|
22
22
|
logs.push(items2[i]);
|
|
23
23
|
logs.push(items3[0]);
|
|
@@ -25,8 +25,8 @@ describe('compiler > assignments', () => {
|
|
|
25
25
|
|
|
26
26
|
items[0] = 123;
|
|
27
27
|
items[i] = 123;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
tracked_items.value[0] = 123;
|
|
29
|
+
tracked_items.value[i] = 123;
|
|
30
30
|
items2[0] = 123;
|
|
31
31
|
items2[i] = 123;
|
|
32
32
|
items3[0] = 123;
|
|
@@ -34,8 +34,8 @@ describe('compiler > assignments', () => {
|
|
|
34
34
|
|
|
35
35
|
logs.push(items[0]);
|
|
36
36
|
logs.push(items[i]);
|
|
37
|
-
logs.push(
|
|
38
|
-
logs.push(
|
|
37
|
+
logs.push(tracked_items.value[0]);
|
|
38
|
+
logs.push(tracked_items.value[i]);
|
|
39
39
|
logs.push(items2[0]);
|
|
40
40
|
logs.push(items2[i]);
|
|
41
41
|
logs.push(items3[0]);
|
|
@@ -43,8 +43,8 @@ describe('compiler > assignments', () => {
|
|
|
43
43
|
|
|
44
44
|
items[0]++;
|
|
45
45
|
items[i]++;
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
tracked_items.value[0]++;
|
|
47
|
+
tracked_items.value[i]++;
|
|
48
48
|
items2[0]++;
|
|
49
49
|
items2[i]++;
|
|
50
50
|
items3[0]++;
|
|
@@ -52,8 +52,8 @@ describe('compiler > assignments', () => {
|
|
|
52
52
|
|
|
53
53
|
logs.push(items[0]);
|
|
54
54
|
logs.push(items[i]);
|
|
55
|
-
logs.push(
|
|
56
|
-
logs.push(
|
|
55
|
+
logs.push(tracked_items.value[0]);
|
|
56
|
+
logs.push(tracked_items.value[i]);
|
|
57
57
|
logs.push(items2[0]);
|
|
58
58
|
logs.push(items2[i]);
|
|
59
59
|
logs.push(items3[0]);
|
|
@@ -61,8 +61,8 @@ describe('compiler > assignments', () => {
|
|
|
61
61
|
|
|
62
62
|
logs.push(--items[0]);
|
|
63
63
|
logs.push(--items[i]);
|
|
64
|
-
logs.push(
|
|
65
|
-
logs.push(
|
|
64
|
+
logs.push(--tracked_items.value[0]);
|
|
65
|
+
logs.push(--tracked_items.value[i]);
|
|
66
66
|
logs.push(--items2[0]);
|
|
67
67
|
logs.push(--items2[i]);
|
|
68
68
|
logs.push(--items3[0]);
|
|
@@ -110,10 +110,10 @@ describe('compiler > assignments', () => {
|
|
|
110
110
|
it('compiles tracked values in effect with assignment expression', () => {
|
|
111
111
|
const source = `import { track, effect } from 'ripple';
|
|
112
112
|
component App() {
|
|
113
|
-
let count = track(0);
|
|
113
|
+
let &[count] = track(0);
|
|
114
114
|
|
|
115
115
|
effect(() => {
|
|
116
|
-
state.count =
|
|
116
|
+
state.count = count;
|
|
117
117
|
});
|
|
118
118
|
}`;
|
|
119
119
|
const result = compile(source, 'test.ripple');
|
|
@@ -124,14 +124,14 @@ component App() {
|
|
|
124
124
|
it('compiles tracked values in effect with update expressions', () => {
|
|
125
125
|
const source = `import { track, effect, untrack } from 'ripple';
|
|
126
126
|
component App() {
|
|
127
|
-
let count = track(5);
|
|
127
|
+
let &[count] = track(5);
|
|
128
128
|
|
|
129
129
|
effect(() => {
|
|
130
130
|
untrack(() => {
|
|
131
|
-
state.preIncrement =
|
|
132
|
-
state.postIncrement =
|
|
133
|
-
state.preDecrement =
|
|
134
|
-
state.postDecrement =
|
|
131
|
+
state.preIncrement = ++count;
|
|
132
|
+
state.postIncrement = count++;
|
|
133
|
+
state.preDecrement = --count;
|
|
134
|
+
state.postDecrement = count--;
|
|
135
135
|
});
|
|
136
136
|
});
|
|
137
137
|
}`;
|
|
@@ -324,35 +324,23 @@ describe('compiler > basics', () => {
|
|
|
324
324
|
const source = `
|
|
325
325
|
import { RippleArray, RippleMap, RippleObject, RippleSet, createRefKey, effect, track, untrack } from 'ripple';
|
|
326
326
|
component App() {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
327
|
+
let value = track('test');
|
|
328
|
+
function inputRef(node) {}
|
|
329
|
+
|
|
330
|
+
const props = {
|
|
331
|
+
id: 'example',
|
|
332
|
+
value: value.value,
|
|
333
|
+
[createRefKey()]: inputRef,
|
|
334
|
+
};
|
|
335
335
|
}
|
|
336
336
|
`;
|
|
337
337
|
|
|
338
338
|
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
339
339
|
|
|
340
|
-
expect(result).toMatch(/value:\s*value
|
|
340
|
+
expect(result).toMatch(/value:\s*value\.value/);
|
|
341
341
|
});
|
|
342
342
|
|
|
343
343
|
it('keeps lazy destructuring as plain destructuring in to_ts output', () => {
|
|
344
|
-
const track_split_source = `
|
|
345
|
-
import { trackSplit } from 'ripple';
|
|
346
|
-
component App() {
|
|
347
|
-
const source = { a: 1, b: 2, c: 3 };
|
|
348
|
-
let &[a, b, rest] = trackSplit(source, ['a', 'b']);
|
|
349
|
-
const sum = @a + @b + @rest.c;
|
|
350
|
-
}
|
|
351
|
-
`;
|
|
352
|
-
const track_split_result = compile_to_volar_mappings(track_split_source, 'test.ripple').code;
|
|
353
|
-
expect(track_split_result).toContain('let [a, b, rest] = trackSplit(source, [\'a\', \'b\']);');
|
|
354
|
-
expect(track_split_result).not.toContain('let lazy = trackSplit');
|
|
355
|
-
|
|
356
344
|
const track_source = `
|
|
357
345
|
import { track } from 'ripple';
|
|
358
346
|
component App() {
|
|
@@ -369,6 +357,37 @@ component App() {
|
|
|
369
357
|
expect(track_result).not.toContain('lazy0');
|
|
370
358
|
});
|
|
371
359
|
|
|
360
|
+
it('uses tracked fast path for nested lazy params typed as Tracked', () => {
|
|
361
|
+
const source = `
|
|
362
|
+
import type { Tracked } from 'ripple';
|
|
363
|
+
function use_nested({ value: &[count, tracked] }: { value: Tracked<number> }) {
|
|
364
|
+
count++;
|
|
365
|
+
return tracked;
|
|
366
|
+
}
|
|
367
|
+
`;
|
|
368
|
+
const { js } = compile(source, 'tracked-nested-lazy.ripple', { mode: 'client' });
|
|
369
|
+
|
|
370
|
+
// Nested lazy array should still use tracked tuple fast path from outer annotation.
|
|
371
|
+
expect(js.code).toContain('_$_.update(');
|
|
372
|
+
expect(js.code).not.toContain('[0]');
|
|
373
|
+
expect(js.code).not.toContain('[1]');
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('uses tracked fast path for nested lazy params at tuple rest positions', () => {
|
|
377
|
+
const source = `
|
|
378
|
+
import type { Tracked } from 'ripple';
|
|
379
|
+
function use_tuple_rest({ value: [head, &[count, tracked]] }: { value: [number, ...Tracked<number>[]] }) {
|
|
380
|
+
count++;
|
|
381
|
+
return tracked;
|
|
382
|
+
}
|
|
383
|
+
`;
|
|
384
|
+
const { js } = compile(source, 'tracked-nested-lazy-tuple-rest.ripple', { mode: 'client' });
|
|
385
|
+
|
|
386
|
+
// Tuple rest element access should resolve to Tracked<number>, not Tracked<number>[].
|
|
387
|
+
expect(js.code).toContain('_$_.update(');
|
|
388
|
+
expect(js.code).not.toContain('[1]');
|
|
389
|
+
});
|
|
390
|
+
|
|
372
391
|
it('preserves generic type args in interface extends for Volar mappings', () => {
|
|
373
392
|
const source = `
|
|
374
393
|
interface PolymorphicProps<T extends keyof HTMLElementTagNameMap> {
|
|
@@ -393,13 +412,13 @@ export component App(props: Props) {
|
|
|
393
412
|
const source = `
|
|
394
413
|
import { track } from 'ripple';
|
|
395
414
|
export component App() {
|
|
396
|
-
let level = track(1);
|
|
415
|
+
let &[level] = track(1);
|
|
397
416
|
|
|
398
417
|
<button
|
|
399
418
|
onClick={() => {
|
|
400
|
-
if (
|
|
401
|
-
else if (
|
|
402
|
-
else
|
|
419
|
+
if (level === 1) level = 2;
|
|
420
|
+
else if (level === 2) level = 3;
|
|
421
|
+
else level = 1;
|
|
403
422
|
}}
|
|
404
423
|
>
|
|
405
424
|
{'Toggle'}
|
|
@@ -496,10 +515,10 @@ export component App() {
|
|
|
496
515
|
import { track, effect, untrack } from 'ripple';
|
|
497
516
|
|
|
498
517
|
component App() {
|
|
499
|
-
let count = track(0);
|
|
518
|
+
let &[count] = track(0);
|
|
500
519
|
|
|
501
520
|
effect(() => {
|
|
502
|
-
const snapshot = untrack(() =>
|
|
521
|
+
const snapshot = untrack(() => count);
|
|
503
522
|
console.log(snapshot);
|
|
504
523
|
});
|
|
505
524
|
}
|
|
@@ -70,8 +70,8 @@ import { track } from 'ripple';
|
|
|
70
70
|
const code = `
|
|
71
71
|
import { track } from 'ripple';
|
|
72
72
|
export default component App() {
|
|
73
|
-
let count = track(0);
|
|
74
|
-
console.log(
|
|
73
|
+
let &[count] = track(0);
|
|
74
|
+
console.log(count);
|
|
75
75
|
}
|
|
76
76
|
`;
|
|
77
77
|
expect(() => compile(code, 'test.ripple')).not.toThrow();
|
|
@@ -18,7 +18,7 @@ describe('composite > dynamic components', () => {
|
|
|
18
18
|
expect(container.textContent).toBe('Basic Component');
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it('supports rendering composite components
|
|
21
|
+
it('supports rendering composite components from object properties', () => {
|
|
22
22
|
component App() {
|
|
23
23
|
component basic() {
|
|
24
24
|
<div>{'Basic Component'}</div>
|
|
@@ -30,7 +30,8 @@ describe('composite > dynamic components', () => {
|
|
|
30
30
|
tracked_basic,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const comp = obj.tracked_basic;
|
|
34
|
+
<@comp />
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
render(App);
|
|
@@ -39,7 +40,7 @@ describe('composite > dynamic components', () => {
|
|
|
39
40
|
expect(container.textContent).toBe('Basic Component');
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
it('supports rendering composite components
|
|
43
|
+
it('supports rendering composite components from tracked object properties', () => {
|
|
43
44
|
component App() {
|
|
44
45
|
component basic() {
|
|
45
46
|
<div>{'Basic Component'}</div>
|
|
@@ -51,9 +52,10 @@ describe('composite > dynamic components', () => {
|
|
|
51
52
|
tracked_basic,
|
|
52
53
|
};
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
let &[inner] = track(obj);
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
const comp = inner.tracked_basic;
|
|
58
|
+
<@comp />
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
render(App);
|
|
@@ -72,15 +74,13 @@ describe('composite > dynamic components', () => {
|
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
component App() {
|
|
75
|
-
let thing = track(() => Child1);
|
|
77
|
+
let &[thing] = track(() => Child1);
|
|
76
78
|
|
|
77
79
|
<div id="container">
|
|
78
80
|
<@thing />
|
|
79
81
|
</div>
|
|
80
82
|
|
|
81
|
-
<button onClick={() => (
|
|
82
|
-
{'Change Child'}
|
|
83
|
-
</button>
|
|
83
|
+
<button onClick={() => (thing = thing === Child1 ? Child2 : Child1)}>{'Change Child'}</button>
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
render(App);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tracked, Props } from 'ripple';
|
|
2
|
-
import { effect, flushSync, track
|
|
2
|
+
import { effect, flushSync, track } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('composite > props', () => {
|
|
5
5
|
it('correctly handles default prop values', () => {
|
|
@@ -8,10 +8,10 @@ describe('composite > props', () => {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
component App() {
|
|
11
|
-
let foo = track(123);
|
|
11
|
+
let &[foo] = track(123);
|
|
12
12
|
|
|
13
13
|
<Child />
|
|
14
|
-
<Child {
|
|
14
|
+
<Child {foo} />
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
render(App);
|
|
@@ -40,7 +40,7 @@ describe('composite > props', () => {
|
|
|
40
40
|
|
|
41
41
|
it('correctly handles no props', () => {
|
|
42
42
|
component Child(props: { foo?: Tracked<number> }) {
|
|
43
|
-
<div>{props
|
|
43
|
+
<div>{props.foo?.value}</div>
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
component App() {
|
|
@@ -62,10 +62,10 @@ describe('composite > props', () => {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
component App() {
|
|
65
|
-
let foo = track(123);
|
|
65
|
+
let &[foo] = track(123);
|
|
66
66
|
|
|
67
67
|
<Child />
|
|
68
|
-
<Child {
|
|
68
|
+
<Child {foo} />
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
render(App);
|
|
@@ -79,10 +79,10 @@ describe('composite > props', () => {
|
|
|
79
79
|
|
|
80
80
|
component Counter({ count }: { count: Tracked<number> }) {
|
|
81
81
|
effect(() => {
|
|
82
|
-
logs.push(
|
|
82
|
+
logs.push(count.value);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
<button onClick={() => (
|
|
85
|
+
<button onClick={() => (count.value = count.value + 1)}>{'+'}</button>
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
component App() {
|
|
@@ -106,9 +106,8 @@ describe('composite > props', () => {
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
it('correctly retains prop accessors and reactivity when using rest props', () => {
|
|
109
|
-
component Button(
|
|
110
|
-
|
|
111
|
-
<button {...@rest}>
|
|
109
|
+
component Button(&{ children, ...rest }: Props) {
|
|
110
|
+
<button {...rest}>
|
|
112
111
|
<@children />
|
|
113
112
|
</button>
|
|
114
113
|
<style>
|
|
@@ -121,11 +120,10 @@ describe('composite > props', () => {
|
|
|
121
120
|
</style>
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
component Toggle(
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
<Button
|
|
128
|
-
<Button class={@pressed ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
|
|
123
|
+
component Toggle(&{ pressed, ...rest }: { pressed: Tracked<boolean> }) {
|
|
124
|
+
const onClick = () => (pressed.value = !pressed.value);
|
|
125
|
+
<Button {...rest} class={pressed.value ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
|
|
126
|
+
<Button class={pressed.value ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
component App() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Props, Tracked } from 'ripple';
|
|
2
|
-
import { RippleObject, effect, flushSync, track
|
|
2
|
+
import { RippleObject, effect, flushSync, track } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('composite > reactivity', () => {
|
|
5
5
|
it('renders composite components with object state', () => {
|
|
@@ -7,10 +7,10 @@ describe('composite > reactivity', () => {
|
|
|
7
7
|
<button
|
|
8
8
|
class="count2"
|
|
9
9
|
onClick={() => {
|
|
10
|
-
obj
|
|
10
|
+
obj.count.value++;
|
|
11
11
|
}}
|
|
12
12
|
>
|
|
13
|
-
{obj
|
|
13
|
+
{obj.count.value}
|
|
14
14
|
</button>
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ describe('composite > reactivity', () => {
|
|
|
20
20
|
count: track(0),
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
<span class="count">{obj
|
|
23
|
+
<span class="count">{obj.count.value}</span>
|
|
24
24
|
<Button {obj} />
|
|
25
25
|
</div>
|
|
26
26
|
}
|
|
@@ -41,15 +41,15 @@ describe('composite > reactivity', () => {
|
|
|
41
41
|
<button
|
|
42
42
|
class="count2"
|
|
43
43
|
onClick={() => {
|
|
44
|
-
obj
|
|
44
|
+
obj.count.value++;
|
|
45
45
|
}}
|
|
46
46
|
>
|
|
47
|
-
{obj
|
|
47
|
+
{obj.count.value}
|
|
48
48
|
</button>
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
component OtherComponent({ obj }: { obj: { count: Tracked<number> } }) {
|
|
52
|
-
<div class="count3">{obj
|
|
52
|
+
<div class="count3">{obj.count.value}</div>
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
component App() {
|
|
@@ -58,7 +58,7 @@ describe('composite > reactivity', () => {
|
|
|
58
58
|
count: track(0),
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
<span class="count">{obj
|
|
61
|
+
<span class="count">{obj.count.value}</span>
|
|
62
62
|
<span>{' '}</span>
|
|
63
63
|
if (obj) {
|
|
64
64
|
<Button {obj} />
|
|
@@ -84,28 +84,28 @@ describe('composite > reactivity', () => {
|
|
|
84
84
|
|
|
85
85
|
it('parents and children have isolated state', () => {
|
|
86
86
|
component Button(props: { count: number }) {
|
|
87
|
-
let count = track(() => props.count);
|
|
87
|
+
let &[count] = track(() => props.count);
|
|
88
88
|
<button
|
|
89
89
|
onClick={() => {
|
|
90
|
-
|
|
90
|
+
count++;
|
|
91
91
|
}}
|
|
92
92
|
>
|
|
93
|
-
{'child: ' +
|
|
93
|
+
{'child: ' + count}
|
|
94
94
|
</button>
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
component App() {
|
|
98
98
|
<div>
|
|
99
|
-
let count = track(0);
|
|
99
|
+
let &[count] = track(0);
|
|
100
100
|
|
|
101
101
|
<button
|
|
102
102
|
onClick={() => {
|
|
103
|
-
|
|
103
|
+
count++;
|
|
104
104
|
}}
|
|
105
105
|
>
|
|
106
|
-
{'parent: ' +
|
|
106
|
+
{'parent: ' + count}
|
|
107
107
|
</button>
|
|
108
|
-
<Button {
|
|
108
|
+
<Button {count} />
|
|
109
109
|
</div>
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -131,28 +131,28 @@ describe('composite > reactivity', () => {
|
|
|
131
131
|
|
|
132
132
|
it('parents and children have isolated connected state (destructured props)', () => {
|
|
133
133
|
component Button(&{ count }: { count: number }) {
|
|
134
|
-
let local_count = track(() => count);
|
|
134
|
+
let &[local_count] = track(() => count);
|
|
135
135
|
<button
|
|
136
136
|
onClick={() => {
|
|
137
|
-
|
|
137
|
+
local_count++;
|
|
138
138
|
}}
|
|
139
139
|
>
|
|
140
|
-
{'child: ' +
|
|
140
|
+
{'child: ' + local_count}
|
|
141
141
|
</button>
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
component App() {
|
|
145
145
|
<div>
|
|
146
|
-
let count = track(0);
|
|
146
|
+
let &[count] = track(0);
|
|
147
147
|
|
|
148
148
|
<button
|
|
149
149
|
onClick={() => {
|
|
150
|
-
|
|
150
|
+
count++;
|
|
151
151
|
}}
|
|
152
152
|
>
|
|
153
|
-
{'parent: ' +
|
|
153
|
+
{'parent: ' + count}
|
|
154
154
|
</button>
|
|
155
|
-
<Button {
|
|
155
|
+
<Button {count} />
|
|
156
156
|
</div>
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -180,25 +180,25 @@ describe('composite > reactivity', () => {
|
|
|
180
180
|
let logs: string[] = [];
|
|
181
181
|
|
|
182
182
|
component App() {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
let &[a] = track(1);
|
|
184
|
+
let &[b] = track(2);
|
|
185
|
+
let &[c] = track(3);
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
let &[obj] = track(
|
|
188
188
|
() => ({
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
a,
|
|
190
|
+
b,
|
|
191
|
+
c,
|
|
192
192
|
}),
|
|
193
193
|
);
|
|
194
194
|
|
|
195
|
-
<Child {
|
|
195
|
+
<Child {...obj} />
|
|
196
196
|
|
|
197
197
|
<button
|
|
198
198
|
onClick={() => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
a++;
|
|
200
|
+
b++;
|
|
201
|
+
c++;
|
|
202
202
|
}}
|
|
203
203
|
>
|
|
204
204
|
{'Increment all'}
|
|
@@ -227,51 +227,47 @@ describe('composite > reactivity', () => {
|
|
|
227
227
|
expect(logs).toEqual(['Child effect: 1, 2, 3', 'Child effect: 2, 3, 4']);
|
|
228
228
|
});
|
|
229
229
|
|
|
230
|
-
it(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
<CounterWrapper {@count} up={() => @count++} down={() => @count--} />
|
|
236
|
-
}
|
|
230
|
+
it('keeps reactivity for spread props via intermediate components and lazy destructuring', () => {
|
|
231
|
+
component App() {
|
|
232
|
+
let &[count] = track(0);
|
|
233
|
+
<CounterWrapper {count} up={() => count++} down={() => count--} />
|
|
234
|
+
}
|
|
237
235
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
236
|
+
component CounterWrapper(props: Props) {
|
|
237
|
+
<div>
|
|
238
|
+
<Counter {...props} />
|
|
239
|
+
</div>
|
|
240
|
+
}
|
|
243
241
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
242
|
+
component Counter(&{ count, up, down, ...rest }: Props) {
|
|
243
|
+
<button onClick={() => up()}>{'UP'}</button>
|
|
244
|
+
<button onClick={() => down()}>{'DOWN'}</button>
|
|
245
|
+
<span {...rest}>{`Counter: ${count}`}</span>
|
|
246
|
+
}
|
|
250
247
|
|
|
251
|
-
|
|
248
|
+
render(App);
|
|
252
249
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
250
|
+
const buttonIncrement = container.querySelectorAll('button')[0];
|
|
251
|
+
const buttonDecrement = container.querySelectorAll('button')[1];
|
|
252
|
+
const span = container.querySelector('span');
|
|
256
253
|
|
|
257
|
-
|
|
254
|
+
expect(span.textContent).toBe('Counter: 0');
|
|
258
255
|
|
|
259
|
-
|
|
260
|
-
|
|
256
|
+
buttonIncrement.click();
|
|
257
|
+
flushSync();
|
|
261
258
|
|
|
262
|
-
|
|
259
|
+
expect(span.textContent).toBe('Counter: 1');
|
|
263
260
|
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
buttonDecrement.click();
|
|
262
|
+
flushSync();
|
|
266
263
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
);
|
|
264
|
+
expect(span.textContent).toBe('Counter: 0');
|
|
265
|
+
});
|
|
270
266
|
|
|
271
267
|
it('keeps reactivity on elements for element spreads and adds / removes dynamic props', () => {
|
|
272
268
|
component App() {
|
|
273
|
-
|
|
274
|
-
<CounterWrapper {
|
|
269
|
+
let &[count] = track(0);
|
|
270
|
+
<CounterWrapper {count} up={() => count++} />
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
component CounterWrapper(props: { count: number; up: () => void }) {
|
|
@@ -295,16 +291,19 @@ describe('composite > reactivity', () => {
|
|
|
295
291
|
</div>
|
|
296
292
|
}
|
|
297
293
|
|
|
298
|
-
component Counter(
|
|
294
|
+
component Counter(&{
|
|
295
|
+
count,
|
|
296
|
+
up,
|
|
297
|
+
...rest
|
|
298
|
+
}: {
|
|
299
299
|
count: number;
|
|
300
300
|
up: () => void;
|
|
301
301
|
double: Tracked<number>;
|
|
302
302
|
another?: number;
|
|
303
303
|
extra: number;
|
|
304
304
|
}) {
|
|
305
|
-
|
|
306
|
-
<
|
|
307
|
-
<button onClick={() => @up()}>{'UP'}</button>
|
|
305
|
+
<div {...rest}>{`Counter: ${count} Double: ${rest.double.value}`}</div>
|
|
306
|
+
<button onClick={() => up()}>{'UP'}</button>
|
|
308
307
|
}
|
|
309
308
|
|
|
310
309
|
render(App);
|
|
@@ -7,10 +7,10 @@ describe('composite > render', () => {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
component App() {
|
|
10
|
-
let count = track(0);
|
|
10
|
+
let &[count] = track(0);
|
|
11
11
|
|
|
12
|
-
<button onClick={() =>
|
|
13
|
-
<Button {
|
|
12
|
+
<button onClick={() => count++}>{'Increment'}</button>
|
|
13
|
+
<Button {count} />
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
render(App);
|
|
@@ -7,11 +7,11 @@ describe('computed tracked properties', () => {
|
|
|
7
7
|
[0]: track(0),
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
<div>{obj
|
|
10
|
+
<div>{obj[0].value}</div>
|
|
11
11
|
|
|
12
12
|
<button
|
|
13
13
|
onClick={() => {
|
|
14
|
-
obj
|
|
14
|
+
obj[0].value += 1;
|
|
15
15
|
}}
|
|
16
16
|
>
|
|
17
17
|
{'Increment'}
|
|
@@ -34,11 +34,11 @@ describe('computed tracked properties', () => {
|
|
|
34
34
|
[0]: track(0),
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
<div>{obj
|
|
37
|
+
<div>{obj[0].value}</div>
|
|
38
38
|
|
|
39
39
|
<button
|
|
40
40
|
onClick={() => {
|
|
41
|
-
obj
|
|
41
|
+
obj[0].value++;
|
|
42
42
|
}}
|
|
43
43
|
>
|
|
44
44
|
{'Increment'}
|