ripple 0.3.83 → 0.3.85
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 +73 -0
- package/package.json +3 -3
- package/src/constants.js +4 -0
- package/src/runtime/index-client.js +2 -0
- package/src/runtime/index-server.js +13 -0
- package/src/runtime/internal/client/component.js +3 -3
- package/src/runtime/internal/client/constants.js +4 -0
- package/src/runtime/internal/client/for.js +22 -1
- package/src/runtime/internal/client/if.js +18 -2
- package/src/runtime/internal/client/index.js +1 -0
- package/src/runtime/internal/client/operations.js +25 -0
- package/src/runtime/internal/client/runtime.js +62 -10
- package/src/runtime/internal/client/switch.js +16 -2
- package/src/runtime/internal/client/template.js +10 -2
- package/src/runtime/internal/client/try.js +12 -2
- package/src/runtime/internal/client/types.d.ts +4 -0
- package/src/runtime/proxy.js +17 -1
- package/tests/client/__snapshots__/for.test.tsrx.snap +0 -2
- package/tests/client/compiler/compiler.basic.test.tsrx +5 -2
- package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -4
- package/tests/client/object.test.tsrx +47 -1
- package/tests/client/scoped-flush.test.tsrx +105 -0
- package/tests/hydration/compiled/client/basic.js +198 -214
- package/tests/hydration/compiled/client/composite.js +23 -72
- package/tests/hydration/compiled/client/for.js +66 -72
- package/tests/hydration/compiled/client/hmr.js +2 -13
- package/tests/hydration/compiled/client/html.js +619 -479
- package/tests/hydration/compiled/client/if-children.js +72 -84
- package/tests/hydration/compiled/client/if.js +87 -92
- package/tests/hydration/compiled/client/mixed-control-flow.js +120 -160
- package/tests/hydration/compiled/client/nested-control-flow.js +288 -360
- package/tests/hydration/compiled/client/portal.js +15 -21
- package/tests/hydration/compiled/client/reactivity.js +7 -12
- package/tests/hydration/compiled/client/switch.js +113 -115
- package/tests/hydration/compiled/client/track-async-serialization.js +71 -122
- package/tests/hydration/compiled/client/try.js +26 -41
- package/tests/hydration/compiled/server/basic.js +268 -556
- package/tests/hydration/compiled/server/composite.js +31 -50
- package/tests/hydration/compiled/server/events.js +37 -173
- package/tests/hydration/compiled/server/for.js +236 -847
- package/tests/hydration/compiled/server/head.js +110 -241
- package/tests/hydration/compiled/server/hmr.js +14 -41
- package/tests/hydration/compiled/server/html-in-template.js +14 -38
- package/tests/hydration/compiled/server/html.js +951 -1176
- package/tests/hydration/compiled/server/if-children.js +59 -493
- package/tests/hydration/compiled/server/if.js +57 -209
- package/tests/hydration/compiled/server/mixed-control-flow.js +144 -250
- package/tests/hydration/compiled/server/nested-control-flow.js +309 -559
- package/tests/hydration/compiled/server/portal.js +94 -156
- package/tests/hydration/compiled/server/reactivity.js +23 -65
- package/tests/hydration/compiled/server/return.js +6 -16
- package/tests/hydration/compiled/server/switch.js +91 -219
- package/tests/hydration/compiled/server/track-async-serialization.js +211 -256
- package/tests/hydration/compiled/server/try.js +67 -126
- package/tests/hydration/components/html.tsrx +75 -0
- package/tests/hydration/html.test.js +50 -0
- package/tests/server/compiler.test.tsrx +6 -2
- package/types/index.d.ts +2 -0
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`composite > render > correct handles passing through component props and children 1`] = `
|
|
4
4
|
<div>
|
|
5
|
-
<!---->
|
|
6
5
|
<div>
|
|
7
6
|
<div>
|
|
8
7
|
I am A
|
|
@@ -17,21 +16,18 @@ exports[`composite > render > correct handles passing through component props an
|
|
|
17
16
|
</div>
|
|
18
17
|
<!---->
|
|
19
18
|
</div>
|
|
20
|
-
<!---->
|
|
21
19
|
|
|
22
20
|
</div>
|
|
23
21
|
`;
|
|
24
22
|
|
|
25
23
|
exports[`composite > render > render simple text as children 1`] = `
|
|
26
24
|
<div>
|
|
27
|
-
<!---->
|
|
28
25
|
<button
|
|
29
26
|
class="my-button"
|
|
30
27
|
>
|
|
31
28
|
Click Me
|
|
32
29
|
<!---->
|
|
33
30
|
</button>
|
|
34
|
-
<!---->
|
|
35
31
|
|
|
36
32
|
</div>
|
|
37
33
|
`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RippleObject, flushSync } from 'ripple';
|
|
1
|
+
import { RippleObject, effect, flushSync, snapshot } from 'ripple';
|
|
2
2
|
import { TRACKED_OBJECT } from '../../src/runtime/internal/client/constants.js';
|
|
3
3
|
|
|
4
4
|
describe('RippleObject', () => {
|
|
@@ -194,4 +194,50 @@ describe('RippleObject', () => {
|
|
|
194
194
|
expect(pre1.textContent).toBe('1');
|
|
195
195
|
expect(pre3.textContent).toBe('{"a":1,"b":1,"c":{"d":{"e":8}}}');
|
|
196
196
|
});
|
|
197
|
+
|
|
198
|
+
it('snapshot() returns a detached plain copy of current values', () => {
|
|
199
|
+
let snap: any;
|
|
200
|
+
|
|
201
|
+
function ObjectTest() @{
|
|
202
|
+
const obj = new RippleObject({ a: 1, b: 2 });
|
|
203
|
+
obj.a = 10;
|
|
204
|
+
snap = snapshot(obj);
|
|
205
|
+
// a later mutation must not affect the snapshot
|
|
206
|
+
obj.a = 99;
|
|
207
|
+
<div />
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
render(ObjectTest);
|
|
211
|
+
|
|
212
|
+
expect(snap).toEqual({ a: 10, b: 2 });
|
|
213
|
+
// detached: a plain object, not a proxy
|
|
214
|
+
expect(TRACKED_OBJECT in snap).toBe(false);
|
|
215
|
+
expect(snap.a).toBe(10);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('snapshot() reads without registering reactivity', () => {
|
|
219
|
+
let runs = 0;
|
|
220
|
+
|
|
221
|
+
function ObjectTest() @{
|
|
222
|
+
const obj = new RippleObject({ a: 0 });
|
|
223
|
+
effect(() => {
|
|
224
|
+
snapshot(obj);
|
|
225
|
+
runs++;
|
|
226
|
+
});
|
|
227
|
+
<button
|
|
228
|
+
onClick={() => {
|
|
229
|
+
obj.a++;
|
|
230
|
+
}}
|
|
231
|
+
>{'Increment A'}</button>
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
render(ObjectTest);
|
|
235
|
+
flushSync();
|
|
236
|
+
expect(runs).toBe(1);
|
|
237
|
+
|
|
238
|
+
container.querySelectorAll('button')[0].click();
|
|
239
|
+
flushSync();
|
|
240
|
+
// snapshot did not subscribe, so the effect must not re-run
|
|
241
|
+
expect(runs).toBe(1);
|
|
242
|
+
});
|
|
197
243
|
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { flushSync, track, Context } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('scoped flush', () => {
|
|
4
|
+
// Scoped descent must not change observable behaviour: a tracked shared across
|
|
5
|
+
// sibling subtrees via a module-level variable (escaping its owner subtree)
|
|
6
|
+
// must still update its out-of-subtree subscriber.
|
|
7
|
+
it('updates a sibling subtree that reads a module-smuggled tracked', () => {
|
|
8
|
+
let shared = null;
|
|
9
|
+
let bump = null;
|
|
10
|
+
|
|
11
|
+
function Producer() @{
|
|
12
|
+
let &[v, vT] = track(0);
|
|
13
|
+
shared = vT;
|
|
14
|
+
bump = () => {
|
|
15
|
+
v += 1;
|
|
16
|
+
};
|
|
17
|
+
<div class="producer">{'producer'}</div>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function Consumer() @{
|
|
21
|
+
<div class="consumer">
|
|
22
|
+
{shared ? shared.value : -1}
|
|
23
|
+
</div>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function App() @{
|
|
27
|
+
<>
|
|
28
|
+
<Producer />
|
|
29
|
+
<Consumer />
|
|
30
|
+
</>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
render(App);
|
|
34
|
+
|
|
35
|
+
expect(container.querySelector('.consumer').textContent).toBe('0');
|
|
36
|
+
|
|
37
|
+
flushSync(() => bump());
|
|
38
|
+
|
|
39
|
+
expect(container.querySelector('.consumer').textContent).toBe('1');
|
|
40
|
+
|
|
41
|
+
flushSync(() => bump());
|
|
42
|
+
|
|
43
|
+
expect(container.querySelector('.consumer').textContent).toBe('2');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// The common, scope-safe case: a Context-provided tracked read at many leaves.
|
|
47
|
+
// A root update must fan out to all leaves; a scoped update must reach only the
|
|
48
|
+
// targeted subtree's leaf and leave the others untouched.
|
|
49
|
+
it('fans out a root update and scopes a nested update', () => {
|
|
50
|
+
const Ctx = new Context(null);
|
|
51
|
+
let bumpRoot = null;
|
|
52
|
+
let bumpLeftLocal = null;
|
|
53
|
+
|
|
54
|
+
function Leaf(props) @{
|
|
55
|
+
const rootT = Ctx.get();
|
|
56
|
+
<span class={'leaf-' + props.id}>
|
|
57
|
+
{rootT ? rootT.value : -1}
|
|
58
|
+
</span>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function Branch(props) @{
|
|
62
|
+
let &[local, localT] = track(0);
|
|
63
|
+
if (props.side === 'L') {
|
|
64
|
+
bumpLeftLocal = () => {
|
|
65
|
+
local += 1;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
<div class={'branch-' + props.side}>
|
|
69
|
+
<Leaf id={props.side + '0'} />
|
|
70
|
+
<Leaf id={props.side + '1'} />
|
|
71
|
+
</div>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function App() @{
|
|
75
|
+
let &[root, rootT] = track(0);
|
|
76
|
+
Ctx.set(rootT);
|
|
77
|
+
bumpRoot = () => {
|
|
78
|
+
root += 1;
|
|
79
|
+
};
|
|
80
|
+
<div>
|
|
81
|
+
<Branch side="L" />
|
|
82
|
+
<Branch side="R" />
|
|
83
|
+
</div>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
render(App);
|
|
87
|
+
|
|
88
|
+
const leaves = () => ['L0', 'L1', 'R0', 'R1'].map(
|
|
89
|
+
(id) => container.querySelector('.leaf-' + id).textContent,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
expect(leaves()).toEqual(['0', '0', '0', '0']);
|
|
93
|
+
|
|
94
|
+
flushSync(() => bumpRoot());
|
|
95
|
+
expect(leaves()).toEqual(['1', '1', '1', '1']);
|
|
96
|
+
|
|
97
|
+
flushSync(() => bumpLeftLocal());
|
|
98
|
+
// Local bump touches no Context value, so leaf text is unchanged, but the
|
|
99
|
+
// update must flush without error and not disturb sibling subtrees.
|
|
100
|
+
expect(leaves()).toEqual(['1', '1', '1', '1']);
|
|
101
|
+
|
|
102
|
+
flushSync(() => bumpRoot());
|
|
103
|
+
expect(leaves()).toEqual(['2', '2', '2', '2']);
|
|
104
|
+
});
|
|
105
|
+
});
|