"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Content = Content;
exports.Outer = Outer;
exports.SheetCompatProvider = SheetCompatProvider;
exports.Target = Target;
exports.TextBubble = 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 _useTheme = require("../theme/use-theme.js");
var _index = require("../styles/index.js");
var _portal = require("../portal");
var _const = require("./const.js");
var _TextBubble = require("./TextBubble.js");
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); }
/**
 * These are native specific values, not shared with web
 */const ARROW_VISUAL_OFFSET = _const.ARROW_SIZE / 1.25;
const BUBBLE_SHADOW_OFFSET = _const.ARROW_SIZE / 3;
const TooltipContext = /*#__PURE__*/(0, _react.createContext)({
  position: 'bottom',
  visible: false,
  onVisibleChange: () => {}
});
TooltipContext.displayName = 'TooltipContext';
const TargetContext = /*#__PURE__*/(0, _react.createContext)({
  targetMeasurements: undefined,
  setTargetMeasurements: () => {},
  shouldMeasure: false
});
TargetContext.displayName = 'TargetContext';

/**
 * Provider for Tooltip component. Only needed when you need to position the
 * tooltip relative to a container, such as in a sheet.
 *
 * Only really necessary on iOS but can work on Android.
 */
function SheetCompatProvider({
  children
}) {
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
    children: children
  });
}
SheetCompatProvider.displayName = 'TooltipSheetCompatProvider';
function Outer({
  children,
  position = 'bottom',
  visible: requestVisible,
  onVisibleChange
}) {
  /**
   * Lagging state to track the externally-controlled visibility of the
   * tooltip, which needs to wait for the target to be measured before
   * actually being shown.
   */
  const [visible, setVisible] = (0, _react.useState)(false);
  const [targetMeasurements, setTargetMeasurements] = (0, _react.useState)(undefined);
  if (requestVisible && !visible && targetMeasurements) {
    setVisible(true);
  } else if (!requestVisible && visible) {
    setVisible(false);
    setTargetMeasurements(undefined);
  }
  const ctx = (0, _react.useMemo)(() => ({
    position,
    visible,
    onVisibleChange
  }), [position, visible, onVisibleChange]);
  const targetCtx = (0, _react.useMemo)(() => ({
    targetMeasurements,
    setTargetMeasurements,
    shouldMeasure: requestVisible
  }), [requestVisible, targetMeasurements, setTargetMeasurements]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(TooltipContext.Provider, {
    value: ctx,
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TargetContext.Provider, {
      value: targetCtx,
      children: children
    })
  });
}
function Target({
  children
}) {
  const {
    shouldMeasure,
    setTargetMeasurements
  } = (0, _react.useContext)(TargetContext);
  const [hasLayedOut, setHasLayedOut] = (0, _react.useState)(false);
  const targetRef = (0, _react.useRef)(null);
  (0, _react.useEffect)(() => {
    if (!shouldMeasure || !hasLayedOut) return;
    targetRef.current?.measure((_x, _y, width, height, x, y) => {
      if (x !== undefined && y !== undefined && width && height) {
        setTargetMeasurements({
          x,
          y,
          width,
          height
        });
      }
    });
  }, [shouldMeasure, setTargetMeasurements, hasLayedOut]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
    collapsable: false,
    ref: targetRef,
    onLayout: () => setHasLayedOut(true),
    children: children
  });
}
function Content({
  children,
  label
}) {
  const {
    position,
    visible,
    onVisibleChange
  } = (0, _react.useContext)(TooltipContext);
  const {
    targetMeasurements
  } = (0, _react.useContext)(TargetContext);
  const requestClose = (0, _react.useCallback)(() => {
    onVisibleChange(false);
  }, [onVisibleChange]);
  if (!visible || !targetMeasurements) return null;
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_portal.Portal, {
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Bubble, {
      label: label,
      position: position,
      targetMeasurements: targetMeasurements,
      requestClose: requestClose,
      children: children
    })
  });
}
function Bubble({
  children,
  label,
  position,
  requestClose,
  targetMeasurements
}) {
  const theme = (0, _useTheme.useTheme)();
  const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
  const dimensions = (0, _reactNative.useWindowDimensions)();
  const [bubbleMeasurements, setBubbleMeasurements] = (0, _react.useState)(undefined);
  const bubbleBg = theme.isDark ? {
    backgroundColor: theme.colors.backgroundSecondary
  } : {
    backgroundColor: theme.colors.background
  };
  const coords = (0, _react.useMemo)(() => {
    if (!bubbleMeasurements) return {
      computedPosition: position,
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      tipTop: 0,
      tipLeft: 0
    };
    const {
      width: ww,
      height: wh
    } = dimensions;
    const maxTop = insets.top;
    const maxBottom = wh - insets.bottom;
    const {
      width: cw,
      height: ch
    } = bubbleMeasurements;
    const minLeft = _const.MIN_EDGE_SPACE;
    const maxLeft = ww - minLeft;
    let computedPosition = position;
    let top = targetMeasurements.y + targetMeasurements.height;
    let left = Math.max(minLeft, targetMeasurements.x + targetMeasurements.width / 2 - cw / 2);
    const tipTranslate = _const.ARROW_HALF_SIZE * -1;
    let tipTop = tipTranslate;
    if (left + cw > maxLeft) {
      left -= left + cw - maxLeft;
    }
    const tipLeft = targetMeasurements.x - left + targetMeasurements.width / 2 - _const.ARROW_HALF_SIZE;
    let bottom = top + ch;
    function positionTop() {
      top = top - ch - targetMeasurements.height;
      bottom = top + ch;
      tipTop = tipTop + ch;
      computedPosition = 'top';
    }
    function positionBottom() {
      top = targetMeasurements.y + targetMeasurements.height;
      bottom = top + ch;
      tipTop = tipTranslate;
      computedPosition = 'bottom';
    }
    if (position === 'top') {
      positionTop();
      if (top < maxTop) {
        positionBottom();
      }
    } else {
      if (bottom > maxBottom) {
        positionTop();
      }
    }
    if (computedPosition === 'bottom') {
      top += ARROW_VISUAL_OFFSET;
      bottom += ARROW_VISUAL_OFFSET;
    } else {
      top -= ARROW_VISUAL_OFFSET;
      bottom -= ARROW_VISUAL_OFFSET;
    }
    return {
      computedPosition,
      top,
      bottom,
      left,
      right: left + cw,
      tipTop,
      tipLeft
    };
  }, [position, targetMeasurements, bubbleMeasurements, insets, dimensions]);
  const requestCloseWrapped = (0, _react.useCallback)(() => {
    setBubbleMeasurements(undefined);
    requestClose();
  }, [requestClose]);
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
      style: _reactNative.StyleSheet.absoluteFill,
      onPress: requestCloseWrapped,
      accessibilityRole: "none"
    }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
      accessible: true,
      role: "alert",
      accessibilityHint: "",
      accessibilityLabel: label,
      importantForAccessibility: "yes",
      accessibilityViewIsModal: true,
      style: [_index.atoms.absolute, _index.atoms.align_start, {
        width: _const.BUBBLE_MAX_WIDTH,
        opacity: bubbleMeasurements ? 1 : 0,
        top: coords.top,
        left: coords.left
      }],
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.View, {
        entering: _reactNativeReanimated.ZoomIn.easing(_reactNativeReanimated.Easing.out(_reactNativeReanimated.Easing.exp)),
        style: {
          transformOrigin: opposite(position)
        },
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
          style: [_index.atoms.absolute, _index.atoms.top_0, _index.atoms.z_10, bubbleBg, {
            borderTopLeftRadius: _index.atoms.rounded_2xs.borderRadius,
            borderBottomRightRadius: _index.atoms.rounded_2xs.borderRadius,
            width: _const.ARROW_SIZE,
            height: _const.ARROW_SIZE,
            transform: [{
              rotate: '45deg'
            }],
            top: coords.tipTop,
            left: coords.tipLeft
          }]
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
          style: [_index.atoms.px_md, _index.atoms.py_sm, _index.atoms.rounded_sm, bubbleBg, {
            shadowColor: theme.colors.shadow,
            shadowOpacity: 0.2,
            shadowRadius: 12,
            shadowOffset: {
              width: 0,
              height: BUBBLE_SHADOW_OFFSET * (coords.computedPosition === 'bottom' ? -1 : 1)
            },
            elevation: 8
          }],
          onLayout: e => {
            setBubbleMeasurements({
              width: e.nativeEvent.layout.width,
              height: e.nativeEvent.layout.height
            });
          },
          children: children
        })]
      })
    })]
  });
}
function opposite(position) {
  switch (position) {
    case 'top':
      return 'center bottom';
    case 'bottom':
      return 'center top';
    default:
      return 'center';
  }
}
const TextBubble = exports.TextBubble = (0, _TextBubble.createTextBubble)(Content);
//# sourceMappingURL=index.js.map