2 * Fade out the given element.
3 * @param {Element} element
4 * @param {Number} animTime
5 * @param {Function|null} onComplete
7 export function fadeOut(element, animTime = 400, onComplete = null) {
8 animateStyles(element, {
11 element.style.display = 'none';
12 if (onComplete) onComplete();
17 * Hide the element by sliding the contents upwards.
18 * @param {Element} element
19 * @param {Number} animTime
21 export function slideUp(element, animTime = 400) {
22 const currentHeight = element.getBoundingClientRect().height;
23 const computedStyles = getComputedStyle(element);
24 const currentPaddingTop = computedStyles.getPropertyValue('padding-top');
25 const currentPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
27 height: [`${currentHeight}px`, '0px'],
28 overflow: ['hidden', 'hidden'],
29 paddingTop: [currentPaddingTop, '0px'],
30 paddingBottom: [currentPaddingBottom, '0px'],
33 animateStyles(element, animStyles, animTime, () => {
34 element.style.display = 'none';
39 * Show the given element by expanding the contents.
40 * @param {Element} element - Element to animate
41 * @param {Number} animTime - Animation time in ms
43 export function slideDown(element, animTime = 400) {
44 element.style.display = 'block';
45 const targetHeight = element.getBoundingClientRect().height;
46 const computedStyles = getComputedStyle(element);
47 const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
48 const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
50 height: ['0px', `${targetHeight}px`],
51 overflow: ['hidden', 'hidden'],
52 paddingTop: ['0px', targetPaddingTop],
53 paddingBottom: ['0px', targetPaddingBottom],
56 animateStyles(element, animStyles, animTime);
60 * Used in the function below to store references of clean-up functions.
61 * Used to ensure only one transitionend function exists at any time.
62 * @type {WeakMap<object, any>}
64 const animateStylesCleanupMap = new WeakMap();
67 * Animate the css styles of an element using FLIP animation techniques.
68 * Styles must be an object where the keys are style properties, camelcase, and the values
69 * are an array of two items in the format [initialValue, finalValue]
70 * @param {Element} element
71 * @param {Object} styles
72 * @param {Number} animTime
73 * @param {Function} onComplete
75 function animateStyles(element, styles, animTime = 400, onComplete = null) {
76 const styleNames = Object.keys(styles);
77 for (let style of styleNames) {
78 element.style[style] = styles[style][0];
81 const cleanup = () => {
82 for (let style of styleNames) {
83 element.style[style] = null;
85 element.style.transition = null;
86 element.removeEventListener('transitionend', cleanup);
87 if (onComplete) onComplete();
91 requestAnimationFrame(() => {
92 element.style.transition = `all ease-in-out ${animTime}ms`;
93 for (let style of styleNames) {
94 element.style[style] = styles[style][1];
97 if (animateStylesCleanupMap.has(element)) {
98 const oldCleanup = animateStylesCleanupMap.get(element);
99 element.removeEventListener('transitionend', oldCleanup);
102 element.addEventListener('transitionend', cleanup);
103 animateStylesCleanupMap.set(element, cleanup);