"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _reactNative = require("react-native");
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _slotFill = require("../slot-fill");
var _style = _interopRequireDefault(require("./style.scss"));
var _jsxRuntime = require("react/jsx-runtime");
/**
 * External dependencies
 */

/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

const RIGHT_ALIGN_ARROW_OFFSET = 16;
const TOOLTIP_VERTICAL_OFFSET = 2;
const TooltipContext = (0, _element.createContext)({
  onHandleScreenTouch: () => {}
});
const {
  Fill,
  Slot
} = (0, _slotFill.createSlotFill)('Tooltip');
const useKeyboardVisibility = () => {
  const [keyboardVisible, setKeyboardVisible] = (0, _element.useState)(false);
  const previousKeyboardVisible = (0, _compose.usePrevious)(keyboardVisible);
  (0, _element.useEffect)(() => {
    const showListener = _reactNative.Keyboard.addListener('keyboardDidShow', () => {
      if (previousKeyboardVisible !== true) {
        setKeyboardVisible(true);
      }
    });
    const keyboardHideEvent = _reactNative.Platform.select({
      android: 'keyboardDidHide',
      ios: 'keyboardWillHide'
    });
    const hideListener = _reactNative.Keyboard.addListener(keyboardHideEvent, () => {
      if (previousKeyboardVisible !== false) {
        setKeyboardVisible(false);
      }
    });
    return () => {
      showListener.remove();
      hideListener.remove();
    };
    // See https://github.com/WordPress/gutenberg/pull/41166
  }, []);
  return keyboardVisible;
};
const Tooltip = ({
  children,
  position = 'top',
  text,
  visible: initialVisible = false
}) => {
  const referenceElementRef = (0, _element.useRef)(null);
  const animationValue = (0, _element.useRef)(new _reactNative.Animated.Value(0)).current;
  const [, horizontalPosition = 'center'] = position.split(' ');
  const [visible, setVisible] = (0, _element.useState)(initialVisible);
  const [animating, setAnimating] = (0, _element.useState)(false);
  const hidden = !visible && !animating;
  const previousVisible = (0, _compose.usePrevious)(visible);
  const [referenceLayout, setReferenceLayout] = (0, _element.useState)({
    height: 0,
    width: 0,
    x: 0,
    y: 0
  });
  const [tooltipLayout, setTooltipLayout] = (0, _element.useState)({
    height: 0,
    width: 0
  });
  const {
    onHandleScreenTouch
  } = (0, _element.useContext)(TooltipContext);
  const keyboardVisible = useKeyboardVisibility();

  // Register callback to dismiss the tooltip whenever the screen is touched.
  (0, _element.useEffect)(() => {
    if (visible) {
      onHandleScreenTouch(() => {
        setAnimating(true);
        setVisible(false);
      });
    }
    return () => onHandleScreenTouch(null);
    // See https://github.com/WordPress/gutenberg/pull/41166
  }, [visible]);

  // Manage visibility animation.
  (0, _element.useEffect)(() => {
    if (
    // Initial render and visibility enabled, animate show.
    typeof previousVisible === 'undefined' && visible ||
    // Previously visible, animate hide
    previousVisible && previousVisible !== visible) {
      setAnimating(true);
      startAnimation();
    }
    // See https://github.com/WordPress/gutenberg/pull/41166
  }, [visible]);

  // Manage tooltip visibility and position in relation to keyboard.
  (0, _element.useEffect)(() => {
    if (!visible) {
      return;
    }

    // Update tooltip position if keyboard is visible.
    if (keyboardVisible) {
      getReferenceElementPosition();
    }

    // Hide tooltip if keyboard hides
    if (typeof previousVisible !== 'undefined' && !keyboardVisible) {
      setAnimating(true);
      setVisible(false);
    }
    // See https://github.com/WordPress/gutenberg/pull/41166
  }, [visible, keyboardVisible]);

  // Manage tooltip position during keyboard frame changes.
  (0, _element.useEffect)(() => {
    const frameListener = _reactNative.Keyboard.addListener('keyboardWillChangeFrame', () => {
      if (visible) {
        getReferenceElementPosition();
      }
    });
    return () => {
      frameListener.remove();
    };
  }, [visible]);
  const startAnimation = () => {
    _reactNative.Animated.timing(animationValue, {
      toValue: visible ? 1 : 0,
      duration: visible ? 300 : 150,
      useNativeDriver: true,
      delay: visible ? 500 : 0,
      easing: _reactNative.Easing.out(_reactNative.Easing.quad)
    }).start(() => {
      setAnimating(false);
    });
  };
  const tooltipStyles = [_style.default.tooltip, {
    left: referenceLayout.x + Math.floor(referenceLayout.width / 2) - (horizontalPosition === 'right' ? RIGHT_ALIGN_ARROW_OFFSET : Math.floor(tooltipLayout.width / 2)),
    top: referenceLayout.y - tooltipLayout.height - TOOLTIP_VERTICAL_OFFSET
  }];
  const tooltipBoxStyles = [_style.default.tooltip__box, horizontalPosition === 'right' && _style.default['tooltip--rightAlign'], {
    elevation: 2,
    opacity: animationValue,
    shadowColor: _style.default.tooltip__shadow?.color,
    shadowOffset: {
      height: 2,
      width: 0
    },
    shadowOpacity: 0.25,
    shadowRadius: 2,
    transform: [{
      translateY: animationValue.interpolate({
        inputRange: [0, 1],
        outputRange: [visible ? 4 : -8, -8]
      })
    }]
  }];
  const arrowStyles = [_style.default.tooltip__arrow, horizontalPosition === 'right' && _style.default['tooltip__arrow--rightAlign']];
  const getReferenceElementPosition = () => {
    // rAF allows render to complete before calculating layout
    // eslint-disable-next-line no-undef
    requestAnimationFrame(() => {
      if (!referenceElementRef.current) {
        return;
      }
      referenceElementRef.current.measure((_x, _y, width, height, pageX, pageY) => {
        setReferenceLayout({
          height,
          width,
          x: pageX,
          y: pageY
        });
      });
    });
  };
  const getTooltipLayout = ({
    nativeEvent
  }) => {
    const {
      height,
      width
    } = nativeEvent.layout;
    setTooltipLayout({
      height,
      width
    });
  };
  if (hidden) {
    return children;
  }
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [(0, _element.cloneElement)(children, {
      ref: referenceElementRef,
      onLayout: getReferenceElementPosition
    }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Fill, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
        onLayout: getTooltipLayout,
        style: tooltipStyles,
        children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
          style: tooltipBoxStyles,
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
            style: _style.default.tooltip__text,
            children: text
          }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
            style: arrowStyles
          })]
        })
      })
    })]
  });
};
const TooltipSlot = ({
  children,
  ...rest
}) => {
  const [handleScreenTouch, setHandleScreenTouch] = (0, _element.useState)(null);
  const onHandleScreenTouch = callback => {
    // Must use function to set state below as `callback` is a function itself.
    setHandleScreenTouch(() => callback);
  };
  const handleTouchStart = () => {
    handleScreenTouch();
    setHandleScreenTouch(null);
  };
  // Memoize context value to avoid unnecessary rerenders of the Provider's children
  // See https://github.com/WordPress/gutenberg/pull/41166
  const value = (0, _element.useMemo)(() => ({
    onHandleScreenTouch
  }));
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(TooltipContext.Provider, {
    value: value,
    children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
      onTouchStart: typeof handleScreenTouch === 'function' ? handleTouchStart : undefined,
      pointerEvents: "box-none",
      style: _reactNative.StyleSheet.absoluteFill,
      testID: "tooltip-overlay",
      children: [children, /*#__PURE__*/(0, _jsxRuntime.jsx)(Slot, {
        ...rest
      })]
    })
  });
};
Tooltip.Slot = TooltipSlot;
var _default = exports.default = Tooltip;
//# sourceMappingURL=index.native.js.map