|
|
@ -1,48 +1,35 @@
|
|
|
|
import { createElement } from './dom.js';
|
|
|
|
import { createElement } from './dom.js';
|
|
|
|
|
|
|
|
import { noop } from './utils.js';
|
|
|
|
|
|
|
|
|
|
|
|
export function linear(t) {
|
|
|
|
export function linear(t) {
|
|
|
|
return t;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function generateRule(
|
|
|
|
export function generateRule({ a, b, delta, duration }, ease, fn) {
|
|
|
|
a,
|
|
|
|
let keyframes = '{\n';
|
|
|
|
b,
|
|
|
|
|
|
|
|
delta,
|
|
|
|
for (let p = 0; p <= 1; p += 16.666 / duration) {
|
|
|
|
duration,
|
|
|
|
const t = a + delta * ease(p);
|
|
|
|
ease,
|
|
|
|
keyframes += p * 100 + `%{${fn(t)}}\n`;
|
|
|
|
fn
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
var keyframes = '{\n';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var p = 0; p <= 1; p += 16.666 / duration) {
|
|
|
|
|
|
|
|
var t = a + delta * ease(p);
|
|
|
|
|
|
|
|
keyframes += p * 100 + '%{' + fn(t) + '}\n';
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return keyframes + '100% {' + fn(b) + '}\n}';
|
|
|
|
return keyframes + `100% {${fn(b)}}\n}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/darkskyapp/string-hash/blob/master/index.js
|
|
|
|
// https://github.com/darkskyapp/string-hash/blob/master/index.js
|
|
|
|
export function hash(str) {
|
|
|
|
export function hash(str) {
|
|
|
|
var hash = 5381;
|
|
|
|
let hash = 5381;
|
|
|
|
var i = str.length;
|
|
|
|
let i = str.length;
|
|
|
|
|
|
|
|
|
|
|
|
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
|
|
|
|
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
|
|
|
|
return hash >>> 0;
|
|
|
|
return hash >>> 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function wrapTransition(component, node, fn, params, intro, outgroup) {
|
|
|
|
export function wrapTransition(component, node, fn, params, intro) {
|
|
|
|
var obj = fn(node, params);
|
|
|
|
const obj = fn(node, params);
|
|
|
|
var duration = obj.duration || 300;
|
|
|
|
const duration = obj.duration || 300;
|
|
|
|
var ease = obj.easing || linear;
|
|
|
|
const ease = obj.easing || linear;
|
|
|
|
var cssText;
|
|
|
|
let cssText;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO share <style> tag between all transitions?
|
|
|
|
|
|
|
|
if (obj.css && !transitionManager.stylesheet) {
|
|
|
|
|
|
|
|
var style = createElement('style');
|
|
|
|
|
|
|
|
document.head.appendChild(style);
|
|
|
|
|
|
|
|
transitionManager.stylesheet = style.sheet;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intro) {
|
|
|
|
if (intro) {
|
|
|
|
if (obj.css && obj.delay) {
|
|
|
|
if (obj.css && obj.delay) {
|
|
|
@ -58,13 +45,19 @@ export function wrapTransition(component, node, fn, params, intro, outgroup) {
|
|
|
|
running: false,
|
|
|
|
running: false,
|
|
|
|
program: null,
|
|
|
|
program: null,
|
|
|
|
pending: null,
|
|
|
|
pending: null,
|
|
|
|
run: function(intro, callback) {
|
|
|
|
|
|
|
|
var program = {
|
|
|
|
run(b, callback) {
|
|
|
|
|
|
|
|
const program = {
|
|
|
|
start: window.performance.now() + (obj.delay || 0),
|
|
|
|
start: window.performance.now() + (obj.delay || 0),
|
|
|
|
intro: intro,
|
|
|
|
b,
|
|
|
|
callback: callback
|
|
|
|
callback: callback || noop
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!b) {
|
|
|
|
|
|
|
|
program.group = transitionManager.outros;
|
|
|
|
|
|
|
|
transitionManager.outros.remaining += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (obj.delay) {
|
|
|
|
if (obj.delay) {
|
|
|
|
this.pending = program;
|
|
|
|
this.pending = program;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -76,11 +69,11 @@ export function wrapTransition(component, node, fn, params, intro, outgroup) {
|
|
|
|
transitionManager.add(this);
|
|
|
|
transitionManager.add(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
start: function(program) {
|
|
|
|
|
|
|
|
component.fire(program.intro ? 'intro.start' : 'outro.start', { node: node });
|
|
|
|
start(program) {
|
|
|
|
|
|
|
|
component.fire(`${program.b ? 'intro' : 'outro'}.start`, { node });
|
|
|
|
|
|
|
|
|
|
|
|
program.a = this.t;
|
|
|
|
program.a = this.t;
|
|
|
|
program.b = program.intro ? 1 : 0;
|
|
|
|
|
|
|
|
program.delta = program.b - program.a;
|
|
|
|
program.delta = program.b - program.a;
|
|
|
|
program.duration = duration * Math.abs(program.b - program.a);
|
|
|
|
program.duration = duration * Math.abs(program.b - program.a);
|
|
|
|
program.end = program.start + program.duration;
|
|
|
|
program.end = program.start + program.duration;
|
|
|
@ -88,48 +81,55 @@ export function wrapTransition(component, node, fn, params, intro, outgroup) {
|
|
|
|
if (obj.css) {
|
|
|
|
if (obj.css) {
|
|
|
|
if (obj.delay) node.style.cssText = cssText;
|
|
|
|
if (obj.delay) node.style.cssText = cssText;
|
|
|
|
|
|
|
|
|
|
|
|
program.rule = generateRule(
|
|
|
|
const rule = generateRule(program, ease, obj.css);
|
|
|
|
program.a,
|
|
|
|
transitionManager.addRule(rule, program.name = '__svelte_' + hash(rule));
|
|
|
|
program.b,
|
|
|
|
|
|
|
|
program.delta,
|
|
|
|
|
|
|
|
program.duration,
|
|
|
|
|
|
|
|
ease,
|
|
|
|
|
|
|
|
obj.css
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transitionManager.addRule(program.rule, program.name = '__svelte_' + hash(program.rule));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
node.style.animation = (node.style.animation || '')
|
|
|
|
node.style.animation = (node.style.animation || '')
|
|
|
|
.split(', ')
|
|
|
|
.split(', ')
|
|
|
|
.filter(function(anim) {
|
|
|
|
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
|
|
|
|
// when introing, discard old animations if there are any
|
|
|
|
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
|
|
|
|
return anim && (program.delta < 0 || !/__svelte/.test(anim));
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.concat(program.name + ' ' + program.duration + 'ms linear 1 forwards')
|
|
|
|
|
|
|
|
.join(', ');
|
|
|
|
.join(', ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.program = program;
|
|
|
|
this.program = program;
|
|
|
|
this.pending = null;
|
|
|
|
this.pending = null;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
update: function(now) {
|
|
|
|
|
|
|
|
var program = this.program;
|
|
|
|
update(now) {
|
|
|
|
|
|
|
|
const program = this.program;
|
|
|
|
if (!program) return;
|
|
|
|
if (!program) return;
|
|
|
|
|
|
|
|
|
|
|
|
var p = now - program.start;
|
|
|
|
const p = now - program.start;
|
|
|
|
this.t = program.a + program.delta * ease(p / program.duration);
|
|
|
|
this.t = program.a + program.delta * ease(p / program.duration);
|
|
|
|
if (obj.tick) obj.tick(this.t);
|
|
|
|
if (obj.tick) obj.tick(this.t);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
done: function() {
|
|
|
|
|
|
|
|
var program = this.program;
|
|
|
|
done() {
|
|
|
|
|
|
|
|
const program = this.program;
|
|
|
|
this.t = program.b;
|
|
|
|
this.t = program.b;
|
|
|
|
|
|
|
|
|
|
|
|
if (obj.tick) obj.tick(this.t);
|
|
|
|
if (obj.tick) obj.tick(this.t);
|
|
|
|
if (obj.css) transitionManager.deleteRule(node, program.name);
|
|
|
|
|
|
|
|
program.callback();
|
|
|
|
component.fire(`${program.b ? 'intro' : 'outro'}.end`, { node });
|
|
|
|
program = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (!program.b) {
|
|
|
|
|
|
|
|
program.group.callbacks.push(() => {
|
|
|
|
|
|
|
|
program.callback();
|
|
|
|
|
|
|
|
if (obj.css) transitionManager.deleteRule(node, program.name);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (--program.group.remaining === 0) {
|
|
|
|
|
|
|
|
program.group.callbacks.forEach(fn => {
|
|
|
|
|
|
|
|
fn();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.program = null;
|
|
|
|
this.running = !!this.pending;
|
|
|
|
this.running = !!this.pending;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
abort: function() {
|
|
|
|
|
|
|
|
|
|
|
|
abort() {
|
|
|
|
if (obj.tick) obj.tick(1);
|
|
|
|
if (obj.tick) obj.tick(1);
|
|
|
|
if (obj.css) transitionManager.deleteRule(node, this.program.name);
|
|
|
|
if (obj.css) transitionManager.deleteRule(node, this.program.name);
|
|
|
|
this.program = this.pending = null;
|
|
|
|
this.program = this.pending = null;
|
|
|
@ -145,7 +145,7 @@ export var transitionManager = {
|
|
|
|
stylesheet: null,
|
|
|
|
stylesheet: null,
|
|
|
|
activeRules: {},
|
|
|
|
activeRules: {},
|
|
|
|
|
|
|
|
|
|
|
|
add: function(transition) {
|
|
|
|
add(transition) {
|
|
|
|
this.transitions.push(transition);
|
|
|
|
this.transitions.push(transition);
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.running) {
|
|
|
|
if (!this.running) {
|
|
|
@ -154,21 +154,27 @@ export var transitionManager = {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
addRule: function(rule, name) {
|
|
|
|
addRule(rule, name) {
|
|
|
|
|
|
|
|
if (!this.stylesheet) {
|
|
|
|
|
|
|
|
const style = createElement('style');
|
|
|
|
|
|
|
|
document.head.appendChild(style);
|
|
|
|
|
|
|
|
transitionManager.stylesheet = style.sheet;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.activeRules[name]) {
|
|
|
|
if (!this.activeRules[name]) {
|
|
|
|
this.activeRules[name] = true;
|
|
|
|
this.activeRules[name] = true;
|
|
|
|
this.stylesheet.insertRule('@keyframes ' + name + ' ' + rule, this.stylesheet.cssRules.length);
|
|
|
|
this.stylesheet.insertRule(`@keyframes ${name} ${rule}`, this.stylesheet.cssRules.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
next: function() {
|
|
|
|
next() {
|
|
|
|
this.running = false;
|
|
|
|
this.running = false;
|
|
|
|
|
|
|
|
|
|
|
|
var now = window.performance.now();
|
|
|
|
const now = window.performance.now();
|
|
|
|
var i = this.transitions.length;
|
|
|
|
let i = this.transitions.length;
|
|
|
|
|
|
|
|
|
|
|
|
while (i--) {
|
|
|
|
while (i--) {
|
|
|
|
var transition = this.transitions[i];
|
|
|
|
const transition = this.transitions[i];
|
|
|
|
|
|
|
|
|
|
|
|
if (transition.program && now >= transition.program.end) {
|
|
|
|
if (transition.program && now >= transition.program.end) {
|
|
|
|
transition.done();
|
|
|
|
transition.done();
|
|
|
@ -189,18 +195,23 @@ export var transitionManager = {
|
|
|
|
if (this.running) {
|
|
|
|
if (this.running) {
|
|
|
|
requestAnimationFrame(this.bound);
|
|
|
|
requestAnimationFrame(this.bound);
|
|
|
|
} else if (this.stylesheet) {
|
|
|
|
} else if (this.stylesheet) {
|
|
|
|
var i = this.stylesheet.cssRules.length;
|
|
|
|
let i = this.stylesheet.cssRules.length;
|
|
|
|
while (i--) this.stylesheet.deleteRule(i);
|
|
|
|
while (i--) this.stylesheet.deleteRule(i);
|
|
|
|
this.activeRules = {};
|
|
|
|
this.activeRules = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
deleteRule: function(node, name) {
|
|
|
|
deleteRule(node, name) {
|
|
|
|
node.style.animation = node.style.animation
|
|
|
|
node.style.animation = node.style.animation
|
|
|
|
.split(', ')
|
|
|
|
.split(', ')
|
|
|
|
.filter(function(anim) {
|
|
|
|
.filter(anim => anim.indexOf(name) === -1)
|
|
|
|
return anim.indexOf(name) === -1;
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.join(', ');
|
|
|
|
.join(', ');
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
groupOutros() {
|
|
|
|
|
|
|
|
this.outros = {
|
|
|
|
|
|
|
|
remaining: 0,
|
|
|
|
|
|
|
|
callbacks: []
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|