UNPKG

@carbon/ibm-security

Version:

Carbon for Cloud & Cognitive IBM Security UI components

184 lines (183 loc) 9.72 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; 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"; 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 Portal. * @copyright IBM Security 2019 - 2021 */ import FocusTrap from 'focus-trap-react'; import PropTypes from 'prop-types'; import React, { Children, Component } from 'react'; import { createPortal } from 'react-dom'; import { getComponentNamespace } from '../../globals/namespace'; import deprecatedProp from '../../globals/prop-types'; import { isClient, isNode } from '../../globals/utils/capabilities'; import composeEventHandlers from '../../globals/utils/events'; var namespace = getComponentNamespace('portal'); export var PORTAL_EVENTS = ['onAbort', 'onAnimationEnd', 'onAnimationIteration', 'onAnimationStart', /* 'onBlur', // Does not Bubble */ /* 'onCanPlay', // Does not Bubble */ /* 'onCanPlayThrough', // Does not Bubble */ 'onChange', 'onClick', 'onContextMenu', 'onCopy', 'onCut', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', /* 'onDurationChange', // Does not Bubble */ 'onEmptied', 'onEncrypted', /* 'onEnded', // Does not Bubble */ /* 'onError', // Does not Bubble */ /* 'onFocus', // Does not Bubble */ /* 'onGotPointerCapture', // Does not Bubble */ 'onInput', /* 'onInvalid', // Does not Bubble */ 'onKeyDown', 'onKeyPress', 'onKeyUp', /* 'onLoad', // Does not Bubble */ /* 'onLoadedData', // Does not Bubble */ /* 'onLoadedMetadata', // Does not Bubble */ /* 'onLoadStart', // Does not Bubble */ /* 'onLostPointerCapture', // Does not Bubble */ 'onMouseDown', /* 'onMouseEnter', // Does not Bubble */ /* 'onMouseLeave', // Does not Bubble */ 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 'onPaste', /* 'onPause', // Does not Bubble */ /* 'onPlay', // Does not Bubble */ /* 'onPlaying', // Does not Bubble */ 'onPointerCancel', 'onPointerDown', /* 'onPointerEnter', // Does not Bubble */ /* 'onPointerLeave', // Does not Bubble */ 'onPointerMove', 'onPointerOut', 'onPointerOver', 'onPointerUp', /* 'onProgress', // Does not Bubble */ 'onRateChange', 'onScroll', 'onSeeked', 'onSeeking', 'onSelect', 'onStalled', 'onSubmit', 'onSuspend', 'onTimeUpdate', 'onToggle', 'onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart', 'onTransitionEnd', 'onVolumeChange', 'onWaiting', 'onWheel']; var Portal = /*#__PURE__*/function (_Component) { function Portal() { var _this; _classCallCheck(this, Portal); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Portal, [].concat(args)); _defineProperty(_this, "handleOverlayClick", function () { _this.onOverlayClick(); }); _defineProperty(_this, "createPropagationTrap", function () { var _this$props = _this.props, children = _this$props.children, stopPropagationEvents = _this$props.stopPropagationEvents; var childProps = {}; var child = React.Children.only(children); var events = stopPropagationEvents || PORTAL_EVENTS; events.forEach(function (event) { if (child.props[event]) { childProps[event] = composeEventHandlers([_this.handleBubble, child.props[event]]); } else { childProps[event] = _this.handleBubble; } }); return /*#__PURE__*/React.cloneElement(child, _objectSpread({}, childProps)); }); _defineProperty(_this, "handleBubble", function (event) { event.stopPropagation(); }); _defineProperty(_this, "containerClass", "".concat(namespace, "__container")); _defineProperty(_this, "panelContainerClass", "".concat(getComponentNamespace('panel'), "__container")); return _this; } _inherits(Portal, _Component); return _createClass(Portal, [{ key: "componentDidMount", value: function componentDidMount() { if (isClient()) { var _this$props2 = this.props, rootNode = _this$props2.rootNode, hasOverlay = _this$props2.hasOverlay, onOverlayClick = _this$props2.onOverlayClick, _this$props2$overlayO = _this$props2.overlayOptions, className = _this$props2$overlayO.className, onClick = _this$props2$overlayO.onClick; this.onOverlayClick = onClick || onOverlayClick; rootNode.classList.toggle(this.containerClass); if (hasOverlay && document.getElementsByClassName(namespace).length === 0) { var _this$overlay$classLi; this.overlay = document.createElement('div'); this.overlay.setAttribute('tabIndex', '-1'); (_this$overlay$classLi = this.overlay.classList).add.apply(_this$overlay$classLi, _toConsumableArray(["".concat(namespace, "__overlay"), className].filter(Boolean))); rootNode.appendChild(this.overlay); if (this.onOverlayClick) { this.overlay.addEventListener('mousedown', this.handleOverlayClick); } } } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { if (isClient()) { var _this$props3 = this.props, rootNode = _this$props3.rootNode, hasOverlay = _this$props3.hasOverlay; rootNode.classList.toggle(this.containerClass); if (hasOverlay && this.overlay) { rootNode.removeChild(this.overlay); } if (this.onOverlayClick) { this.overlay.removeEventListener('mousedown', this.handleOverlayClick); } } } }, { key: "render", value: function render() { var _this$props4 = this.props, children = _this$props4.children, focusTrap = _this$props4.focusTrap, focusTrapOptions = _this$props4.focusTrapOptions, initialFocus = _this$props4.initialFocus, rootNode = _this$props4.rootNode, stopPropagation = _this$props4.stopPropagation, stopPropagationEvents = _this$props4.stopPropagationEvents; return isClient() && /*#__PURE__*/createPortal(/*#__PURE__*/React.createElement(FocusTrap, { active: focusTrap, focusTrapOptions: _objectSpread({ fallbackFocus: focusTrapOptions.fallbackFocus || (isClient() ? rootNode : Children.toArray(children)[0].type), initialFocus: initialFocus }, focusTrapOptions) }, stopPropagation || stopPropagationEvents ? this.createPropagationTrap() : children), rootNode); } }]); }(Component); // TODO: `2.x` - Remove deprecated prop `onOverlayClick`. Portal.propTypes = { /** @type {element} The children of the panel. */ children: PropTypes.element, /** @type {boolean} Focus trap. */ focusTrap: PropTypes.bool, /** Pass any of the options available in https://github.com/focus-trap/focus-trap#createfocustrapelement-createoptions */ focusTrapOptions: FocusTrap.propTypes.focusTrapOptions, /** @type {boolean} Include an overlay. */ hasOverlay: PropTypes.bool, /** @type {node} Initially focused element. */ initialFocus: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), /** Deprecated in favor of `overlayOptions.onClick` */ onOverlayClick: deprecatedProp('overlayOptions.onClick', PropTypes.func), /** Specify the options for the overlay */ overlayOptions: PropTypes.shape({ /** Provide an optional class to be applied to the overlay */ className: PropTypes.string, /** Specify the click event handler for the overlay */ onClick: PropTypes.func }), /** @type {ReactNode|any} The root node for rendering the panel */ rootNode: isNode() ? PropTypes.instanceOf(Node) : PropTypes.any, /** @type {boolean} Stop event propagation for events that can bubble. */ stopPropagation: PropTypes.bool, /** @type {Array} Array of event types to stop propagation. */ stopPropagationEvents: PropTypes.arrayOf(PropTypes.oneOf(PORTAL_EVENTS)) }; Portal.defaultProps = { children: null, focusTrap: true, focusTrapOptions: FocusTrap.defaultProps.focusTrapOptions, hasOverlay: true, onOverlayClick: undefined, overlayOptions: {}, rootNode: isClient() && document.body, stopPropagation: false, stopPropagationEvents: undefined }; export default Portal;