"use strict";
'use client';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.ScreenContext = exports.InnerScreen = void 0;
var _react = _interopRequireDefault(require("react"));
var _reactNative = require("react-native");
var _TransitionProgressContext = _interopRequireDefault(require("../TransitionProgressContext"));
var _DelayedFreeze = _interopRequireDefault(require("./helpers/DelayedFreeze"));
var _core = require("../core");
var _ScreenNativeComponent = _interopRequireDefault(require("../fabric/ScreenNativeComponent"));
var _ModalScreenNativeComponent = _interopRequireDefault(require("../fabric/ModalScreenNativeComponent"));
var _usePrevious = require("./helpers/usePrevious");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } // Native components
const AnimatedNativeScreen = _reactNative.Animated.createAnimatedComponent(_ScreenNativeComponent.default);
const AnimatedNativeModalScreen = _reactNative.Animated.createAnimatedComponent(_ModalScreenNativeComponent.default);

// Incomplete type, all accessible properties available at:
// react-native/Libraries/Components/View/ReactNativeViewViewConfig.js
// This value must be kept in sync with native side.
const SHEET_FIT_TO_CONTENTS = [-1];
const SHEET_COMPAT_LARGE = [1.0];
const SHEET_COMPAT_MEDIUM = [0.5];
const SHEET_COMPAT_ALL = [0.5, 1.0];
const SHEET_DIMMED_ALWAYS = -1;
// const SHEET_DIMMED_NEVER = 9999;

function assertDetentsArrayIsSorted(array) {
  for (let i = 1; i < array.length; i++) {
    if (array[i - 1] > array[i]) {
      throw new Error('[RNScreens] The detent array is not sorted in ascending order!');
    }
  }
}

// These exist to transform old 'legacy' values used by the formsheet API to the new API shape.
// We can get rid of it, once we get rid of support for legacy values: 'large', 'medium', 'all'.
function resolveSheetAllowedDetents(allowedDetentsCompat) {
  if (Array.isArray(allowedDetentsCompat)) {
    if (_reactNative.Platform.OS === 'android' && allowedDetentsCompat.length > 3) {
      if (__DEV__) {
        console.warn('[RNScreens] Sheets API on Android do accept only up to 3 values. Any surplus value are ignored.');
      }
      allowedDetentsCompat = allowedDetentsCompat.slice(0, 3);
    }
    if (__DEV__) {
      assertDetentsArrayIsSorted(allowedDetentsCompat);
    }
    return allowedDetentsCompat;
  } else if (allowedDetentsCompat === 'fitToContents') {
    return SHEET_FIT_TO_CONTENTS;
  } else if (allowedDetentsCompat === 'large') {
    return SHEET_COMPAT_LARGE;
  } else if (allowedDetentsCompat === 'medium') {
    return SHEET_COMPAT_MEDIUM;
  } else if (allowedDetentsCompat === 'all') {
    return SHEET_COMPAT_ALL;
  } else {
    // Safe default, only large detent is allowed.
    return [1.0];
  }
}
function resolveSheetLargestUndimmedDetent(lud, lastDetentIndex) {
  if (typeof lud === 'number') {
    if (!isIndexInClosedRange(lud, SHEET_DIMMED_ALWAYS, lastDetentIndex)) {
      if (__DEV__) {
        throw new Error("[RNScreens] Provided value of 'sheetLargestUndimmedDetentIndex' prop is out of bounds of 'sheetAllowedDetents' array.");
      }
      // Return default in production
      return SHEET_DIMMED_ALWAYS;
    }
    return lud;
  } else if (lud === 'last') {
    return lastDetentIndex;
  } else if (lud === 'none' || lud === 'all') {
    return SHEET_DIMMED_ALWAYS;
  } else if (lud === 'large') {
    return 1;
  } else if (lud === 'medium') {
    return 0;
  } else {
    // Safe default, every detent is dimmed
    return SHEET_DIMMED_ALWAYS;
  }
}
function resolveSheetInitialDetentIndex(index, lastDetentIndex) {
  if (index === 'last') {
    index = lastDetentIndex;
  } else if (index == null) {
    // Intentional check for undefined & null ^
    index = 0;
  }
  if (!isIndexInClosedRange(index, 0, lastDetentIndex)) {
    if (__DEV__) {
      throw new Error("[RNScreens] Provided value of 'sheetInitialDetentIndex' prop is out of bounds of 'sheetAllowedDetents' array.");
    }
    // Return default in production
    return 0;
  }
  return index;
}
function isIndexInClosedRange(value, lowerBound, upperBound) {
  return Number.isInteger(value) && value >= lowerBound && value <= upperBound;
}
const InnerScreen = exports.InnerScreen = /*#__PURE__*/_react.default.forwardRef(function InnerScreen(props, ref) {
  const innerRef = _react.default.useRef(null);
  _react.default.useImperativeHandle(ref, () => innerRef.current, []);
  const prevActivityState = (0, _usePrevious.usePrevious)(props.activityState);
  const setRef = ref => {
    innerRef.current = ref;
    props.onComponentRef?.(ref);
  };
  const closing = _react.default.useRef(new _reactNative.Animated.Value(0)).current;
  const progress = _react.default.useRef(new _reactNative.Animated.Value(0)).current;
  const goingForward = _react.default.useRef(new _reactNative.Animated.Value(0)).current;
  const {
    enabled = (0, _core.screensEnabled)(),
    freezeOnBlur = (0, _core.freezeEnabled)(),
    ...rest
  } = props;

  // To maintain default behavior of formSheet stack presentation style and to have reasonable
  // defaults for new medium-detent iOS API we need to set defaults here
  const {
    // formSheet presentation related props
    sheetAllowedDetents = [1.0],
    sheetLargestUndimmedDetentIndex = SHEET_DIMMED_ALWAYS,
    sheetGrabberVisible = false,
    sheetCornerRadius = -1.0,
    sheetExpandsWhenScrolledToEdge = true,
    sheetElevation = 24,
    sheetInitialDetentIndex = 0,
    // Other
    stackPresentation,
    // Events for override
    onAppear,
    onDisappear,
    onWillAppear,
    onWillDisappear
  } = rest;
  if (enabled && _core.isNativePlatformSupported) {
    const resolvedSheetAllowedDetents = resolveSheetAllowedDetents(sheetAllowedDetents);
    const resolvedSheetLargestUndimmedDetent = resolveSheetLargestUndimmedDetent(sheetLargestUndimmedDetentIndex, resolvedSheetAllowedDetents.length - 1);
    const resolvedSheetInitialDetentIndex = resolveSheetInitialDetentIndex(sheetInitialDetentIndex, resolvedSheetAllowedDetents.length - 1);
    // Due to how Yoga resolves layout, we need to have different components for modal nad non-modal screens
    const AnimatedScreen = _reactNative.Platform.OS === 'android' || stackPresentation === undefined || stackPresentation === 'push' || stackPresentation === 'containedModal' || stackPresentation === 'containedTransparentModal' ? AnimatedNativeScreen : AnimatedNativeModalScreen;
    let {
      // Filter out active prop in this case because it is unused and
      // can cause problems depending on react-native version:
      // https://github.com/react-navigation/react-navigation/issues/4886
      active,
      activityState,
      children,
      isNativeStack,
      gestureResponseDistance,
      onGestureCancel,
      style,
      ...props
    } = rest;
    if (active !== undefined && activityState === undefined) {
      console.warn('It appears that you are using old version of react-navigation library. Please update @react-navigation/bottom-tabs, @react-navigation/stack and @react-navigation/drawer to version 5.10.0 or above to take full advantage of new functionality added to react-native-screens');
      activityState = active !== 0 ? 2 : 0; // in the new version, we need one of the screens to have value of 2 after the transition
    }

    if (isNativeStack && prevActivityState !== undefined && activityState !== undefined) {
      if (prevActivityState > activityState) {
        throw new Error('[RNScreens] activityState cannot be decreased in NativeStack');
      }
    }
    const handleRef = ref => {
      if (ref?.viewConfig?.validAttributes?.style) {
        ref.viewConfig.validAttributes.style = {
          ...ref.viewConfig.validAttributes.style,
          display: false
        };
        setRef(ref);
      } else if (ref?._viewConfig?.validAttributes?.style) {
        ref._viewConfig.validAttributes.style = {
          ...ref._viewConfig.validAttributes.style,
          display: false
        };
        setRef(ref);
      }
    };
    return /*#__PURE__*/_react.default.createElement(_DelayedFreeze.default, {
      freeze: freezeOnBlur && activityState === 0
    }, /*#__PURE__*/_react.default.createElement(AnimatedScreen, _extends({}, props, {
      /**
       * This messy override is to conform NativeProps used by codegen and
       * our Public API. To see reasoning go to this PR:
       * https://github.com/software-mansion/react-native-screens/pull/2423#discussion_r1810616995
       */
      onAppear: onAppear,
      onDisappear: onDisappear,
      onWillAppear: onWillAppear,
      onWillDisappear: onWillDisappear,
      onGestureCancel: onGestureCancel ?? (() => {
        // for internal use
      })
      //
      // Hierarchy of screens is handled on the native side and setting zIndex value causes this issue:
      // https://github.com/software-mansion/react-native-screens/issues/2345
      // With below change of zIndex, we force RN diffing mechanism to NOT include detaching and attaching mutation in one transaction.
      // Detailed information can be found here https://github.com/software-mansion/react-native-screens/pull/2351
      ,
      style: [style, {
        zIndex: undefined
      }],
      activityState: activityState,
      sheetAllowedDetents: resolvedSheetAllowedDetents,
      sheetLargestUndimmedDetent: resolvedSheetLargestUndimmedDetent,
      sheetElevation: sheetElevation,
      sheetGrabberVisible: sheetGrabberVisible,
      sheetCornerRadius: sheetCornerRadius,
      sheetExpandsWhenScrolledToEdge: sheetExpandsWhenScrolledToEdge,
      sheetInitialDetent: resolvedSheetInitialDetentIndex,
      gestureResponseDistance: {
        start: gestureResponseDistance?.start ?? -1,
        end: gestureResponseDistance?.end ?? -1,
        top: gestureResponseDistance?.top ?? -1,
        bottom: gestureResponseDistance?.bottom ?? -1
      }
      // This prevents showing blank screen when navigating between multiple screens with freezing
      // https://github.com/software-mansion/react-native-screens/pull/1208
      ,
      ref: handleRef,
      onTransitionProgress: !isNativeStack ? undefined : _reactNative.Animated.event([{
        nativeEvent: {
          progress,
          closing,
          goingForward
        }
      }], {
        useNativeDriver: true
      })
    }), !isNativeStack ?
    // see comment of this prop in types.tsx for information why it is needed
    children : /*#__PURE__*/_react.default.createElement(_TransitionProgressContext.default.Provider, {
      value: {
        progress,
        closing,
        goingForward
      }
    }, children)));
  } else {
    // same reason as above
    let {
      active,
      activityState,
      style,
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      onComponentRef,
      ...props
    } = rest;
    if (active !== undefined && activityState === undefined) {
      activityState = active !== 0 ? 2 : 0;
    }
    return /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, _extends({
      style: [style, {
        display: activityState !== 0 ? 'flex' : 'none'
      }],
      ref: setRef
    }, props));
  }
});

// context to be used when the user wants to use enhanced implementation
// e.g. to use `useReanimatedTransitionProgress` (see `reanimated` folder in repo)
const ScreenContext = exports.ScreenContext = /*#__PURE__*/_react.default.createContext(InnerScreen);
const Screen = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
  const ScreenWrapper = _react.default.useContext(ScreenContext) || InnerScreen;
  return /*#__PURE__*/_react.default.createElement(ScreenWrapper, _extends({}, props, {
    ref: ref
  }));
});
Screen.displayName = 'Screen';
var _default = exports.default = Screen;
//# sourceMappingURL=Screen.js.map