react-native-paper icon indicating copy to clipboard operation
react-native-paper copied to clipboard

Modals on iOS do not respond to the presence of the on-screen keyboard

Open JPStrydom opened this issue 1 year ago • 9 comments

Current behaviour

On web and Android, the Modal component respects the state of the keyboard, adjusting it's height accordingly. On iOS, however, the Modal does not move up when the keyboard is opened.

This issue is likely related to 2172

Expected behaviour

The Modal component should respect the positions of the keyboard and respond accordingly on all platforms.

How to reproduce?

  1. Add a Modal component inside a Portal component.
  2. Add content to the Modal component and open the Modal.
  3. Open the device on-screen keyboard on an iOS device.
  4. Notice how the Modal doesn't respond (move up) to accommodate the keyboard, even though there is empty space available above the modal.

Preview

iOS: image

Android: image

What have you tried so far?

We're currently following the workaround listed here.

Your Environment

software version
ios x
android x
react-native 0.71.14
react-native-paper 5.11.2
node 20.9.0
npm or yarn 10.1.0
expo sdk 48.0.20

JPStrydom avatar Dec 08 '23 10:12 JPStrydom

Having the same issue

Bi0max avatar Jan 22 '24 11:01 Bi0max

@Bi0max please add your issue reproduction

lukewalczak avatar Jan 22 '24 11:01 lukewalczak

@lukewalczak , hi , it's literally the same as the OP described. It is reproduced just with and empty Modal and an opened keyboard on iOS.

Bi0max avatar Jan 24 '24 15:01 Bi0max

Hello! I confirm the issue. It seems there is a problem with Portal and its keyboard avoiding behavior on iOS. It also makes SnackBar (placed in Portal) appear under the keyboard on iOS. Reproduced it the same way the issue's author described.

https://github.com/callstack/react-native-paper/assets/32746079/49953d6b-45e7-4d0a-9168-d4b5ea6c6b34

My environment

software version
ios 17.2
android 13.0
react-native 0.72.10
react-native-paper 5.12.2
node 21.3.0
yarn 1.22.21

Sanal avatar Jan 27 '24 08:01 Sanal

Same issue after upgrading to latest and placing modal within Portal component.

foxysolutions avatar Feb 25 '24 05:02 foxysolutions

Same issue, Portal does not response to keybored in IOS even with KeyboardAvoidingView, for anyone who is looking for a solution, you can use Modal from react nativre for IOS with keyboredAvoidView, it works fine

Abdalrzakalsouki avatar Feb 27 '24 12:02 Abdalrzakalsouki

Has there been any update or progress on this?

JPStrydom avatar Jul 24 '24 13:07 JPStrydom

I have fixed this by patching the react-native-paper dependency (using yarn)

Here I share the changes in case it's helpful for others.

There's probably a better approach, but this might suffice while RNP implement an actual fix.

cc @lukewalczak

Please ignore some formatting changes in here

diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index 313ecee43bde4a0b6be9cbd13b673452725f0f6e..12a7e3d0494a5e256ba5e22a89d71572df547789 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -7,6 +7,8 @@ import {
   Pressable,
   View,
   ViewStyle,
+  KeyboardAvoidingView,
+  Platform,
 } from 'react-native';
 
 import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -177,11 +179,7 @@ function Modal({
       return true;
     };
 
-    const subscription = addEventListener(
-      BackHandler,
-      'hardwareBackPress',
-      onHardwareBackPress
-    );
+    const subscription = addEventListener(BackHandler, 'hardwareBackPress', onHardwareBackPress);
     return () => subscription.remove();
   }, [dismissable, dismissableBackButton, hideModal, visible]);
 
@@ -204,17 +202,16 @@ function Modal({
     <Animated.View
       pointerEvents={visible ? 'auto' : 'none'}
       accessibilityViewIsModal
-      accessibilityLiveRegion="polite"
+      accessibilityLiveRegion='polite'
       style={StyleSheet.absoluteFill}
       onAccessibilityEscape={hideModal}
-      testID={testID}
-    >
+      testID={testID}>
       <AnimatedPressable
         accessibilityLabel={overlayAccessibilityLabel}
-        accessibilityRole="button"
+        accessibilityRole='button'
         disabled={!dismissable}
         onPress={dismissable ? hideModal : undefined}
-        importantForAccessibility="no"
+        importantForAccessibility='no'
         style={[
           styles.backdrop,
           {
@@ -225,21 +222,20 @@ function Modal({
         testID={`${testID}-backdrop`}
       />
       <View
-        style={[
-          styles.wrapper,
-          { marginTop: top, marginBottom: bottom },
-          style,
-        ]}
-        pointerEvents="box-none"
-        testID={`${testID}-wrapper`}
-      >
-        <Surface
-          testID={`${testID}-surface`}
-          theme={theme}
-          style={[{ opacity }, styles.content, contentContainerStyle]}
-        >
-          {children}
-        </Surface>
+        style={[styles.wrapper, { marginTop: top, marginBottom: bottom }, style]}
+        pointerEvents='box-none'
+        testID={`${testID}-wrapper`}>
+        <KeyboardAvoidingView
+          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+          keyboardVerticalOffset={100}
+          style={styles.keyboardAvoidingView}>
+          <Surface
+            testID={`${testID}-surface`}
+            theme={theme}
+            style={[{ opacity }, styles.content, contentContainerStyle]}>
+            {children}
+          </Surface>
+        </KeyboardAvoidingView>
       </View>
     </Animated.View>
   );
@@ -260,4 +256,10 @@ const styles = StyleSheet.create({
     backgroundColor: 'transparent',
     justifyContent: 'center',
   },
+  keyboardAvoidingView: {
+    display: 'flex',
+    flexDirection: 'column',
+    alignItems: 'stretch',
+    justifyContent: 'center',
+  },
 });


Here's proof of it working:

iOS

https://github.com/user-attachments/assets/436bde65-f8af-415a-af28-22b0233b9a21

Android

https://github.com/user-attachments/assets/a3f28d21-f95b-481f-9f98-9aab056c5265

jahirfiquitiva avatar Aug 21 '24 23:08 jahirfiquitiva