You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/src/internal/animations.js

116 lines
2.7 KiB

import { identity as linear } from './utils.js';
import { loop } from './loop.js';
import { create_rule, delete_rule } from './style_manager.js';
export function wrapAnimation(node, from, fn, params) {
if (!from) return;
const to = node.getBoundingClientRect();
if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) return;
const info = fn(node, { from, to }, params);
const duration = 'duration' in info ? info.duration : 300;
const delay = 'delay' in info ? info.delay : 0;
const ease = info.easing || linear;
const start = window.performance.now() + delay;
const end = start + duration;
const program = {
a: 0,
t: 0,
b: 1,
delta: 1,
duration,
start,
end
};
const cssText = node.style.cssText;
const animation = {
pending: delay ? program : null,
program: delay ? null : program,
running: true,
start() {
if (info.css) {
if (delay) node.style.cssText = cssText;
program.name = create_rule(program, ease, info.css);
node.style.animation = (node.style.animation || '')
.split(', ')
.filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim)))
.concat(`${program.name} ${program.duration}ms linear 1 forwards`)
.join(', ');
}
animation.program = program;
animation.pending = null;
},
update: now => {
const p = now - program.start;
const t = program.a + program.delta * ease(p / program.duration);
if (info.tick) info.tick(t, 1 - t);
},
done() {
if (info.tick) info.tick(1, 0);
animation.stop();
},
stop() {
if (info.css) delete_rule(node, program.name);
animation.running = false;
}
};
const { abort, promise } = loop(() => {
const now = window.performance.now();
if (animation.program && now >= animation.program.end) {
animation.done();
}
if (animation.pending && now >= animation.pending.start) {
animation.start(animation.pending);
}
if (animation.running) {
animation.update(now);
return true;
}
});
if (info.tick) info.tick(0, 1);
if (delay) {
if (info.css) node.style.cssText += info.css(0, 1);
} else {
animation.start();
}
return animation;
}
export function fixPosition(node) {
const style = getComputedStyle(node);
if (style.position !== 'absolute' && style.position !== 'fixed') {
const { width, height } = style;
const a = node.getBoundingClientRect();
node.style.position = 'absolute';
node.style.width = width;
node.style.height = height;
const b = node.getBoundingClientRect();
if (a.left !== b.left || a.top !== b.top) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`;
}
}
}