Skip to content

Commit

Permalink
Merge pull request Expensify#30338 from JKobrynski/migrateModalToType…
Browse files Browse the repository at this point in the history
…Script

[TS Migration] Migrate withWindowDimensions and Modal directories to TypeScript
  • Loading branch information
mountiny authored Nov 15, 2023
2 parents 0a4ca7b + 434e472 commit 181aeb2
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 162 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import ReactNativeModal from 'react-native-modal';
Expand All @@ -14,44 +13,34 @@ import themeColors from '@styles/themes/default';
import variables from '@styles/variables';
import * as Modal from '@userActions/Modal';
import CONST from '@src/CONST';
import {defaultProps as modalDefaultProps, propTypes as modalPropTypes} from './modalPropTypes';

const propTypes = {
...modalPropTypes,

/** The ref to the modal container */
forwardedRef: PropTypes.func,
};

const defaultProps = {
...modalDefaultProps,
forwardedRef: () => {},
};

function BaseModal({
isVisible,
onClose,
shouldSetModalVisibility,
onModalHide,
type,
popoverAnchorPosition,
innerContainerStyle,
outerStyle,
onModalShow,
propagateSwipe,
fullscreen,
animationIn,
animationOut,
useNativeDriver: useNativeDriverProp,
hideModalContentWhileAnimating,
animationInTiming,
animationOutTiming,
statusBarTranslucent,
onLayout,
avoidKeyboard,
forwardedRef,
children,
}) {
import BaseModalProps from './types';

function BaseModal(
{
isVisible,
onClose,
shouldSetModalVisibility = true,
onModalHide = () => {},
type,
popoverAnchorPosition = {},
innerContainerStyle = {},
outerStyle,
onModalShow = () => {},
propagateSwipe,
fullscreen = true,
animationIn,
animationOut,
useNativeDriver: useNativeDriverProp,
hideModalContentWhileAnimating = false,
animationInTiming,
animationOutTiming,
statusBarTranslucent = true,
onLayout,
avoidKeyboard = false,
children,
}: BaseModalProps,
ref: React.ForwardedRef<View>,
) {
const {windowWidth, windowHeight, isSmallScreenWidth} = useWindowDimensions();

const safeAreaInsets = useSafeAreaInsets();
Expand All @@ -61,7 +50,7 @@ function BaseModal({

/**
* Hides modal
* @param {Boolean} [callHideCallback=true] Should we call the onModalHide callback
* @param callHideCallback - Should we call the onModalHide callback
*/
const hideModal = useCallback(
(callHideCallback = true) => {
Expand Down Expand Up @@ -113,10 +102,11 @@ function BaseModal({
onModalShow();
};

const handleBackdropPress = (e) => {
if (e && e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) {
const handleBackdropPress = (e?: KeyboardEvent) => {
if (e?.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) {
return;
}

onClose();
};

Expand Down Expand Up @@ -196,8 +186,8 @@ function BaseModal({
style={modalStyle}
deviceHeight={windowHeight}
deviceWidth={windowWidth}
animationIn={animationIn || modalStyleAnimationIn}
animationOut={animationOut || modalStyleAnimationOut}
animationIn={animationIn ?? modalStyleAnimationIn}
animationOut={animationOut ?? modalStyleAnimationOut}
useNativeDriver={useNativeDriverProp && useNativeDriver}
hideModalContentWhileAnimating={hideModalContentWhileAnimating}
animationInTiming={animationInTiming}
Expand All @@ -208,26 +198,14 @@ function BaseModal({
>
<View
style={[styles.defaultModalContainer, modalContainerStyle, modalPaddingStyles, !isVisible && styles.pointerEventsNone]}
ref={forwardedRef}
ref={ref}
>
{children}
</View>
</ReactNativeModal>
);
}

BaseModal.propTypes = propTypes;
BaseModal.defaultProps = defaultProps;
BaseModal.displayName = 'BaseModal';

const BaseModalWithRef = forwardRef((props, ref) => (
<BaseModal
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
forwardedRef={ref}
/>
));

BaseModalWithRef.displayName = 'BaseModalWithRef';
BaseModal.displayName = 'BaseModalWithRef';

export default BaseModalWithRef;
export default forwardRef(BaseModal);
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {AppState} from 'react-native';
import withWindowDimensions from '@components/withWindowDimensions';
import ComposerFocusManager from '@libs/ComposerFocusManager';
import BaseModal from './BaseModal';
import {defaultProps, propTypes} from './modalPropTypes';
import BaseModalProps from './types';

AppState.addEventListener('focus', () => {
ComposerFocusManager.setReadyToFocus();
Expand All @@ -15,19 +15,17 @@ AppState.addEventListener('blur', () => {

// Only want to use useNativeDriver on Android. It has strange flashes issue on IOS
// https://github.com/react-native-modal/react-native-modal#the-modal-flashes-in-a-weird-way-when-animating
function Modal(props) {
function Modal({useNativeDriver = true, ...rest}: BaseModalProps) {
return (
<BaseModal
useNativeDriver
useNativeDriver={useNativeDriver}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
{...rest}
>
{props.children}
{rest.children}
</BaseModal>
);
}

Modal.propTypes = propTypes;
Modal.defaultProps = defaultProps;
Modal.displayName = 'Modal';
export default withWindowDimensions(Modal);
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React from 'react';
import withWindowDimensions from '@components/withWindowDimensions';
import BaseModal from './BaseModal';
import {defaultProps, propTypes} from './modalPropTypes';
import BaseModalProps from './types';

function Modal(props) {
function Modal({children, ...rest}: BaseModalProps) {
return (
<BaseModal
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
{...rest}
>
{props.children}
{children}
</BaseModal>
);
}

Modal.propTypes = propTypes;
Modal.defaultProps = defaultProps;
Modal.displayName = 'Modal';
export default withWindowDimensions(Modal);
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import * as StyleUtils from '@styles/StyleUtils';
import themeColors from '@styles/themes/default';
import CONST from '@src/CONST';
import BaseModal from './BaseModal';
import {defaultProps, propTypes} from './modalPropTypes';
import BaseModalProps from './types';

function Modal(props) {
const [previousStatusBarColor, setPreviousStatusBarColor] = useState();
function Modal({fullscreen = true, onModalHide = () => {}, type, onModalShow = () => {}, children, ...rest}: BaseModalProps) {
const [previousStatusBarColor, setPreviousStatusBarColor] = useState<string>();

const setStatusBarColor = (color = themeColors.appBG) => {
if (!props.fullscreen) {
if (!fullscreen) {
return;
}

Expand All @@ -20,33 +20,37 @@ function Modal(props) {

const hideModal = () => {
setStatusBarColor(previousStatusBarColor);
props.onModalHide();
onModalHide();
};

const showModal = () => {
const statusBarColor = StatusBar.getBackgroundColor();
const isFullScreenModal =
props.type === CONST.MODAL.MODAL_TYPE.CENTERED || props.type === CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE || props.type === CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED;
setPreviousStatusBarColor(statusBarColor);
// If it is a full screen modal then match it with appBG, otherwise we use the backdrop color
setStatusBarColor(isFullScreenModal ? themeColors.appBG : StyleUtils.getThemeBackgroundColor(statusBarColor));
props.onModalShow();

const isFullScreenModal = type === CONST.MODAL.MODAL_TYPE.CENTERED || type === CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE || type === CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED;

if (statusBarColor) {
setPreviousStatusBarColor(statusBarColor);
// If it is a full screen modal then match it with appBG, otherwise we use the backdrop color
setStatusBarColor(isFullScreenModal ? themeColors.appBG : StyleUtils.getThemeBackgroundColor(statusBarColor));
}

onModalShow?.();
};

return (
<BaseModal
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
{...rest}
onModalHide={hideModal}
onModalShow={showModal}
avoidKeyboard={false}
fullscreen={fullscreen}
type={type}
>
{props.children}
{children}
</BaseModal>
);
}

Modal.propTypes = propTypes;
Modal.defaultProps = defaultProps;
Modal.displayName = 'Modal';
export default withWindowDimensions(Modal);
66 changes: 66 additions & 0 deletions src/components/Modal/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {ViewStyle} from 'react-native';
import {ModalProps} from 'react-native-modal';
import {ValueOf} from 'type-fest';
import {WindowDimensionsProps} from '@components/withWindowDimensions/types';
import CONST from '@src/CONST';

type PopoverAnchorPosition = {
top?: number;
right?: number;
bottom?: number;
left?: number;
};

type BaseModalProps = WindowDimensionsProps &
ModalProps & {
/** Decides whether the modal should cover fullscreen. FullScreen modal has backdrop */
fullscreen?: boolean;

/** Should we close modal on outside click */
shouldCloseOnOutsideClick?: boolean;

/** Should we announce the Modal visibility changes? */
shouldSetModalVisibility?: boolean;

/** Callback method fired when the user requests to close the modal */
onClose: () => void;

/** State that determines whether to display the modal or not */
isVisible: boolean;

/** Callback method fired when the user requests to submit the modal content. */
onSubmit?: () => void;

/** Callback method fired when the modal is hidden */
onModalHide?: () => void;

/** Callback method fired when the modal is shown */
onModalShow?: () => void;

/** Style of modal to display */
type?: ValueOf<typeof CONST.MODAL.MODAL_TYPE>;

/** The anchor position of a popover modal. Has no effect on other modal types. */
popoverAnchorPosition?: PopoverAnchorPosition;

outerStyle?: ViewStyle;

/** Whether the modal should go under the system statusbar */
statusBarTranslucent?: boolean;

/** Whether the modal should avoid the keyboard */
avoidKeyboard?: boolean;

/** Modal container styles */
innerContainerStyle?: ViewStyle;

/**
* Whether the modal should hide its content while animating. On iOS, set to true
* if `useNativeDriver` is also true, to avoid flashes in the UI.
*
* See: https://github.com/react-native-modal/react-native-modal/pull/116
* */
hideModalContentWhileAnimating?: boolean;
};

export default BaseModalProps;
Loading

0 comments on commit 181aeb2

Please sign in to comment.