Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ const restrictedImportPaths = [
importNames: ['isEqual'],
message: "Please use 'deepEqual' from 'fast-equals' instead.",
},
{
name: 'react-native-animatable',
message: "Please use 'react-native-reanimated' instead.",
},
{
name: 'react-native-onyx',
importNames: ['useOnyx'],
Expand Down
2 changes: 2 additions & 0 deletions config/webpack/webpack.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type PreloadWebpackPluginClass = Class<WebpackPluginInstance, [Options]>;
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin') as PreloadWebpackPluginClass;

const includeModules = [
'react-native-animatable',
'react-native-reanimated',
'react-native-picker-select',
'react-native-web',
Expand All @@ -36,6 +37,7 @@ const includeModules = [
'@react-navigation/native',
'@react-navigation/native-stack',
'@react-navigation/stack',
'react-native-modal',
'react-native-gesture-handler',
'react-native-google-places-autocomplete',
'react-native-qrcode-svg',
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
"react-native-keyboard-controller": "1.18.5",
"react-native-launch-arguments": "^4.0.2",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-nitro-modules": "0.26.2",
"react-native-nitro-sqlite": "9.1.10",
"react-native-onyx": "2.0.138",
Expand Down
23 changes: 23 additions & 0 deletions patches/react-native-animatable+1.3.3+001+initial.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
diff --git a/node_modules/react-native-animatable/createAnimatableComponent.js b/node_modules/react-native-animatable/createAnimatableComponent.js
index 2847e12..331d44f 100644
--- a/node_modules/react-native-animatable/createAnimatableComponent.js
+++ b/node_modules/react-native-animatable/createAnimatableComponent.js
@@ -465,7 +465,9 @@ export default function createAnimatableComponent(WrappedComponent) {
const needsZeroClamping =
ZERO_CLAMPED_STYLE_PROPERTIES.indexOf(property) !== -1;
if (needsInterpolation) {
- transitionValue.setValue(0);
+ transitionValue = new Animated.Value(0);
+ transitionValues[property] = transitionValue;
+
transitionStyle[property] = transitionValue.interpolate({
inputRange: [0, 1],
outputRange: [fromValue, toValue],
@@ -546,7 +548,6 @@ export default function createAnimatableComponent(WrappedComponent) {
transitions.to[property] = toValue;
}
});
-
if (Object.keys(transitions.from).length) {
this.transition(transitions.from, transitions.to, duration, easing);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
diff --git a/node_modules/react-native-animatable/createAnimatableComponent.js b/node_modules/react-native-animatable/createAnimatableComponent.js
index 331d44f..fd92b8e 100644
--- a/node_modules/react-native-animatable/createAnimatableComponent.js
+++ b/node_modules/react-native-animatable/createAnimatableComponent.js
@@ -362,14 +362,17 @@ export default function createAnimatableComponent(WrappedComponent) {

setAnimation(animation, callback) {
const compiledAnimation = getCompiledAnimation(animation);
+ const animationValue = new Animated.Value(0);
+
this.setState(
- state => ({
+ {
animationStyle: makeInterpolatedStyle(
compiledAnimation,
- state.animationValue,
+ animationValue,
),
compiledAnimation,
- }),
+ animationValue,
+ },
callback,
);
}
@@ -401,7 +404,6 @@ export default function createAnimatableComponent(WrappedComponent) {
let currentIteration = iteration || 0;
const fromValue = getAnimationOrigin(currentIteration, direction);
const toValue = getAnimationTarget(currentIteration, direction);
- animationValue.setValue(fromValue);

if (typeof easing === 'string') {
easing = EASING_FUNCTIONS[easing];
@@ -422,7 +424,6 @@ export default function createAnimatableComponent(WrappedComponent) {
useNativeDriver,
delay: iterationDelay || 0,
};
-
Animated.timing(animationValue, config).start(endState => {
currentIteration += 1;
if (
@@ -467,7 +468,6 @@ export default function createAnimatableComponent(WrappedComponent) {
if (needsInterpolation) {
transitionValue = new Animated.Value(0);
transitionValues[property] = transitionValue;
-
transitionStyle[property] = transitionValue.interpolate({
inputRange: [0, 1],
outputRange: [fromValue, toValue],
22 changes: 22 additions & 0 deletions patches/react-native-modal/details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# `react-native-modal` patches

### [react-native-modal+13.0.1+001+initial.patch](react-native-modal+13.0.1+001+initial.patch)
- Reason: Add ESC key to close the modal
- Upstream PR/issue: N/A
- E/App issue: [#11930](https://github.com/Expensify/App/issues/11930)
- PR Introducing Patch: [#12864](https://github.com/Expensify/App/pull/12864)
- PR Updating Patch: [#18221](https://github.com/Expensify/App/pull/18221), [#48160](https://github.com/Expensify/App/pull/48160)

### [react-native-modal+13.0.1+002+fix-modal-flicker-on-open.patch](react-native-modal+13.0.1+002+fix-modal-flicker-on-open.patch)
- Reason: Fix modal flickers on iOS
- Upstream PR/issue: N/A
- E/App issue: [#48911](https://github.com/Expensify/App/issues/48911)
- PR Introducing Patch: [#51475](https://github.com/Expensify/App/pull/51475)
- PR Updating Patch: N/A

### [react-native-modal+13.0.1+002+modal-navigation-bar-translucent.patch](react-native-modal+13.0.1+002+modal-navigation-bar-translucent.patch)
- Reason: Fix navigationBarTranslucent property
- Upstream PR/issue: N/A
- E/App issue: [#52116](https://github.com/Expensify/App/issues/52116)
- PR Introducing Patch: [#52392](https://github.com/Expensify/App/pull/52392)
- PR Updating Patch: [#55861](https://github.com/Expensify/App/pull/55861)
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
diff --git a/node_modules/react-native-modal/dist/modal.d.ts b/node_modules/react-native-modal/dist/modal.d.ts
index b63bcfc..bd6419e 100644
--- a/node_modules/react-native-modal/dist/modal.d.ts
+++ b/node_modules/react-native-modal/dist/modal.d.ts
@@ -161,6 +161,7 @@ export declare class ReactNativeModal extends React.Component<ModalProps, State>
getDeviceHeight: () => number;
getDeviceWidth: () => number;
onBackButtonPress: () => boolean;
+ handleEscape: (e: KeyboardEvent) => void;
shouldPropagateSwipe: (evt: GestureResponderEvent, gestureState: PanResponderGestureState) => boolean;
buildPanResponder: () => void;
getAccDistancePerDirection: (gestureState: PanResponderGestureState) => number;
diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js
index 80f4e75..5c9d275 100644
--- a/node_modules/react-native-modal/dist/modal.js
+++ b/node_modules/react-native-modal/dist/modal.js
@@ -75,6 +75,13 @@ export class ReactNativeModal extends React.Component {
}
return false;
};
+ this.handleEscape = (e) => {
+ if (e.key === 'Escape') {
+ if (this.onBackButtonPress() === true) {
+ e.stopImmediatePropagation();
+ }
+ }
+ };
this.shouldPropagateSwipe = (evt, gestureState) => {
return typeof this.props.propagateSwipe === 'function'
? this.props.propagateSwipe(evt, gestureState)
@@ -383,7 +390,9 @@ export class ReactNativeModal extends React.Component {
this.setState({
isVisible: false,
}, () => {
- this.props.onModalHide();
+ if (Platform.OS !== 'ios') {
+ this.props.onModalHide();
+ }
});
});
}
@@ -453,10 +462,18 @@ export class ReactNativeModal extends React.Component {
if (this.state.isVisible) {
this.open();
}
+ if (Platform.OS === 'web') {
+ document?.body?.addEventListener?.('keyup', this.handleEscape, true);
+ return;
+ }
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPress);
}
componentWillUnmount() {
- BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPress);
+ if (Platform.OS === 'web') {
+ document?.body?.removeEventListener?.('keyup', this.handleEscape, true);
+ } else {
+ BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPress);
+ }
if (this.didUpdateDimensionsEmitter) {
this.didUpdateDimensionsEmitter.remove();
}
@@ -490,7 +507,7 @@ export class ReactNativeModal extends React.Component {
}
render() {
/* eslint-disable @typescript-eslint/no-unused-vars */
- const { animationIn, animationInTiming, animationOut, animationOutTiming, avoidKeyboard, coverScreen, hasBackdrop, backdropColor, backdropOpacity, backdropTransitionInTiming, backdropTransitionOutTiming, customBackdrop, children, isVisible, onModalShow, onBackButtonPress, useNativeDriver, propagateSwipe, style, ...otherProps } = this.props;
+ const { animationIn, animationInTiming, animationOut, animationOutTiming, avoidKeyboard, coverScreen, hasBackdrop, backdropColor, backdropOpacity, backdropTransitionInTiming, backdropTransitionOutTiming, customBackdrop, children, isVisible, onModalShow, onBackButtonPress, useNativeDriver, propagateSwipe, style, onDismiss, ...otherProps } = this.props;
const { testID, ...containerProps } = otherProps;
const computedStyle = [
{ margin: this.getDeviceWidth() * 0.05, transform: [{ translateY: 0 }] },
@@ -523,9 +540,9 @@ export class ReactNativeModal extends React.Component {
this.makeBackdrop(),
containerView));
}
- return (React.createElement(Modal, Object.assign({ transparent: true, animationType: 'none', visible: this.state.isVisible, onRequestClose: onBackButtonPress }, otherProps),
+ return (React.createElement(Modal, Object.assign({ transparent: true, animationType: 'none', visible: this.state.isVisible, onRequestClose: onBackButtonPress, onDismiss: () => {onDismiss();if (Platform.OS === 'ios'){this.props.onModalHide();}} }, otherProps),
this.makeBackdrop(),
- avoidKeyboard ? (React.createElement(KeyboardAvoidingView, { behavior: Platform.OS === 'ios' ? 'padding' : undefined, pointerEvents: "box-none", style: computedStyle.concat([{ margin: 0 }]) }, containerView)) : (containerView)));
+ avoidKeyboard ? (React.createElement(KeyboardAvoidingView, { behavior: 'padding', pointerEvents: "box-none", style: computedStyle.concat([{ margin: 0 }]) }, containerView)) : (containerView)));
}
}
ReactNativeModal.propTypes = {
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js
index 46277ea..2e70c0c 100644
--- a/node_modules/react-native-modal/dist/modal.js
+++ b/node_modules/react-native-modal/dist/modal.js
@@ -4,6 +4,7 @@ import * as PropTypes from 'prop-types';
import * as animatable from 'react-native-animatable';
import { initializeAnimations, buildAnimations, reversePercentage, } from './utils';
import styles from './modal.style';
+
// Override default react-native-animatable animations
initializeAnimations();
const defaultProps = {
@@ -535,7 +536,7 @@ export class ReactNativeModal extends React.Component {
const _children = this.props.hideModalContentWhileAnimating &&
this.props.useNativeDriver &&
!this.state.showContent ? (React.createElement(animatable.View, null)) : (children);
- const containerView = (React.createElement(animatable.View, Object.assign({}, panHandlers, { ref: ref => (this.contentRef = ref), style: [panPosition, computedStyle], pointerEvents: "box-none", useNativeDriver: useNativeDriver }, containerProps), _children));
+ const containerView = (React.createElement(animatable.View, Object.assign({}, panHandlers, { ref: ref => (this.contentRef = ref), style: [panPosition, computedStyle], pointerEvents: "box-none", useNativeDriver: useNativeDriver, animation: animationIn }, containerProps), _children));
// If coverScreen is set to false by the user
// we render the modal inside the parent view directly
if (!coverScreen && this.state.isVisible) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
diff --git a/node_modules/react-native-modal/dist/modal.d.ts b/node_modules/react-native-modal/dist/modal.d.ts
index bd6419e..029762c 100644
--- a/node_modules/react-native-modal/dist/modal.d.ts
+++ b/node_modules/react-native-modal/dist/modal.d.ts
@@ -46,6 +46,7 @@ declare const defaultProps: {
scrollOffsetMax: number;
scrollHorizontal: boolean;
statusBarTranslucent: boolean;
+ navigationBarTranslucent: boolean;
supportedOrientations: ("landscape" | "portrait" | "portrait-upside-down" | "landscape-left" | "landscape-right")[];
};
export declare type ModalProps = ViewProps & {
@@ -137,6 +138,7 @@ export declare class ReactNativeModal extends React.Component<ModalProps, State>
scrollOffsetMax: number;
scrollHorizontal: boolean;
statusBarTranslucent: boolean;
+ navigationBarTranslucent: boolean;
supportedOrientations: ("landscape" | "portrait" | "portrait-upside-down" | "landscape-left" | "landscape-right")[];
};
state: State;
diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js
index 2e70c0c..7a39705 100644
--- a/node_modules/react-native-modal/dist/modal.js
+++ b/node_modules/react-native-modal/dist/modal.js
@@ -39,6 +39,7 @@ const defaultProps = {
scrollOffsetMax: 0,
scrollHorizontal: false,
statusBarTranslucent: false,
+ navigationBarTranslucent: false,
supportedOrientations: ['portrait', 'landscape'],
};
const extractAnimationFromProps = (props) => ({
@@ -69,6 +70,7 @@ export class ReactNativeModal extends React.Component {
this.interactionHandle = null;
this.getDeviceHeight = () => this.props.deviceHeight || this.state.deviceHeight;
this.getDeviceWidth = () => this.props.deviceWidth || this.state.deviceWidth;
+ this.backHandlerEventSubscription = null;
this.onBackButtonPress = () => {
if (this.props.onBackButtonPress && this.props.isVisible) {
this.props.onBackButtonPress();
@@ -467,13 +469,15 @@ export class ReactNativeModal extends React.Component {
document?.body?.addEventListener?.('keyup', this.handleEscape, true);
return;
}
- BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPress);
+ this.backHandlerEventSubscription = BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPress);
}
componentWillUnmount() {
if (Platform.OS === 'web') {
document?.body?.removeEventListener?.('keyup', this.handleEscape, true);
} else {
- BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPress);
+ if (this.backHandlerEventSubscription) {
+ this.backHandlerEventSubscription.remove();
+ }
}
if (this.didUpdateDimensionsEmitter) {
this.didUpdateDimensionsEmitter.remove();
1 change: 1 addition & 0 deletions src/components/AttachmentComposerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ function AttachmentComposerModal({onConfirm, onModalShow = () => {}, onModalHide
setCurrentAttachment(null);
setPage(0);
}}
propagateSwipe
initialFocus={() => {
if (!submitRef.current) {
return false;
Expand Down
1 change: 1 addition & 0 deletions src/components/AttachmentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ function AttachmentModal({
});
}
}}
propagateSwipe
initialFocus={() => {
if (!submitRef.current) {
return false;
Expand Down
Loading
Loading