import _extends from 'babel-runtime/helpers/extends'; import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; import classNames from 'classnames'; import css from 'dom-helpers/style'; import React from 'react'; import Transition from 'react-overlays/lib/Transition'; import capitalize from './utils/capitalize'; import createChainedFunction from './utils/createChainedFunction'; var MARGINS = { height: ['marginTop', 'marginBottom'], width: ['marginLeft', 'marginRight'] }; // reading a dimension prop will cause the browser to recalculate, // which will let our animations work function triggerBrowserReflow(node) { node.offsetHeight; // eslint-disable-line no-unused-expressions } function getDimensionValue(dimension, elem) { var value = elem['offset' + capitalize(dimension)]; var margins = MARGINS[dimension]; return value + parseInt(css(elem, margins[0]), 10) + parseInt(css(elem, margins[1]), 10); } var propTypes = { /** * Show the component; triggers the expand or collapse animation */ 'in': React.PropTypes.bool, /** * Unmount the component (remove it from the DOM) when it is collapsed */ unmountOnExit: React.PropTypes.bool, /** * Run the expand animation when the component mounts, if it is initially * shown */ transitionAppear: React.PropTypes.bool, /** * Duration of the collapse animation in milliseconds, to ensure that * finishing callbacks are fired even if the original browser transition end * events are canceled */ timeout: React.PropTypes.number, /** * Callback fired before the component expands */ onEnter: React.PropTypes.func, /** * Callback fired after the component starts to expand */ onEntering: React.PropTypes.func, /** * Callback fired after the component has expanded */ onEntered: React.PropTypes.func, /** * Callback fired before the component collapses */ onExit: React.PropTypes.func, /** * Callback fired after the component starts to collapse */ onExiting: React.PropTypes.func, /** * Callback fired after the component has collapsed */ onExited: React.PropTypes.func, /** * The dimension used when collapsing, or a function that returns the * dimension * * _Note: Bootstrap only partially supports 'width'! * You will need to supply your own CSS animation for the `.width` CSS class._ */ dimension: React.PropTypes.oneOfType([React.PropTypes.oneOf(['height', 'width']), React.PropTypes.func]), /** * Function that returns the height or width of the animating DOM node * * Allows for providing some custom logic for how much the Collapse component * should animate in its specified dimension. Called with the current * dimension prop value and the DOM node. */ getDimensionValue: React.PropTypes.func, /** * ARIA role of collapsible element */ role: React.PropTypes.string }; var defaultProps = { 'in': false, timeout: 300, unmountOnExit: false, transitionAppear: false, dimension: 'height', getDimensionValue: getDimensionValue }; var Collapse = function (_React$Component) { _inherits(Collapse, _React$Component); function Collapse(props, context) { _classCallCheck(this, Collapse); var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context)); _this.handleEnter = _this.handleEnter.bind(_this); _this.handleEntering = _this.handleEntering.bind(_this); _this.handleEntered = _this.handleEntered.bind(_this); _this.handleExit = _this.handleExit.bind(_this); _this.handleExiting = _this.handleExiting.bind(_this); return _this; } /* -- Expanding -- */ Collapse.prototype.handleEnter = function handleEnter(elem) { var dimension = this._dimension(); elem.style[dimension] = '0'; }; Collapse.prototype.handleEntering = function handleEntering(elem) { var dimension = this._dimension(); elem.style[dimension] = this._getScrollDimensionValue(elem, dimension); }; Collapse.prototype.handleEntered = function handleEntered(elem) { var dimension = this._dimension(); elem.style[dimension] = null; }; /* -- Collapsing -- */ Collapse.prototype.handleExit = function handleExit(elem) { var dimension = this._dimension(); elem.style[dimension] = this.props.getDimensionValue(dimension, elem) + 'px'; triggerBrowserReflow(elem); }; Collapse.prototype.handleExiting = function handleExiting(elem) { var dimension = this._dimension(); elem.style[dimension] = '0'; }; Collapse.prototype._dimension = function _dimension() { return typeof this.props.dimension === 'function' ? this.props.dimension() : this.props.dimension; }; // for testing Collapse.prototype._getScrollDimensionValue = function _getScrollDimensionValue(elem, dimension) { return elem['scroll' + capitalize(dimension)] + 'px'; }; Collapse.prototype.render = function render() { var _props = this.props, onEnter = _props.onEnter, onEntering = _props.onEntering, onEntered = _props.onEntered, onExit = _props.onExit, onExiting = _props.onExiting, className = _props.className, props = _objectWithoutProperties(_props, ['onEnter', 'onEntering', 'onEntered', 'onExit', 'onExiting', 'className']); delete props.dimension; delete props.getDimensionValue; var handleEnter = createChainedFunction(this.handleEnter, onEnter); var handleEntering = createChainedFunction(this.handleEntering, onEntering); var handleEntered = createChainedFunction(this.handleEntered, onEntered); var handleExit = createChainedFunction(this.handleExit, onExit); var handleExiting = createChainedFunction(this.handleExiting, onExiting); var classes = { width: this._dimension() === 'width' }; return React.createElement(Transition, _extends({}, props, { 'aria-expanded': props.role ? props['in'] : null, className: classNames(className, classes), exitedClassName: 'collapse', exitingClassName: 'collapsing', enteredClassName: 'collapse in', enteringClassName: 'collapsing', onEnter: handleEnter, onEntering: handleEntering, onEntered: handleEntered, onExit: handleExit, onExiting: handleExiting })); }; return Collapse; }(React.Component); Collapse.propTypes = propTypes; Collapse.defaultProps = defaultProps; export default Collapse;