chayns-components
Version:
A set of beautiful React components for developing chayns® applications.
205 lines (201 loc) • 7.03 kB
JavaScript
"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