"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Tooltip = void 0;
var _react = require("react");
var _reactNative = require("react-native");
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
var _context = require("../../context");
var _IOColors = require("../../core/IOColors");
var _buttons = require("../buttons");
var _typography = require("../typography");
var _Arrows = require("./Arrows");
var _utils = require("./utils");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const screenDimensions = _reactNative.Dimensions.get("window");
const INITIAL_COORDS = {
  x: 0,
  y: 0,
  width: 0,
  height: 0
};
const ARROWS_BY_PLACEMENT = {
  top: _Arrows.TopArrow,
  bottom: _Arrows.BottomArrow,
  left: _Arrows.LeftArrow,
  right: _Arrows.RightArrow
};
const styles = _reactNative.StyleSheet.create({
  backdrop: {
    position: "absolute",
    width: "100%",
    height: "100%",
    backgroundColor: _IOColors.IOColors.black,
    zIndex: 997
  },
  childrenContainer: {
    position: "absolute",
    zIndex: 1000
  },
  tooltipContainer: {
    position: "absolute",
    paddingHorizontal: 16,
    paddingVertical: 16,
    borderRadius: 8,
    zIndex: 2000,
    overflow: "visible"
  },
  arrowContainer: {
    position: "absolute",
    display: "flex",
    zIndex: 3000
  },
  closeIcon: {
    position: "absolute",
    right: 8,
    top: 9 // It's been used `9` instead of `8` to fix accessibility focus order. In this way title is read before close icon.
  }
});
const getChildrenPosition = childrenCoords => ({
  top: childrenCoords.y,
  left: childrenCoords.x,
  width: childrenCoords.width,
  height: childrenCoords.height
});

/**
 * Tooltip component that displays a contextual tooltip around its children.
 * The tooltip position is controlled by the `placement` prop and can adjust
 * dynamically if there is insufficient space.
 * @param {Props} props - The component props
 *
 * @returns {ReactElement} A tooltip component rendered around the specified children.
 */
const Tooltip = ({
  children,
  title,
  content,
  placement: initialPlacement = "top",
  closeIconAccessibilityLabel,
  isVisible,
  displayInsets = {},
  allowCloseOnBackgroundTap,
  childrenInteractionsEnabled = false,
  onClose
}) => {
  const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
  const [currentPlacement, setCurrentPlacement] = (0, _react.useState)(initialPlacement);
  const [childrenCoords, setChildrenCoords] = (0, _react.useState)(INITIAL_COORDS);
  const [tooltipLayout, setTooltipLayout] = (0, _react.useState)();
  const childRef = (0, _react.useRef)(null);
  const titleRef = (0, _react.useRef)(null);
  const timeoutRef = (0, _react.useRef)(undefined);

  // Theme
  const theme = (0, _context.useIOTheme)();
  const {
    themeType
  } = (0, _context.useIOThemeContext)();
  const backdropOpacity = themeType === "light" ? 0.4 : 0.8;
  const tooltipBackground = _IOColors.IOColors[theme["appBackground-secondary"]];
  const Arrow = (0, _react.useMemo)(() => ARROWS_BY_PLACEMENT[currentPlacement], [currentPlacement]);
  const childrenCoordsValues = Object.values(childrenCoords);
  const isChildrenMeasurementFinished = childrenCoordsValues.every(_utils.isDefined) && childrenCoordsValues.some(_utils.isNotZero);
  const isTooltipMeasurementCompleted = (0, _utils.isDefined)(tooltipLayout);
  const tooltipVisibility = {
    opacity: isTooltipMeasurementCompleted ? 1 : 0
  };

  /**
   * This function sets the `Tooltip` children coordinates
   */
  const measureChildrenCoords = (0, _react.useCallback)(() => {
    if (childRef.current && typeof childRef.current.measure === "function") {
      childRef.current.measure((_, __, width, height, px, py) => {
        const coords = {
          x: px,
          y: py,
          width,
          height
        };
        if (Object.values(coords).every(_utils.isDefined)) {
          setChildrenCoords(coords);
        }
      });
    }
  }, []);
  (0, _react.useEffect)(() => {
    if (isVisible) {
      // A new measure is executed every time the `Tooltip` is visible
      // This is required for use within ScrollView components.
      // eslint-disable-next-line functional/immutable-data
      timeoutRef.current = setTimeout(measureChildrenCoords, 100);
    } else {
      setChildrenCoords(INITIAL_COORDS);
      setCurrentPlacement(initialPlacement);
    }
    return () => {
      if (isVisible) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, [isVisible, initialPlacement, measureChildrenCoords]);

  /**
   * This function works with `top` and `bottom` placement and sets the current placement to their opposite value
   * if in the selected one there is no space to prompt the tooltip
   */
  const invertPlacementIfNeeded = (0, _react.useCallback)(nativeEvent => {
    if (initialPlacement === "top") {
      const hasSpace = nativeEvent.layout.y >= insets.top;
      if (!hasSpace) {
        setCurrentPlacement("bottom");
      }
    }
    if (initialPlacement === "bottom") {
      const remainingSpace = screenDimensions.height - nativeEvent.layout.y - insets.bottom;
      const tooltipMinHeight = nativeEvent.layout.height + _utils.ARROW_HEIGHT + _utils.EMPTY_SPACE;
      const hasSpace = remainingSpace >= tooltipMinHeight;
      if (!hasSpace) {
        setCurrentPlacement("top");
      }
    }
  }, [insets.bottom, insets.top, initialPlacement]);
  const handleTooltipOnLayout = (0, _react.useCallback)(({
    nativeEvent
  }) => {
    invertPlacementIfNeeded(nativeEvent);
    setTooltipLayout(nativeEvent.layout);
  }, [invertPlacementIfNeeded]);
  const handleTapOnBackground = (0, _react.useCallback)(() => {
    if (allowCloseOnBackgroundTap) {
      onClose();
    }
  }, [allowCloseOnBackgroundTap, onClose]);
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View
    // This prop is necessary for .measure to work correctly, as explained here: https://github.com/facebook/react-native/issues/29712
    , {
      collapsable: false,
      ref: childRef,
      children: children
    }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Modal, {
      transparent: true,
      visible: isVisible && isChildrenMeasurementFinished,
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
        accessibilityElementsHidden: !childrenInteractionsEnabled,
        importantForAccessibility: childrenInteractionsEnabled ? "auto" : "no-hide-descendants",
        pointerEvents: childrenInteractionsEnabled ? "auto" : "box-only",
        style: [styles.childrenContainer, getChildrenPosition(childrenCoords)],
        children: children
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableWithoutFeedback, {
        accessible: allowCloseOnBackgroundTap,
        accessibilityRole: allowCloseOnBackgroundTap ? "button" : "none",
        importantForAccessibility: allowCloseOnBackgroundTap ? "yes" : "no",
        accessibilityElementsHidden: !allowCloseOnBackgroundTap,
        onPress: handleTapOnBackground,
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
          entering: _reactNativeReanimated.FadeIn.duration(200).easing(_reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.quad))
          // The exiting transition is not visible, due to the component being unmounted
          // before the transition ends. I leave it here for future reference.
          ,
          exiting: _reactNativeReanimated.FadeOut.duration(200).easing(_reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.quad)),
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
            style: [styles.backdrop, {
              opacity: backdropOpacity,
              height: screenDimensions.height
            }]
          })
        })
      }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
        onLayout: handleTooltipOnLayout,
        style: [styles.tooltipContainer, {
          backgroundColor: tooltipBackground
        }, (0, _utils.getTooltipCoords)(currentPlacement, childrenCoords, (0, _utils.getDisplayInsets)(displayInsets), screenDimensions), (0, _utils.getTooltipVerticalAlignment)(currentPlacement, childrenCoords.height, tooltipLayout?.height), tooltipVisibility],
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.H6, {
          ref: titleRef,
          children: title
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
          style: styles.closeIcon,
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_buttons.IconButton, {
            color: "neutral",
            icon: "closeSmall",
            accessibilityLabel: closeIconAccessibilityLabel,
            onPress: onClose
          })
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.Body, {
          children: content
        })]
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
        style: [styles.arrowContainer, (0, _utils.getArrowBoxByPlacement)(currentPlacement), (0, _utils.getArrowCoords)(currentPlacement, childrenCoords, screenDimensions), (0, _utils.getArrowVerticalAlignment)(currentPlacement, childrenCoords.height), tooltipVisibility],
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Arrow, {
          color: tooltipBackground
        })
      })]
    })]
  });
};
exports.Tooltip = Tooltip;
//# sourceMappingURL=Tooltip.js.map