@atlaskit/motion
Version:
A set of utilities to apply motion in your application.
64 lines • 2.33 kB
JavaScript
import { durations } from '../utils/durations';
import { isReducedMotion } from '../utils/is-reduced-motion';
import { useElementRef } from '../utils/use-element-ref';
import { useLayoutEffect } from '../utils/use-layout-effect';
import { useRequestAnimationFrame } from '../utils/use-request-animation-frame';
import { useSetTimeout } from '../utils/use-set-timeout';
import { useExitingPersistence } from './exiting-persistence';
/**
* __ShrinkOut__
*
* Will shrink an element down to nothing when exiting.
* Works best with flex children as collapsing margins can come with undesired behaviour.
*
* - [Examples](https://atlaskit.atlassian.com/packages/design-system/motion/docs/entering-motion)
*/
const ShrinkOut = ({
children,
duration = 'small',
onFinish
}) => {
const [element, setElementRef] = useElementRef();
const exiting = useExitingPersistence();
const requestAnimationFrame = useRequestAnimationFrame();
const setTimeout = useSetTimeout();
const direction = exiting.isExiting ? 'exiting' : 'entering';
useLayoutEffect(() => {
if (exiting.isExiting && element) {
if (isReducedMotion()) {
exiting.onFinish && exiting.onFinish();
onFinish && onFinish('exiting');
return;
}
const newStyles = {
// We fix both width and height because when changing box sizing to border-box.
width: `${element.offsetWidth}px`,
height: `${element.offsetHeight}px`,
boxSizing: 'border-box',
willChange: 'width,margin'
};
Object.assign(element.style, newStyles);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const newStyles = {
width: '0px',
margin: '0px',
// We animate margin down to zero so it doesn't take any space.
transitionTimingFunction: 'cubic-bezier(0.8,0,0,0.8)',
transitionDuration: durations[duration] + 'ms',
transitionProperty: 'width,margin'
};
Object.assign(element.style, newStyles);
setTimeout(() => {
exiting.onFinish && exiting.onFinish();
onFinish && onFinish('exiting');
}, durations[duration]);
});
});
}
});
return children({
ref: setElementRef
}, direction);
};
export default ShrinkOut;