diff --git a/src/internal/animations.js b/src/internal/animations.js index cf02827dd8..8f65a268db 100644 --- a/src/internal/animations.js +++ b/src/internal/animations.js @@ -26,15 +26,8 @@ export function animate(node, from, fn, params) { function start() { if (css) { - if (delay) node.style.cssText = cssText; - - 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(', '); + if (delay) node.style.cssText = cssText; // TODO create delayed animation instead? + name = create_rule(node, 0, 1, duration, 0, easing, css); } started = true; diff --git a/src/internal/style_manager.js b/src/internal/style_manager.js index 1e73d37b0a..38f0acd94e 100644 --- a/src/internal/style_manager.js +++ b/src/internal/style_manager.js @@ -13,7 +13,7 @@ function hash(str) { 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; 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 name = `__svelte_${hash(rule)}`; + const name = `__svelte_${hash(rule)}_${uid}`; if (!current_rules[name]) { if (!stylesheet) { @@ -36,14 +36,20 @@ export function create_rule(a, b, duration, ease, fn) { 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; return name; } export function delete_rule(node, name) { - node.style.animation = node.style.animation + node.style.animation = (node.style.animation || '') .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(', '); if (!--active) clear_rules(); diff --git a/src/internal/transitions.js b/src/internal/transitions.js index 61d383bb99..d0018bdd8a 100644 --- a/src/internal/transitions.js +++ b/src/internal/transitions.js @@ -1,6 +1,6 @@ import { identity as linear, noop, run, run_all } from './utils.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; @@ -39,6 +39,7 @@ export function create_in_transition(node, fn, params) { let running = false; let animation_name; let task; + let uid = 0; function cleanup() { if (animation_name) delete_rule(node, animation_name); @@ -53,11 +54,7 @@ export function create_in_transition(node, fn, params) { css } = config; - if (css) { - animation_name = create_rule(0, 1, duration, easing, css); - node.style.animation = (node.style.animation ? ', ' : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`; - } - + if (css) animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++); tick(0, 1); const start_time = window.performance.now() + delay; @@ -90,6 +87,8 @@ export function create_in_transition(node, fn, params) { start() { if (started) return; + delete_rule(node); + if (typeof config === 'function') { config = config(); wait().then(go); @@ -132,8 +131,7 @@ export function create_out_transition(node, fn, params) { } = config; if (css) { - animation_name = create_rule(1, 0, duration, easing, css); - node.style.animation += (node.style.animation ? ', ' : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`; + animation_name = create_rule(node, 1, 0, duration, delay, easing, css); } 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 if (css) { clear_animation(); - animation_name = create_rule(t, b, duration, easing, css); - node.style.animation = (node.style.animation ? `${node.style.animation}, ` : '') + `${animation_name} ${duration}ms linear ${delay}ms 1 both`; + animation_name = create_rule(node, t, b, duration, delay, easing, css); } if (b) tick(0, 1); @@ -256,9 +253,7 @@ export function create_bidirectional_transition(node, fn, params, intro) { if (css) { clear_animation(); - animation_name = create_rule(t, running_program.b, running_program.duration, easing, config.css); - - node.style.animation = (node.style.animation ? ', ' : '') + `${animation_name} ${running_program.duration}ms linear 1 forwards`; + animation_name = create_rule(node, t, running_program.b, running_program.duration, 0, easing, config.css); } } diff --git a/test/runtime/samples/transition-css-in-out-in/_config.js b/test/runtime/samples/transition-css-in-out-in/_config.js new file mode 100644 index 0000000000..10719280e9 --- /dev/null +++ b/test/runtime/samples/transition-css-in-out-in/_config.js @@ -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`); + }, +}; diff --git a/test/runtime/samples/transition-css-in-out-in/main.html b/test/runtime/samples/transition-css-in-out-in/main.html new file mode 100644 index 0000000000..5108452a39 --- /dev/null +++ b/test/runtime/samples/transition-css-in-out-in/main.html @@ -0,0 +1,25 @@ + + +{#if visible} +
+{/if} \ No newline at end of file