Merge pull request #1420 from sveltejs/gh-956

Allow transitions in await blocks
pull/1422/head
Rich Harris 7 years ago committed by GitHub
commit 21bc182fe7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,6 +42,8 @@ export default class AwaitBlock extends Node {
block.addDependencies(this.expression.dependencies);
let isDynamic = false;
let hasIntros = false;
let hasOutros = false;
['pending', 'then', 'catch'].forEach(status => {
const child = this[status];
@ -58,11 +60,22 @@ export default class AwaitBlock extends Node {
isDynamic = true;
block.addDependencies(child.block.dependencies);
}
if (child.block.hasIntroMethod) hasIntros = true;
if (child.block.hasOutroMethod) hasOutros = true;
});
this.pending.block.hasUpdateMethod = isDynamic;
this.then.block.hasUpdateMethod = isDynamic;
this.catch.block.hasUpdateMethod = isDynamic;
this.pending.block.hasIntroMethod = hasIntros;
this.then.block.hasIntroMethod = hasIntros;
this.catch.block.hasIntroMethod = hasIntros;
this.pending.block.hasOutroMethod = hasOutros;
this.then.block.hasOutroMethod = hasOutros;
this.catch.block.hasOutroMethod = hasOutros;
}
build(
@ -92,7 +105,8 @@ export default class AwaitBlock extends Node {
this.then.block.name && `then: ${this.then.block.name}`,
this.catch.block.name && `catch: ${this.catch.block.name}`,
this.then.block.name && `value: '${this.value}'`,
this.catch.block.name && `error: '${this.error}'`
this.catch.block.name && `error: '${this.error}'`,
this.pending.block.hasOutroMethod && `blocks: Array(3)`
].filter(Boolean);
block.builders.init.addBlock(deindent`
@ -101,10 +115,6 @@ export default class AwaitBlock extends Node {
};
`);
// the `#component.root.set({})` below is just a cheap way to flush
// any oncreate handlers. We could have a dedicated `flush()` method
// but it's probably not worth it
block.builders.init.addBlock(deindent`
@handlePromise(${promise} = ${snippet}, ${info});
`);
@ -123,7 +133,7 @@ export default class AwaitBlock extends Node {
const anchorNode = parentNode ? 'null' : 'anchor';
block.builders.mount.addBlock(deindent`
${info}.block.m(${initialMountNode}, ${info}.anchor = ${anchorNode});
${info}.block.${this.pending.block.hasIntroMethod ? 'i' : 'm'}(${initialMountNode}, ${info}.anchor = ${anchorNode});
${info}.mount = () => ${updateMountNode};
`);

@ -3,7 +3,7 @@ import { assign, isPromise } from './utils.js';
export function handlePromise(promise, info) {
var token = info.token = {};
function update(type, key, value) {
function update(type, index, key, value) {
if (info.token !== token) return;
info.resolved = key && { [key]: value };
@ -12,32 +12,44 @@ export function handlePromise(promise, info) {
const block = type && (info.current = type)(info.component, child_ctx);
if (info.block) {
info.block.u();
info.block.d();
if (info.blocks) {
info.blocks.forEach((block, i) => {
if (i !== index && block) block.o(() => {
block.u();
block.d();
info.blocks[i] = null;
});
});
} else {
info.block.u();
info.block.d();
}
block.c();
block.m(info.mount(), info.anchor);
block[block.i ? 'i' : 'm'](info.mount(), info.anchor);
info.component.root.set({});
info.component.root.set({}); // flush any handlers that were created
}
info.block = block;
if (info.blocks) info.blocks[index] = block;
}
if (isPromise(promise)) {
promise.then(value => {
update(info.then, info.value, value);
update(info.then, 1, info.value, value);
}, error => {
update(info.catch, info.error, error);
update(info.catch, 2, info.error, error);
});
// if we previously had a then/catch block, destroy it
if (info.current !== info.pending) {
update(info.pending);
update(info.pending, 0);
return true;
}
} else {
if (info.current !== info.then) {
update(info.then, info.value, promise);
update(info.then, 1, info.value, promise);
return true;
}

@ -0,0 +1,35 @@
let fulfil;
let reject;
let promise = new Promise((f, r) => {
fulfil = f;
reject = r;
});
export default {
data: {
promise
},
test(assert, component, target, window, raf) {
component.set({ visible: true });
let p = target.querySelector('p');
assert.equal(p.className, 'pending');
assert.equal(p.foo, 0);
raf.tick(50);
assert.equal(p.foo, 0.5);
fulfil(42);
return promise.then(() => {
raf.tick(80);
let ps = document.querySelectorAll('p');
assert.equal(ps[0].className, 'pending');
assert.equal(ps[1].className, 'then');
assert.equal(ps[0].foo, 0.2);
assert.equal(ps[1].foo, 0.3);
});
}
};

@ -0,0 +1,22 @@
{#await promise}
<p class='pending' transition:foo>loading...</p>
{:then value}
<p class='then' transition:foo>{value}</p>
{:catch error}
<p class='catch' transition:foo>{error.message}</p>
{/await}
<script>
export default {
transitions: {
foo(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
}
};
</script>
Loading…
Cancel
Save