addimated
Version:
An always interruptable, declarative animation library for React
95 lines (82 loc) • 3.83 kB
JavaScript
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