UNPKG

react-component-transition

Version:
124 lines (123 loc) 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transition = void 0; var tslib_1 = require("tslib"); var react_1 = tslib_1.__importStar(require("react")); var react_dom_1 = require("react-dom"); var classnames_1 = tslib_1.__importDefault(require("classnames")); var types_1 = require("./animation-hooks/types"); var animation_hooks_1 = require("./animation-hooks"); var defaults_1 = require("../animations/defaults"); var Transition = function (_a) { var _b = _a.animateContainer, animateContainer = _b === void 0 ? false : _b, _c = _a.animateContainerDuration, animateContainerDuration = _c === void 0 ? defaults_1.defaultTransitionDuration : _c, _d = _a.animateContainerEasing, animateContainerEasing = _d === void 0 ? defaults_1.defaultTransitionEasing : _d, animateOnMount = _a.animateOnMount, children = _a.children, className = _a.className, classNameEnter = _a.classNameEnter, classNameExit = _a.classNameExit, disabled = _a.disabled, enterAnimation = _a.enterAnimation, exitAnimation = _a.exitAnimation, inViewRef = _a.inViewRef, inViewEnabled = _a.inViewEnabled, lazy = _a.lazy, onEnterFinished = _a.onEnterFinished, onExitFinished = _a.onExitFinished, style = _a.style; var _e = react_1.useState(children && !lazy && animateOnMount && !animateContainer ? types_1.TransitionState.ContainerRect : null), transitionState = _e[0], setTransitionState = _e[1]; var prevChildren = react_1.useRef(animateOnMount && animateContainer ? null : children); var containerRef = react_1.useRef(null); var unmounted = react_1.useRef(false); var hasChildrenChanged = didChildrenChanged(prevChildren.current, children); if (!hasChildrenChanged && !transitionState) { prevChildren.current = children; } var updatedState = function (state) { if (!unmounted.current) { setTransitionState(state); } }; react_1.useEffect(function () { return function () { unmounted.current = true; }; }, []); react_1.useLayoutEffect(function () { if (inViewEnabled && animateOnMount && !animateContainer) { updatedState(types_1.TransitionState.ContainerRect); } }, [inViewEnabled]); // start exit transition if children changed react_1.useEffect(function () { if (!hasChildrenChanged) { return; } if (!transitionState) { updatedState(types_1.TransitionState.Exit); } }); var animationHooks = { children: children, getElement: function () { return containerRef.current; }, prevChildren: prevChildren.current, transitionState: transitionState, disabled: disabled, onFinish: null, }; var _f = animation_hooks_1.useContainerRectangle(tslib_1.__assign(tslib_1.__assign({}, animationHooks), { onFinish: function () { return updatedState(types_1.TransitionState.Container); } })), nextClientRect = _f.nextClientRect, prevClientRect = _f.prevClientRect; var exitFinishedHandler = function () { onExitFinished && onExitFinished(); }; animation_hooks_1.useExitAnimation(tslib_1.__assign(tslib_1.__assign({}, animationHooks), { prevClientRect: prevClientRect, settings: exitAnimation, onFinish: function () { var hadPrevChildren = !!prevChildren.current; prevChildren.current = children; if (hadPrevChildren && !animateContainer) { exitFinishedHandler(); } // If flushSync is done when there are no children, then we get a warning because we are still in react lifecycle // So, if there are no children it means that there was no exit animation therefore we are yet in useEffect of useExitAnimation if (hadPrevChildren && !disabled) { // need to rerender the component after setting state to avoid animation blinking on animation exit react_dom_1.flushSync(function () { updatedState(types_1.TransitionState.ContainerRect); }); } else { updatedState(types_1.TransitionState.ContainerRect); } } })); animation_hooks_1.useContainerAnimation(tslib_1.__assign(tslib_1.__assign({}, animationHooks), { prevClientRect: prevClientRect, nextClientRect: nextClientRect, animateContainer: animateContainer, animateContainerDuration: animateContainerDuration, animateContainerEasing: animateContainerEasing, onFinish: function () { if (!prevChildren.current && animateContainer) { exitFinishedHandler(); } updatedState(types_1.TransitionState.Enter); } })); animation_hooks_1.useEnterAnimation(tslib_1.__assign(tslib_1.__assign({}, animationHooks), { nextClientRect: nextClientRect, settings: enterAnimation, onFinish: function () { if (prevChildren.current) { onEnterFinished && onEnterFinished(); } updatedState(null); } })); var shouldRenderPrevChildren = hasChildrenChanged || transitionState === types_1.TransitionState.Exit; var hideContent = (lazy && !inViewEnabled) || transitionState === types_1.TransitionState.ContainerRect || transitionState === types_1.TransitionState.Container; var setRefs = react_1.useCallback(function (element) { containerRef.current = element; inViewRef && inViewRef(element); }, [inViewRef]); if (!lazy && !hasChildrenChanged && !transitionState && !children) { return null; } return (react_1.default.createElement("div", { ref: setRefs, className: classnames_1.default(className, transitionState === types_1.TransitionState.Enter && classNameEnter, transitionState === types_1.TransitionState.Exit && classNameExit) || null, style: tslib_1.__assign(tslib_1.__assign({}, style), { opacity: hideContent ? 0 : null }) }, shouldRenderPrevChildren ? prevChildren.current : children)); }; exports.Transition = Transition; var didChildrenChanged = function (prevChildren, children) { var prevChildrenElement = prevChildren; var childrenElement = children; if (!prevChildren && !children) { return false; } if (!prevChildren && children) { return true; } if (prevChildren && !children) { return true; } if (prevChildrenElement.key === childrenElement.key && prevChildrenElement.type === childrenElement.type) { return false; } return true; }; exports.Transition.displayName = "Transition";