react-tween
Version:
Tween animation for React components
247 lines (199 loc) • 8.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _d3Ease = require('d3-ease');
var _d3Interpolate = require('d3-interpolate');
var _lodash = require('lodash.isequal');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.isundefined');
var _lodash4 = _interopRequireDefault(_lodash3);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _d3Timer = require('d3-timer');
var _mergeDiff = require('./mergeDiff');
var _mergeDiff2 = _interopRequireDefault(_mergeDiff);
var _toObject = require('./toObject');
var _toObject2 = _interopRequireDefault(_toObject);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var TransitionGroup = function (_React$Component) {
_inherits(TransitionGroup, _React$Component);
_createClass(TransitionGroup, null, [{
key: 'getTransitionStyle',
value: function getTransitionStyle(style) {
return {
key: style.key,
style: style.currentStyle,
data: style.data
};
}
}]);
function TransitionGroup(props) {
_classCallCheck(this, TransitionGroup);
var _this = _possibleConstructorReturn(this, (TransitionGroup.__proto__ || Object.getPrototypeOf(TransitionGroup)).call(this, props));
var styles = props.styles;
_this.state = {
styles: styles.map(function (style) {
return {
key: style.key,
startStyle: style.style,
currentStyle: style.style,
endStyle: style.style,
data: style.data
};
})
};
_this.timer = (0, _d3Timer.timer)(function () {
return _this.timer.stop();
});
return _this;
}
_createClass(TransitionGroup, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if ((0, _lodash4.default)(nextProps.group) ?
// Don't animate if the new end styles are the same as the old end styles.
// This prevents nested tweens from constantly restarting their animation because they keep receiving new props.
(0, _lodash2.default)(this.state.styles.map(function (style) {
return {
key: style.key,
style: style.endStyle
};
}), nextProps.styles.map(function (style) {
return {
key: style.key,
style: style.style
};
})) : this.props.group === nextProps.group) {
return;
}
var oldStyles = (0, _toObject2.default)(this.state.styles, function (style) {
return style.key;
});
var newStyles = (0, _toObject2.default)(nextProps.styles, function (style) {
return style.key;
});
var mergedKeys = (0, _mergeDiff2.default)(oldStyles, newStyles);
var styles = mergedKeys.map(function (key) {
if (Object.prototype.hasOwnProperty.call(oldStyles, key) && Object.prototype.hasOwnProperty.call(newStyles, key)) {
// shared key case
return {
key: key,
startStyle: oldStyles[key].currentStyle,
currentStyle: oldStyles[key].currentStyle,
endStyle: newStyles[key].style,
data: newStyles[key].data
};
} else if (Object.prototype.hasOwnProperty.call(oldStyles, key)) {
// removed key case
var leaveStyle = nextProps.willLeave(TransitionGroup.getTransitionStyle(oldStyles[key]));
return {
key: key,
startStyle: oldStyles[key].currentStyle,
currentStyle: oldStyles[key].currentStyle,
endStyle: leaveStyle,
data: oldStyles[key].data
};
} else {
// eslint-disable-line no-else-return
// added key case
var enterStyle = nextProps.willEnter(newStyles[key]);
return {
key: key,
startStyle: enterStyle,
currentStyle: enterStyle,
endStyle: newStyles[key].style,
data: newStyles[key].data
};
}
});
this.setState({ styles: styles });
this.startTimer();
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.stopTimer();
}
}, {
key: 'startTimer',
value: function startTimer() {
var _this2 = this;
var delay = this.props.delay;
this.timer.restart(function (elapsed) {
return _this2.update(elapsed);
}, delay);
this.running = true;
}
}, {
key: 'stopTimer',
value: function stopTimer() {
if (!this.running) {
return;
}
this.timer.stop();
this.running = false;
this.setState({
styles: this.state.styles.map(function (style) {
return _extends({}, style, {
currentStyle: style.endStyle
});
})
});
}
}, {
key: 'update',
value: function update(elapsed) {
var _props = this.props,
duration = _props.duration,
easing = _props.easing;
var t = elapsed / duration;
var easedTime = easing(t);
if (easedTime > 0.99) {
this.stopTimer();
return;
}
this.setState({
styles: this.state.styles.map(function (style) {
return _extends({}, style, {
currentStyle: (0, _d3Interpolate.interpolate)(style.startStyle, style.endStyle)(easedTime)
});
})
});
}
}, {
key: 'render',
value: function render() {
var children = this.props.children;
var styles = this.state.styles.map(TransitionGroup.getTransitionStyle);
return children(styles);
}
}]);
return TransitionGroup;
}(_react2.default.Component);
TransitionGroup.propTypes = {
children: _react2.default.PropTypes.func,
delay: _react2.default.PropTypes.number,
duration: _react2.default.PropTypes.number,
easing: _react2.default.PropTypes.func,
group: _react2.default.PropTypes.any, // eslint-disable-line react/forbid-prop-types
styles: _react2.default.PropTypes.array, // eslint-disable-line react/forbid-prop-types
willEnter: _react2.default.PropTypes.func, // eslint-disable-line react/no-unused-prop-types
willLeave: _react2.default.PropTypes.func };
TransitionGroup.defaultProps = {
delay: 0,
duration: 500,
easing: _d3Ease.easeCubicInOut,
willEnter: function willEnter(style) {
return style.style;
},
willLeave: function willLeave(style) {
return style.style;
}
};
exports.default = TransitionGroup;