@carbon/ibm-security
Version:
Carbon for Cloud & Cognitive IBM Security UI components
253 lines (249 loc) • 12.4 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
var _PanelContainer$propT;
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
/**
* @file Panel container.
* @copyright IBM Security 2019 - 2021
*/
/* eslint-disable no-useless-computed-key, react/require-default-props */
import { Close20 } from '@carbon/icons-react';
import requiredIfGivenPropIsTruthy from 'carbon-components-react/es/prop-types/requiredIfGivenPropIsTruthy';
import setupGetInstanceId from 'carbon-components-react/es/tools/setupGetInstanceId';
import classnames from 'classnames';
import PropTypes, { func } from 'prop-types';
import React, { Component, createRef, Fragment } from 'react';
import { createPortal } from 'react-dom';
import { getComponentNamespace } from '../../globals/namespace';
import * as defaultLabels from '../../globals/nls';
import { isClient, isNode } from '../../globals/utils/capabilities';
import { focusFirstElement, trapTabFocus } from '../../globals/utils/focus';
import Button from '../Button';
import IconButton from '../IconButton';
export var namespace = getComponentNamespace('panel');
var getInstanceId = setupGetInstanceId();
/**
* Panel container component.
* @param {Record<string, any>} props Panel container props.
* @returns {PanelContainer} Panel container instance.
*/
var PanelContainer = /*#__PURE__*/function (_Component) {
function PanelContainer(props) {
var _this;
_classCallCheck(this, PanelContainer);
_this = _callSuper(this, PanelContainer, [props]);
_defineProperty(_this, "state", {
bodyMargin: 0
});
/**
* Retrieves the element to render the panel container in to via a portal.
* @returns {HTMLElement} The element to render the panel container in to via a portal.
*/
_defineProperty(_this, "getContainer", function () {
if (isClient()) {
var panels = document.getElementsByClassName(namespace);
if (panels.length > 0) {
return panels[0].parentNode;
}
}
return null;
});
_defineProperty(_this, "panelInstanceId", "panel-".concat(getInstanceId()));
_defineProperty(_this, "panelTitleId", "".concat(namespace, "__title--").concat(_this.panelInstanceId));
_defineProperty(_this, "panelSubtitleId", "".concat(namespace, "__subtitle--").concat(_this.panelInstanceId));
_defineProperty(_this, "footer", /*#__PURE__*/createRef());
_defineProperty(_this, "header", /*#__PURE__*/createRef());
/**
* Handles the key press focus trap.
* @param {SyntheticEvent} event The event fired when a key has been pressed while the panel container is in focus.
*/
_defineProperty(_this, "handleKeyPress", function (event) {
if (event.key === 'Tab') {
trapTabFocus(_this.element, event);
} else if (!_this.props.disableEscape && event.key === 'Escape') {
_this.props.closeButton.onClick();
}
});
_defineProperty(_this, "renderPanelContainer", function (_ref) {
var _ref$labels = _ref.labels,
PANEL_CONTAINER_PRIMARY_BUTTON = _ref$labels.PANEL_CONTAINER_PRIMARY_BUTTON,
PANEL_CONTAINER_SECONDARY_BUTTON = _ref$labels.PANEL_CONTAINER_SECONDARY_BUTTON,
PANEL_CONTAINER_CLOSE_BUTTON = _ref$labels.PANEL_CONTAINER_CLOSE_BUTTON;
var _this$props = _this.props,
children = _this$props.children,
closeButton = _this$props.closeButton,
primaryButton = _this$props.primaryButton,
renderFooter = _this$props.renderFooter,
secondaryButton = _this$props.secondaryButton,
subtitle = _this$props.subtitle,
title = _this$props.title,
hasScrollingContent = _this$props.hasScrollingContent;
var hasFooter = renderFooter || primaryButton;
var ariaLabel = _this.props['aria-label'] || title || subtitle;
var getAriaLabelledBy = title || subtitle ? {
'aria-labelledby': title ? _this.panelTitleId : _this.panelSubtitleId
} : {};
var hasScrollingContentProps = hasScrollingContent ? {
tabIndex: 0,
role: 'region',
'aria-label': ariaLabel
} : {};
return /*#__PURE__*/React.createElement("div", {
role: "dialog",
"aria-label": ariaLabel,
"aria-modal": "true"
}, /*#__PURE__*/React.createElement("header", {
ref: _this.header,
className: "".concat(namespace, "__header")
}, title && /*#__PURE__*/React.createElement("div", {
className: "".concat(namespace, "__header__container--title")
}, /*#__PURE__*/React.createElement("div", {
id: _this.panelTitleId,
className: "".concat(namespace, "__header--title")
}, title), subtitle && /*#__PURE__*/React.createElement("div", {
id: _this.panelSubtitleId,
className: "".concat(namespace, "__header--subtitle")
}, subtitle)), /*#__PURE__*/React.createElement(IconButton, {
id: closeButton.id,
className: "".concat(namespace, "__button--close"),
label: PANEL_CONTAINER_CLOSE_BUTTON,
onClick: closeButton.onClick,
renderIcon: closeButton.icon || Close20,
tooltip: false
})), /*#__PURE__*/React.createElement("section", _extends({
className: classnames("".concat(namespace, "__body"), _defineProperty({}, "".concat(namespace, "__body--footer"), hasFooter)),
style: {
marginTop: "".concat(_this.state.bodyMargin.top, "px"),
marginBottom: "".concat(_this.state.bodyMargin.bottom, "px")
}
}, hasScrollingContentProps, getAriaLabelledBy), children), hasFooter && /*#__PURE__*/React.createElement("div", {
ref: _this.footer,
className: "".concat(namespace, "__footer")
}, renderFooter ? renderFooter() : /*#__PURE__*/React.createElement(Fragment, null, secondaryButton && /*#__PURE__*/React.createElement(Button, {
id: secondaryButton.id,
className: "".concat(namespace, "__footer__button ").concat(namespace, "__footer__button--secondary"),
disabled: secondaryButton.isDisabled,
iconDescription: secondaryButton.iconDescription,
kind: "secondary",
onClick: secondaryButton.onClick,
renderIcon: secondaryButton.icon
}, PANEL_CONTAINER_SECONDARY_BUTTON), /*#__PURE__*/React.createElement(Button, {
id: primaryButton.id,
className: "".concat(namespace, "__footer__button"),
disabled: primaryButton.isDisabled,
iconDescription: primaryButton.iconDescription,
onClick: primaryButton.onClick,
renderIcon: primaryButton.icon
}, PANEL_CONTAINER_PRIMARY_BUTTON))));
});
if (isClient()) {
_this.container = _this.getContainer();
_this.containerClass = "".concat(namespace, "__container");
_this.element = document.createElement('section');
_this.element.classList.add(namespace);
_this.previousFocus = document.activeElement;
_this.rootNode = _this.props.rootNode;
var className = _this.props.className;
if (className) {
_this.element.classList.add(className);
}
}
return _this;
}
_inherits(PanelContainer, _Component);
return _createClass(PanelContainer, [{
key: "componentDidMount",
value: function componentDidMount() {
if (isClient()) {
if (!this.container) {
this.container = document.createElement('div');
this.rootNode.appendChild(this.container);
}
this.container.appendChild(this.element);
if (this.container.childElementCount === 1) {
this.rootNode.classList.toggle(this.containerClass);
}
focusFirstElement(this.element);
this.element.addEventListener('keydown', this.handleKeyPress);
this.setBodyMargin();
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (isClient()) {
this.container.removeChild(this.element);
if (this.container.childElementCount === 0) {
this.rootNode.classList.toggle(this.containerClass);
this.rootNode.removeChild(this.container);
}
this.element.removeEventListener('keydown', this.handleKeyPress);
this.previousFocus.focus();
}
}
}, {
key: "setBodyMargin",
value:
/**
* Sets the body margin to match the height of the header for fixed scrolling.
*/
function setBodyMargin() {
var footer = this.footer.current;
this.setState({
bodyMargin: {
top: this.header.current.clientHeight,
bottom: footer && footer.clientHeight
}
});
}
}, {
key: "render",
value: function render() {
var _this$props2 = this.props,
closeButton = _this$props2.closeButton,
primaryButton = _this$props2.primaryButton,
secondaryButton = _this$props2.secondaryButton,
labels = _this$props2.labels;
var componentLabels = _objectSpread(_objectSpread(_objectSpread({}, defaultLabels.labels), labels), defaultLabels.filterFalsey({
PANEL_CONTAINER_PRIMARY_BUTTON: primaryButton && primaryButton.label || '',
PANEL_CONTAINER_SECONDARY_BUTTON: secondaryButton && secondaryButton.label || '',
PANEL_CONTAINER_CLOSE_BUTTON: closeButton && closeButton.label || ''
}));
return isClient() && /*#__PURE__*/createPortal(this.renderPanelContainer({
labels: componentLabels
}), this.element);
}
}]);
}(Component);
export { PanelContainer as default };
var buttonType = PropTypes.shape({
id: PropTypes.string,
onClick: PropTypes.func,
label: PropTypes.string,
isDisabled: PropTypes.bool,
icon: PropTypes.object,
iconDescription: PropTypes.string
});
PanelContainer.propTypes = (_PanelContainer$propT = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_PanelContainer$propT, 'aria-label', requiredIfGivenPropIsTruthy('hasScrollingContent', PropTypes.string)), "children", PropTypes.node), "className", PropTypes.string), "closeButton", buttonType.isRequired), "disableEscape", PropTypes.bool), "hasScrollingContent", PropTypes.bool), "labels", defaultLabels.propType), "primaryButton", buttonType), "renderFooter", func), "rootNode", isNode() ? PropTypes.instanceOf(Node) : PropTypes.any), _defineProperty(_defineProperty(_defineProperty(_PanelContainer$propT, "secondaryButton", buttonType), "subtitle", PropTypes.node), "title", PropTypes.node));
PanelContainer.defaultProps = {
children: null,
className: null,
disableEscape: false,
primaryButton: null,
secondaryButton: undefined,
subtitle: undefined,
title: undefined,
renderFooter: null,
rootNode: isNode() ? document.body : undefined,
labels: {},
hasScrollingContent: false
};
/* eslint-enable */