UNPKG

@carbon/ibm-security

Version:

Carbon for Cloud & Cognitive IBM Security UI components

393 lines (390 loc) 17.3 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; 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 _excluded = ["children", "href", "content", "icon", "id", "title"], _excluded2 = ["href", "element", "content", "id", "title"]; 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 Toolbar. * @copyright IBM Security 2019 - 2021 */ import { ArrowLeft20, Close20, Help20, Menu20, Settings20 } from '@carbon/icons-react'; import classnames from 'classnames'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { isClient } from '../../globals/utils/capabilities'; import root from '../../globals/utils/globalRoot'; import toggle from '../Component'; import IconButton from '../IconButton'; import Nav from '../Nav'; import NavList from '../Nav/NavList'; import NavItem from '../Nav/NavItem'; import Transition from '../Transition'; import { getComponentNamespace } from '../../globals/namespace'; export var namespace = getComponentNamespace('toolbar'); /** * Toolbar component. * @param {Record<string, any>} htmlContent Toolbar props. * @returns {Toolbar} Toolbar instance. */ var Toolbar = /*#__PURE__*/function (_Component) { function Toolbar() { var _this; _classCallCheck(this, Toolbar); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Toolbar, [].concat(args)); _defineProperty(_this, "state", { isActive: { menu: false, settings: false, support: false }, content: undefined, showContent: false }); _defineProperty(_this, "wrapper", /*#__PURE__*/React.createRef()); /** * Handle a click outside of the Toolbar wrapper. * @param {Event} event A click event. */ _defineProperty(_this, "handleClickOutside", function (event) { var activeElement = event.target.getRootNode().activeElement || document.activeElement; if (event.target !== activeElement && event.target.nodeName !== 'SHELL-COMPONENT' && _this.wrapper && !_this.wrapper.current.contains(event.target)) { _this.setState({ isActive: { menu: false, settings: false, support: false } }); _this.props.onToggle(false); } }); _defineProperty(_this, "toggleContent", function () { var htmlContent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined; _this.setState({ content: htmlContent, showContent: !_this.state.showContent }); }); return _this; } _inherits(Toolbar, _Component); return _createClass(Toolbar, [{ key: "componentDidMount", value: function componentDidMount() { if (isClient() && root.document) { root.document.addEventListener('click', this.handleClickOutside); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { if (isClient() && root.document) { root.document.removeEventListener('click', this.handleClickOutside); } } }, { key: "toggleIcon", value: /** * Toggles the appropriate icon button based on whether the relevant panel is open. * @param {string} label The icon label. * @param {Function} renderIcon The icon to use. * @param {string} type The panel to check. * @returns {IconButton} The icon button to return. */ function toggleIcon(label, renderIcon, type) { var _this2 = this; var isActiveItem = this.state.isActive[type]; var iconButtonClass = "".concat(namespace, "__button"); var iconButtonClasses = classnames(iconButtonClass, _defineProperty({}, "".concat(iconButtonClass, "--active"), isActiveItem)); return /*#__PURE__*/React.createElement(IconButton, _extends({ className: iconButtonClasses, "aria-expanded": isActiveItem }, isActiveItem ? _defineProperty({}, "aria-controls", "".concat(namespace, "--toolbar--").concat(type)) : {}, { "aria-label": label, iconClassName: "".concat(namespace, "__icon"), label: label, onClick: function onClick() { return _this2.togglePanel(type); }, renderIcon: isActiveItem ? Close20 : renderIcon, state: isActiveItem, tooltip: !isActiveItem, tooltipDirection: IconButton.TooltipDirection.RIGHT })); } /** * Toggles the panel and applies the appropriate class to the body. * @param {string} type The type of panel to toggle. */ }, { key: "togglePanel", value: function togglePanel(type) { var _this3 = this; toggle.call(this, type, function (state) { var isToggled = state[type]; _this3.props.onToggle(isToggled); root.dispatchEvent(new CustomEvent("".concat(namespace, ":toggle"), { detail: { isToggled: isToggled } })); }); } }, { key: "renderContent", value: /** * Renders the panel content. * @param {string} type The type of panel to render. * @returns {React.Element} The rendered panel. */ function renderContent(type) { var _this4 = this; var navigationType = this.props[type]; var isActiveItem = this.state.isActive[type]; return isActiveItem && navigationType.length > 0 && navigationType.map(function (_ref2) { var id = _ref2.id, navigation = _ref2.navigation, title = _ref2.title; return /*#__PURE__*/React.createElement(Nav, { key: id, heading: title, label: title }, navigation.filter(function (item) { return item !== null && item !== undefined; }).map(function (_ref3) { var children = _ref3.children, href = _ref3.href, content = _ref3.content, icon = _ref3.icon, navigationItemId = _ref3.id, navigationItemTitle = _ref3.title, props = _objectWithoutProperties(_ref3, _excluded); var hasIcon = icon !== undefined; return children ? /*#__PURE__*/React.createElement(NavList, { className: classnames(_defineProperty({}, "".concat(namespace, "__nav__list__title--icon"), hasIcon)), renderIcon: hasIcon, icon: icon, key: navigationItemId, navigationItemTitle: navigationItemTitle, title: navigationItemTitle }, children.map(function (_ref4) { var navigationListItemHref = _ref4.href, navigationListItemElement = _ref4.element, content = _ref4.content, navigationListItemId = _ref4.id, navigationListItemTitle = _ref4.title, props = _objectWithoutProperties(_ref4, _excluded2); return /*#__PURE__*/React.createElement(NavItem, _extends({ key: navigationListItemId, onClick: function onClick() { return _this4.togglePanel(type); }, id: navigationListItemId, href: navigationListItemHref, element: navigationListItemElement, link: content === undefined, handleItemSelect: function handleItemSelect() { return _this4.toggleContent(content); } }, props), navigationListItemTitle); })) : /*#__PURE__*/React.createElement(NavItem, _extends({ key: navigationItemId, id: navigationItemId, onClick: function onClick() { return _this4.togglePanel(type); }, href: href, link: content === undefined, handleItemSelect: function handleItemSelect() { return _this4.toggleContent(content); } }, props), hasIcon && /*#__PURE__*/React.createElement("img", { alt: navigationItemTitle, className: "".concat(namespace, "__nav__item__icon"), src: icon }), /*#__PURE__*/React.createElement("div", { className: classnames("".concat(namespace, "__nav__item__title"), _defineProperty({}, "".concat(namespace, "__nav__item__title--icon"), hasIcon)) }, navigationItemTitle)); })); }); } }, { key: "render", value: function render() { var _this5 = this; var _this$props = this.props, className = _this$props.className, _this$props$labels = _this$props.labels, _this$props$labels$ma = _this$props$labels.mainNavigation, _this$props$labels$ma2 = _this$props$labels$ma === void 0 ? {} : _this$props$labels$ma, _this$props$labels$ma3 = _this$props$labels$ma2.ariaLabel, ariaLabel = _this$props$labels$ma3 === void 0 ? null : _this$props$labels$ma3, menu = _this$props$labels.menu, settings = _this$props$labels.settings, support = _this$props$labels.support, _this$props$renderAdd = _this$props.renderAddons, renderAddons = _this$props$renderAdd === void 0 ? [] : _this$props$renderAdd; var renderSupport = this.props.support.length > 0; var renderSettings = this.props.settings.length > 0; var classes = classnames(namespace, className, _defineProperty({}, "".concat(namespace, "__minimized"), !renderSupport && !renderSettings)); var isActive = this.state.isActive; var activeItems = Object.entries(isActive) // eslint-disable-next-line no-unused-vars .filter(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), type = _ref6[0], isActiveItem = _ref6[1]; return isActiveItem; }); var currentType = ''; var isPanelActive = false; if (activeItems.length > 0) { var _activeItems = _slicedToArray(activeItems, 1); var _activeItems$ = _slicedToArray(_activeItems[0], 2); currentType = _activeItems$[0]; isPanelActive = _activeItems$[1]; } return /*#__PURE__*/React.createElement("div", { ref: this.wrapper }, /*#__PURE__*/React.createElement("nav", { "aria-label": ariaLabel, className: classes }, /*#__PURE__*/React.createElement("ul", { className: "".concat(namespace, "__group") }, /*#__PURE__*/React.createElement("li", null, this.toggleIcon(menu.button, Menu20, 'menu')), renderSettings && /*#__PURE__*/React.createElement("li", null, this.toggleIcon(settings.button, Settings20, 'settings')), renderSupport && /*#__PURE__*/React.createElement("li", null, this.toggleIcon(support.button, Help20, 'support')), renderAddons.map(function (_ref7) { var id = _ref7.id, render = _ref7.render; return /*#__PURE__*/React.createElement("li", { key: id }, render({ className: "".concat(namespace, "__button"), iconClassName: "".concat(namespace, "__icon") })); }))), /*#__PURE__*/React.createElement(Transition, { className: namespace, component: "span" }, isPanelActive && this.state.showContent ? /*#__PURE__*/React.createElement("div", { role: "navigation", "aria-label": currentType, id: "".concat(namespace, "--toolbar--").concat(currentType), className: "".concat(namespace, "__panel") }, /*#__PURE__*/React.createElement(IconButton, { onClick: this.toggleContent, renderIcon: ArrowLeft20 }), /*#__PURE__*/React.createElement("div", { className: "".concat(namespace, "__content"), dangerouslySetInnerHTML: { __html: this.state.content } // eslint-disable-line react/no-danger })) : isPanelActive && /*#__PURE__*/React.createElement("div", { role: "navigation", "aria-label": currentType, id: "".concat(namespace, "--toolbar--").concat(currentType), className: "".concat(namespace, "__panel") }, Object.keys(isActive).map(function (type) { return /*#__PURE__*/React.createElement(Transition, { key: type, className: "".concat(namespace, "__content"), component: "span" }, _this5.renderContent(type)); })))); } }]); }(Component); export { Toolbar as default }; var href = PropTypes.string.isRequired; var navigation = { /** @type {string} The ID of the navigation. */ id: PropTypes.string.isRequired, /** @type {string} The title of the navigation. */ title: PropTypes.node.isRequired, /** @type {node} Content. */ content: PropTypes.node, /** @type {string} Icon. */ icon: PropTypes.string }; var panel = function panel() { return /** @type {Array<Object.*>} An array list of navigation lists and sub-navigation. */PropTypes.arrayOf(/** @type {Record<object, object>} An object list of navigation. */ PropTypes.shape(_objectSpread(_objectSpread({}, navigation), {}, { /** @type {Array<Object.*>} An array list of navigation items. */ navigation: PropTypes.arrayOf(/** @type {Record<object, object>} An object list of navigation. */ PropTypes.shape(Object.assign({}, navigation, { /** @type {Array<Object.*>} An array list of sub-navigation items. */ children: PropTypes.arrayOf(/** @type {Record<object, object>} An object list of sub-navigation. */ PropTypes.shape(Object.assign({}, navigation, href))), href: href }))).isRequired })).isRequired); }; Toolbar.propTypes = { /** @type {string} Extra classes to add. */ className: PropTypes.string, /** @type {Record<object, object>} An object list of labels. */ labels: PropTypes.shape({ /** @type {Record<string, string>} An object list of navigation labels for the top level navigation item. */ mainNavigation: PropTypes.shape({ /** Specify the `aria-label` for the primary navigation */ ariaLabel: PropTypes.string.isRequired }).isRequired, /** @type {Record<string, string>} An object list of menu labels. */ menu: PropTypes.shape({ /** @type {string} The button label. */ button: PropTypes.string.isRequired, /** @type {string} The tooltip label. */ tooltip: PropTypes.string }).isRequired, /** @type {Record<string, string>} An object list of settings labels. */ settings: PropTypes.shape({ /** @type {string} The button label. */ button: PropTypes.string.isRequired, /** @type {string} The tooltip label. */ tooltip: PropTypes.string }), /** @type {Record<string, string>} An object list of support labels. */ support: PropTypes.shape({ /** @type {string} The button label. */ button: PropTypes.string.isRequired, /** @type {string} The tooltip label. */ tooltip: PropTypes.string }) }).isRequired, // eslint-disable-next-line react/no-unused-prop-types menu: panel(), /** @type {Function} Toggle handler. */ onToggle: PropTypes.func, /** @type {Array<{id: string, tooltip: string, render: Function: React.Element}>} An object list to render custom addon icons. */ renderAddons: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string.isRequired, render: PropTypes.func.isRequired, tooltip: PropTypes.string })), // eslint-disable-next-line react/no-unused-prop-types settings: panel(), // eslint-disable-next-line react/no-unused-prop-types support: panel() }; Toolbar.defaultProps = { className: null, menu: [], onToggle: function onToggle(isToggled) { return isToggled; }, renderAddons: [], settings: [], support: [] };