UNPKG

addimated

Version:

An always interruptable, declarative animation library for React

95 lines (82 loc) 3.83 kB
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import _typeof from "@babel/runtime/helpers/esm/typeof"; import invariant from "invariant"; import React from "react"; import { AnimatedProps } from "./AnimatedProps"; import { ApplyAnimatedValues, transformStyles } from "./ApplyAnimatedValues"; function createAnimatedComponent(Component) { var AnimatedComponent = React.forwardRef(function (props, ref) { var isMountedRef = React.useRef(true); var propsAnimatedRef = React.useRef(null); var forceUpdate = React.useState(null)[1]; var componentRef = React.useRef(null); var setNativeProps = React.useCallback(function (props) { var didUpdate = ApplyAnimatedValues(componentRef.current, props); if (!didUpdate) { isMountedRef.current && forceUpdate(); } }, []); var attachProps = React.useCallback(function (nextProps) { var oldPropsAnimated = propsAnimatedRef.current; // The system is best designed when setNativeProps is implemented. It is // able to avoid re-rendering and directly set the attributes that // changed. However, setNativeProps can only be implemented on leaf // native components. If you want to animate a composite component, you // need to re-render it. In this case, we have a fallback that uses // forceUpdate. var callback = function callback() { var propsAnimated = propsAnimatedRef.current; if (propsAnimated) { var didUpdate = ApplyAnimatedValues(componentRef.current, propsAnimated.__getAnimatedValue()); if (!didUpdate) { isMountedRef.current && forceUpdate(); } } }; propsAnimatedRef.current = new AnimatedProps(nextProps, callback); // When you call detach, it removes the element from the parent list // of children. If it goes to 0, then the parent also detaches itself // and so on. // An optimization is to attach the new elements and THEN detach the old // ones instead of detaching and THEN attaching. // This way the intermediate state isn't to go to 0 and trigger // this expensive recursive detaching to then re-attach everything on // the very next operation. oldPropsAnimated && oldPropsAnimated.__detach(); }, []); attachProps(props); var propsAnimated = propsAnimatedRef.current; !propsAnimated ? process.env.NODE_ENV !== "production" ? invariant(false, "Uh oh, `propsAnimated` appears not to be populated :(") : invariant(false) : void 0; // componentWillUnmount-ish React.useEffect(function () { return function () { isMountedRef.current = false; propsAnimatedRef.current && propsAnimatedRef.current.__detach(); }; }, []); // $FlowFixMe React.useImperativeHandle(ref, function () { return { setNativeProps: setNativeProps, getNode: function getNode() { return componentRef.current; } }; }); var componentRefHandler = React.useCallback(function (value) { if (typeof ref === "function") { ref(value); } else if (ref != null && _typeof(ref) === "object") { ref.current = value; } componentRef.current = value; }, [componentRef, ref]); var _propsAnimated$__getV = propsAnimated.__getValue(), style = _propsAnimated$__getV.style, other = _objectWithoutProperties(_propsAnimated$__getV, ["style"]); return React.createElement(Component, _objectSpread({}, other, { style: transformStyles(style), ref: componentRefHandler })); }); return AnimatedComponent; } export { createAnimatedComponent }; //# sourceMappingURL=createAnimatedComponent.js.map