@wix/design-system
Version:
@wix/design-system
121 lines • 5.74 kB
JavaScript
import React, { Children, useEffect, useMemo, useState, useRef, } from 'react';
import { TransitionGroup, Transition as ReactTransition, } from 'react-transition-group';
import { dataHooks, timingMap } from './constants';
import { classes } from './Transition.classes';
import { getSwooshProps, getTimeout, getTransitionStyles } from './utils/utils';
const swooshEdgeMap = {
leftToRight: 'left',
rightToLeft: 'right',
topToBottom: 'top',
bottomToTop: 'bottom',
};
/** Transition is a wrapper that allows animations of other components. */
const Transition = ({ animateOnLoad = false, dataHook, children, enterAnimation, exitAnimation, mountOnEnter, unmountOnExit, onEnd, onStart, show, className, }) => {
const [dimensions, setDimensions] = useState({});
const [stateRef, setStateRef] = useState(null);
const ref = useRef(null);
// swoosh plays only for children that ran an enter phase
const swooshEnteredKeys = useRef(new Set()).current;
const swoosh = useMemo(() => {
if (!enterAnimation?.swoosh) {
return undefined;
}
const swooshProps = getSwooshProps(enterAnimation.swoosh);
return {
className: classes.root({
swoosh: swooshEdgeMap[swooshProps.direction],
}),
delayStyle: swooshProps.delay
? { animationDelay: `${timingMap[swooshProps.delay]}ms` }
: undefined,
};
}, [enterAnimation]);
const swooshExit = useMemo(() => {
if (!exitAnimation?.swoosh) {
return undefined;
}
const swooshProps = getSwooshProps(exitAnimation.swoosh);
return {
className: classes.root({
swooshExit: swooshEdgeMap[swooshProps.direction],
}),
delayStyle: swooshProps.delay
? { animationDelay: `${timingMap[swooshProps.delay]}ms` }
: undefined,
};
}, [exitAnimation]);
useEffect(() => {
if (stateRef) {
setDimensions({
height: stateRef.scrollHeight,
width: stateRef.scrollWidth,
});
}
}, [stateRef]);
const { fade, move, scale, toggle } = useMemo(() => {
if (dimensions) {
return getTransitionStyles(dimensions, enterAnimation, exitAnimation);
}
return {
fade: {},
move: {},
scale: {},
toggle: {},
};
}, [enterAnimation, exitAnimation, dimensions]);
const timeout = useMemo(() => {
return getTimeout(enterAnimation, exitAnimation);
}, [enterAnimation, exitAnimation]);
const childrenClone = Children.map(children, child => {
if (React.isValidElement(child) && (show === undefined || !!show)) {
return React.cloneElement(child);
}
return;
});
const handleStart = (animationTiming) => {
onStart?.(animationTiming);
};
const handleEnd = (animationTiming) => {
onEnd?.(animationTiming);
};
return (React.createElement("div", { "data-hook": dataHook, className: className },
React.createElement(TransitionGroup, { appear: animateOnLoad }, childrenClone &&
childrenClone.map(child => {
const childKey = child.key;
return (React.createElement(ReactTransition
// Transition component needs React key property to find correct child in the list
, {
// Transition component needs React key property to find correct child in the list
key: childKey, "data-hook": dataHooks.transition, mountOnEnter: mountOnEnter, unmountOnExit: unmountOnExit, in: show, timeout: {
// Transition component won't show enter animation when enter timeout is set
enter: 0,
exit: timeout.exit,
},
// onEnter fires before the entering render
onEnter: () => swoosh && swooshEnteredKeys.add(childKey), onEntering: () => handleStart('enter'), onExiting: () => handleStart('exit'), onEntered: () => handleEnd('enter'), onExited: () => {
swooshEnteredKeys.delete(childKey);
handleEnd('exit');
}, nodeRef: ref }, (state) => {
const exiting = state === 'exiting' || state === 'exited';
let activeSwoosh;
if (swooshExit && exiting) {
activeSwoosh = swooshExit;
}
else if (swoosh && swooshEnteredKeys.has(childKey)) {
activeSwoosh = swoosh;
}
return (React.createElement("div", { "data-hook": dataHooks.fadeStyles, className: activeSwoosh?.className, style: activeSwoosh?.delayStyle
? { ...fade[state], ...activeSwoosh.delayStyle }
: fade[state] },
React.createElement("div", { "data-hook": dataHooks.moveStyles, style: move[state] },
React.createElement("div", { "data-hook": dataHooks.scaleStyles, style: scale[state] },
React.createElement("div", { "data-hook": dataHooks.toggleStyles, style: toggle[state], ref: callback => {
setStateRef(callback);
ref.current = callback;
} }, child)))));
}));
}))));
};
Transition.displayName = 'Transition';
export { Transition };
//# sourceMappingURL=Transition.js.map