UNPKG

addimated

Version:

An always interruptable, declarative animation library for React

117 lines (87 loc) 4.39 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createAnimatedComponent = createAnimatedComponent; var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _invariant = _interopRequireDefault(require("invariant")); var _react = _interopRequireDefault(require("react")); var _AnimatedProps = require("./AnimatedProps"); var _ApplyAnimatedValues = require("./ApplyAnimatedValues"); function createAnimatedComponent(Component) { var AnimatedComponent = _react.default.forwardRef(function (props, ref) { var isMountedRef = _react.default.useRef(true); var propsAnimatedRef = _react.default.useRef(null); var forceUpdate = _react.default.useState(null)[1]; var componentRef = _react.default.useRef(null); var setNativeProps = _react.default.useCallback(function (props) { var didUpdate = (0, _ApplyAnimatedValues.ApplyAnimatedValues)(componentRef.current, props); if (!didUpdate) { isMountedRef.current && forceUpdate(); } }, []); var attachProps = _react.default.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 = (0, _ApplyAnimatedValues.ApplyAnimatedValues)(componentRef.current, propsAnimated.__getAnimatedValue()); if (!didUpdate) { isMountedRef.current && forceUpdate(); } } }; propsAnimatedRef.current = new _AnimatedProps.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" ? (0, _invariant.default)(false, "Uh oh, `propsAnimated` appears not to be populated :(") : invariant(false) : void 0; // componentWillUnmount-ish _react.default.useEffect(function () { return function () { isMountedRef.current = false; propsAnimatedRef.current && propsAnimatedRef.current.__detach(); }; }, []); // $FlowFixMe _react.default.useImperativeHandle(ref, function () { return { setNativeProps: setNativeProps, getNode: function getNode() { return componentRef.current; } }; }); var componentRefHandler = _react.default.useCallback(function (value) { if (typeof ref === "function") { ref(value); } else if (ref != null && (0, _typeof2.default)(ref) === "object") { ref.current = value; } componentRef.current = value; }, [componentRef, ref]); var _propsAnimated$__getV = propsAnimated.__getValue(), style = _propsAnimated$__getV.style, other = (0, _objectWithoutProperties2.default)(_propsAnimated$__getV, ["style"]); return _react.default.createElement(Component, (0, _objectSpread2.default)({}, other, { style: (0, _ApplyAnimatedValues.transformStyles)(style), ref: componentRefHandler })); }); return AnimatedComponent; } //# sourceMappingURL=createAnimatedComponent.js.map