Skip to content

Commit 21bc182

Browse files
authored
Merge pull request #1420 from sveltejs/gh-956
Allow transitions in await blocks
2 parents 49c594e + 08480b7 commit 21bc182

File tree

4 files changed

+94
-15
lines changed

4 files changed

+94
-15
lines changed

src/compile/nodes/AwaitBlock.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export default class AwaitBlock extends Node {
4242
block.addDependencies(this.expression.dependencies);
4343

4444
let isDynamic = false;
45+
let hasIntros = false;
46+
let hasOutros = false;
4547

4648
['pending', 'then', 'catch'].forEach(status => {
4749
const child = this[status];
@@ -58,11 +60,22 @@ export default class AwaitBlock extends Node {
5860
isDynamic = true;
5961
block.addDependencies(child.block.dependencies);
6062
}
63+
64+
if (child.block.hasIntroMethod) hasIntros = true;
65+
if (child.block.hasOutroMethod) hasOutros = true;
6166
});
6267

6368
this.pending.block.hasUpdateMethod = isDynamic;
6469
this.then.block.hasUpdateMethod = isDynamic;
6570
this.catch.block.hasUpdateMethod = isDynamic;
71+
72+
this.pending.block.hasIntroMethod = hasIntros;
73+
this.then.block.hasIntroMethod = hasIntros;
74+
this.catch.block.hasIntroMethod = hasIntros;
75+
76+
this.pending.block.hasOutroMethod = hasOutros;
77+
this.then.block.hasOutroMethod = hasOutros;
78+
this.catch.block.hasOutroMethod = hasOutros;
6679
}
6780

6881
build(
@@ -92,7 +105,8 @@ export default class AwaitBlock extends Node {
92105
this.then.block.name && `then: ${this.then.block.name}`,
93106
this.catch.block.name && `catch: ${this.catch.block.name}`,
94107
this.then.block.name && `value: '${this.value}'`,
95-
this.catch.block.name && `error: '${this.error}'`
108+
this.catch.block.name && `error: '${this.error}'`,
109+
this.pending.block.hasOutroMethod && `blocks: Array(3)`
96110
].filter(Boolean);
97111

98112
block.builders.init.addBlock(deindent`
@@ -101,10 +115,6 @@ export default class AwaitBlock extends Node {
101115
};
102116
`);
103117

104-
// the `#component.root.set({})` below is just a cheap way to flush
105-
// any oncreate handlers. We could have a dedicated `flush()` method
106-
// but it's probably not worth it
107-
108118
block.builders.init.addBlock(deindent`
109119
@handlePromise(${promise} = ${snippet}, ${info});
110120
`);
@@ -123,7 +133,7 @@ export default class AwaitBlock extends Node {
123133
const anchorNode = parentNode ? 'null' : 'anchor';
124134

125135
block.builders.mount.addBlock(deindent`
126-
${info}.block.m(${initialMountNode}, ${info}.anchor = ${anchorNode});
136+
${info}.block.${this.pending.block.hasIntroMethod ? 'i' : 'm'}(${initialMountNode}, ${info}.anchor = ${anchorNode});
127137
${info}.mount = () => ${updateMountNode};
128138
`);
129139

src/shared/await-block.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { assign, isPromise } from './utils.js';
33
export function handlePromise(promise, info) {
44
var token = info.token = {};
55

6-
function update(type, key, value) {
6+
function update(type, index, key, value) {
77
if (info.token !== token) return;
88

99
info.resolved = key && { [key]: value };
@@ -12,32 +12,44 @@ export function handlePromise(promise, info) {
1212
const block = type && (info.current = type)(info.component, child_ctx);
1313

1414
if (info.block) {
15-
info.block.u();
16-
info.block.d();
15+
if (info.blocks) {
16+
info.blocks.forEach((block, i) => {
17+
if (i !== index && block) block.o(() => {
18+
block.u();
19+
block.d();
20+
info.blocks[i] = null;
21+
});
22+
});
23+
} else {
24+
info.block.u();
25+
info.block.d();
26+
}
27+
1728
block.c();
18-
block.m(info.mount(), info.anchor);
29+
block[block.i ? 'i' : 'm'](info.mount(), info.anchor);
1930

20-
info.component.root.set({});
31+
info.component.root.set({}); // flush any handlers that were created
2132
}
2233

2334
info.block = block;
35+
if (info.blocks) info.blocks[index] = block;
2436
}
2537

2638
if (isPromise(promise)) {
2739
promise.then(value => {
28-
update(info.then, info.value, value);
40+
update(info.then, 1, info.value, value);
2941
}, error => {
30-
update(info.catch, info.error, error);
42+
update(info.catch, 2, info.error, error);
3143
});
3244

3345
// if we previously had a then/catch block, destroy it
3446
if (info.current !== info.pending) {
35-
update(info.pending);
47+
update(info.pending, 0);
3648
return true;
3749
}
3850
} else {
3951
if (info.current !== info.then) {
40-
update(info.then, info.value, promise);
52+
update(info.then, 1, info.value, promise);
4153
return true;
4254
}
4355

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
let fulfil;
2+
let reject;
3+
4+
let promise = new Promise((f, r) => {
5+
fulfil = f;
6+
reject = r;
7+
});
8+
9+
export default {
10+
data: {
11+
promise
12+
},
13+
14+
test(assert, component, target, window, raf) {
15+
component.set({ visible: true });
16+
let p = target.querySelector('p');
17+
18+
assert.equal(p.className, 'pending');
19+
assert.equal(p.foo, 0);
20+
21+
raf.tick(50);
22+
assert.equal(p.foo, 0.5);
23+
24+
fulfil(42);
25+
26+
return promise.then(() => {
27+
raf.tick(80);
28+
let ps = document.querySelectorAll('p');
29+
assert.equal(ps[0].className, 'pending');
30+
assert.equal(ps[1].className, 'then');
31+
assert.equal(ps[0].foo, 0.2);
32+
assert.equal(ps[1].foo, 0.3);
33+
});
34+
}
35+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{#await promise}
2+
<p class='pending' transition:foo>loading...</p>
3+
{:then value}
4+
<p class='then' transition:foo>{value}</p>
5+
{:catch error}
6+
<p class='catch' transition:foo>{error.message}</p>
7+
{/await}
8+
9+
<script>
10+
export default {
11+
transitions: {
12+
foo(node, params) {
13+
return {
14+
duration: 100,
15+
tick: t => {
16+
node.foo = t;
17+
}
18+
};
19+
}
20+
}
21+
};
22+
</script>

0 commit comments

Comments
 (0)