UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

316 lines (254 loc) 11.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = exports.TooltipContext = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _headless = _interopRequireDefault(require("@tippyjs/react/headless")); var _lodash = _interopRequireDefault(require("lodash.isfunction")); var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps")); var _classnames = _interopRequireDefault(require("classnames")); var _Tooltip = require("./Tooltip.css"); var _KeyboardBadge = _interopRequireDefault(require("../KeyboardBadge")); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } var TooltipContext = /*#__PURE__*/(0, _react.createContext)({}); exports.TooltipContext = TooltipContext; var getClassName = function getClassName(className) { return (0, _classnames.default)('c-Tooltip', className); }; var hideOnEsc = { name: 'hideOnEsc', defaultValue: true, fn: function fn(_ref) { var hide = _ref.hide; function onKeyDown(event) { if (event.keyCode === 27) { hide(); } } return { onShow: function onShow() { document.addEventListener('keydown', onKeyDown); }, onHide: function onHide() { document.removeEventListener('keydown', onKeyDown); } }; } }; var Tooltip = function Tooltip(_ref2) { var animationDelay = _ref2.animationDelay, animationDuration = _ref2.animationDuration, arrowSize = _ref2.arrowSize, badge = _ref2.badge, children = _ref2.children, className = _ref2.className, closeOnContentClick = _ref2.closeOnContentClick, closeOnEscPress = _ref2.closeOnEscPress, display = _ref2.display, dataCy = _ref2['data-cy'], _ref2$getTippyInstanc = _ref2.getTippyInstance, getTippyInstance = _ref2$getTippyInstanc === void 0 ? function () {} : _ref2$getTippyInstanc, innerRef = _ref2.innerRef, isOpen = _ref2.isOpen, minWidth = _ref2.minWidth, maxWidth = _ref2.maxWidth, placement = _ref2.placement, renderProp = _ref2.render, renderContent = _ref2.renderContent, title = _ref2.title, triggerOn = _ref2.triggerOn, withTriggerWrapper = _ref2.withTriggerWrapper, _ref2$withArrow = _ref2.withArrow, withArrow = _ref2$withArrow === void 0 ? true : _ref2$withArrow, zIndexProp = _ref2.zIndex, rest = (0, _objectWithoutPropertiesLoose2.default)(_ref2, ["animationDelay", "animationDuration", "arrowSize", "badge", "children", "className", "closeOnContentClick", "closeOnEscPress", "display", "data-cy", "getTippyInstance", "innerRef", "isOpen", "minWidth", "maxWidth", "placement", "render", "renderContent", "title", "triggerOn", "withTriggerWrapper", "withArrow", "zIndex"]); var _ref3 = (0, _react.useContext)(TooltipContext) || {}, _ref3$zIndex = _ref3.zIndex, zIndex = _ref3$zIndex === void 0 ? zIndexProp : _ref3$zIndex, animationDurationContext = _ref3.animationDuration; var _useState = (0, _react.useState)(animationDuration === 0), isEntered = _useState[0], setEntered = _useState[1]; var isMounted = (0, _react.useRef)(true); (0, _react.useEffect)(function () { return function () { isMounted.current = false; }; }, []); var hasRenderContent = renderContent && (0, _lodash.default)(renderContent); var hasRender = renderProp && (0, _lodash.default)(renderProp); var shouldRenderTooltip = title || hasRenderContent || hasRender; var hasKeyboardBadge = badge && !hasRender; var duration = animationDurationContext ? animationDurationContext : animationDuration; var tooltipProps = { className: getClassName(className), arrowSize: arrowSize, animationDuration: duration, 'data-entered': isEntered, maxWidth: maxWidth, minWidth: minWidth, ref: innerRef, tabIndex: '-1' }; var renderTooltip = function renderTooltip(_ref4) { var className = _ref4.className, props = (0, _objectWithoutPropertiesLoose2.default)(_ref4, ["className"]); var titleContent = null; if (typeof title === 'string') { titleContent = /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "c-Tooltip__title", dangerouslySetInnerHTML: { __html: title } }); } else { titleContent = title; } var tooltipClassnames = (0, _classnames.default)(className, hasKeyboardBadge && 'with-badge', typeof title === 'string' && 'with-plain-title'); var toolTipComponent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.TooltipAnimationUI, { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Tooltip.TooltipUI, (0, _extends2.default)({ className: tooltipClassnames }, props, { children: [renderContent ? renderContent() : titleContent, hasKeyboardBadge ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_KeyboardBadge.default, { value: badge }) : null, withArrow && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.ArrowUI, { className: "c-Tooltip_ArrowUI", arrowSize: arrowSize, "data-popper-arrow": true })] })) }); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "hsds-react hsds-beacon", children: toolTipComponent }); }; var render = function render(attrs) { var props = (0, _extends2.default)({}, tooltipProps, attrs); if (renderProp) return renderProp(props); return renderTooltip(props); }; var onShow = function onShow() { setTimeout(function () { if (isMounted.current) { setEntered(true); } }, animationDelay); }; var onCreate = function onCreate(instance) { getTippyInstance && getTippyInstance(instance); }; var onHide = function onHide() { setEntered(false); }; var extraProps = {}; if (zIndex) { extraProps.zIndex = zIndex; } if (!closeOnContentClick) { extraProps.interactive = true; extraProps.interactiveBorder = 20; } var plugins = []; if (closeOnEscPress) { plugins.push(hideOnEsc); } var defaultTippyProps = { onCreate: onCreate, onHide: onHide, onShow: onShow, placement: placement, plugins: plugins, render: render, maxWidth: maxWidth }; // only set those props if the component is not in a controlled way if (!rest.hasOwnProperty('visible')) { defaultTippyProps.showOnCreate = isOpen; defaultTippyProps.trigger = triggerOn === 'hover' ? 'mouseenter' : triggerOn; } var tippyProps = (0, _extends2.default)({}, defaultTippyProps, rest, extraProps); if (!shouldRenderTooltip) { return children ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", (0, _extends2.default)({}, (0, _getValidProps.default)(rest), { className: getClassName(className), children: children })) : null; } var triggerComponent; if (!withTriggerWrapper && /*#__PURE__*/_react.default.isValidElement(children) && _react.default.Children.count(children) === 1) { var component = _react.default.Children.only(children); var triggerProps = { className: (0, _classnames.default)('TooltipTrigger', component.props.className), 'data-cy': component.props['data-cy'] || dataCy, tabIndex: component.props['tabIndex'] || 0, 'aria-expanded': null // let tippy handle that prop }; triggerComponent = /*#__PURE__*/_react.default.cloneElement(component, triggerProps); } else { triggerComponent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.TooltipTriggerUI, { tabIndex: "0", display: display, "data-cy": dataCy, className: "TooltipTrigger", children: children }); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_headless.default, (0, _extends2.default)({}, tippyProps, { children: triggerComponent })); }; Tooltip.defaultProps = { animationDelay: 0, animationDuration: 200, arrowSize: 12, closeOnEscPress: true, 'data-cy': 'Tooltip', display: null, isOpen: false, placement: 'top', triggerOn: 'mouseenter focus', withTriggerWrapper: true }; Tooltip.propTypes = { animationDelay: _propTypes.default.number, animationDuration: _propTypes.default.number, /** Size of the Arrow in pixels */ arrowSize: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Render the value within a KeyboardBadge component after the title. Will be render only when using the title prop */ badge: _propTypes.default.string, /** Custom class names to be added to the component. */ className: _propTypes.default.string, /** Whether to allow closing the tooltip on pressing ESC */ closeOnEscPress: _propTypes.default.bool, /** Data attr for Cypress tests. */ 'data-cy': _propTypes.default.string, /** Apply custom css rule `display` */ display: _propTypes.default.string, getTippyInstance: _propTypes.default.any, /** Determine if the tooltip is open via a prop */ isOpen: _propTypes.default.bool, /** Max width for the component. */ maxWidth: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Min width for the component. */ minWidth: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** Renders a component within the Tooltip. Is prioritized over `title` */ renderContent: _propTypes.default.func, /** Where to place the Tooltip. */ placement: _propTypes.default.string, /** Text to display within the Tooltip. */ title: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.string]), /** Determines how to engage the component. */ triggerOn: _propTypes.default.string, /** Set the tooltip to be controlled externally */ visible: _propTypes.default.bool, /** Wrap the trigger with a span */ withTriggerWrapper: _propTypes.default.bool, /** Whether to render the arrow */ withArrow: _propTypes.default.bool }; var _default = Tooltip; exports.default = _default;