Skip to content

Commit

Permalink
fix(#86): applied offset being rarely removed from incorrect root view (
Browse files Browse the repository at this point in the history
  • Loading branch information
mateusz1913 committed Sep 29, 2022
1 parent 499ab9c commit c9bd1ec
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 38 deletions.
8 changes: 8 additions & 0 deletions packages/app/src/navigation/index.tsx
Expand Up @@ -9,7 +9,9 @@ import { FormExample } from '../screens/FormExample';
import { HomeScreen } from '../screens/HomeScreen';
import { KeyboardTypeExample } from '../screens/KeyboardTypeExample';
import { ModalExample } from '../screens/ModalExample';
import { ModalFormSheetExample } from '../screens/ModalFormSheetExample';
import { ReanimatedExample } from '../screens/ReanimatedExample';
import { ScreensNativeModalExample } from '../screens/ScreensNativeModalExample';
import { StickyFooterExample } from '../screens/StickyFooterExample';

import { ROUTES } from './routes';
Expand All @@ -27,7 +29,13 @@ export const Navigation: React.FC = () => {
<Stack.Screen name={ROUTES.Form} component={FormExample} />
<Stack.Screen name={ROUTES.KeyboardType} component={KeyboardTypeExample} />
<Stack.Screen name={ROUTES.Modal} component={ModalExample} />
<Stack.Screen name={ROUTES.ModalFormSheet} component={ModalFormSheetExample} />
<Stack.Screen name={ROUTES.Reanimated} component={ReanimatedExample} />
<Stack.Screen
name={ROUTES.ScreensNativeModal}
component={ScreensNativeModalExample}
options={{ animation: 'default', headerShown: false, presentation: 'formSheet' }}
/>
<Stack.Screen name={ROUTES.StickyFooter} component={StickyFooterExample} />
</Stack.Navigator>;
};
2 changes: 2 additions & 0 deletions packages/app/src/navigation/routes.ts
Expand Up @@ -7,6 +7,8 @@ export const ROUTES = {
Form: 'Form' as const,
KeyboardType: 'KeyboardType' as const,
Modal: 'Modal' as const,
ModalFormSheet: 'ModalFormSheet' as const,
Reanimated: 'Reanimated' as const,
ScreensNativeModal: 'ScreensNativeModal' as const,
StickyFooter: 'StickyFooter' as const,
};
2 changes: 2 additions & 0 deletions packages/app/src/navigation/types.ts
Expand Up @@ -11,7 +11,9 @@ export type RootStackParamList = {
[ROUTES.Home]: undefined;
[ROUTES.KeyboardType]: undefined;
[ROUTES.Modal]: undefined;
[ROUTES.ModalFormSheet]: undefined;
[ROUTES.Reanimated]: undefined;
[ROUTES.ScreensNativeModal]: undefined;
[ROUTES.StickyFooter]: undefined;
}

Expand Down
10 changes: 10 additions & 0 deletions packages/app/src/screens/HomeScreen.tsx
Expand Up @@ -50,11 +50,21 @@ const DATA: Array<Example> = [
label: 'Modal',
route: ROUTES.Modal,
},
{
description: 'Learn how to handle text fields rendered inside formsheet modal',
label: 'ModalFormSheet',
route: ROUTES.ModalFormSheet,
},
{
description: 'Look how to implement animation with Reanimated library based on keyboard events',
label: 'Reanimated',
route: ROUTES.Reanimated,
},
{
description: 'Learn how to handle text fields rendered inside React Navigation (Native Stack) formsheet modal',
label: 'ScreensNativeModal',
route: ROUTES.ScreensNativeModal,
},
{
description: 'Learn how to handle seperate parts of a form - text field in scroll component and CTA button with fixed position at the bottom of the screen',
label: 'Sticky footer',
Expand Down
145 changes: 145 additions & 0 deletions packages/app/src/screens/ModalFormSheetExample.tsx
@@ -0,0 +1,145 @@
import { useFocusEffect } from '@react-navigation/native';
import * as React from 'react';
import { Image, Modal, ScrollView, StyleSheet, View } from 'react-native';
import { AvoidSoftInput } from 'react-native-avoid-softinput';
import { SafeAreaView } from 'react-native-safe-area-context';

import Button from '../components/Button';
import CloseButton from '../components/CloseButton';
import SingleInput from '../components/SingleInput';
import { styles as commonStyles } from '../consts/styles';

const icon = require('../../assets/AppIconTransparent.png');

export const ModalFormSheetExample: React.FC = () => {
const [ formSheetModalVisible, setFormSheetModalVisible ] = React.useState(false);

const onFocusEffect = React.useCallback(() => {
AvoidSoftInput.setShouldMimicIOSBehavior(true);
AvoidSoftInput.setEnabled(true);
return () => {
AvoidSoftInput.setEnabled(false);
AvoidSoftInput.setShouldMimicIOSBehavior(false);
};
}, []);

useFocusEffect(onFocusEffect);

function closeFormSheetModal() {
setFormSheetModalVisible(false);
}

function openFormSheetModal() {
setFormSheetModalVisible(true);
}

return <SafeAreaView edges={[ 'left', 'right' ]} style={commonStyles.screenContainer}>
<Button
onPress={openFormSheetModal}
title="Open formsheet modal"
/>
<Modal
animationType="slide"
onRequestClose={closeFormSheetModal}
presentationStyle="formSheet"
statusBarTranslucent={true}
style={styles.modal}
supportedOrientations={[ 'landscape', 'portrait' ]}
visible={formSheetModalVisible}>
<SafeAreaView edges={[ 'left', 'right', 'bottom' ]} style={styles.modalContent}>
<View style={styles.container}>
<View style={styles.closeContainer}>
<CloseButton onPress={closeFormSheetModal} />
</View>
<ScrollView
bounces={false}
contentContainerStyle={commonStyles.scrollContainer}
contentInsetAdjustmentBehavior="always"
overScrollMode="always"
showsVerticalScrollIndicator={true}
style={commonStyles.stretch}
>
<View style={styles.logoContainer}>
<Image
resizeMode="contain"
source={icon}
style={styles.logo}
/>
</View>
<View style={styles.formContainer}>
<Button
onPress={closeFormSheetModal}
title="Submit"
/>
<Button
onPress={closeFormSheetModal}
title="Submit"
/>
<Button
onPress={closeFormSheetModal}
title="Submit"
/>
<Button
onPress={closeFormSheetModal}
title="Submit"
/>
<Button
onPress={closeFormSheetModal}
title="Submit"
/>
</View>
</ScrollView>
<SingleInput placeholder="Single line" />
</View>
</SafeAreaView>
</Modal>
</SafeAreaView>;
};

const styles = StyleSheet.create({
closeContainer: {
backgroundColor: 'transparent',
position: 'absolute',
left: 0,
top: 0,
zIndex: 999,
},
container: {
alignItems: 'center',
alignSelf: 'stretch',
backgroundColor: 'white',
borderColor: 'black',
borderRadius: 10,
borderWidth: 1,
marginBottom: 80,
marginHorizontal: 10,
marginTop: 60,
overflow: 'hidden',
},
formContainer: {
alignItems: 'center',
alignSelf: 'stretch',
justifyContent: 'center',
marginBottom: 80,
marginHorizontal: 10,
},
logo: {
height: 200,
width: 200,
},
logoContainer: {
alignItems: 'center',
alignSelf: 'stretch',
flex: 1,
justifyContent: 'center',
paddingVertical: 100,
},
modal: {
alignSelf: 'stretch',
},
modalContent: {
alignSelf: 'stretch',
backgroundColor: '#00000033',
flex: 1,
},
});
123 changes: 123 additions & 0 deletions packages/app/src/screens/ScreensNativeModalExample.tsx
@@ -0,0 +1,123 @@
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import * as React from 'react';
import { Button, Image, ScrollView, StyleSheet, View } from 'react-native';
import { AvoidSoftInput } from 'react-native-avoid-softinput';
import { SafeAreaView } from 'react-native-safe-area-context';

import CloseButton from '../components/CloseButton';
import SingleInput from '../components/SingleInput';
import { styles as commonStyles } from '../consts/styles';
import type { RootStackNavigationProp } from '../navigation/types';

const icon = require('../../assets/AppIconTransparent.png');

export const ScreensNativeModalExample: React.FC = () => {
const navigation = useNavigation<RootStackNavigationProp>();

const onFocusEffect = React.useCallback(() => {
AvoidSoftInput.setEnabled(true);
AvoidSoftInput.setShouldMimicIOSBehavior(true);
return () => {
AvoidSoftInput.setShouldMimicIOSBehavior(false);
AvoidSoftInput.setEnabled(false);
};
}, []);

useFocusEffect(onFocusEffect);

function closeModal() {
navigation.goBack();
}

return <SafeAreaView edges={[ 'left', 'right', 'bottom' ]} style={styles.modalContent}>
<View style={styles.container}>
<View style={styles.closeContainer}>
<CloseButton onPress={closeModal} />
</View>
<ScrollView
bounces={false}
contentContainerStyle={commonStyles.scrollContainer}
contentInsetAdjustmentBehavior="always"
overScrollMode="always"
showsVerticalScrollIndicator={true}
style={commonStyles.stretch}
>
<View style={styles.logoContainer}>
<Image
resizeMode="contain"
source={icon}
style={styles.logo}
/>
</View>
<View style={styles.formContainer}>
<Button
onPress={closeModal}
title="Submit"
/>
<Button
onPress={closeModal}
title="Submit"
/>
<Button
onPress={closeModal}
title="Submit"
/>
<Button
onPress={closeModal}
title="Submit"
/>
<Button
onPress={closeModal}
title="Submit"
/>
</View>
</ScrollView>
<SingleInput placeholder="Single line" />
</View>
</SafeAreaView>;
};

const styles = StyleSheet.create({
closeContainer: {
backgroundColor: 'transparent',
position: 'absolute',
left: 0,
top: 0,
zIndex: 999,
},
container: {
alignItems: 'center',
alignSelf: 'stretch',
backgroundColor: 'white',
borderColor: 'black',
borderRadius: 10,
borderWidth: 1,
marginBottom: 80,
marginHorizontal: 10,
marginTop: 60,
overflow: 'hidden',
},
formContainer: {
alignItems: 'center',
alignSelf: 'stretch',
justifyContent: 'center',
marginBottom: 80,
marginHorizontal: 10,
},
logo: {
height: 200,
width: 200,
},
logoContainer: {
alignItems: 'center',
alignSelf: 'stretch',
flex: 1,
justifyContent: 'center',
paddingVertical: 100,
},
modalContent: {
alignSelf: 'stretch',
backgroundColor: '#00000033',
flex: 1,
},
});
Expand Up @@ -115,8 +115,6 @@
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AvoidSoftinputExample" */;
buildPhases = (
4F0A6FC082772762E3E4C96C /* [CP] Check Pods Manifest.lock */,
8343D51628DB5F8B00177E2B /* SwiftFormat */,
836BA77928DB39EA00E33E3D /* SwiftLint */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
Expand Down Expand Up @@ -214,42 +212,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
8343D51628DB5F8B00177E2B /* SwiftFormat */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = SwiftFormat;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" \"$SRCROOT\" \"$SRCROOT/../../react-native-avoid-softinput/ios\" --config \"$SRCROOT/.swiftformat\"\n";
};
836BA77928DB39EA00E33E3D /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = SwiftLint;
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/SwiftLint/swiftlint\" --config \"$SRCROOT/.swiftlint.yml\" \"$SRCROOT\" \"$SRCROOT/../../react-native-avoid-softinput/ios\"\n";
};
C1D60D28B925C94BD88E79D7 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down

0 comments on commit c9bd1ec

Please sign in to comment.