@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
283 lines (222 loc) • 8.6 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 _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps"));
var _classnames = _interopRequireDefault(require("classnames"));
var _Collapsible = require("./Collapsible.css");
var _jsxRuntime = require("react/jsx-runtime");
var Collapsible = /*#__PURE__*/function (_React$Component) {
(0, _inheritsLoose2.default)(Collapsible, _React$Component);
function Collapsible() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
_this.state = {
height: 0,
animationState: 'idle'
};
_this._isMounted = false;
_this.node = void 0;
_this.heightNode = void 0;
_this.shouldFireStateCallback = function (prevProps, prevState) {
return prevProps.isOpen !== _this.props.isOpen && prevState.animationState !== _this.state.animationState;
};
_this.setNodeRef = function (node) {
return _this.node = node;
};
_this.setHeightNodeRef = function (node) {
return _this.heightNode = node;
};
return _this;
}
var _proto = Collapsible.prototype;
_proto.componentDidMount = function componentDidMount() {
this._isMounted = true;
};
_proto.componentWillUnmount = function componentWillUnmount() {
this._isMounted = false;
};
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) {
var willOpen = nextProps.isOpen;
if (willOpen !== this.props.isOpen) {
this.safeSetState({
animationState: 'measuring'
});
}
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
var wasOpen = prevProps.isOpen;
this.handleAnimation(wasOpen);
if (this.shouldFireStateCallback(prevProps, prevState)) {
this.handleAnimationStateCallback();
}
};
_proto.safeSetState = function safeSetState(state) {
if (this._isMounted) {
this.setState(state);
}
};
_proto.handleAnimation = function handleAnimation(wasOpen) {
var _this2 = this;
var animationState = this.state.animationState;
var duration = this.props.duration;
requestAnimationFrame(function () {
switch (animationState) {
case 'measuring':
_this2.safeSetState({
animationState: wasOpen ? 'closingStart' : 'openingStart',
height: wasOpen && _this2.heightNode ? _this2.heightNode.scrollHeight : 0
});
break;
case 'closingStart':
_this2.safeSetState({
animationState: 'closing',
height: 0
});
break;
/* Reliable to test in JSDOM due to timeouts */
case 'closing':
setTimeout(function () {
_this2.safeSetState({
animationState: 'closed'
});
}, duration);
break;
case 'openingStart':
_this2.safeSetState({
animationState: 'opening',
height: _this2.heightNode ? _this2.heightNode.scrollHeight : 0
});
break;
/* Reliable to test in JSDOM due to timeouts */
case 'opening':
setTimeout(function () {
_this2.safeSetState({
animationState: 'opened'
});
}, duration);
break;
default:
break;
}
});
};
_proto.handleAnimationStateCallback = function handleAnimationStateCallback() {
var animationState = this.state.animationState;
var _this$props = this.props,
onOpen = _this$props.onOpen,
onClose = _this$props.onClose;
switch (animationState) {
case 'opened':
onOpen();
break;
case 'closed':
onClose();
break;
default:
break;
}
};
_proto.collapsibleHeight = function collapsibleHeight(isOpen, animationState, height) {
if (animationState === 'idle' && isOpen) {
return isOpen ? 'auto' : null;
}
if (animationState === 'measuring') {
return isOpen ? null : 'auto';
}
if (animationState === 'opened') {
return 'auto';
}
return (height || 0) + "px";
};
_proto.getTransitionDuration = function getTransitionDuration() {
var _this$props2 = this.props,
duration = _this$props2.duration,
durationOpen = _this$props2.durationOpen,
durationClose = _this$props2.durationClose;
var animationState = this.state.animationState;
var openDuration = durationOpen !== undefined ? durationOpen : duration;
var closeDuration = durationClose !== undefined ? durationClose : duration;
var isOpening = animationState.indexOf('closing') < 0;
return isOpening ? openDuration : closeDuration;
};
_proto.render = function render() {
var _this$props3 = this.props,
className = _this$props3.className,
children = _this$props3.children,
duration = _this$props3.duration,
durationOpen = _this$props3.durationOpen,
durationClose = _this$props3.durationClose,
isOpen = _this$props3.isOpen,
onOpen = _this$props3.onOpen,
onClose = _this$props3.onClose,
style = _this$props3.style,
preRenderContent = _this$props3.preRenderContent,
rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props3, ["className", "children", "duration", "durationOpen", "durationClose", "isOpen", "onOpen", "onClose", "style", "preRenderContent"]);
var _this$state = this.state,
animationState = _this$state.animationState,
height = _this$state.height;
var animating = animationState !== 'idle';
var closed = animationState === 'closed';
var componentClassName = (0, _classnames.default)('c-Collapsible', isOpen && 'is-open', animating && 'is-animating', closed && 'is-closed', className);
var displayHeight = this.collapsibleHeight(isOpen, animationState, height);
var content = animating || isOpen || preRenderContent ? children : null;
var collapseStyle = {
height: displayHeight,
transitionDuration: this.getTransitionDuration() + "ms"
};
var componentStyle = (0, _extends2.default)({}, style, collapseStyle);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Collapsible.CollapsibleUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), {
"aria-hidden": !isOpen,
style: componentStyle,
className: componentClassName,
ref: this.setNodeRef,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
ref: this.setHeightNodeRef,
children: content
})
}));
};
return Collapsible;
}(_react.default.Component);
function noop() {}
Collapsible.defaultProps = {
'data-cy': 'Collapsible',
duration: 300,
isOpen: false,
onOpen: noop,
onClose: noop,
preRenderContent: false
};
Collapsible.propTypes = {
/** Custom class names to be added to the component. */
className: _propTypes.default.string,
/** Time (ms) for the expand/collapse animation. */
duration: _propTypes.default.number,
/** Time (ms) for the expand animation. */
durationOpen: _propTypes.default.number,
/** Time (ms) for the collapse animation. */
durationClose: _propTypes.default.number,
/** Opens/collapses the component. */
isOpen: _propTypes.default.bool,
/** Callback function when the component closes. */
onClose: _propTypes.default.func,
/** Callback function when the component opens. */
onOpen: _propTypes.default.func,
/** Custom styles to be added to the component. */
style: _propTypes.default.any,
/** Data attr for Cypress tests. */
'data-cy': _propTypes.default.string,
/** Flag indicating if content should be pre-rendered to the DOM (otherwise the content would not be in the DOM until opened) */
preRenderContent: _propTypes.default.bool
};
var _default = Collapsible;
exports.default = _default;