-
-
Notifications
You must be signed in to change notification settings - Fork 535
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(iOS): select correct VC for nested modal presentation (#1912)
## Description Closes #1829 Currently it is not possible to navigate to a modal from another modal view that is mounted in JS under nested stack (see #1829 description for better context). This is the case, because modal is presented by `RNSNavigationController` corresponding to the stack under which it is mounted in JS ==> UIKit reports that such controller is already presenting. IMO the last presented modal should be the one, to present new one. ## Changes Added code handling above case, by checking whether modals from other stacks are present & using top-most modal for presentation in such case. ## Test code and steps to reproduce See `Test1829` in test example apps ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes (merged only comments after final CI checks)
- Loading branch information
Showing
17 changed files
with
619 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react'; | ||
import { SafeAreaProvider } from 'react-native-safe-area-context'; | ||
import { NavigationContainer } from '@react-navigation/native'; | ||
|
||
import Stacks from './navigation/Stacks'; | ||
|
||
const App = () => ( | ||
<SafeAreaProvider> | ||
<NavigationContainer> | ||
<Stacks /> | ||
</NavigationContainer> | ||
</SafeAreaProvider> | ||
); | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react'; | ||
import { createNativeStackNavigator } from '@react-navigation/native-stack'; | ||
|
||
import HomeView from '../screens/HomeView'; | ||
import ModalView from '../screens/ModalView'; | ||
import BaseView from '../screens/InnerView'; | ||
import InnerModal from '../screens/InnerModal'; | ||
|
||
const RootStack = createNativeStackNavigator(); | ||
const InnerStack = createNativeStackNavigator(); | ||
|
||
const Inner = () => ( | ||
<InnerStack.Navigator> | ||
<InnerStack.Screen name="base" component={BaseView} /> | ||
<InnerStack.Screen | ||
name="inner-modal" | ||
component={InnerModal} | ||
options={{ presentation: 'modal' }} | ||
/> | ||
</InnerStack.Navigator> | ||
); | ||
|
||
const Stacks = () => ( | ||
<RootStack.Navigator | ||
screenOptions={{ | ||
headerShown: false, | ||
}}> | ||
<RootStack.Screen name="home" component={HomeView} /> | ||
<RootStack.Screen name="inner" component={Inner} /> | ||
<RootStack.Screen | ||
name="modal" | ||
component={ModalView} | ||
options={{ | ||
presentation: 'modal', | ||
}} | ||
/> | ||
<RootStack.Screen | ||
name="modal-2" | ||
component={ModalView} | ||
options={{ | ||
presentation: 'modal', | ||
}} | ||
/> | ||
</RootStack.Navigator> | ||
); | ||
|
||
export default Stacks; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
|
||
const CardView = () => { | ||
return <View style={styles.container} />; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'blue', | ||
}, | ||
}); | ||
|
||
export default CardView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
|
||
const HomeView = () => { | ||
const navigation = useNavigation(); | ||
return ( | ||
<View style={styles.container}> | ||
<TouchableOpacity onPress={() => navigation.navigate('inner')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open Inner Navigator</Text> | ||
</View> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => navigation.navigate('modal')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open Outer Modal</Text> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'yellow', | ||
}, | ||
button: { | ||
width: 200, | ||
height: 50, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
borderRadius: 5, | ||
backgroundColor: 'blue', | ||
}, | ||
buttonText: { | ||
color: 'white', | ||
}, | ||
}); | ||
|
||
export default HomeView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
|
||
const HomeView = () => { | ||
const navigation = useNavigation(); | ||
return ( | ||
<View style={styles.container}> | ||
<Text> | ||
This is the inner modal. Opening the outer modal here does not work. | ||
WTF? | ||
</Text> | ||
<TouchableOpacity onPress={() => navigation.navigate('modal')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open Outer Modal</Text> | ||
</View> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => navigation.goBack()}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Back</Text> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'yellow', | ||
}, | ||
button: { | ||
width: 200, | ||
height: 50, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
borderRadius: 5, | ||
backgroundColor: 'blue', | ||
}, | ||
buttonText: { | ||
color: 'white', | ||
}, | ||
}); | ||
|
||
export default HomeView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
|
||
const HomeView = () => { | ||
const navigation = useNavigation(); | ||
return ( | ||
<View style={styles.container}> | ||
<Text> | ||
This is the inner navigator. Opening the outer modal here works! | ||
</Text> | ||
<TouchableOpacity onPress={() => navigation.navigate('inner-modal')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open Inner Modal</Text> | ||
</View> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => navigation.navigate('modal')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open Outer Modal</Text> | ||
</View> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => navigation.goBack()}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Go back</Text> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'yellow', | ||
}, | ||
button: { | ||
width: 200, | ||
height: 50, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
borderRadius: 5, | ||
backgroundColor: 'blue', | ||
}, | ||
buttonText: { | ||
color: 'white', | ||
}, | ||
}); | ||
|
||
export default HomeView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import React, { useEffect } from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
import { useNavigation } from '@react-navigation/native'; | ||
|
||
const ModalView = () => { | ||
useEffect(() => { | ||
console.log('ModalView mounted'); | ||
}, []); | ||
|
||
const navigation = useNavigation(); | ||
return ( | ||
<View style={styles.container}> | ||
<Text> | ||
This is the outer modal. If you try to open it from the inner modal, it | ||
doesn't work. But if you comment out the `presentation: modal` on the | ||
inner modal, it does work! In addition, if opening a modal in the same | ||
navigator stack also works. | ||
</Text> | ||
<TouchableOpacity onPress={() => navigation.navigate('modal-2')}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Open sibling outer modal.</Text> | ||
</View> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => navigation.goBack()}> | ||
<View style={styles.button}> | ||
<Text style={styles.buttonText}>Back</Text> | ||
</View> | ||
</TouchableOpacity> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'green', | ||
}, | ||
button: { | ||
width: 200, | ||
height: 50, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
borderRadius: 5, | ||
backgroundColor: 'blue', | ||
}, | ||
buttonText: { | ||
color: 'white', | ||
}, | ||
}); | ||
|
||
export default ModalView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react'; | ||
import { SafeAreaProvider } from 'react-native-safe-area-context'; | ||
import { NavigationContainer } from '@react-navigation/native'; | ||
|
||
import Stacks from './navigation/Stacks'; | ||
|
||
const App = () => ( | ||
<SafeAreaProvider> | ||
<NavigationContainer> | ||
<Stacks /> | ||
</NavigationContainer> | ||
</SafeAreaProvider> | ||
); | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react'; | ||
import { createNativeStackNavigator } from '@react-navigation/native-stack'; | ||
|
||
import HomeView from '../screens/HomeView'; | ||
import ModalView from '../screens/ModalView'; | ||
import BaseView from '../screens/InnerView'; | ||
import InnerModal from '../screens/InnerModal'; | ||
|
||
const RootStack = createNativeStackNavigator(); | ||
const InnerStack = createNativeStackNavigator(); | ||
|
||
const Inner = () => ( | ||
<InnerStack.Navigator> | ||
<InnerStack.Screen name="base" component={BaseView} /> | ||
<InnerStack.Screen | ||
name="inner-modal" | ||
component={InnerModal} | ||
options={{ presentation: 'modal' }} | ||
/> | ||
</InnerStack.Navigator> | ||
); | ||
|
||
const Stacks = () => ( | ||
<RootStack.Navigator | ||
screenOptions={{ | ||
headerShown: false, | ||
}}> | ||
<RootStack.Screen name="home" component={HomeView} /> | ||
<RootStack.Screen name="inner" component={Inner} /> | ||
<RootStack.Screen | ||
name="modal" | ||
component={ModalView} | ||
options={{ | ||
presentation: 'modal', | ||
}} | ||
/> | ||
<RootStack.Screen | ||
name="modal-2" | ||
component={ModalView} | ||
options={{ | ||
presentation: 'modal', | ||
}} | ||
/> | ||
</RootStack.Navigator> | ||
); | ||
|
||
export default Stacks; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import React from 'react'; | ||
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native'; | ||
|
||
const CardView = () => { | ||
return <View style={styles.container} />; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
backgroundColor: 'blue', | ||
}, | ||
}); | ||
|
||
export default CardView; |
Oops, something went wrong.