twreporter-react
Version:
React-Redux site for The Reporter Foundation in Taiwan
314 lines (291 loc) • 10.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _ChildrenUtils = require('./ChildrenUtils');
var _AnimateChild = require('./AnimateChild');
var _AnimateChild2 = _interopRequireDefault(_AnimateChild);
var _util = require('./util');
var _util2 = _interopRequireDefault(_util);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var defaultKey = 'rc_animate_' + Date.now();
function getChildrenFromProps(props) {
var children = props.children;
if (_react2["default"].isValidElement(children)) {
if (!children.key) {
return _react2["default"].cloneElement(children, {
key: defaultKey
});
}
}
return children;
}
function noop() {}
var Animate = _react2["default"].createClass({
displayName: 'Animate',
propTypes: {
component: _react2["default"].PropTypes.any,
animation: _react2["default"].PropTypes.object,
transitionName: _react2["default"].PropTypes.oneOfType([_react2["default"].PropTypes.string, _react2["default"].PropTypes.object]),
transitionEnter: _react2["default"].PropTypes.bool,
transitionAppear: _react2["default"].PropTypes.bool,
exclusive: _react2["default"].PropTypes.bool,
transitionLeave: _react2["default"].PropTypes.bool,
onEnd: _react2["default"].PropTypes.func,
onEnter: _react2["default"].PropTypes.func,
onLeave: _react2["default"].PropTypes.func,
onAppear: _react2["default"].PropTypes.func,
showProp: _react2["default"].PropTypes.string
},
getDefaultProps: function getDefaultProps() {
return {
animation: {},
component: 'span',
transitionEnter: true,
transitionLeave: true,
transitionAppear: false,
onEnd: noop,
onEnter: noop,
onLeave: noop,
onAppear: noop
};
},
getInitialState: function getInitialState() {
this.currentlyAnimatingKeys = {};
this.keysToEnter = [];
this.keysToLeave = [];
return {
children: (0, _ChildrenUtils.toArrayChildren)(getChildrenFromProps(this.props))
};
},
componentDidMount: function componentDidMount() {
var _this = this;
var showProp = this.props.showProp;
var children = this.state.children;
if (showProp) {
children = children.filter(function (child) {
return !!child.props[showProp];
});
}
children.forEach(function (child) {
_this.performAppear(child.key);
});
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
var _this2 = this;
this.nextProps = nextProps;
var nextChildren = (0, _ChildrenUtils.toArrayChildren)(getChildrenFromProps(nextProps));
var props = this.props;
// exclusive needs immediate response
if (props.exclusive) {
Object.keys(this.currentlyAnimatingKeys).forEach(function (key) {
_this2.stop(key);
});
}
var showProp = props.showProp;
var currentlyAnimatingKeys = this.currentlyAnimatingKeys;
// last props children if exclusive
var currentChildren = props.exclusive ? (0, _ChildrenUtils.toArrayChildren)(getChildrenFromProps(props)) : this.state.children;
// in case destroy in showProp mode
var newChildren = [];
if (showProp) {
currentChildren.forEach(function (currentChild) {
var nextChild = (0, _ChildrenUtils.findChildInChildrenByKey)(nextChildren, currentChild.key);
var newChild = void 0;
if ((!nextChild || !nextChild.props[showProp]) && currentChild.props[showProp]) {
newChild = _react2["default"].cloneElement(nextChild || currentChild, _defineProperty({}, showProp, true));
} else {
newChild = nextChild;
}
if (newChild) {
newChildren.push(newChild);
}
});
nextChildren.forEach(function (nextChild) {
if (!(0, _ChildrenUtils.findChildInChildrenByKey)(currentChildren, nextChild.key)) {
newChildren.push(nextChild);
}
});
} else {
newChildren = (0, _ChildrenUtils.mergeChildren)(currentChildren, nextChildren);
}
// need render to avoid update
this.setState({
children: newChildren
});
nextChildren.forEach(function (child) {
var key = child.key;
if (currentlyAnimatingKeys[key]) {
return;
}
var hasPrev = (0, _ChildrenUtils.findChildInChildrenByKey)(currentChildren, key);
if (showProp) {
var showInNext = child.props[showProp];
if (hasPrev) {
var showInNow = (0, _ChildrenUtils.findShownChildInChildrenByKey)(currentChildren, key, showProp);
if (!showInNow && showInNext) {
_this2.keysToEnter.push(key);
}
} else if (showInNext) {
_this2.keysToEnter.push(key);
}
} else if (!hasPrev) {
_this2.keysToEnter.push(key);
}
});
currentChildren.forEach(function (child) {
var key = child.key;
if (currentlyAnimatingKeys[key]) {
return;
}
var hasNext = (0, _ChildrenUtils.findChildInChildrenByKey)(nextChildren, key);
if (showProp) {
var showInNow = child.props[showProp];
if (hasNext) {
var showInNext = (0, _ChildrenUtils.findShownChildInChildrenByKey)(nextChildren, key, showProp);
if (!showInNext && showInNow) {
_this2.keysToLeave.push(key);
}
} else if (showInNow) {
_this2.keysToLeave.push(key);
}
} else if (!hasNext) {
_this2.keysToLeave.push(key);
}
});
},
componentDidUpdate: function componentDidUpdate() {
var keysToEnter = this.keysToEnter;
this.keysToEnter = [];
keysToEnter.forEach(this.performEnter);
var keysToLeave = this.keysToLeave;
this.keysToLeave = [];
keysToLeave.forEach(this.performLeave);
},
performEnter: function performEnter(key) {
// may already remove by exclusive
if (this.refs[key]) {
this.currentlyAnimatingKeys[key] = true;
this.refs[key].componentWillEnter(this.handleDoneAdding.bind(this, key, 'enter'));
}
},
performAppear: function performAppear(key) {
if (this.refs[key]) {
this.currentlyAnimatingKeys[key] = true;
this.refs[key].componentWillAppear(this.handleDoneAdding.bind(this, key, 'appear'));
}
},
handleDoneAdding: function handleDoneAdding(key, type) {
var props = this.props;
delete this.currentlyAnimatingKeys[key];
// if update on exclusive mode, skip check
if (props.exclusive && props !== this.nextProps) {
return;
}
var currentChildren = (0, _ChildrenUtils.toArrayChildren)(getChildrenFromProps(props));
if (!this.isValidChildByKey(currentChildren, key)) {
// exclusive will not need this
this.performLeave(key);
} else {
if (type === 'appear') {
if (_util2["default"].allowAppearCallback(props)) {
props.onAppear(key);
props.onEnd(key, true);
}
} else {
if (_util2["default"].allowEnterCallback(props)) {
props.onEnter(key);
props.onEnd(key, true);
}
}
}
},
performLeave: function performLeave(key) {
// may already remove by exclusive
if (this.refs[key]) {
this.currentlyAnimatingKeys[key] = true;
this.refs[key].componentWillLeave(this.handleDoneLeaving.bind(this, key));
}
},
handleDoneLeaving: function handleDoneLeaving(key) {
var props = this.props;
delete this.currentlyAnimatingKeys[key];
// if update on exclusive mode, skip check
if (props.exclusive && props !== this.nextProps) {
return;
}
var currentChildren = (0, _ChildrenUtils.toArrayChildren)(getChildrenFromProps(props));
// in case state change is too fast
if (this.isValidChildByKey(currentChildren, key)) {
this.performEnter(key);
} else {
/* eslint react/no-is-mounted:0 */
if (this.isMounted() && !(0, _ChildrenUtils.isSameChildren)(this.state.children, currentChildren, props.showProp)) {
this.setState({
children: currentChildren
});
}
if (_util2["default"].allowLeaveCallback(props)) {
props.onLeave(key);
props.onEnd(key, false);
}
}
},
isValidChildByKey: function isValidChildByKey(currentChildren, key) {
var showProp = this.props.showProp;
if (showProp) {
return (0, _ChildrenUtils.findShownChildInChildrenByKey)(currentChildren, key, showProp);
}
return (0, _ChildrenUtils.findChildInChildrenByKey)(currentChildren, key);
},
stop: function stop(key) {
delete this.currentlyAnimatingKeys[key];
var component = this.refs[key];
if (component) {
component.stop();
}
},
render: function render() {
var props = this.props;
this.nextProps = props;
var stateChildren = this.state.children;
var children = null;
if (stateChildren) {
children = stateChildren.map(function (child) {
if (child === null) {
return child;
}
if (!child.key) {
throw new Error('must set key for <rc-animate> children');
}
return _react2["default"].createElement(
_AnimateChild2["default"],
{
key: child.key,
ref: child.key,
animation: props.animation,
transitionName: props.transitionName,
transitionEnter: props.transitionEnter,
transitionAppear: props.transitionAppear,
transitionLeave: props.transitionLeave
},
child
);
});
}
var Component = props.component;
if (Component) {
return _react2["default"].createElement(
Component,
this.props,
children
);
}
return children[0] || null;
}
});
exports["default"] = Animate;
module.exports = exports['default'];