start refactoring transitions

pull/1937/head
Richard Harris 7 years ago
parent a7370ce024
commit e56c5653a7

@ -341,7 +341,7 @@ export default class EachBlockWrapper extends Wrapper {
block.builders.update.addBlock(deindent` block.builders.update.addBlock(deindent`
const ${this.vars.each_block_value} = ${snippet}; const ${this.vars.each_block_value} = ${snippet};
${this.block.hasOutros && `@groupOutros();`} ${this.block.hasOutros && `@group_outros();`}
${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].r();`} ${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].r();`}
${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.vars.each_block_value}, ${lookup}, ${updateMountNode}, ${destroy}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.vars.get_each_context}); ${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.vars.each_block_value}, ${lookup}, ${updateMountNode}, ${destroy}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.vars.get_each_context});
${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].a();`} ${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].a();`}
@ -466,7 +466,7 @@ export default class EachBlockWrapper extends Wrapper {
if (this.block.hasOutros) { if (this.block.hasOutros) {
destroy = deindent` destroy = deindent`
@groupOutros(); @group_outros();
for (; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 1); for (; #i < ${iterations}.length; #i += 1) ${outroBlock}(#i, 1);
`; `;
} else { } else {

@ -322,7 +322,7 @@ export default class IfBlockWrapper extends Wrapper {
const updateMountNode = this.getUpdateMountNode(anchor); const updateMountNode = this.getUpdateMountNode(anchor);
const destroyOldBlock = deindent` const destroyOldBlock = deindent`
@groupOutros(); @group_outros();
${name}.o(function() { ${name}.o(function() {
${if_blocks}[${previous_block_index}].d(1); ${if_blocks}[${previous_block_index}].d(1);
${if_blocks}[${previous_block_index}] = null; ${if_blocks}[${previous_block_index}] = null;
@ -445,7 +445,7 @@ export default class IfBlockWrapper extends Wrapper {
// as that will typically result in glitching // as that will typically result in glitching
const exit = branch.block.hasOutroMethod const exit = branch.block.hasOutroMethod
? deindent` ? deindent`
@groupOutros(); @group_outros();
${name}.o(function() { ${name}.o(function() {
${name}.d(1); ${name}.d(1);
${name} = null; ${name} = null;

@ -368,7 +368,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.builders.update.addBlock(deindent` block.builders.update.addBlock(deindent`
if (${switch_value} !== (${switch_value} = ${snippet})) { if (${switch_value} !== (${switch_value} = ${snippet})) {
if (${name}) { if (${name}) {
@groupOutros(); @group_outros();
const old_component = ${name}; const old_component = ${name};
old_component.$$.fragment.o(() => { old_component.$$.fragment.o(() => {
old_component.$destroy(); old_component.$destroy();

@ -1,5 +1,5 @@
import { assign, run_all, isPromise } from './utils.js'; import { assign, run_all, isPromise } from './utils.js';
import { groupOutros } from './transitions.js'; import { group_outros } from './transitions.js';
import { flush } from '../internal/scheduler.js'; import { flush } from '../internal/scheduler.js';
export function handlePromise(promise, info) { export function handlePromise(promise, info) {
@ -17,7 +17,7 @@ export function handlePromise(promise, info) {
if (info.blocks) { if (info.blocks) {
info.blocks.forEach((block, i) => { info.blocks.forEach((block, i) => {
if (i !== index && block) { if (i !== index && block) {
groupOutros(); group_outros();
block.o(() => { block.o(() => {
block.d(1); block.d(1);
info.blocks[i] = null; info.blocks[i] = null;

@ -2,179 +2,177 @@ import { identity as linear, noop, run } from './utils.js';
import { loop } from './loop.js'; import { loop } from './loop.js';
import { create_rule, delete_rule } from './style_manager.js'; import { create_rule, delete_rule } from './style_manager.js';
let promise;
function wait() {
if (!promise) {
promise = Promise.resolve();
promise.then(() => {
promise = null;
});
}
return promise;
}
let outros;
export function group_outros() {
outros = {
remaining: 0,
callbacks: []
};
}
export function wrapTransition(component, node, fn, params, intro) { export function wrapTransition(component, node, fn, params, intro) {
let obj = fn.call(component, node, params); let config = fn.call(component, node, params);
let duration; let duration;
let ease; let ease;
let cssText; let cssText;
let initialised = false; let initialised = false;
return { let t = intro ? 0 : 1;
t: intro ? 0 : 1, let running = false;
running: false, let running_program = null;
program: null, let pending_program = null;
pending: null,
run(b, callback) { function start(program) {
if (typeof obj === 'function') { node.dispatchEvent(new window.CustomEvent(`${program.b ? 'intro' : 'outro'}start`));
transitionManager.wait().then(() => {
obj = obj();
this._run(b, callback);
});
} else {
this._run(b, callback);
}
},
_run(b, callback) { program.a = t;
duration = obj.duration || 300; program.delta = program.b - program.a;
ease = obj.easing || linear; program.duration = duration * Math.abs(program.b - program.a);
program.end = program.start + program.duration;
const program = { if (config.css) {
start: window.performance.now() + (obj.delay || 0), if (config.delay) node.style.cssText = cssText;
b,
callback: callback || noop
};
if (intro && !initialised) { program.name = create_rule(program, ease, config.css);
if (obj.css && obj.delay) {
cssText = node.style.cssText;
node.style.cssText += obj.css(0, 1);
}
if (obj.tick) obj.tick(0, 1); node.style.animation = (node.style.animation || '')
initialised = true; .split(', ')
} .filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
.join(', ');
}
if (!b) { running_program = program;
program.group = outros.current; pending_program = null;
outros.current.remaining += 1; }
}
if (obj.delay) { function update(now) {
this.pending = program; const program = running_program;
} else { if (!program) return;
this.start(program);
}
if (!this.running) { const p = now - program.start;
this.running = true; t = program.a + program.delta * ease(p / program.duration);
if (config.tick) config.tick(t, 1 - t);
}
const { abort, promise } = loop(now => { function done() {
if (this.program && now >= this.program.end) { const program = running_program;
this.done(); running_program = null;
}
if (this.pending && now >= this.pending.start) { t = program.b;
this.start(this.pending);
}
if (this.running) { if (config.tick) config.tick(t, 1 - t);
this.update(now);
return true; node.dispatchEvent(new window.CustomEvent(`${program.b ? 'intro' : 'outro'}end`));
}
});
}
},
start(program) { if (!program.b && !program.invalidated) {
node.dispatchEvent(new window.CustomEvent(`${program.b ? 'intro' : 'outro'}start`)); program.group.callbacks.push(() => {
program.callback();
if (config.css) delete_rule(node, program.name);
});
if (--program.group.remaining === 0) {
program.group.callbacks.forEach(run);
}
} else {
if (config.css) delete_rule(node, program.name);
}
program.a = this.t; running = !!pending_program;
program.delta = program.b - program.a; }
program.duration = duration * Math.abs(program.b - program.a);
program.end = program.start + program.duration;
if (obj.css) { function go(b, callback) {
if (obj.delay) node.style.cssText = cssText; duration = config.duration || 300;
ease = config.easing || linear;
program.name = create_rule(program, ease, obj.css); const program = {
start: window.performance.now() + (config.delay || 0),
b,
callback: callback || noop
};
node.style.animation = (node.style.animation || '') if (intro && !initialised) {
.split(', ') if (config.css && config.delay) {
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim))) cssText = node.style.cssText;
.concat(`${program.name} ${program.duration}ms linear 1 forwards`) node.style.cssText += config.css(0, 1);
.join(', ');
} }
this.program = program; if (config.tick) config.tick(0, 1);
this.pending = null; initialised = true;
}, }
update(now) { if (!b) {
const program = this.program; program.group = outros;
if (!program) return; outros.remaining += 1;
}
const p = now - program.start; if (config.delay) {
this.t = program.a + program.delta * ease(p / program.duration); pending_program = program;
if (obj.tick) obj.tick(this.t, 1 - this.t); } else {
}, start(program);
}
done() { if (!running) {
const program = this.program; running = true;
this.program = null;
this.t = program.b; const { abort, promise } = loop(now => {
if (running_program && now >= running_program.end) {
done();
}
if (obj.tick) obj.tick(this.t, 1 - this.t); if (pending_program && now >= pending_program.start) {
start(pending_program);
}
node.dispatchEvent(new window.CustomEvent(`${program.b ? 'intro' : 'outro'}end`)); if (running) {
update(now);
return true;
}
});
}
}
if (!program.b && !program.invalidated) { return {
program.group.callbacks.push(() => { run(b, callback) {
program.callback(); if (typeof config === 'function') {
if (obj.css) delete_rule(node, program.name); wait().then(() => {
config = config();
go(b, callback);
}); });
if (--program.group.remaining === 0) {
program.group.callbacks.forEach(run);
}
} else { } else {
if (obj.css) delete_rule(node, program.name); go(b, callback);
} }
this.running = !!this.pending;
}, },
abort(reset) { abort(reset) {
if (reset && obj.tick) obj.tick(1, 0); if (reset && config.tick) config.tick(1, 0);
if (this.program) { if (running_program) {
if (obj.css) delete_rule(node, this.program.name); if (config.css) delete_rule(node, running_program.name);
this.program = this.pending = null; running_program = pending_program = null;
this.running = false; running = false;
} }
}, },
invalidate() { invalidate() {
if (this.program) { if (running_program) {
this.program.invalidated = true; running_program.invalidated = true;
} }
} }
}; };
} }
export let outros = {};
export function groupOutros() {
outros.current = {
remaining: 0,
callbacks: []
};
}
export var transitionManager = {
promise: null,
wait() {
if (!transitionManager.promise) {
transitionManager.promise = Promise.resolve();
transitionManager.promise.then(() => {
transitionManager.promise = null;
});
}
return transitionManager.promise;
}
};

@ -3,7 +3,7 @@ import * as path from "path";
import * as fs from "fs"; import * as fs from "fs";
import { rollup } from 'rollup'; import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual'; import * as virtual from 'rollup-plugin-virtual';
import { transitionManager, clear_loops } from "../../internal.js"; import { clear_loops } from "../../internal.js";
import { import {
showOutput, showOutput,
@ -93,9 +93,7 @@ describe("runtime", () => {
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
// set of hacks to support transition tests // hack to support transition tests
transitionManager.running = false;
transitionManager.transitions = [];
clear_loops(); clear_loops();
const raf = { const raf = {

Loading…
Cancel
Save