"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.Tooltip = void 0;
var _CSSTransition = _interopRequireDefault(require("react-transition-group/CSSTransition"));
var _focusTrapReact = _interopRequireDefault(require("focus-trap-react"));
var _react = require("react");
var _classnames = _interopRequireDefault(require("classnames"));
var _core = require("@popperjs/core");
var _useId = _interopRequireDefault(require("../utilities/useId"));
var _Button = require("../Button");
var _Icons = require("../Icons");
var _usePrevious = _interopRequireDefault(require("../utilities/usePrevious"));
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// TODO: Update react-transition-group once we update react peer dep

// Similarly to the Button component, we want to expand the props type definition to
// permit pass-through props for the most commonly used underlying components.
// However, unlike in Button, we have not removed the ability for applications to
// define a custom `component` prop, which means there are theoretically props
// specific to that component type which will not be available in the TooltipProps
// definition. The strategy here is to keep the types simple by including just the
// possible attributes of button and anchor, but it comes at the expense of accuracy.
// If applications have extra props for their custom components, they will need to
// tell TypeScript to ignore those props for now. We'd like to revisit Tooltip in
// the future and improve it.

/**
 * Tooltips provide additional information upon hover, focus or click.
 * For information about how and when to use this component,
 * [refer to its full documentation page](https://design.cms.gov/components/tooltip/).
 *
 * When using the `<TooltipIcon>` as the only child of `<Tooltip>`, be sure to
 * provide an `aria-label` on the `<Tooltip>` to ensure an accessible name for
 * the trigger.
 */
const Tooltip = props => {
  const popper = (0, _react.useRef)(null);
  const contentId = (0, _useId.default)('tooltip-trigger--', props.id);
  const triggerElement = (0, _react.useRef)(null);
  const tooltipElement = (0, _react.useRef)(null);
  const setTriggerElement = elem => {
    triggerElement.current = elem;
  };
  const setTooltipElement = elem => {
    tooltipElement.current = elem;
  };
  const [active, setActive] = (0, _react.useState)(false);
  const [isHover, setIsHover] = (0, _react.useState)(false);
  const [isMobile, setIsMobile] = (0, _react.useState)(false);
  const prevActiveStateVar = (0, _usePrevious.default)(active);
  const handleEscapeKey = event => {
    const ESCAPE_KEY = 27;
    if (active && event.keyCode === ESCAPE_KEY) {
      setActive(false);
    }
  };
  const handleClickOutside = event => {
    if (active && (props.dialog || isMobile)) {
      const clickedTrigger = triggerElement.current?.contains(event.target);
      const clickedTooltip = tooltipElement.current?.contains(event.target);
      if (!clickedTooltip && !clickedTrigger) {
        setActive(false);
      }
    }
  };
  const handleCloseButtonClick = () => {
    if (active && (props.dialog || isMobile)) {
      setActive(false);
    }
  };
  const handleBlur = event => {
    setTimeout(() => {
      if (!isHover && event.currentTarget !== event.target) setActive(false);
    }, 10);
  };
  const handleTouch = () => {
    // On mobile, touch -> mouseenter -> click events can all be fired simultaneously
    // `isMobile` flag is used inside onClick and onMouseEnter handlers, so touch events can be used in isolation on mobile
    // https://stackoverflow.com/a/65055198
    setIsMobile(true);
    setActive(!active);
  };
  (0, _react.useEffect)(() => {
    if (!triggerElement.current || !tooltipElement.current) return;
    popper.current = (0, _core.createPopper)(triggerElement.current, tooltipElement.current, {
      placement: props.placement,
      modifiers: [{
        name: 'offset',
        options: {
          offset: props.offset
        }
      }]
    });
    return () => {
      if (popper.current) popper.current.destroy();
    };
  }, []);
  (0, _react.useEffect)(() => {
    document.addEventListener('mousedown', handleClickOutside);
    document.addEventListener('keydown', handleEscapeKey);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
      document.removeEventListener('keydown', handleEscapeKey);
    };
  }, [handleClickOutside, handleEscapeKey]);
  (0, _react.useEffect)(() => {
    if (active) {
      props.onOpen && props.onOpen();
    } else {
      props.onClose && props.onClose();

      // if tooltip goes from active to inactive and is the dialog version, focus the trigger
      if (prevActiveStateVar && (props.dialog || isMobile) && props.showCloseButton) {
        if (triggerElement && triggerElement.current) {
          triggerElement.current.focus();
        }
      }
    }
  }, [active]);
  (0, _react.useLayoutEffect)(() => {
    if (popper.current) {
      popper.current.setOptions(props);
      popper.current.forceUpdate();
    }
  });
  const renderTrigger = props => {
    const {
      activeClassName,
      ariaLabel,
      children,
      className,
      component,
      dialog,
      id,
      offset,
      onClose,
      onOpen,
      inversed,
      interactiveBorder,
      placement,
      maxWidth,
      title,
      transitionDuration,
      zIndex,
      showCloseButton,
      closeButtonLabel,
      contentHeading,
      ...others
    } = props;
    const TriggerComponent = component;
    const triggerClasses = (0, _classnames.default)('ds-c-tooltip__trigger', className, {
      [activeClassName]: activeClassName && active,
      'ds-c-tooltip__trigger--inverse': inversed
    });
    const linkTriggerOverrides = {
      tabIndex: TriggerComponent === 'a' ? 0 : undefined
    };
    const eventHandlers = dialog ? {
      onTouchStart: () => handleTouch(),
      onClick: () => {
        if (!isMobile) {
          setActive(!active);
        }
      }
    } : {
      onTouchStart: () => handleTouch(),
      onClick: () => {
        if (!isMobile) {
          setActive(!active);
        }
      },
      onFocus: () => setActive(true),
      onBlur: event => handleBlur(event)
    };
    return /*#__PURE__*/(0, _jsxRuntime.jsx)(TriggerComponent, {
      type: TriggerComponent === 'button' ? 'button' : undefined,
      "aria-label": ariaLabel || undefined,
      "aria-describedby": dialog ? undefined : contentId,
      className: triggerClasses,
      ref: setTriggerElement,
      ...others,
      ...linkTriggerOverrides,
      ...eventHandlers,
      children: children
    });
  };
  const renderContent = props => {
    const {
      closeButtonLabel,
      dialog,
      contentHeading,
      inversed,
      interactiveBorder,
      placement,
      maxWidth,
      showCloseButton,
      title,
      transitionDuration,
      zIndex
    } = props;
    const tooltipStyle = {
      maxWidth,
      zIndex
    };
    const interactiveBorderStyle = {
      left: `-${interactiveBorder}px`,
      top: `-${interactiveBorder}px`,
      border: `${interactiveBorder}px solid transparent`,
      zIndex: -999 // ensures interactive border doesnt cover tooltip content
    };

    const eventHandlers = dialog ? {} : {
      onBlur: event => handleBlur(event)
    };
    const tooltipContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      id: contentId,
      tabIndex: dialog ? -1 : null,
      ref: setTooltipElement,
      className: (0, _classnames.default)('ds-c-tooltip', {
        'ds-c-tooltip--inverse': inversed
      }),
      style: tooltipStyle,
      "data-placement": placement,
      "aria-hidden": !active,
      role: dialog ? 'dialog' : 'tooltip',
      ...eventHandlers,
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
        className: "ds-c-tooltip__arrow",
        "data-popper-arrow": true
      }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "ds-c-tooltip__content",
        children: [contentHeading || showCloseButton ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
          className: (0, _classnames.default)('ds-c-tooltip__header', {
            'ds-c-tooltip__header--right': !contentHeading
          }),
          children: [contentHeading, showCloseButton && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.Button, {
            variation: "ghost",
            size: "small",
            className: "ds-c-tooltip__close-button",
            onClick: handleCloseButtonClick,
            "aria-label": closeButtonLabel || 'Close',
            children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icons.CloseIconThin, {})
          })]
        }) : null, title]
      }), !dialog && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
        className: "ds-c-tooltip__interactive-border",
        style: interactiveBorderStyle
      })]
    });
    return /*#__PURE__*/(0, _jsxRuntime.jsx)(_CSSTransition.default, {
      in: active,
      classNames: "ds-c-tooltip",
      timeout: transitionDuration,
      children: dialog ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_focusTrapReact.default, {
        active: active,
        focusTrapOptions: {
          fallbackFocus: () => document.getElementById(`${contentId}`).parentElement,
          initialFocus: () => document.getElementById(`${contentId}`),
          clickOutsideDeactivates: true
        },
        children: tooltipContent
      }) : tooltipContent
    });
  };
  const mainEventHandlers = props.dialog ? {} : {
    onMouseEnter: () => {
      if (!isMobile) {
        setIsHover(true);
        setActive(true);
      }
    },
    onMouseLeave: () => {
      if (!isMobile) {
        setIsHover(false);
        setActive(false);
      }
    }
  };
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
    className: "ds-c-tooltip__container",
    ...mainEventHandlers,
    children: [renderTrigger(props), renderContent(props)]
  });
};
exports.Tooltip = Tooltip;
Tooltip.defaultProps = {
  component: 'button',
  interactiveBorder: 15,
  maxWidth: '300px',
  offset: [0, 5],
  placement: 'top',
  transitionDuration: 250,
  // Equivalent to $animation-speed-1
  zIndex: 9999
};
var _default = Tooltip;
exports.default = _default;