UNPKG

react-collapsible

Version:

React component to wrap content in Collapsible element with trigger to open and close.

281 lines (248 loc) 10.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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 _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); 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 Collapsible = function (_Component) { _inherits(Collapsible, _Component); function Collapsible(props) { _classCallCheck(this, Collapsible); // Bind class methods var _this = _possibleConstructorReturn(this, (Collapsible.__proto__ || Object.getPrototypeOf(Collapsible)).call(this, props)); _this.handleTriggerClick = _this.handleTriggerClick.bind(_this); _this.handleTransitionEnd = _this.handleTransitionEnd.bind(_this); _this.continueOpenCollapsible = _this.continueOpenCollapsible.bind(_this); // Defaults the dropdown to be closed if (props.open) { _this.state = { isClosed: false, shouldSwitchAutoOnNextCycle: false, height: 'auto', transition: 'none', hasBeenOpened: true, overflow: props.overflowWhenOpen, inTransition: false }; } else { _this.state = { isClosed: true, shouldSwitchAutoOnNextCycle: false, height: 0, transition: 'height ' + props.transitionTime + 'ms ' + props.easing, hasBeenOpened: false, overflow: 'hidden', inTransition: false }; } return _this; } _createClass(Collapsible, [{ key: 'componentDidUpdate', value: function componentDidUpdate(prevProps, prevState) { var _this2 = this; if (this.state.shouldOpenOnNextCycle) { this.continueOpenCollapsible(); } if (prevState.height === 'auto' && this.state.shouldSwitchAutoOnNextCycle === true) { window.setTimeout(function () { // Set small timeout to ensure a true re-render _this2.setState({ height: 0, overflow: 'hidden', isClosed: true, shouldSwitchAutoOnNextCycle: false }); }, 50); } // If there has been a change in the open prop (controlled by accordion) if (prevProps.open !== this.props.open) { if (this.props.open === true) { this.openCollapsible(); this.props.onOpening(); } else { this.closeCollapsible(); this.props.onClosing(); } } } }, { key: 'closeCollapsible', value: function closeCollapsible() { this.setState({ shouldSwitchAutoOnNextCycle: true, height: this.refs.inner.offsetHeight, transition: 'height ' + this.props.transitionTime + 'ms ' + this.props.easing, inTransition: true }); } }, { key: 'openCollapsible', value: function openCollapsible() { this.setState({ inTransition: true, shouldOpenOnNextCycle: true }); } }, { key: 'continueOpenCollapsible', value: function continueOpenCollapsible() { this.setState({ height: this.refs.inner.offsetHeight, transition: 'height ' + this.props.transitionTime + 'ms ' + this.props.easing, isClosed: false, hasBeenOpened: true, inTransition: true, shouldOpenOnNextCycle: false }); } }, { key: 'handleTriggerClick', value: function handleTriggerClick(event) { event.preventDefault(); if (this.props.triggerDisabled) { return; } if (this.props.handleTriggerClick) { this.props.handleTriggerClick(this.props.accordionPosition); } else { if (this.state.isClosed === true) { this.openCollapsible(); this.props.onOpening(); } else { this.closeCollapsible(); this.props.onClosing(); } } } }, { key: 'renderNonClickableTriggerElement', value: function renderNonClickableTriggerElement() { if (this.props.triggerSibling && typeof this.props.triggerSibling === 'string') { return _react2.default.createElement( 'span', { className: this.props.classParentString + '__trigger-sibling' }, this.props.triggerSibling ); } else if (this.props.triggerSibling) { return _react2.default.createElement(this.props.triggerSibling, null); } return null; } }, { key: 'handleTransitionEnd', value: function handleTransitionEnd() { // Switch to height auto to make the container responsive if (!this.state.isClosed) { this.setState({ height: 'auto', overflow: this.props.overflowWhenOpen, inTransition: false }); this.props.onOpen(); } else { this.setState({ inTransition: false }); this.props.onClose(); } } }, { key: 'render', value: function render() { var dropdownStyle = { height: this.state.height, WebkitTransition: this.state.transition, msTransition: this.state.transition, transition: this.state.transition, overflow: this.state.overflow }; var openClass = this.state.isClosed ? 'is-closed' : 'is-open'; var disabledClass = this.props.triggerDisabled ? 'is-disabled' : ''; //If user wants different text when tray is open var trigger = this.state.isClosed === false && this.props.triggerWhenOpen !== undefined ? this.props.triggerWhenOpen : this.props.trigger; // Don't render children until the first opening of the Collapsible if lazy rendering is enabled var children = this.props.lazyRender && !this.state.hasBeenOpened && this.state.isClosed && !this.state.inTransition ? null : this.props.children; // Construct CSS classes strings var triggerClassString = this.props.classParentString + '__trigger ' + openClass + ' ' + disabledClass + ' ' + (this.state.isClosed ? this.props.triggerClassName : this.props.triggerOpenedClassName); var parentClassString = this.props.classParentString + ' ' + (this.state.isClosed ? this.props.className : this.props.openedClassName); var outerClassString = this.props.classParentString + '__contentOuter ' + this.props.contentOuterClassName; var innerClassString = this.props.classParentString + '__contentInner ' + this.props.contentInnerClassName; return _react2.default.createElement( 'div', { className: parentClassString.trim() }, _react2.default.createElement( 'span', { className: triggerClassString.trim(), onClick: this.handleTriggerClick }, trigger ), this.renderNonClickableTriggerElement(), _react2.default.createElement( 'div', { className: outerClassString.trim(), ref: 'outer', style: dropdownStyle, onTransitionEnd: this.handleTransitionEnd }, _react2.default.createElement( 'div', { className: innerClassString.trim(), ref: 'inner' }, children ) ) ); } }]); return Collapsible; }(_react.Component); Collapsible.propTypes = { transitionTime: _propTypes2.default.number, easing: _propTypes2.default.string, open: _propTypes2.default.bool, classParentString: _propTypes2.default.string, openedClassName: _propTypes2.default.string, triggerClassName: _propTypes2.default.string, triggerOpenedClassName: _propTypes2.default.string, contentOuterClassName: _propTypes2.default.string, contentInnerClassName: _propTypes2.default.string, accordionPosition: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]), handleTriggerClick: _propTypes2.default.func, onOpen: _propTypes2.default.func, onClose: _propTypes2.default.func, onOpening: _propTypes2.default.func, onClosing: _propTypes2.default.func, trigger: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.element]), triggerWhenOpen: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.element]), triggerDisabled: _propTypes2.default.bool, lazyRender: _propTypes2.default.bool, overflowWhenOpen: _propTypes2.default.oneOf(['hidden', 'visible', 'auto', 'scroll', 'inherit', 'initial', 'unset']), triggerSibling: _propTypes2.default.oneOfType([_propTypes2.default.element, _propTypes2.default.func]) }; Collapsible.defaultProps = { transitionTime: 400, easing: 'linear', open: false, classParentString: 'Collapsible', triggerDisabled: false, lazyRender: false, overflowWhenOpen: 'hidden', openedClassName: '', triggerClassName: '', triggerOpenedClassName: '', contentOuterClassName: '', contentInnerClassName: '', className: '', triggerSibling: null, onOpen: function onOpen() {}, onClose: function onClose() {}, onOpening: function onOpening() {}, onClosing: function onClosing() {} }; exports.default = Collapsible;