UNPKG

@orfeas126/box-ui-elements

Version:
302 lines (300 loc) 10.7 kB
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import * as React from 'react'; import classNames from 'classnames'; import uniqueId from 'lodash/uniqueId'; import getProp from 'lodash/get'; import TetherComponent from 'react-tether'; import TetherPosition from '../../common/tether-positions'; import CloseButton from './CloseButton'; import './Tooltip.scss'; export let TooltipTheme = /*#__PURE__*/function (TooltipTheme) { TooltipTheme["CALLOUT"] = "callout"; TooltipTheme["DEFAULT"] = "default"; TooltipTheme["ERROR"] = "error"; return TooltipTheme; }({}); export let TooltipPosition = /*#__PURE__*/function (TooltipPosition) { TooltipPosition["BOTTOM_CENTER"] = "bottom-center"; TooltipPosition["BOTTOM_LEFT"] = "bottom-left"; TooltipPosition["BOTTOM_RIGHT"] = "bottom-right"; TooltipPosition["MIDDLE_LEFT"] = "middle-left"; TooltipPosition["MIDDLE_RIGHT"] = "middle-right"; TooltipPosition["TOP_CENTER"] = "top-center"; TooltipPosition["TOP_LEFT"] = "top-left"; TooltipPosition["TOP_RIGHT"] = "top-right"; return TooltipPosition; }({}); const positions = { [TooltipPosition.BOTTOM_CENTER]: { attachment: TetherPosition.TOP_CENTER, targetAttachment: TetherPosition.BOTTOM_CENTER }, [TooltipPosition.BOTTOM_LEFT]: { attachment: TetherPosition.TOP_RIGHT, targetAttachment: TetherPosition.BOTTOM_RIGHT }, [TooltipPosition.BOTTOM_RIGHT]: { attachment: TetherPosition.TOP_LEFT, targetAttachment: TetherPosition.BOTTOM_LEFT }, [TooltipPosition.MIDDLE_LEFT]: { attachment: TetherPosition.MIDDLE_RIGHT, targetAttachment: TetherPosition.MIDDLE_LEFT }, [TooltipPosition.MIDDLE_RIGHT]: { attachment: TetherPosition.MIDDLE_LEFT, targetAttachment: TetherPosition.MIDDLE_RIGHT }, [TooltipPosition.TOP_CENTER]: { attachment: TetherPosition.BOTTOM_CENTER, targetAttachment: TetherPosition.TOP_CENTER }, [TooltipPosition.TOP_LEFT]: { attachment: TetherPosition.BOTTOM_RIGHT, targetAttachment: TetherPosition.TOP_RIGHT }, [TooltipPosition.TOP_RIGHT]: { attachment: TetherPosition.BOTTOM_LEFT, targetAttachment: TetherPosition.TOP_LEFT } }; class Tooltip extends React.Component { constructor(props) { super(props); _defineProperty(this, "tooltipID", uniqueId('tooltip')); _defineProperty(this, "tetherRef", /*#__PURE__*/React.createRef()); // Instance API: Forces the radar to be repositioned _defineProperty(this, "position", () => { if (this.tetherRef.current && this.isShown()) { this.tetherRef.current.position(); } }); _defineProperty(this, "closeTooltip", () => { const { onDismiss } = this.props; this.setState({ wasClosedByUser: true }); if (onDismiss) { onDismiss(); } }); _defineProperty(this, "fireChildEvent", (type, event) => { const { children } = this.props; const handler = children.props[type]; if (handler) { handler(event); } }); _defineProperty(this, "handleTooltipEvent", event => { event.stopPropagation(); event.nativeEvent.stopImmediatePropagation(); }); _defineProperty(this, "handleMouseEnter", event => { this.setState({ isShown: true }); this.fireChildEvent('onMouseEnter', event); }); _defineProperty(this, "handleMouseLeave", event => { this.setState({ isShown: false }); this.fireChildEvent('onMouseLeave', event); }); _defineProperty(this, "handleFocus", event => { this.setState({ isShown: true }); this.fireChildEvent('onFocus', event); }); _defineProperty(this, "handleBlur", event => { this.setState({ isShown: false }); this.fireChildEvent('onBlur', event); }); _defineProperty(this, "isControlled", () => { const { isShown: isShownProp } = this.props; return typeof isShownProp !== 'undefined'; }); _defineProperty(this, "handleKeyDown", event => { if (event.key === 'Escape') { event.stopPropagation(); this.setState({ isShown: false }); } this.fireChildEvent('onKeyDown', event); }); _defineProperty(this, "isShown", () => { const { isShown: isShownProp } = this.props; const isControlled = this.isControlled(); const isShown = isControlled ? isShownProp : this.state.isShown; const showTooltip = isShown && !this.state.wasClosedByUser && this.state.hasRendered; return showTooltip; }); this.state = { isShown: !!props.isShown, hasRendered: false, wasClosedByUser: false }; } componentDidMount() { this.setState({ hasRendered: true }); } componentDidUpdate(prevProps, prevState) { const isControlled = this.isControlled(); // Reset wasClosedByUser state when isShown transitions from false to true if (isControlled) { if (!prevProps.isShown && this.props.isShown) { this.setState({ wasClosedByUser: false }); } } else { if (!prevState.isShown && this.state.isShown) { // capture event so that tooltip closes before any other floating components that can be closed by // "Escape" key(e.g. Modal, Menu, etc.) document.addEventListener('keydown', this.handleKeyDown, true); } if (prevState.isShown && !this.state.isShown) { document.removeEventListener('keydown', this.handleKeyDown, true); } } } componentWillUnmount() { document.removeEventListener('keydown', this.handleKeyDown, true); } render() { const { ariaHidden, bodyElement, children, className, constrainToScrollParent, constrainToWindow, isDisabled, isTabbable = true, offset, position = TooltipPosition.TOP_CENTER, showCloseButton, stopBubble, tetherElementClassName, text, theme } = this.props; const childAriaLabel = getProp(children, 'props.aria-label'); const isLabelMatchingTooltipText = !!childAriaLabel && childAriaLabel === text; // If the tooltip is disabled just render the children if (isDisabled) { return React.Children.only(children); } const isControlled = this.isControlled(); const showTooltip = this.isShown(); const withCloseButton = showCloseButton && isControlled; const tetherPosition = typeof position === 'string' ? positions[position] : position; const constraints = []; const componentProps = {}; if (constrainToScrollParent) { constraints.push({ to: 'scrollParent', attachment: 'together' }); } if (constrainToWindow) { constraints.push({ to: 'window', attachment: 'together' }); } if (showTooltip && !ariaHidden) { if (!isLabelMatchingTooltipText || childAriaLabel === undefined) { componentProps['aria-describedby'] = this.tooltipID; } if (theme === TooltipTheme.ERROR) { componentProps['aria-errormessage'] = this.tooltipID; } } if (!isControlled) { componentProps.onBlur = this.handleBlur; componentProps.onFocus = this.handleFocus; componentProps.onMouseEnter = this.handleMouseEnter; componentProps.onMouseLeave = this.handleMouseLeave; if (isTabbable) { componentProps.tabIndex = '0'; } } const bodyEl = bodyElement instanceof HTMLElement ? bodyElement : document.body; const classes = classNames('tooltip', 'bdl-Tooltip', className, { 'is-callout': theme === TooltipTheme.CALLOUT, 'is-error': theme === TooltipTheme.ERROR, 'with-close-button': withCloseButton }); const tetherProps = { attachment: tetherPosition.attachment, bodyElement: bodyEl, classPrefix: 'tooltip', constraints, enabled: showTooltip, targetAttachment: tetherPosition.targetAttachment }; if (tetherElementClassName) { tetherProps.className = tetherElementClassName; } if (offset) { tetherProps.offset = offset; } const tooltipInner = /*#__PURE__*/React.createElement(React.Fragment, null, text, withCloseButton && /*#__PURE__*/React.createElement(CloseButton, { onClick: this.closeTooltip })); const tooltip = stopBubble ? /*#__PURE__*/React.createElement("div", { className: classes, id: this.tooltipID, onClick: this.handleTooltipEvent, onContextMenu: this.handleTooltipEvent, onKeyPress: this.handleTooltipEvent, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, role: "presentation" }, /*#__PURE__*/React.createElement("div", { role: theme === TooltipTheme.ERROR ? undefined : 'tooltip', "aria-live": "polite", "aria-hidden": ariaHidden || isLabelMatchingTooltipText, "data-testid": "bdl-Tooltip" }, tooltipInner)) : /*#__PURE__*/React.createElement("div", { "aria-live": "polite", "aria-hidden": ariaHidden || isLabelMatchingTooltipText, className: classes, "data-testid": "bdl-Tooltip", id: this.tooltipID, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, role: theme === TooltipTheme.ERROR ? undefined : 'tooltip' }, tooltipInner); return /*#__PURE__*/React.createElement(TetherComponent, _extends({ ref: this.tetherRef }, tetherProps), /*#__PURE__*/React.cloneElement(React.Children.only(children), componentProps), showTooltip && tooltip); } } _defineProperty(Tooltip, "defaultProps", { constrainToScrollParent: false, constrainToWindow: true, isDisabled: false, position: TooltipPosition.TOP_CENTER, theme: TooltipTheme.DEFAULT }); export default Tooltip; //# sourceMappingURL=Tooltip.js.map