css animations

pull/1454/head
Rich Harris 7 years ago
parent b3594da23c
commit bade6df241

@ -1,4 +1,4 @@
import { transitionManager, linear } from './transitions';
import { transitionManager, linear, generateRule, hash } from './transitions';
export function destroyBlock(block, lookup) {
block.d(1);
@ -113,8 +113,10 @@ export function animate(blocks, rects, fn, params) {
const from = rects[block.key];
if (!from) continue;
const to = block.node.getBoundingClientRect();
if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) continue;
const info = fn(block.node, { from, to }, params);
const duration = 'duration' in info ? info.duration : 300;
@ -138,6 +140,21 @@ export function animate(blocks, rects, fn, params) {
program: delay ? null : program,
running: !delay,
start() {
if (info.css) {
const rule = generateRule(program, ease, info.css);
program.name = `__svelte_${hash(rule)}`;
transitionManager.addRule(rule, program.name);
block.node.style.animation = (block.node.style.animation || '')
.split(', ')
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
.join(', ');
}
},
update: now => {
const p = now - program.start;
const t = program.a + program.delta * ease(p / program.duration);
@ -145,7 +162,10 @@ export function animate(blocks, rects, fn, params) {
},
done() {
// TODO remove styles
if (info.css) {
transitionManager.deleteRule(block.node, program.name);
}
animation.running = false;
}
};
@ -153,5 +173,7 @@ export function animate(blocks, rects, fn, params) {
transitionManager.add(animation);
if (info.tick) info.tick(0, 1);
if (!delay) animation.start();
}
}

@ -0,0 +1,62 @@
export default {
data: {
things: [
{ id: 1, name: 'a' },
{ id: 2, name: 'b' },
{ id: 3, name: 'c' },
{ id: 4, name: 'd' },
{ id: 5, name: 'e' }
]
},
html: `
<div>a</div>
<div>b</div>
<div>c</div>
<div>d</div>
<div>e</div>
`,
test(assert, component, target, window, raf) {
let divs = document.querySelectorAll('div');
divs.forEach(div => {
div.getBoundingClientRect = function() {
const index = [...this.parentNode.children].indexOf(this);
const top = index * 30;
return {
left: 0,
right: 100,
top,
bottom: top + 20
}
};
})
const bcr1 = divs[0].getBoundingClientRect();
const bcr2 = divs[4].getBoundingClientRect();
component.set({
things: [
{ id: 5, name: 'e' },
{ id: 2, name: 'b' },
{ id: 3, name: 'c' },
{ id: 4, name: 'd' },
{ id: 1, name: 'a' }
]
});
divs = document.querySelectorAll('div');
assert.ok(~divs[0].style.animation.indexOf('__svelte'));
assert.equal(divs[1].style.animation, undefined);
assert.equal(divs[2].style.animation, undefined);
assert.equal(divs[3].style.animation, undefined);
assert.ok(~divs[4].style.animation.indexOf('__svelte'));
raf.tick(100);
assert.deepEqual([
divs[0].style.animation,
divs[4].style.animation
], ['', '']);
}
};

@ -0,0 +1,19 @@
{#each things as thing (thing.id)}
<div animate:flip>{thing.name}</div>
{/each}
<script>
export default {
animations: {
flip(node, animation, params) {
const dx = animation.from.left - animation.to.left;
const dy = animation.from.top - animation.to.top;
return {
duration: 100,
css: (t, u) => `transform: translate(${u + dx}px, ${u * dy}px)`
};
}
}
};
</script>
Loading…
Cancel
Save