small refactor, fix in-out-in transitions

pull/1971/head
Richard Harris 7 years ago
parent 1f6d0221e2
commit 7f258bec71

@ -26,15 +26,8 @@ export function animate(node, from, fn, params) {
function start() { function start() {
if (css) { if (css) {
if (delay) node.style.cssText = cssText; if (delay) node.style.cssText = cssText; // TODO create delayed animation instead?
name = create_rule(node, 0, 1, duration, 0, easing, css);
name = create_rule(0, 1, duration, easing, css);
node.style.animation = (node.style.animation || '')
.split(', ')
.filter(anim => anim && !/__svelte/.test(anim))
.concat(`${name} ${duration}ms linear 1 forwards`)
.join(', ');
} }
started = true; started = true;

@ -13,7 +13,7 @@ function hash(str) {
return hash >>> 0; return hash >>> 0;
} }
export function create_rule(a, b, duration, ease, fn) { export function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) {
const step = 16.666 / duration; const step = 16.666 / duration;
let keyframes = '{\n'; let keyframes = '{\n';
@ -23,7 +23,7 @@ export function create_rule(a, b, duration, ease, fn) {
} }
const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`; const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
const name = `__svelte_${hash(rule)}`; const name = `__svelte_${hash(rule)}_${uid}`;
if (!current_rules[name]) { if (!current_rules[name]) {
if (!stylesheet) { if (!stylesheet) {
@ -36,14 +36,20 @@ export function create_rule(a, b, duration, ease, fn) {
stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length); stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
} }
const animation = node.style.animation || '';
node.style.animation = `${animation ? `${animation}, ` : ``}${name} ${duration}ms linear ${delay}ms 1 both`;
active += 1; active += 1;
return name; return name;
} }
export function delete_rule(node, name) { export function delete_rule(node, name) {
node.style.animation = node.style.animation node.style.animation = (node.style.animation || '')
.split(', ') .split(', ')
.filter(anim => anim.indexOf(name) < 0) .filter(name
? anim => anim.indexOf(name) < 0 // remove specific animation
: anim => anim.indexOf('__svelte') === -1 // remove all Svelte animations
)
.join(', '); .join(', ');
if (!--active) clear_rules(); if (!--active) clear_rules();

@ -1,6 +1,6 @@
import { identity as linear, noop, run, run_all } from './utils.js'; import { identity as linear, noop, run, run_all } 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, delete_rules } from './style_manager.js';
let promise; let promise;
@ -39,6 +39,7 @@ export function create_in_transition(node, fn, params) {
let running = false; let running = false;
let animation_name; let animation_name;
let task; let task;
let uid = 0;
function cleanup() { function cleanup() {
if (animation_name) delete_rule(node, animation_name); if (animation_name) delete_rule(node, animation_name);
@ -53,11 +54,7 @@ export function create_in_transition(node, fn, params) {
css css
} = config; } = config;
if (css) { if (css) animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++);
animation_name = create_rule(0, 1, duration, easing, css);
node.style.animation = (node.style.animation ? ', ' : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`;
}
tick(0, 1); tick(0, 1);
const start_time = window.performance.now() + delay; const start_time = window.performance.now() + delay;
@ -90,6 +87,8 @@ export function create_in_transition(node, fn, params) {
start() { start() {
if (started) return; if (started) return;
delete_rule(node);
if (typeof config === 'function') { if (typeof config === 'function') {
config = config(); config = config();
wait().then(go); wait().then(go);
@ -132,8 +131,7 @@ export function create_out_transition(node, fn, params) {
} = config; } = config;
if (css) { if (css) {
animation_name = create_rule(1, 0, duration, easing, css); animation_name = create_rule(node, 1, 0, duration, delay, easing, css);
node.style.animation += (node.style.animation ? ', ' : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`;
} }
const start_time = window.performance.now() + delay; const start_time = window.performance.now() + delay;
@ -238,8 +236,7 @@ export function create_bidirectional_transition(node, fn, params, intro) {
// an initial tick and/or apply CSS animation immediately // an initial tick and/or apply CSS animation immediately
if (css) { if (css) {
clear_animation(); clear_animation();
animation_name = create_rule(t, b, duration, easing, css); animation_name = create_rule(node, t, b, duration, delay, easing, css);
node.style.animation = (node.style.animation ? `${node.style.animation}, ` : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`;
} }
if (b) tick(0, 1); if (b) tick(0, 1);
@ -256,9 +253,7 @@ export function create_bidirectional_transition(node, fn, params, intro) {
if (css) { if (css) {
clear_animation(); clear_animation();
animation_name = create_rule(t, running_program.b, running_program.duration, easing, config.css); animation_name = create_rule(node, t, running_program.b, running_program.duration, 0, easing, config.css);
node.style.animation = (node.style.animation ? ', ' : '') + `${animation_name} ${running_program.duration}ms linear 1 forwards`;
} }
} }

@ -0,0 +1,20 @@
export default {
test({ assert, component, target, window, raf }) {
component.visible = true;
const div = target.querySelector('div');
assert.equal(div.style.animation, `__svelte_3809512021_0 100ms linear 0ms 1 both`);
raf.tick(50);
component.visible = false;
// both in and out styles
assert.equal(div.style.animation, `__svelte_3809512021_0 100ms linear 0ms 1 both, __svelte_3750847757_0 100ms linear 0ms 1 both`);
raf.tick(75);
component.visible = true;
// reset original styles
assert.equal(div.style.animation, `__svelte_3809512021_1 100ms linear 0ms 1 both`);
},
};

@ -0,0 +1,25 @@
<script>
export let visible;
function foo() {
return {
duration: 100,
css: t => {
return `opacity: ${t}`;
}
};
}
function bar() {
return {
duration: 100,
css: t => {
return `opacity: ${t}`;
}
};
}
</script>
{#if visible}
<div in:foo out:bar></div>
{/if}
Loading…
Cancel
Save