UNPKG

chayns-components

Version:

A set of beautiful React components for developing chayns® applications.

205 lines (201 loc) 7.03 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _clsx = _interopRequireDefault(require("clsx")); var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireWildcard(require("react")); var _insertStyle = _interopRequireDefault(require("../../utils/insertStyle")); var _isInteger = _interopRequireDefault(require("../../utils/isInteger")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * @component */ const CLOSED = 0; const PRE_CLOSING = 4; const CLOSING = 1; const OPENING = 2; const OPENED = 3; const DEFAULT_OPEN_TIMEOUT = 500; const DEFAULT_CLOSE_TIMEOUT = 500; const DEFAULT_CLASSNAME = 'expandable_content'; const DEFAULT_CLASSNAMES = { opened: 'animation__accordion--open', opening: 'animation__accordion--open', closed: 'animation__accordion--close', closing: 'animation__accordion--close' }; const DEFAULT_TIMEOUTS = { opening: DEFAULT_OPEN_TIMEOUT, closing: DEFAULT_CLOSE_TIMEOUT }; /** * A collapsible section that reveals its children with a height transition. */ class ExpandableContent extends _react.Component { static getMaxHeight(state, style) { if (state === PRE_CLOSING) { return null; } if (state === CLOSED || state === CLOSING) { return '0px'; } if (style && style.maxHeight) { return style.maxHeight; } if (state === OPENING) { return '9999px'; } return 'initial'; } static getClassNames(state, classNames) { if (!classNames) { return null; } if ((state === CLOSING || state === PRE_CLOSING) && classNames.closing) { return classNames.closing; } if (state === CLOSED && classNames.closed) { return classNames.closed; } if (state === OPENING && classNames.opening) { return classNames.opening; } if (state === OPENED && classNames.opened) { return classNames.opened; } return null; } constructor(props) { super(props); this.state = { currentState: props.open ? OPENED : CLOSED }; this.contentRendered = props.open; } componentDidMount() { (0, _insertStyle.default)('expandable_content', '.expandable_content { max-height: 9999px; }'); } componentDidUpdate(prevProps) { const { open, timeout } = this.props; if (open === prevProps.open) { return; } if (open) { this.open(timeout && timeout.opening); } else { this.close(timeout && timeout.closing); } } open(timeout) { clearTimeout(this.timeout); this.setState({ currentState: OPENING }); this.timeout = window.setTimeout(() => { this.setState({ currentState: OPENED }); }, (0, _isInteger.default)(timeout) ? timeout : DEFAULT_OPEN_TIMEOUT); this.contentRendered = true; } close(timeout) { clearTimeout(this.timeout); requestAnimationFrame(() => { this.setState({ currentState: PRE_CLOSING }); this.timeout = requestAnimationFrame(() => { this.setState({ currentState: CLOSING }); }); this.timeout = window.setTimeout(() => { this.setState({ currentState: CLOSED }); }, (0, _isInteger.default)(timeout) ? timeout : DEFAULT_CLOSE_TIMEOUT); }); } render() { const { style, className, classNames, open, timeout, children, removeContentClosed, ...props } = this.props; const { currentState } = this.state; const divStyle = { ...style, overflow: style && style.overflow || 'hidden', maxHeight: ExpandableContent.getMaxHeight(currentState, style) }; const newClassNames = (0, _clsx.default)(className, ExpandableContent.getClassNames(currentState, classNames), classNames === DEFAULT_CLASSNAMES && DEFAULT_CLASSNAME); return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ style: divStyle, className: newClassNames }, props), (currentState !== CLOSED || this.contentRendered && !removeContentClosed) && children); } } exports.default = ExpandableContent; ExpandableContent.propTypes = { /** * An object of classname strings that should be applied in the different * states. */ classNames: _propTypes.default.shape({ opening: _propTypes.default.string, opened: _propTypes.default.string, closing: _propTypes.default.string, closed: _propTypes.default.string }), /** * This controls the animation timeouts for opening and closing. */ timeout: _propTypes.default.shape({ opening: _propTypes.default.number, closing: _propTypes.default.number }), /** * Wether the content should be visible. If changed, a height transition * will start. */ open: _propTypes.default.bool.isRequired, /** * A React style object that is passed to the wrapper `<div>`-element. */ style: _propTypes.default.objectOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])), /** * A classname string that is applied to the wrapper element. */ className: _propTypes.default.string, /** * The children of the component. */ children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.arrayOf(_propTypes.default.node)]).isRequired, /** * Wether the content should be removed when the component is closed and the * content would not be visible anyways. */ removeContentClosed: _propTypes.default.bool }; ExpandableContent.defaultProps = { classNames: DEFAULT_CLASSNAMES, timeout: DEFAULT_TIMEOUTS, style: null, className: null, removeContentClosed: false }; ExpandableContent.displayName = 'ExpandableContent'; //# sourceMappingURL=ExpandableContent.js.map