344 lines
14 KiB
JavaScript
344 lines
14 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = undefined;
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
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 _class, _temp;
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _reactDom = require('react-dom');
|
|
|
|
var _propTypes = require('prop-types');
|
|
|
|
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
|
|
var _chainFunction = require('chain-function');
|
|
|
|
var _chainFunction2 = _interopRequireDefault(_chainFunction);
|
|
|
|
var _warning = require('warning');
|
|
|
|
var _warning2 = _interopRequireDefault(_warning);
|
|
|
|
var _requestAnimationFrame = require('dom-helpers/util/requestAnimationFrame');
|
|
|
|
var _requestAnimationFrame2 = _interopRequireDefault(_requestAnimationFrame);
|
|
|
|
var _ReactCSSTransitionReplaceChild = require('./ReactCSSTransitionReplaceChild');
|
|
|
|
var _ReactCSSTransitionReplaceChild2 = _interopRequireDefault(_ReactCSSTransitionReplaceChild);
|
|
|
|
var _PropTypes = require('./utils/PropTypes');
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
|
|
|
|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
|
|
|
|
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 ? _defaults(subClass, superClass) : _defaults(subClass, superClass); }
|
|
|
|
var reactCSSTransitionReplaceChild = _react2.default.createFactory(_ReactCSSTransitionReplaceChild2.default);
|
|
|
|
var ReactCSSTransitionReplace = (_temp = _class = function (_React$Component) {
|
|
_inherits(ReactCSSTransitionReplace, _React$Component);
|
|
|
|
function ReactCSSTransitionReplace(props, context) {
|
|
_classCallCheck(this, ReactCSSTransitionReplace);
|
|
|
|
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
|
|
|
|
_this.handleDoneAppearing = function (key) {
|
|
delete _this.transitioningKeys[key];
|
|
if (key !== _this.state.currentKey) {
|
|
// This child was removed before it had fully appeared. Remove it.
|
|
_this.performLeave(key);
|
|
}
|
|
};
|
|
|
|
_this.performLeave = function (key) {
|
|
_this.transitioningKeys[key] = true;
|
|
_this.childRefs[key].componentWillLeave(_this.handleDoneLeaving.bind(_this, key));
|
|
if (!_this.state.currentChild || !(0, _reactDom.findDOMNode)(_this.childRefs[_this.state.currentKey])) {
|
|
// The enter transition dominates, but if there is no entering
|
|
// component or it renders null the height is set to zero.
|
|
_this.enqueueHeightTransition();
|
|
}
|
|
};
|
|
|
|
_this.performHeightTransition = function () {
|
|
if (!_this.unmounted) {
|
|
var state = _this.state;
|
|
|
|
var currentChildNode = state.currentChild ? (0, _reactDom.findDOMNode)(_this.childRefs[state.currentKey]) : null;
|
|
_this.setState({
|
|
height: currentChildNode ? currentChildNode.offsetHeight : 0,
|
|
width: _this.props.changeWidth ? currentChildNode ? currentChildNode.offsetWidth : 0 : null
|
|
});
|
|
}
|
|
_this.rafHandle = null;
|
|
};
|
|
|
|
_this.childRefs = Object.create(null);
|
|
|
|
_this.state = {
|
|
currentKey: '1',
|
|
currentChild: _this.props.children ? _react2.default.Children.only(_this.props.children) : undefined,
|
|
prevChildren: {},
|
|
height: null,
|
|
width: null
|
|
};
|
|
return _this;
|
|
}
|
|
|
|
ReactCSSTransitionReplace.prototype.componentWillMount = function componentWillMount() {
|
|
this.shouldEnterCurrent = false;
|
|
this.keysToLeave = [];
|
|
this.transitioningKeys = {};
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.componentDidMount = function componentDidMount() {
|
|
if (this.props.transitionAppear && this.state.currentChild) {
|
|
this.performAppear(this.state.currentKey);
|
|
}
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.componentWillUnmount = function componentWillUnmount() {
|
|
this.unmounted = true;
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
|
|
var nextChild = nextProps.children ? _react2.default.Children.only(nextProps.children) : undefined;
|
|
var currentChild = this.state.currentChild;
|
|
|
|
|
|
if (currentChild && nextChild && nextChild.key === currentChild.key && !this.state.nextChild) {
|
|
// This is the same child, but receiving new props means the child itself has re-rendered
|
|
return this.setState({
|
|
currentChild: nextChild
|
|
});
|
|
}
|
|
|
|
var _state = this.state,
|
|
currentKey = _state.currentKey,
|
|
prevChildren = _state.prevChildren;
|
|
|
|
|
|
var nextState = {
|
|
currentKey: String(Number(currentKey) + 1),
|
|
currentChild: nextChild,
|
|
height: 0,
|
|
width: this.props.changeWidth ? 0 : null
|
|
};
|
|
|
|
if (nextChild) {
|
|
this.shouldEnterCurrent = true;
|
|
}
|
|
|
|
if (currentChild) {
|
|
var _extends2;
|
|
|
|
var currentChildNode = (0, _reactDom.findDOMNode)(this.childRefs[currentKey]);
|
|
nextState.height = currentChildNode ? currentChildNode.offsetHeight : 0;
|
|
nextState.width = this.props.changeWidth ? currentChildNode ? currentChildNode.offsetWidth : 0 : null;
|
|
nextState.prevChildren = _extends({}, prevChildren, (_extends2 = {}, _extends2[currentKey] = currentChild, _extends2));
|
|
if (!this.transitioningKeys[currentKey]) {
|
|
this.keysToLeave.push(currentKey);
|
|
}
|
|
}
|
|
|
|
this.setState(nextState);
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.componentDidUpdate = function componentDidUpdate() {
|
|
if (this.shouldEnterCurrent) {
|
|
this.shouldEnterCurrent = false;
|
|
// If the current child renders null there is nothing to enter
|
|
if ((0, _reactDom.findDOMNode)(this.childRefs[this.state.currentKey])) {
|
|
this.performEnter(this.state.currentKey);
|
|
}
|
|
}
|
|
|
|
var keysToLeave = this.keysToLeave;
|
|
this.keysToLeave = [];
|
|
keysToLeave.forEach(this.performLeave);
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.performAppear = function performAppear(key) {
|
|
this.transitioningKeys[key] = true;
|
|
this.childRefs[key].componentWillAppear(this.handleDoneAppearing.bind(this, key));
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.performEnter = function performEnter(key) {
|
|
this.transitioningKeys[key] = true;
|
|
this.childRefs[key].componentWillEnter(this.handleDoneEntering.bind(this, key));
|
|
this.enqueueHeightTransition();
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.handleDoneEntering = function handleDoneEntering(key) {
|
|
delete this.transitioningKeys[key];
|
|
if (key === this.state.currentKey) {
|
|
// The current child has finished entering so the height transition is also cleared.
|
|
this.setState({ height: null });
|
|
} else {
|
|
// This child was removed before it had fully appeared. Remove it.
|
|
this.performLeave(key);
|
|
}
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.handleDoneLeaving = function handleDoneLeaving(key) {
|
|
delete this.transitioningKeys[key];
|
|
|
|
var nextState = { prevChildren: _extends({}, this.state.prevChildren) };
|
|
delete nextState.prevChildren[key];
|
|
delete this.childRefs[key];
|
|
|
|
if (!this.state.currentChild || !(0, _reactDom.findDOMNode)(this.childRefs[this.state.currentKey])) {
|
|
nextState.height = null;
|
|
}
|
|
|
|
this.setState(nextState);
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.enqueueHeightTransition = function enqueueHeightTransition() {
|
|
if (!this.rafHandle) {
|
|
this.rafHandle = (0, _requestAnimationFrame2.default)(this.performHeightTransition);
|
|
}
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.wrapChild = function wrapChild(child, moreProps) {
|
|
var transitionName = this.props.transitionName;
|
|
|
|
if ((typeof transitionName === 'undefined' ? 'undefined' : _typeof(transitionName)) === 'object' && transitionName !== null) {
|
|
transitionName = _extends({}, transitionName);
|
|
delete transitionName.height;
|
|
}
|
|
|
|
// We need to provide this childFactory so that
|
|
// ReactCSSTransitionReplaceChild can receive updates to name,
|
|
// enter, and leave while it is leaving.
|
|
return reactCSSTransitionReplaceChild(_extends({
|
|
name: transitionName,
|
|
appear: this.props.transitionAppear,
|
|
enter: this.props.transitionEnter,
|
|
leave: this.props.transitionLeave,
|
|
appearTimeout: this.props.transitionAppearTimeout,
|
|
enterTimeout: this.props.transitionEnterTimeout,
|
|
leaveTimeout: this.props.transitionLeaveTimeout
|
|
}, moreProps), child);
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.storeChildRef = function storeChildRef(child, key) {
|
|
var _this2 = this;
|
|
|
|
var isCallbackRef = typeof child.ref !== 'string';
|
|
(0, _warning2.default)(isCallbackRef, 'string refs are not supported on children of ReactCSSTransitionReplace and will be ignored. ' + 'Please use a callback ref instead: https://facebook.github.io/react/docs/refs-and-the-dom.html#the-ref-callback-attribute');
|
|
|
|
return (0, _chainFunction2.default)(isCallbackRef ? child.ref : null, function (r) {
|
|
_this2.childRefs[key] = r;
|
|
});
|
|
};
|
|
|
|
ReactCSSTransitionReplace.prototype.render = function render() {
|
|
var _this3 = this;
|
|
|
|
var _state2 = this.state,
|
|
currentKey = _state2.currentKey,
|
|
currentChild = _state2.currentChild,
|
|
prevChildren = _state2.prevChildren,
|
|
height = _state2.height,
|
|
width = _state2.width;
|
|
|
|
var childrenToRender = [];
|
|
|
|
var _props = this.props,
|
|
overflowHidden = _props.overflowHidden,
|
|
transitionName = _props.transitionName,
|
|
component = _props.component,
|
|
childComponent = _props.childComponent,
|
|
notifyLeaving = _props.notifyLeaving,
|
|
transitionAppear = _props.transitionAppear,
|
|
transitionEnter = _props.transitionEnter,
|
|
transitionLeave = _props.transitionLeave,
|
|
changeWidth = _props.changeWidth,
|
|
transitionAppearTimeout = _props.transitionAppearTimeout,
|
|
transitionEnterTimeout = _props.transitionEnterTimeout,
|
|
transitionLeaveTimeout = _props.transitionLeaveTimeout,
|
|
containerProps = _objectWithoutProperties(_props, ['overflowHidden', 'transitionName', 'component', 'childComponent', 'notifyLeaving', 'transitionAppear', 'transitionEnter', 'transitionLeave', 'changeWidth', 'transitionAppearTimeout', 'transitionEnterTimeout', 'transitionLeaveTimeout']);
|
|
|
|
var transitioning = this.shouldEnterCurrent || this.keysToLeave.length || Object.keys(this.transitioningKeys).length;
|
|
|
|
containerProps.style = _extends({}, containerProps.style);
|
|
|
|
if (transitioning) {
|
|
containerProps.style.position = 'relative';
|
|
if (overflowHidden) {
|
|
containerProps.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
|
|
if (height !== null) {
|
|
var heightClassName = typeof transitionName === 'string' ? transitionName + '-height' : transitionName && transitionName.height || '';
|
|
|
|
containerProps.className = String(containerProps.className || '') + ' ' + String(heightClassName);
|
|
containerProps.style.height = height;
|
|
}
|
|
|
|
if (width !== null) {
|
|
containerProps.style.width = width;
|
|
}
|
|
|
|
var positionAbsolute = {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
// In Chrome a selection on a child due to multiple clicks often transfers to the final child after
|
|
// the transitions completes. This prevents selection of the child without other side-effects.
|
|
userSelect: 'none'
|
|
};
|
|
|
|
Object.keys(prevChildren).forEach(function (key) {
|
|
var child = prevChildren[key];
|
|
childrenToRender.push(_react2.default.createElement(childComponent, { key: key, style: positionAbsolute }, _this3.wrapChild(notifyLeaving && typeof child.type !== 'string' ? _react2.default.cloneElement(child, { isLeaving: true }) : child, { ref: _this3.storeChildRef(child, key) })));
|
|
});
|
|
|
|
if (currentChild) {
|
|
childrenToRender.push(_react2.default.createElement(childComponent, {
|
|
key: currentKey,
|
|
// While there are leaving children positioning must always be specified to keep the current
|
|
// child on top; the current child can switch to relative positioning after entering though.
|
|
style: this.transitioningKeys[currentKey] ? positionAbsolute : transitioning ? { position: 'relative' } : null
|
|
}, this.wrapChild(currentChild, { ref: this.storeChildRef(currentChild, currentKey) })));
|
|
}
|
|
|
|
return _react2.default.createElement(component, containerProps, childrenToRender);
|
|
};
|
|
|
|
return ReactCSSTransitionReplace;
|
|
}(_react2.default.Component), _class.displayName = 'ReactCSSTransitionReplace', _class.defaultProps = {
|
|
transitionAppear: false,
|
|
transitionEnter: true,
|
|
transitionLeave: true,
|
|
overflowHidden: true,
|
|
changeWidth: false,
|
|
notifyLeaving: false,
|
|
component: 'div',
|
|
childComponent: 'span'
|
|
}, _temp);
|
|
exports.default = ReactCSSTransitionReplace;
|
|
module.exports = exports['default']; |