react-spring
Version:
Animate React with ease
1,697 lines (1,384 loc) • 56.5 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var _extends = _interopDefault(require('@babel/runtime/helpers/builtin/extends'));
var _inheritsLoose = _interopDefault(require('@babel/runtime/helpers/builtin/inheritsLoose'));
var React = _interopDefault(require('react'));
var _objectWithoutProperties = _interopDefault(require('@babel/runtime/helpers/builtin/objectWithoutProperties'));
var bugfixes = undefined;
var applyAnimatedValues = undefined;
var colorNames = [];
var requestFrame = function requestFrame(cb) {
return global.requestAnimationFrame(cb);
};
var cancelFrame = function cancelFrame(cb) {
return global.cancelAnimationFrame(cb);
};
var interpolation = undefined;
var injectApplyAnimatedValues = function injectApplyAnimatedValues(fn, transform) {
return applyAnimatedValues = {
fn: fn,
transform: transform
};
};
var injectColorNames = function injectColorNames(names) {
return colorNames = names;
};
var injectBugfixes = function injectBugfixes(fn) {
return bugfixes = fn;
};
var injectInterpolation = function injectInterpolation(cls) {
return interpolation = cls;
};
var injectFrame = function injectFrame(raf, caf) {
var _ref;
return _ref = [raf, caf], requestFrame = _ref[0], cancelFrame = _ref[1], _ref;
};
var Globals = /*#__PURE__*/Object.freeze({
get bugfixes () { return bugfixes; },
get applyAnimatedValues () { return applyAnimatedValues; },
get colorNames () { return colorNames; },
get requestFrame () { return requestFrame; },
get cancelFrame () { return cancelFrame; },
get interpolation () { return interpolation; },
injectApplyAnimatedValues: injectApplyAnimatedValues,
injectColorNames: injectColorNames,
injectBugfixes: injectBugfixes,
injectInterpolation: injectInterpolation,
injectFrame: injectFrame
});
// Important note: start() and stop() will only be called at most once.
// Once an animation has been stopped or finished its course, it will
// not be reused.
var Animation =
/*#__PURE__*/
function () {
function Animation() {}
var _proto = Animation.prototype;
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation) {};
_proto.stop = function stop() {}; // Helper function for subclasses to make sure onEnd is only called once.
_proto.__debouncedOnEnd = function __debouncedOnEnd(result) {
var onEnd = this.__onEnd;
this.__onEnd = null;
onEnd && onEnd(result);
};
return Animation;
}();
var Animated =
/*#__PURE__*/
function () {
function Animated() {}
var _proto = Animated.prototype;
_proto.__attach = function __attach() {};
_proto.__detach = function __detach() {};
_proto.__getValue = function __getValue() {};
_proto.__getAnimatedValue = function __getAnimatedValue() {
return this.__getValue();
};
_proto.__addChild = function __addChild(child) {};
_proto.__removeChild = function __removeChild(child) {};
_proto.__getChildren = function __getChildren() {
return [];
};
return Animated;
}();
var AnimatedTracking =
/*#__PURE__*/
function (_Animated) {
_inheritsLoose(AnimatedTracking, _Animated);
function AnimatedTracking(value, parent, animationClass, animationConfig, callback) {
var _this;
_this = _Animated.call(this) || this;
_this.update = throttle(function () {
_this._value.animate(new _this._animationClass(_extends({}, _this._animationConfig, {
to: _this._animationConfig.to.__getValue()
})), _this._callback);
}, 1000 / 30);
_this._value = value;
_this._parent = parent;
_this._animationClass = animationClass;
_this._animationConfig = animationConfig;
_this._callback = callback;
_this.__attach();
return _this;
}
var _proto = AnimatedTracking.prototype;
_proto.__getValue = function __getValue() {
return this._parent.__getValue();
};
_proto.__attach = function __attach() {
this._parent.__addChild(this);
};
_proto.__detach = function __detach() {
this._parent.__removeChild(this);
};
return AnimatedTracking;
}(Animated);
function throttle(callback, limit) {
var wait = false;
return function () {
if (!wait) {
callback.call();
wait = true;
setTimeout(function () {
return wait = false;
}, limit);
}
};
}
var AnimatedWithChildren =
/*#__PURE__*/
function (_Animated) {
_inheritsLoose(AnimatedWithChildren, _Animated);
function AnimatedWithChildren() {
var _this;
_this = _Animated.call(this) || this;
_this._children = [];
return _this;
}
var _proto = AnimatedWithChildren.prototype;
_proto.__addChild = function __addChild(child) {
if (this._children.length === 0) this.__attach();
this._children.push(child);
};
_proto.__removeChild = function __removeChild(child) {
var index = this._children.indexOf(child);
if (index === -1) {
console.warn("Trying to remove a child that doesn't exist");
return;
}
this._children.splice(index, 1);
if (this._children.length === 0) this.__detach();
};
_proto.__getChildren = function __getChildren() {
return this._children;
};
return AnimatedWithChildren;
}(Animated);
var linear = function linear(t) {
return t;
};
var Interpolation =
/*#__PURE__*/
function () {
function Interpolation() {}
Interpolation.create = function create(config) {
if (typeof config === 'function') return config;
if (interpolation && config.output && typeof config.output[0] === 'string') return interpolation(config);
var outputRange = config.output;
var inputRange = config.range;
var easing = config.easing || linear;
var extrapolateLeft = 'extend';
var map = config.map;
if (config.extrapolateLeft !== undefined) {
extrapolateLeft = config.extrapolateLeft;
} else if (config.extrapolate !== undefined) {
extrapolateLeft = config.extrapolate;
}
var extrapolateRight = 'extend';
if (config.extrapolateRight !== undefined) {
extrapolateRight = config.extrapolateRight;
} else if (config.extrapolate !== undefined) {
extrapolateRight = config.extrapolate;
}
return function (input) {
var range = findRange(input, inputRange);
return interpolate(input, inputRange[range], inputRange[range + 1], outputRange[range], outputRange[range + 1], easing, extrapolateLeft, extrapolateRight, map);
};
};
return Interpolation;
}();
function interpolate(input, inputMin, inputMax, outputMin, outputMax, easing, extrapolateLeft, extrapolateRight, map) {
var result = map ? map(input) : input; // Extrapolate
if (result < inputMin) {
if (extrapolateLeft === 'identity') {
return result;
} else if (extrapolateLeft === 'clamp') {
result = inputMin;
}
}
if (result > inputMax) {
if (extrapolateRight === 'identity') {
return result;
} else if (extrapolateRight === 'clamp') {
result = inputMax;
}
}
if (outputMin === outputMax) return outputMin;
if (inputMin === inputMax) {
if (input <= inputMin) return outputMin;
return outputMax;
} // Input Range
if (inputMin === -Infinity) {
result = -result;
} else if (inputMax === Infinity) {
result = result - inputMin;
} else {
result = (result - inputMin) / (inputMax - inputMin);
} // Easing
result = easing(result); // Output Range
if (outputMin === -Infinity) {
result = -result;
} else if (outputMax === Infinity) {
result = result + outputMin;
} else {
result = result * (outputMax - outputMin) + outputMin;
}
return result;
}
function findRange(input, inputRange) {
for (var i = 1; i < inputRange.length - 1; ++i) {
if (inputRange[i] >= input) break;
}
return i - 1;
}
var AnimatedInterpolation =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedInterpolation, _AnimatedWithChildren);
function AnimatedInterpolation(parents, config) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._parents = Array.isArray(parents) ? parents : [parents];
_this._interpolation = Interpolation.create(config);
return _this;
}
var _proto = AnimatedInterpolation.prototype;
_proto.__getValue = function __getValue() {
return this._interpolation.apply(this, this._parents.map(function (value) {
return value.__getValue();
}));
};
_proto.__attach = function __attach() {
for (var i = 0; i < this._parents.length; ++i) {
if (this._parents[i] instanceof Animated) this._parents[i].__addChild(this);
}
};
_proto.__detach = function __detach() {
for (var i = 0; i < this._parents.length; ++i) {
if (this._parents[i] instanceof Animated) this._parents[i].__removeChild(this);
}
};
_proto.__update = function __update(config) {
this._interpolation = Interpolation.create(config);
return this;
};
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
return AnimatedInterpolation;
}(AnimatedWithChildren);
var _uniqueId = 0;
/**
* Animated works by building a directed acyclic graph of dependencies
* transparently when you render your Animated components.
*
* new Animated.Value(0)
* .interpolate() .interpolate() new Animated.Value(1)
* opacity translateY scale
* style transform
* View#234 style
* View#123
*
* A) Top Down phase
* When an Animated.Value is updated, we recursively go down through this
* graph in order to find leaf nodes: the views that we flag as needing
* an update.
*
* B) Bottom Up phase
* When a view is flagged as needing an update, we recursively go back up
* in order to build the new value that it needs. The reason why we need
* this two-phases process is to deal with composite props such as
* transform which can receive values from multiple parents.
*/
function findAnimatedStyles(node, styles) {
if (typeof node.update === 'function') styles.add(node);else node.__getChildren().forEach(function (child) {
return findAnimatedStyles(child, styles);
});
}
/**
* Standard value for driving animations. One `Animated.Value` can drive
* multiple properties in a synchronized fashion, but can only be driven by one
* mechanism at a time. Using a new mechanism (e.g. starting a new animation,
* or calling `setValue`) will stop any previous ones.
*/
var AnimatedValue =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedValue, _AnimatedWithChildren);
function AnimatedValue(value) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._value = value;
_this._animation = null;
_this._animatedStyles = new Set();
_this._listeners = {};
return _this;
}
var _proto = AnimatedValue.prototype;
_proto.__detach = function __detach() {
this.stopAnimation();
};
_proto.__getValue = function __getValue() {
return this._value;
};
_proto._update = function _update() {
findAnimatedStyles(this, this._animatedStyles);
};
_proto._flush = function _flush() {
if (this._animatedStyles.size === 0) this._update();
this._animatedStyles.forEach(function (animatedStyle) {
return animatedStyle.update();
});
};
_proto._updateValue = function _updateValue(value) {
this._value = value;
this._flush();
for (var key in this._listeners) {
this._listeners[key]({
value: this.__getValue()
});
}
};
/**
* Directly set the value. This will stop any animations running on the value
* and update all the bound properties.
*/
_proto.setValue = function setValue(value) {
if (this._animation) {
this._animation.stop();
this._animation = null;
}
this._animatedStyles.clear();
this._updateValue(value);
};
/**
* Stops any running animation or tracking. `callback` is invoked with the
* final value after stopping the animation, which is useful for updating
* state to match the animation position with layout.
*/
_proto.stopAnimation = function stopAnimation(callback) {
this.stopTracking();
this._animation && this._animation.stop();
this._animation = null;
callback && callback(this.__getValue());
};
/**
* Interpolates the value before updating the property, e.g. mapping 0-1 to
* 0-10.
*/
_proto.interpolate = function interpolate(config) {
return new AnimatedInterpolation(this, config);
};
/**
* Typically only used internally, but could be used by a custom Animation
* class.
*/
_proto.animate = function animate(animation, callback) {
var _this2 = this;
var previousAnimation = this._animation;
this._animation && this._animation.stop();
this._animation = animation;
this._animatedStyles.clear();
animation.start(this._value, function (value) {
return _this2._updateValue(value);
}, function (result) {
_this2._animation = null;
callback && callback(result);
}, previousAnimation);
};
/**
* Adds an asynchronous listener to the value so you can observe updates from
* animations. This is useful because there is no way to
* synchronously read the value because it might be driven natively.
*/
_proto.addListener = function addListener(callback) {
var id = String(_uniqueId++);
this._listeners[id] = callback;
return id;
};
_proto.removeListener = function removeListener(id) {
delete this._listeners[id];
};
_proto.removeAllListeners = function removeAllListeners() {
this._listeners = {};
};
/**
* Typically only used internally.
*/
_proto.stopTracking = function stopTracking() {
this._tracking && this._tracking.__detach();
this._tracking = null;
};
/**
* Typically only used internally.
*/
_proto.track = function track(tracking) {
this.stopTracking();
this._tracking = tracking;
};
return AnimatedValue;
}(AnimatedWithChildren);
var withDefault = function withDefault(value, defaultValue) {
return value === undefined || value === null ? defaultValue : value;
};
var tensionFromOrigamiValue = function tensionFromOrigamiValue(oValue) {
return (oValue - 30) * 3.62 + 194;
};
var frictionFromOrigamiValue = function frictionFromOrigamiValue(oValue) {
return (oValue - 8) * 3 + 25;
};
var fromOrigamiTensionAndFriction = function fromOrigamiTensionAndFriction(tension, friction) {
return {
tension: tensionFromOrigamiValue(tension),
friction: frictionFromOrigamiValue(friction)
};
};
var SpringAnimation =
/*#__PURE__*/
function (_Animation) {
_inheritsLoose(SpringAnimation, _Animation);
function SpringAnimation(config) {
var _this;
_this = _Animation.call(this) || this;
_this.onUpdate = function () {
var position = _this._lastPosition;
var velocity = _this._lastVelocity;
var tempPosition = _this._lastPosition;
var tempVelocity = _this._lastVelocity; // If for some reason we lost a lot of frames (e.g. process large payload or
// stopped in the debugger), we only advance by 4 frames worth of
// computation and will continue on the next frame. It's better to have it
// running at faster speed than jumping to the end.
var MAX_STEPS = 64;
var now = Date.now();
if (now > _this._lastTime + MAX_STEPS) now = _this._lastTime + MAX_STEPS; // We are using a fixed time step and a maximum number of iterations.
// The following post provides a lot of thoughts into how to build this
// loop: http://gafferongames.com/game-physics/fix-your-timestep/
var TIMESTEP_MSEC = 1;
var numSteps = Math.floor((now - _this._lastTime) / TIMESTEP_MSEC);
for (var i = 0; i < numSteps; ++i) {
// Velocity is based on seconds instead of milliseconds
var step = TIMESTEP_MSEC / 1000; // This is using RK4. A good blog post to understand how it works:
// http://gafferongames.com/game-physics/integration-basics/
var aVelocity = velocity;
var aAcceleration = _this._tension * (_this._to - tempPosition) - _this._friction * tempVelocity;
var tempPosition = position + aVelocity * step / 2;
var tempVelocity = velocity + aAcceleration * step / 2;
var bVelocity = tempVelocity;
var bAcceleration = _this._tension * (_this._to - tempPosition) - _this._friction * tempVelocity;
tempPosition = position + bVelocity * step / 2;
tempVelocity = velocity + bAcceleration * step / 2;
var cVelocity = tempVelocity;
var cAcceleration = _this._tension * (_this._to - tempPosition) - _this._friction * tempVelocity;
tempPosition = position + cVelocity * step / 2;
tempVelocity = velocity + cAcceleration * step / 2;
var dVelocity = tempVelocity;
var dAcceleration = _this._tension * (_this._to - tempPosition) - _this._friction * tempVelocity;
tempPosition = position + cVelocity * step / 2;
tempVelocity = velocity + cAcceleration * step / 2;
var dxdt = (aVelocity + 2 * (bVelocity + cVelocity) + dVelocity) / 6;
var dvdt = (aAcceleration + 2 * (bAcceleration + cAcceleration) + dAcceleration) / 6;
position += dxdt * step;
velocity += dvdt * step;
}
_this._lastTime = now;
_this._lastPosition = position;
_this._lastVelocity = velocity;
_this._onUpdate(position); // a listener might have stopped us in _onUpdate
if (!_this.__active) return; // Conditions for stopping the spring animation
var isOvershooting = false;
if (_this._overshootClamping && _this._tension !== 0) {
if (_this._startPosition < _this._to) {
isOvershooting = position > _this._to;
} else {
isOvershooting = position < _this._to;
}
}
var isVelocity = Math.abs(velocity) <= _this._restSpeedThreshold;
var isDisplacement = true;
if (_this._tension !== 0) isDisplacement = Math.abs(_this._to - position) <= _this._restDisplacementThreshold;
if (isOvershooting || isVelocity && isDisplacement) {
// Ensure that we end up with a round value
if (_this._tension !== 0) _this._onUpdate(_this._to);
return _this.__debouncedOnEnd({
finished: true
});
}
_this._animationFrame = requestFrame(_this.onUpdate);
};
_this._overshootClamping = withDefault(config.overshootClamping, false);
_this._restDisplacementThreshold = withDefault(config.restDisplacementThreshold, 0.0001);
_this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.0001);
_this._initialVelocity = config.velocity;
_this._lastVelocity = withDefault(config.velocity, 0);
_this._to = config.to;
var springConfig = fromOrigamiTensionAndFriction(withDefault(config.tension, 40), withDefault(config.friction, 7));
_this._tension = springConfig.tension;
_this._friction = springConfig.friction;
return _this;
}
var _proto = SpringAnimation.prototype;
_proto.start = function start(fromValue, onUpdate, onEnd, previousAnimation) {
this.__active = true;
this._startPosition = fromValue;
this._lastPosition = this._startPosition;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
this._lastTime = Date.now();
if (previousAnimation instanceof SpringAnimation) {
var internalState = previousAnimation.getInternalState();
this._lastPosition = internalState.lastPosition;
this._lastVelocity = internalState.lastVelocity;
this._lastTime = internalState.lastTime;
}
if (typeof fromValue === 'string') {
this._onUpdate(fromValue);
return this.__debouncedOnEnd({
finished: true
});
}
if (this._initialVelocity !== undefined && this._initialVelocity !== null) this._lastVelocity = this._initialVelocity;
this.onUpdate();
};
_proto.getInternalState = function getInternalState() {
return {
lastPosition: this._lastPosition,
lastVelocity: this._lastVelocity,
lastTime: this._lastTime
};
};
_proto.stop = function stop() {
this.__active = false;
clearTimeout(this._timeout);
cancelFrame(this._animationFrame);
this.__debouncedOnEnd({
finished: false
});
};
return SpringAnimation;
}(Animation);
var AnimatedArray =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedArray, _AnimatedWithChildren);
function AnimatedArray(array) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
_this._values = array.map(function (n) {
return new AnimatedValue(n);
});
return _this;
}
var _proto = AnimatedArray.prototype;
_proto.setValue = function setValue(values) {
var _this2 = this;
values.forEach(function (n, i) {
return _this2._values[i].setValue(n);
});
};
_proto.__getValue = function __getValue() {
return this._values.map(function (v) {
return v.__getValue();
});
};
_proto.stopAnimation = function stopAnimation(callback) {
this._values.forEach(function (v) {
return v.stopAnimation();
});
callback && callback(this.__getValue());
};
_proto.__attach = function __attach() {
for (var i = 0; i < this._values.length; ++i) {
if (this._values[i] instanceof Animated) this._values[i].__addChild(this);
}
};
_proto.__detach = function __detach() {
for (var i = 0; i < this._values.length; ++i) {
if (this._values[i] instanceof Animated) this._values[i].__removeChild(this);
}
};
return AnimatedArray;
}(AnimatedWithChildren);
function maybeVectorAnim(array, _ref, anim, impl) {
var tension = _ref.tension,
friction = _ref.friction,
to = _ref.to;
// { tension, friction, to: [...]}
if (array instanceof AnimatedArray) return parallel(array._values.map(function (v, i) {
return anim(v, {
tension: tension,
friction: friction,
to: to[i]
}, impl);
}), {
stopTogether: false
});
return null;
}
function parallel(animations, config) {
var doneCount = 0;
var hasEnded = {};
var stopTogether = !(config && config.stopTogether === false);
var result = {
start: function start(callback) {
if (doneCount === animations.length) return callback && callback({
finished: true
});
animations.forEach(function (animation, idx) {
var cb = function cb(endResult) {
hasEnded[idx] = true;
doneCount++;
if (doneCount === animations.length) {
doneCount = 0;
return callback && callback(endResult);
}
if (!endResult.finished && stopTogether) result.stop();
};
if (!animation) cb({
finished: true
});else animation.start(cb);
});
},
stop: function stop() {
animations.forEach(function (animation, idx) {
!hasEnded[idx] && animation.stop();
hasEnded[idx] = true;
});
}
};
return result;
}
function controller(value, config, impl) {
if (impl === void 0) {
impl = SpringAnimation;
}
return maybeVectorAnim(value, config, controller, impl) || {
start: function start(callback) {
var singleValue = value;
var singleConfig = config;
singleValue.stopTracking();
if (config.to instanceof Animated) singleValue.track(new AnimatedTracking(singleValue, config.to, impl, singleConfig, callback));else singleValue.animate(new impl(singleConfig), callback);
},
stop: function stop() {
value.stopAnimation();
}
};
}
var AnimatedStyle =
/*#__PURE__*/
function (_AnimatedWithChildren) {
_inheritsLoose(AnimatedStyle, _AnimatedWithChildren);
function AnimatedStyle(style) {
var _this;
_this = _AnimatedWithChildren.call(this) || this;
style = style || {};
if (style.transform && !(style.transform instanceof Animated)) style = applyAnimatedValues.transform(style);
_this._style = style;
return _this;
}
var _proto = AnimatedStyle.prototype;
_proto.__getValue = function __getValue() {
var style = {};
for (var key in this._style) {
var value = this._style[key];
style[key] = value instanceof Animated ? value.__getValue() : value;
}
return style;
};
_proto.__getAnimatedValue = function __getAnimatedValue() {
var style = {};
for (var key in this._style) {
var value = this._style[key];
if (value instanceof Animated) style[key] = value.__getAnimatedValue();
}
return style;
};
_proto.__attach = function __attach() {
for (var key in this._style) {
var value = this._style[key];
if (value instanceof Animated) value.__addChild(this);
}
};
_proto.__detach = function __detach() {
for (var key in this._style) {
var value = this._style[key];
if (value instanceof Animated) value.__removeChild(this);
}
};
return AnimatedStyle;
}(AnimatedWithChildren);
var AnimatedProps =
/*#__PURE__*/
function (_Animated) {
_inheritsLoose(AnimatedProps, _Animated);
function AnimatedProps(props, callback) {
var _this;
_this = _Animated.call(this) || this;
if (props.style) {
props = _extends({}, props, {
style: new AnimatedStyle(props.style)
});
}
_this._props = props;
_this._callback = callback;
_this.__attach();
return _this;
}
var _proto = AnimatedProps.prototype;
_proto.__getValue = function __getValue() {
var props = {};
for (var key in this._props) {
var value = this._props[key];
if (value instanceof Animated) props[key] = value.__getValue();else props[key] = value;
}
return props;
};
_proto.__getAnimatedValue = function __getAnimatedValue() {
var props = {};
for (var key in this._props) {
var value = this._props[key];
if (value instanceof Animated) props[key] = value.__getAnimatedValue();
}
return props;
};
_proto.__attach = function __attach() {
for (var key in this._props) {
var value = this._props[key];
if (value instanceof Animated) value.__addChild(this);
}
};
_proto.__detach = function __detach() {
for (var key in this._props) {
var value = this._props[key];
if (value instanceof Animated) value.__removeChild(this);
}
};
_proto.update = function update() {
this._callback();
};
return AnimatedProps;
}(Animated);
function createAnimatedComponent(Component) {
return (
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(AnimatedComponent, _React$Component);
function AnimatedComponent() {
return _React$Component.apply(this, arguments) || this;
}
var _proto = AnimatedComponent.prototype;
_proto.componentWillUnmount = function componentWillUnmount() {
this._propsAnimated && this._propsAnimated.__detach();
};
_proto.setNativeProps = function setNativeProps(props) {
var didUpdate = applyAnimatedValues.fn(this.node, props, this);
if (didUpdate === false) this.forceUpdate();
};
_proto.componentWillMount = function componentWillMount() {
this.attachProps(this.props);
};
_proto.attachProps = function attachProps(nextProps) {
var _this = this;
var oldPropsAnimated = this._propsAnimated; // 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() {
if (_this.node) {
var didUpdate = applyAnimatedValues.fn(_this.node, _this._propsAnimated.__getAnimatedValue(), _this);
if (didUpdate === false) _this.forceUpdate();
}
};
this._propsAnimated = 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();
};
_proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
this.attachProps(nextProps);
};
_proto.render = function render() {
var _this2 = this;
var props = this._propsAnimated.__getValue();
return React.createElement(Component, _extends({}, props, {
ref: function ref(node) {
return _this2.node = node;
}
}));
};
return AnimatedComponent;
}(React.Component)
);
}
var config = {
default: {
tension: 170,
friction: 26
},
gentle: {
tension: 120,
friction: 14
},
wobbly: {
tension: 180,
friction: 12
},
stiff: {
tension: 210,
friction: 20
},
slow: {
tension: 280,
friction: 60
}
};
function shallowEqual(a, b) {
for (var i in a) {
if (!(i in b)) return false;
}
for (var _i in b) {
if (a[_i] !== b[_i]) return false;
}
return true;
}
function callProp(arg, state) {
return typeof arg === 'function' ? arg(state) : arg;
}
function getValues(object) {
return Object.keys(object).map(function (k) {
return object[k];
});
}
function getForwardProps(props) {
var to = props.to,
from = props.from,
config = props.config,
native = props.native,
onRest = props.onRest,
onFrame = props.onFrame,
children = props.children,
render = props.render,
reset = props.reset,
force = props.force,
immediate = props.immediate,
impl = props.impl,
inject = props.inject,
delay = props.delay,
attach = props.attach,
forward = _objectWithoutProperties(props, ["to", "from", "config", "native", "onRest", "onFrame", "children", "render", "reset", "force", "immediate", "impl", "inject", "delay", "attach"]);
return forward;
}
function renderChildren(props, componentProps) {
var forward = _extends({}, componentProps, getForwardProps(props));
return props.render ? props.render(_extends({}, forward, {
children: props.children
})) : props.children(forward);
}
function convertToAnimatedValue(acc, _ref) {
var _extends2;
var name = _ref[0],
value = _ref[1];
return _extends({}, acc, (_extends2 = {}, _extends2[name] = new AnimatedValue(value), _extends2));
}
function convertValues(props) {
var from = props.from,
to = props.to,
native = props.native;
var allProps = Object.entries(_extends({}, from, to));
return native ? allProps.reduce(convertToAnimatedValue, {}) : _extends({}, from, to);
}
var Spring =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(Spring, _React$Component);
function Spring() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_this.state = {
lastProps: {
from: {},
to: {}
},
changed: false,
dry: false
};
_this.didUpdate = false;
_this.didInject = false;
_this.animations = {};
_this.interpolators = {};
_this.start = function () {
var _this$props = _this.props,
config$$1 = _this$props.config,
impl = _this$props.impl;
if (_this.props.onStart) _this.props.onStart();
Object.keys(_this.animations).forEach(function (name) {
var _this$animations$name = _this.animations[name],
animation = _this$animations$name.animation,
to = _this$animations$name.toValue; // TODO: figure out why this is needed ...
if (!to.__getValue && animation.__getValue() === to) return _this.finishAnimation(name);
controller(animation, _extends({
to: to
}, callProp(config$$1, name)), impl).start(!to.__getValue && function (props) {
return props.finished && _this.finishAnimation(name);
});
});
};
_this.stop = function () {
return getValues(_this.animations).forEach(function (_ref) {
var animation = _ref.animation;
return animation.stopAnimation();
});
};
_this.finishAnimation = function (name) {
if (!_this.mounted) return;
var _this$animations$name2 = _this.animations[name],
animation = _this$animations$name2.animation,
to = _this$animations$name2.toValue;
_this.animations[name].stopped = true;
if (getValues(_this.animations).every(function (a) {
return a.stopped;
})) {
var current = _extends({}, _this.props.from, _this.props.to);
if (_this.props.onRest) _this.props.onRest(current); // Restore end-state
if (_this.didInject) {
_this.afterInject = convertValues(_this.props);
_this.didInject = false;
_this.setState({
dry: true
});
}
}
};
return _this;
}
var _proto = Spring.prototype;
_proto.componentDidMount = function componentDidMount() {
// componentDidUpdate isn't called on mount, we call it here to start animating
this.componentDidUpdate();
this.mounted = true;
};
_proto.componentWillUnmount = function componentWillUnmount() {
// Stop all ongoing animtions
this.mounted = false;
this.stop();
};
Spring.getDerivedStateFromProps = function getDerivedStateFromProps(props, _ref2) {
var changed = _ref2.changed,
dry = _ref2.dry,
lastProps = _ref2.lastProps;
// The following is a test against props that could alter the animation
var from = props.from,
to = props.to,
reset = props.reset,
force = props.force;
changed = !shallowEqual(to, lastProps.to) || !shallowEqual(from, lastProps.from) || reset || force && !dry;
return {
changed: changed,
lastProps: props,
dry: false
};
};
_proto.render = function render() {
var _this2 = this;
var propsChanged = this.state.changed; // Handle injected frames, for instance targets/web/fix-auto
// An inject will return an intermediary React node which measures itself out
// .. and returns a callback when the values sought after are ready, usually "auto".
if (this.props.inject && propsChanged && !this.injectProps) {
var frame = this.props.inject(this.props, function (injectProps) {
// The inject frame has rendered, now let's update animations...
_this2.injectProps = injectProps;
_this2.setState({
dry: true
});
}); // Render out injected frame
if (frame) return frame;
} // Update animations, this turns from/to props into AnimatedValues
// An update can occur on injected props, or when own-props have changed.
if (this.injectProps) {
this.updateAnimations(this.injectProps);
this.injectProps = undefined; // didInject is needed, because there will be a 3rd stage, where the original values
// .. will be restored after the animation is finished. When someone animates towards
// .. "auto", the end-result should be "auto", not "1999px", which would block nested
// .. height/width changes.
this.didInject = true;
} else if (propsChanged) this.updateAnimations(this.props); // Render out raw values or AnimatedValues depending on "native"
var values = this.getAnimatedValues();
return values && Object.keys(values).length ? renderChildren(this.props, _extends({}, values, this.afterInject)) : null;
};
_proto.componentDidUpdate = function componentDidUpdate() {
// The animation has to start *after* render, since at that point the scene
// .. graph should be established, so we do it here. Unfortunatelly, non-native
// .. animations as well as "auto" injects call forceUpdate, so it's causing a loop.
// .. didUpdate prevents that as it gets set only on prop changes.
if (this.didUpdate) {
if (this.props.delay) {
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(this.start, this.props.delay);
} else this.start();
}
this.didUpdate = false;
};
_proto.updateAnimations = function updateAnimations(_ref3) {
var _this3 = this;
var from = _ref3.from,
to = _ref3.to,
attach = _ref3.attach,
reset = _ref3.reset,
immediate = _ref3.immediate,
onFrame = _ref3.onFrame,
native = _ref3.native;
// This function will turn own-props into AnimatedValues, it tries to re-use
// .. exsting animations as best as it can by detecting the changes made
// Attachment handling, trailed springs can "attach" themselves to a previous spring
var target = attach && attach(this);
var animationsChanged = false;
var allProps = Object.entries(_extends({}, from, to));
this.animations = allProps.reduce(function (acc, _ref4, i) {
var _extends2, _extends3;
var name = _ref4[0],
value = _ref4[1];
var entry = reset === false && acc[name] || {
stopped: true
};
var isNumber = typeof value === 'number';
var isString = typeof value === 'string' && !value.startsWith('#') && !/\d/.test(value) && !colorNames[value];
var isArray = !isNumber && !isString && Array.isArray(value);
var fromValue = from[name] !== undefined ? from[name] : value;
var fromAnimated = fromValue instanceof AnimatedValue;
var toValue = isNumber || isArray ? value : 1;
if (target) {
// Attach value to target animation
var attachedAnimation = target.animations[name];
if (attachedAnimation) toValue = attachedAnimation.animation;
}
var old = entry.animation;
var animation, interpolation$$1;
if (fromAnimated) {
// Use provided animated value
animation = interpolation$$1 = fromValue;
} else if (isNumber || isString) {
// Create animated value
animation = interpolation$$1 = entry.animation || new AnimatedValue(fromValue);
} else if (isArray) {
// Create animated array
animation = interpolation$$1 = entry.animation || new AnimatedArray(fromValue);
} else {
// Deal with interpolations
var previous = entry.interpolation && entry.interpolation._interpolation(entry.animation._value);
if (entry.animation) {
animation = entry.animation;
animation.setValue(0);
} else animation = new AnimatedValue(0);
var _config = {
range: [0, 1],
output: [previous !== undefined ? previous : fromValue, value]
};
if (entry.interpolation) interpolation$$1 = entry.interpolation.__update(_config);else interpolation$$1 = animation.interpolate(_config);
}
if (old !== animation) animationsChanged = true; // Set immediate values
if (callProp(immediate, name)) animation.setValue(toValue); // Save interpolators
_this3.interpolators = _extends({}, _this3.interpolators, (_extends2 = {}, _extends2[name] = interpolation$$1, _extends2));
return _extends({}, acc, (_extends3 = {}, _extends3[name] = _extends({}, entry, {
name: name,
animation: animation,
interpolation: interpolation$$1,
toValue: toValue,
stopped: false
}), _extends3));
}, this.animations); // Update animated props (which from now on will take care of the animation)
if (animationsChanged) {
var oldAnimatedProps = this.animatedProps;
this.animatedProps = new AnimatedProps(this.interpolators, function () {
// This gets called on every animation frame ...
if (onFrame) onFrame(_this3.animatedProps.__getValue());
if (!native) _this3.setState({
dry: true
});
});
oldAnimatedProps && oldAnimatedProps.__detach();
} // Flag an update that occured, componentDidUpdate will start the animation later on
this.didUpdate = true;
this.afterInject = undefined;
this.didInject = false;
};
_proto.flush = function flush() {
getValues(this.animations).forEach(function (_ref5) {
var animation = _ref5.animation;
return animation._update && animation._update();
});
};
_proto.getValues = function getValues$$1() {
return this.animatedProps ? this.animatedProps.__getValue() : {};
};
_proto.getAnimatedValues = function getAnimatedValues() {
return this.props.native ? this.interpolators : this.getValues();
};
return Spring;
}(React.Component);
Spring.defaultProps = {
from: {},
to: {},
config: config.default,
native: false,
immediate: false,
reset: false,
force: false,
impl: SpringAnimation,
inject: bugfixes
};
var empty = function empty() {
return null;
};
var ref = function ref(object, key, defaultValue) {
return typeof object === 'function' ? object(key) : object || defaultValue;
};
var get = function get(props) {
var keys = props.keys,
children = props.children,
render = props.render,
items = props.items,
rest = _objectWithoutProperties(props, ["keys", "children", "render", "items"]);
children = render || children || empty;
keys = typeof keys === 'function' ? items.map(keys) : keys;
if (!Array.isArray(children)) {
children = [children];
keys = keys !== void 0 ? [keys] : children.map(function (c) {
return c.toString();
});
} // Make sure numeric keys are interpreted as Strings (5 !== "5")
keys = keys.map(function (k) {
return String(k);
});
return _extends({
keys: keys,
children: children,
items: items
}, rest);
};
var guid = 0;
var Transition =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(Transition, _React$PureComponent);
function Transition(prevProps) {
var _this;
_this = _React$PureComponent.call(this, prevProps) || this;
_this.springs = [];
_this.state = {
transitions: [],
current: {},
deleted: [],
prevProps: prevProps
};
return _this;
}
Transition.getDerivedStateFromProps = function getDerivedStateFromProps(props, _ref) {
var prevProps = _ref.prevProps,
state = _objectWithoutProperties(_ref, ["prevProps"]);
var _get = get(props),
keys = _get.keys,
children = _get.children,
items = _get.items,
from = _get.from,
enter = _get.enter,
leave = _get.leave,
update = _get.update;
var _get2 = get(prevProps),
_keys = _get2.keys,
_items = _get2.items;
var current = _extends({}, state.current);
var deleted = state.deleted.concat(); // Compare next keys with current keys
var currentKeys = Object.keys(current);
var currentSet = new Set(currentKeys);
var nextSet = new Set(keys);
var added = keys.filter(function (item) {
return !currentSet.has(item);
});
var removed = currentKeys.filter(function (item) {
return !nextSet.has(item);
});
var updated = keys.filter(function (item) {
return currentSet.has(item);
});
added.forEach(function (key) {
var keyIndex = keys.indexOf(key);
var item = items ? items[keyIndex] : key;
current[key] = {
children: children[keyIndex],
key: guid++,
item: item,
to: ref(enter, item),
from: ref(from, item)
};
});
removed.forEach(function (key) {
var keyIndex = _keys.indexOf(key);
deleted.push(_extends({
destroyed: true,
lastIndex: keyIndex
}, current[key], {
to: ref(leave, _items ? _items[keyIndex] : key)
}));
delete current[key];
});
updated.forEach(function (key) {
var keyIndex = keys.indexOf(key);
var item = items ? items[keyIndex] : key;
current[key] = _extends({}, current[key], {
children: children[keyIndex],
to: ref(update, item, current[key].to)
});
});
var transitions = keys.map(function (key) {
return current[key];
});
deleted.forEach(function (_ref2) {
var i = _ref2.lastIndex,
t = _objectWithoutProperties(_ref2, ["lastIndex"]);
return transitions = transitions.slice(0, i).concat([t], transitions.slice(i));
});
return {
transitions: transitions,
current: current,
deleted: deleted,
prevProps: props
};
};
var _proto = Transition.prototype;
_proto.getValues = function getValues() {
return undefined;
};
_proto.render = function render() {
var _this2 = this;
var _this$props = this.props,
render = _this$props.render,
_this$props$from = _this$props.from,
_this$props$enter = _this$props.enter,
_this$props$leave = _this$props.leave,
_this$props$native = _this$props.native,
native = _this$props$native === void 0 ? false : _this$props$native,
keys = _this$props.keys,
items = _this$props.items,
onFrame = _this$props.onFrame,
onRest = _this$props.onRest,
extra = _objectWithoutProperties(_this$props, ["render", "from", "enter", "leave", "native", "keys", "items", "onFrame", "onRest"]);
var props = _extends({
native: native
}, extra);
return this.state.transitions.map(function (transition, i) {
var key = transition.key,
item = transition.item,
children = transition.children,
from = transition.from,
rest = _objectWithoutProperties(transition, ["key", "item", "children", "from"]);
return React.createElement(Spring, _extends({
ref: function ref(r) {
return r && (_this2.springs[key] = r.getValues());
},
key: key,
onRest: rest.destroyed ? function () {
return _this2.setState(function (_ref3) {
var deleted = _ref3.deleted;
return {
deleted: deleted.filter(function (t) {
return t.key !== key;
})
};
}, function () {
return delete _this2.springs[key];
});
} : onRest && function (values) {
return onRest(item, values);
},
onFrame: onFrame && function (values) {
return onFrame(item, values);
}
}, rest, props, {
from: rest.destroyed ? _this2.springs[key] || from : from,
render: render && children,
children: render ? _this2.props.children : children
}));
});
};
return Transition;
}(React.PureComponent);
var Trail =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(Trail, _React$PureComponent);
function Trail() {
return _React$PureComponent.apply(this, arguments) || this;
}
var _proto = Trail.prototype;
_proto.getValues = function getValues() {
return this.instance && this.instance.getValues();
};
_proto.componentDidMount = function componentDidMount() {
this.instance && this.instance.flush();
};
_proto.componentDidUpdate = function componentDidUpdate() {
this.instance && this.instance.flush();
};
_proto.render = function render() {
var _this = this;
var _this$props = this.props,
children = _this$props.children,
render = _this$props.render,
_this$props$from = _this$props.from,
from = _this$props$from === void 0 ? {} : _this$props$from,
_this$props$to = _this$props.to,
to = _this$props$to === void 0 ? {} : _this$props$to,
_this$props$native = _this$props.native,
native = _this$props$native === void 0 ? false : _this$props$native,
keys = _this$props.keys,
delay = _this$props.delay,
onRest = _this$props.onRest,
extra = _objectWithoutProperties(_this$props, ["children", "render", "from", "to", "native", "keys", "delay", "onRest"]);
var animations = new Set();
var hook = function hook(index, animation) {
animations.add(animation);
if (index === 0) return undefined;else return Array.from(animations)[index - 1];
};
var props = _extends({}, extra, {
native: native,
from: from,
to: to
});
var target = render || children;
return target.map(function (child, i) {
var attachedHook = function attachedHook(animation) {
return hook(i, animation);
};
var firstDelay = i === 0 && delay;
return React.createElement(Spring, _extends({
ref: function ref(_ref) {
return i === 0 && (_this.instance = _ref);
},
onRest: i === 0 ? onRest : null,
key: keys[i]
}, props, {
delay: firstDelay || undefined,
attach: attachedHook,
render: render && child,
children: render ? children : child
}));
});
};
return Trail;
}(React.PureComponent);
var DEFAULT = '__default';
var Keyframes =
/*#__PURE__*/
function (_React$PureComponent) {
_inheritsLoose(Keyframes, _React$PureComponent);
function Keyframes