Compare commits

...

64 Commits

Author SHA1 Message Date
Satyajit Sahoo
4f7983134b chore: publish
- react-navigation-stack@2.8.2
2020-06-25 11:52:12 +02:00
Satyajit Sahoo
46b797dd29 fix: sync latest stack 2020-06-25 11:50:39 +02:00
Satyajit Sahoo
1a6f4a581f chore: publish
- react-navigation-stack@2.8.1
2020-06-25 03:02:46 +02:00
Satyajit Sahoo
2e7f4a6d10 fix: pop with correct key from nested stack 2020-06-25 03:01:47 +02:00
Satyajit Sahoo
6515fbe2dc chore: publish
- react-navigation-animated-switch@0.6.0
 - react-navigation-drawer@2.5.0
 - react-navigation-material-bottom-tabs@2.3.0
 - @react-navigation/native@3.8.0
 - react-navigation@4.4.0
 - react-navigation-stack@2.8.0
 - react-navigation-tabs@2.9.0
2020-06-25 02:17:38 +02:00
Satyajit Sahoo
454e05b02e feat: sync latest stack and upgrade typescript 2020-06-25 02:15:28 +02:00
Satyajit Sahoo
442ca3e700 fix: improve error message when installing wrong version 2020-06-22 02:25:00 +02:00
Satyajit Sahoo
e00c63e32b chore: publish
- react-navigation-stack@2.7.0
2020-06-08 11:35:08 +02:00
Satyajit Sahoo
ba6d7dcbed feat: sync latest stack 2020-06-08 11:31:03 +02:00
Satyajit Sahoo
2ca8c34b2d chore: publish
- react-navigation-stack@2.6.0
2020-06-06 22:38:25 +02:00
Satyajit Sahoo
03f9f8cd8e feat: sync latest stack 2020-06-06 02:28:20 +02:00
Satyajit Sahoo
1ee8c76df3 chore: publish
- react-navigation-stack@2.5.1
2020-05-15 22:02:17 +02:00
Satyajit Sahoo
bc1313b61d fix: sync latest stack 2020-05-15 22:00:38 +02:00
Satyajit Sahoo
28982ffca0 chore: publish
- react-navigation-stack@2.5.0
2020-05-12 00:57:02 +02:00
Satyajit Sahoo
bb82d5000f feat: sync latest stack 2020-05-11 18:34:46 +02:00
Satyajit Sahoo
1f30227049 chore: update eslint and prettier 2020-05-11 18:17:15 +02:00
Satyajit Sahoo
f34ec46111 chore: publish
- react-navigation-animated-switch@0.5.12
 - @react-navigation/core@3.7.6
 - react-navigation-drawer@2.4.13
 - react-navigation-material-bottom-tabs@2.2.12
 - @react-navigation/native@3.7.13
 - react-navigation@4.3.9
 - react-navigation-stack@2.4.0
 - react-navigation-tabs@2.8.13
2020-05-01 01:45:52 +02:00
Satyajit Sahoo
8b79e9bee6 feat: sync latest stack 2020-05-01 01:45:10 +02:00
linzera
e09906a423 fix: change old docUrl to new docUrl due v5 2020-04-30 16:57:36 +02:00
Satyajit Sahoo
ed7ffb98f4 chore: publish
- react-navigation-animated-switch@0.5.11
 - react-navigation-drawer@2.4.12
 - react-navigation-material-bottom-tabs@2.2.11
 - @react-navigation/native@3.7.12
 - react-navigation@4.3.8
 - react-navigation-stack@2.3.13
 - react-navigation-tabs@2.8.12
2020-04-22 16:47:35 +02:00
Satyajit Sahoo
90eff6a5e2 chore: sync latest stack 2020-04-22 16:45:32 +02:00
Satyajit Sahoo
b4691d7de2 chore: update react-native-safe-area-view 2020-04-22 16:31:49 +02:00
Satyajit Sahoo
f99f523a37 chore: publish
- react-navigation-stack@2.3.12
2020-04-18 01:49:20 +02:00
Satyajit Sahoo
05b47dbb09 chore: sync latest stack 2020-04-18 01:48:06 +02:00
Alejandro
4c4e66f05c fix: stack peer warnings 2020-04-18 01:15:41 +02:00
Satyajit Sahoo
720d1f970d chore: publish
- react-navigation-animated-switch@0.5.10
 - @react-navigation/core@3.7.5
 - react-navigation-drawer@2.4.11
 - react-navigation-material-bottom-tabs@2.2.10
 - @react-navigation/native@3.7.11
 - react-navigation@4.3.7
 - react-navigation-stack@2.3.11
 - react-navigation-tabs@2.8.11
2020-04-02 12:30:56 +02:00
Satyajit Sahoo
66a4dbccd8 fix: emit refocus for child navigators 2020-04-02 12:29:54 +02:00
Satyajit Sahoo
7925f0c8a3 chore: publish
- react-navigation-animated-switch@0.5.9
 - @react-navigation/core@3.7.4
 - react-navigation-drawer@2.4.10
 - react-navigation-material-bottom-tabs@2.2.9
 - @react-navigation/native@3.7.10
 - react-navigation@4.3.6
 - react-navigation-stack@2.3.10
 - react-navigation-tabs@2.8.10
2020-03-31 18:19:11 +02:00
Satyajit Sahoo
b3d77b79b7 chore: update typescript 2020-03-31 18:15:29 +02:00
Satyajit Sahoo
1d527ce16a chore: sync latest stack 2020-03-31 18:07:52 +02:00
Satyajit Sahoo
3bec1c964a fix: remove isTransitioning from SwitchRouter state 2020-03-31 17:38:42 +02:00
osdnk
a7e0c193cd chore: publish
- react-navigation-animated-switch@0.5.8
 - @react-navigation/core@3.7.3
 - react-navigation-drawer@2.4.9
 - react-navigation-material-bottom-tabs@2.2.8
 - @react-navigation/native@3.7.9
 - react-navigation@4.3.5
 - react-navigation-stack@2.3.9
 - react-navigation-tabs@2.8.9
2020-03-28 22:34:14 +01:00
Satyajit Sahoo
ac98c0a668 fix: always emit didFocus/didBlur for root navigator 2020-03-28 17:20:33 +01:00
Satyajit Sahoo
14a6538cc8 fix: emit didFocus and didBlur events based on parent's transition 2020-03-28 16:04:06 +01:00
Satyajit Sahoo
c9313a1419 chore: publish
- react-navigation-animated-switch@0.5.7
 - @react-navigation/core@3.7.2
 - react-navigation-drawer@2.4.8
 - react-navigation-material-bottom-tabs@2.2.7
 - @react-navigation/native@3.7.8
 - react-navigation@4.3.4
 - react-navigation-stack@2.3.8
 - react-navigation-tabs@2.8.8
2020-03-28 00:45:14 +01:00
Satyajit Sahoo
ec39721a74 chore: update yarn.lock 2020-03-27 21:55:06 +01:00
Satyajit Sahoo
a54d48b650 chore: add babel-jest 2020-03-27 21:44:39 +01:00
Satyajit Sahoo
8a9a9cd7d1 chore: sync latest stack 2020-03-27 21:34:40 +01:00
Satyajit Sahoo
cd08338186 fix: rework focus and blur events to make them more reliable
closes #4867, #6187, #6451, #7628, #7749
2020-03-27 21:28:30 +01:00
Satyajit Sahoo
d2433f0ab8 fix: don't handle prune if there's only one route
This was preventing the action from bubbling up which would prevent the screen from getting removed
2020-03-27 20:09:52 +01:00
osdnk
66374db859 chore: publish
- react-navigation-stack@2.3.7
2020-03-27 10:25:42 +01:00
osdnk
8dbe0299a8 chore: sync latest stack 2020-03-27 10:24:28 +01:00
Satyajit Sahoo
e4bc6dd506 chore: publish
- react-navigation-stack@2.3.6
2020-03-23 11:45:26 +01:00
Satyajit Sahoo
4bac3bfc1a chore: sync latest stack 2020-03-23 11:44:28 +01:00
Satyajit Sahoo
7656b35ee8 chore: publish
- react-navigation-animated-switch@0.5.6
 - @react-navigation/core@3.7.1
 - react-navigation-drawer@2.4.7
 - react-navigation-material-bottom-tabs@2.2.6
 - @react-navigation/native@3.7.7
 - react-navigation@4.3.3
 - react-navigation-stack@2.3.5
 - react-navigation-tabs@2.8.7
2020-03-23 00:09:22 +01:00
Satyajit Sahoo
597aa51fad chore: sync latest stack 2020-03-23 00:08:30 +01:00
Satyajit Sahoo
a929933bde chore: update prettier 2020-03-23 00:02:47 +01:00
Satyajit Sahoo
911d6bb2f4 chore: explicitely set tag for core and native packages 2020-03-22 17:08:01 +01:00
Satyajit Sahoo
5afc82b11a chore: publish
- react-navigation-animated-switch@0.5.5
 - react-navigation-drawer@2.4.6
 - react-navigation-material-bottom-tabs@2.2.5
 - @react-navigation/native@3.7.6
 - react-navigation@4.3.2
 - react-navigation-stack@2.3.4
 - react-navigation-tabs@2.8.6
2020-03-20 14:41:05 +01:00
Satyajit Sahoo
80c8c9d1de fix: don't mix import and module.exports. closes #7660 2020-03-20 14:28:24 +01:00
Satyajit Sahoo
fd7c5ca9b2 chore: publish
- react-navigation-stack@2.3.3
2020-03-20 11:49:37 +01:00
Satyajit Sahoo
72bbebc80e chore: sync latest stack 2020-03-20 11:40:21 +01:00
Satyajit Sahoo
915861e601 chore: publish
- react-navigation-stack@2.3.2
2020-03-19 20:12:07 +01:00
Satyajit Sahoo
8152ae1212 chore: sync latest stack 2020-03-19 20:11:34 +01:00
Satyajit Sahoo
79125bfab9 chore: publish
- react-navigation-drawer@2.4.5
 - react-navigation-tabs@2.8.5
2020-03-19 16:44:44 +01:00
Satyajit Sahoo
44c390075f fix: don't use react-native-screens on web
seems `react-native-screens` doesn't handle active screens properly and shows a blank page
 instead on web when a number is specified in the `active` prop.

closes #7485
2020-03-19 16:43:28 +01:00
Satyajit Sahoo
1c5e7a5ff2 chore: publish
- react-navigation-animated-switch@0.5.4
 - react-navigation-drawer@2.4.4
 - react-navigation-material-bottom-tabs@2.2.4
 - @react-navigation/native@3.7.5
 - react-navigation@4.3.1
 - react-navigation-stack@2.3.1
 - react-navigation-tabs@2.8.4
2020-03-16 19:22:04 +01:00
Satyajit Sahoo
cfc1bac4e1 fix: downgrade react-native-safe-area-view
closes #7813
2020-03-16 19:21:05 +01:00
Satyajit Sahoo
c0fb54b5a2 chore: publish
- react-navigation-animated-switch@0.5.3
 - @react-navigation/core@3.7.0
 - react-navigation-drawer@2.4.3
 - react-navigation-material-bottom-tabs@2.2.3
 - @react-navigation/native@3.7.4
 - react-navigation@4.3.0
 - react-navigation-stack@2.3.0
 - react-navigation-tabs@2.8.3
2020-03-16 17:14:15 +01:00
Satyajit Sahoo
5927f4287f feat: add prune option to pop action to match v5 behaviour 2020-03-16 16:37:20 +01:00
Satyajit Sahoo
37a664b433 chore: upgrade depenendecies 2020-03-16 15:24:11 +01:00
Satyajit Sahoo
8d0b61f1b7 chore: sync latest stack 2020-03-16 14:55:51 +01:00
Satyajit Sahoo
d3f092cb84 chore: publish
- react-navigation-stack@2.2.3
2020-03-04 13:37:40 +01:00
Satyajit Sahoo
f5a3880969 fix: dispatch completeTransition on mount so focus event is emitted 2020-03-04 13:36:34 +01:00
136 changed files with 6228 additions and 4028 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@
.idea
.expo
.gradle
.history
local.properties

View File

@@ -41,7 +41,7 @@ import StackWithTranslucentHeader from './src/StackWithTranslucentHeader';
import SwitchWithStacks from './src/SwitchWithStacks';
import TabsInDrawer from './src/TabsInDrawer';
import DragLimitedToModal from './src/DragLimitedToModal';
import EventsStack from './src/EventsStack';
import FocusEvents from './src/FocusEvents';
import FullScreen from './src/FullScreen';
import GestureInteraction from './src/GestureInteraction';
import {
@@ -144,7 +144,7 @@ const ExampleInfo = {
name: 'Drag limited to modal',
screen: DragLimitedToModal,
},
EventsStack: { name: 'Events Stack', screen: EventsStack },
EventsStack: { name: 'Focus Events', screen: FocusEvents },
FullScreen: { name: 'Fullscreen Stack', screen: FullScreen },
GestureInteraction: {
name: 'Gesture interaction',
@@ -335,7 +335,7 @@ class MainScreen extends React.Component<any, State> {
}}
>
{(Object.keys(ExampleInfo) as (keyof typeof ExampleInfo)[]).map(
routeName => (
(routeName) => (
<RectButton
key={routeName}
underlayColor="#ccc"
@@ -346,6 +346,7 @@ class MainScreen extends React.Component<any, State> {
if (route.screen || route.path || route.params) {
// @ts-ignore
const { path, params, screen } = route;
// @ts-ignore
const { router } = screen;
const action =
path &&
@@ -386,6 +387,7 @@ class MainScreen extends React.Component<any, State> {
const Navigation = createAppContainer(
createStackNavigator(
// @ts-ignore
{
...ExampleInfo,
Index: {

View File

@@ -1,4 +1,4 @@
module.exports = function(api) {
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],

View File

@@ -11,8 +11,8 @@ const modules = ['@expo/vector-icons']
// List all packages under `packages/`
.readdirSync(packages)
// Ignore hidden files such as .DS_Store
.filter(p => !p.startsWith('.'))
.map(p => {
.filter((p) => !p.startsWith('.'))
.map((p) => {
const pak = JSON.parse(
fs.readFileSync(path.join(packages, p, 'package.json'), 'utf8')
);
@@ -50,7 +50,7 @@ module.exports = {
},
server: {
enhanceMiddleware: middleware => {
enhanceMiddleware: (middleware) => {
return (req, res, next) => {
// When an asset is imported outside the project root, it has wrong path on Android
// This happens for the back button in stack, so we fix the path to correct one

View File

@@ -8,9 +8,9 @@
"ios": "expo start --ios"
},
"dependencies": {
"@babel/runtime": "^7.8.4",
"@babel/runtime": "^7.8.7",
"@expo/vector-icons": "^10.0.6",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/masked-view": "0.1.7",
"expo": "^36.0.0",
"expo-asset": "~8.0.0",
"expo-barcode-scanner": "^8.0.0",
@@ -21,16 +21,16 @@
"react-native": "https://github.com/expo/react-native/archive/sdk-36.0.1.tar.gz",
"react-native-gesture-handler": "~1.6.0",
"react-native-iphone-x-helper": "^1.2.1",
"react-native-maps": "0.26.1",
"react-native-maps": "0.27.0",
"react-native-paper": "^3.4.0",
"react-native-reanimated": "~1.7.0",
"react-native-safe-area-context": "0.7.3",
"react-native-screens": "2.0.0-beta.10",
"react-native-screens": "2.3.0",
"react-native-webview": "8.1.2",
"react-navigation-header-buttons": "^3.0.5"
},
"devDependencies": {
"babel-plugin-module-resolver": "^4.0.0",
"expo-cli": "^3.13.1"
"expo-cli": "^3.13.8"
}
}

View File

@@ -62,7 +62,7 @@ const CustomTabBar = ({
const { routes } = navigation.state;
return (
<SafeAreaView style={styles.tabContainer}>
{routes.map(route => (
{routes.map((route) => (
<BorderlessButton
onPress={() => navigation.navigate(route.routeName)}
style={styles.tab}

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { Button, ScrollView, View, Text } from 'react-native';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import {
createStackNavigator,
NavigationStackProp,
@@ -22,24 +23,36 @@ class FocusTag extends React.Component<NavigationStackScreenProps> {
state = { mode: 'didBlur' };
componentDidMount() {
this.props.navigation.addListener('willFocus', () => {
this.setMode('willFocus');
this._willFocusSub = this.props.navigation.addListener('willFocus', () => {
this._handleEvent('willFocus');
});
this.props.navigation.addListener('willBlur', () => {
this.setMode('willBlur');
this._willBlurSub = this.props.navigation.addListener('willBlur', () => {
this._handleEvent('willBlur');
});
this.props.navigation.addListener('didFocus', () => {
this.setMode('didFocus');
this._didFocusSub = this.props.navigation.addListener('didFocus', () => {
this._handleEvent('didFocus');
});
this.props.navigation.addListener('didBlur', () => {
this.setMode('didBlur');
this._didBlurSub = this.props.navigation.addListener('didBlur', () => {
this._handleEvent('didBlur');
});
}
setMode = (mode: string) => {
componentWillUnmount() {
this._willFocusSub?.remove();
this._willBlurSub?.remove();
this._didFocusSub?.remove();
this._didBlurSub?.remove();
}
_willFocusSub: { remove: () => void } | undefined;
_willBlurSub: { remove: () => void } | undefined;
_didFocusSub: { remove: () => void } | undefined;
_didBlurSub: { remove: () => void } | undefined;
_handleEvent = (mode: string) => {
this.setState({ mode });
};
@@ -119,18 +132,19 @@ class SampleScreen extends React.Component<NavigationStackScreenProps> {
}
}
const SimpleStack = createStackNavigator(
const Stack = createStackNavigator(
{
PageOne: {
screen: SampleScreen,
},
PageTwo: {
screen: SampleScreen,
},
PageOne: SampleScreen,
PageTwo: SampleScreen,
},
{
initialRouteName: 'PageOne',
}
);
export default SimpleStack;
const Tabs = createBottomTabNavigator({
A: Stack,
B: Stack,
});
export default Tabs;

View File

@@ -44,7 +44,7 @@ const ContainerWithButtons = withNavigation(
const MapScreen = () => (
<ContainerWithButtons>
<DrawerGestureContext.Consumer>
{ref => (
{(ref) => (
<NativeViewGestureHandler waitFor={ref}>
<MapView style={{ flex: 1 }} />
</NativeViewGestureHandler>
@@ -60,7 +60,7 @@ MapScreen.navigationOptions = {
const WebViewScreen = () => (
<ContainerWithButtons>
<DrawerGestureContext.Consumer>
{ref => (
{(ref) => (
<NativeViewGestureHandler waitFor={ref}>
<WebView
style={{ flex: 1 }}

View File

@@ -33,7 +33,7 @@ const BarCodeScreenBase = (
<BarCodeScanner
onBarCodeScanned={
props.isFocused
? data => {
? (data) => {
console.log('scanned...');
props.navigation.navigate('Info', { data });
}
@@ -51,7 +51,7 @@ BarCodeScreenBase.navigationOptions = {
const BarCodeScreen = withNavigationFocus(BarCodeScreenBase);
const InfoScreen: NavigationStackScreenComponent = props => {
const InfoScreen: NavigationStackScreenComponent = (props) => {
return (
<View style={{ flex: 1 }}>
<Text>{JSON.stringify(props.navigation.getParam('data'))}</Text>

View File

@@ -82,7 +82,7 @@ class ListScreen extends React.Component<
state = { isInverted: false };
onSwitch = () =>
this.setState(prevState => ({ isInverted: !prevState.isInverted }));
this.setState((prevState) => ({ isInverted: !prevState.isInverted }));
render() {
return (

View File

@@ -114,7 +114,7 @@ const MyNavScreen = ({
title="Set unlocked"
/>
),
unlocked: (
'unlocked': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-open' })
@@ -158,7 +158,7 @@ const DrawerContents = ({
<Animated.View style={{ transform: [{ translateX }] }}>
<ScrollView>
<SafeAreaView forceInset={{ top: 'always' }}>
{navigation.state.routes.map(route => (
{navigation.state.routes.map((route) => (
<DrawerItem
key={route.key}
navigation={descriptors[route.key].navigation}

View File

@@ -32,7 +32,7 @@ class RightDrawer extends Component<DrawerContentComponentProps> {
<ScrollView
style={{ height: '100%', width: '100%', backgroundColor: '#333333' }}
>
{this.state.categories.map(key => {
{this.state.categories.map((key) => {
return (
<TouchableOpacity
key={key.n}

View File

@@ -59,7 +59,7 @@ export default function PhotoGrid({ id }: { id: string }) {
return (
<NavigationAwareScrollView contentContainerStyle={styles.content}>
{PHOTOS.map(uri => (
{PHOTOS.map((uri) => (
<View key={uri} style={styles.item}>
<Image source={{ uri }} style={styles.photo} />
</View>

View File

@@ -106,7 +106,7 @@ const MyNavScreen = ({
title="Set unlocked"
/>
),
unlocked: (
'unlocked': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-open' })

View File

@@ -64,7 +64,7 @@ class ListScreen extends React.Component {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
// backgroundColor: '#fff',
}}
>
<Text>List Screen</Text>
@@ -96,7 +96,7 @@ class DetailsScreen extends React.Component<NavigationStackScreenProps> {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
// backgroundColor: '#fff',
}}
>
<Text>Details Screen</Text>
@@ -119,7 +119,7 @@ class HeaderlessScreen extends React.Component {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
// backgroundColor: '#fff',
}}
>
<Text>Headerless Screen</Text>

View File

@@ -25,7 +25,7 @@ const ListScreen = (props: NavigationStackScreenProps) => (
const AnotherScreen = () => (
<CardAnimationContext.Consumer>
{value => {
{(value) => {
const scale = value
? value.current.progress.interpolate({
inputRange: [0, 1],
@@ -67,7 +67,7 @@ const YetAnotherScreen = () => (
}}
>
<CardAnimationContext.Consumer>
{value => (
{(value) => (
<Animated.Text
style={{
fontSize: 24,
@@ -84,7 +84,7 @@ const YetAnotherScreen = () => (
)}
</CardAnimationContext.Consumer>
<CardAnimationContext.Consumer>
{value => (
{(value) => (
<Animated.Text
style={{
fontSize: 24,

View File

@@ -59,7 +59,7 @@ const Drawer = createDrawerNavigator(
},
},
{
contentComponent: props => <Menu {...props} />,
contentComponent: (props) => <Menu {...props} />,
navigationOptions: { title: 'Example' },
}
);

View File

@@ -91,8 +91,4 @@ const DrawerExample = createDrawerNavigator(
}
);
DrawerExample.navigationOptions = {
headerShown: false,
};
export default DrawerExample;

View File

@@ -5,7 +5,7 @@ import {
NavigationStackScreenComponent,
} from 'react-navigation-stack';
const ListScreen: NavigationStackScreenComponent = function(props) {
const ListScreen: NavigationStackScreenComponent = function (props) {
return (
<View
style={{
@@ -29,7 +29,7 @@ const ListScreen: NavigationStackScreenComponent = function(props) {
);
};
const ModalDialogScreen: NavigationStackScreenComponent = function(props) {
const ModalDialogScreen: NavigationStackScreenComponent = function (props) {
return (
<View
style={{

View File

@@ -18,7 +18,7 @@
"author": "Adam Miskiewicz <adam@sk3vy.com>, Eric Vicenti <ericvicenti@gmail.com>, Brent Vatne <brent@expo.io>, Satyajit Sahoo <satyajit.happy@gmail.com>",
"scripts": {
"lint": "eslint --ext '.js,.ts,.tsx' .",
"typescript": "tsc --noEmit",
"typescript": "tsc --noEmit --composite false",
"test": "jest",
"prerelease": "yarn lerna run clean",
"release": "yarn lerna publish",
@@ -27,21 +27,22 @@
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"@babel/preset-env": "^7.8.7",
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@babel/runtime": "^7.8.4",
"@babel/runtime": "^7.8.7",
"@commitlint/config-conventional": "^8.3.4",
"@types/jest": "^25.1.2",
"@types/jest": "^25.1.4",
"babel-jest": "^25.2.3",
"commitlint": "^8.3.5",
"core-js": "^3.6.4",
"eslint": "^6.8.0",
"eslint-config-satya164": "^3.1.5",
"eslint": "^7.0.0",
"eslint-config-satya164": "^3.1.7",
"husky": "^4.2.1",
"jest": "^25.1.0",
"lerna": "^3.20.2",
"prettier": "^1.19.1",
"typescript": "~3.7.5"
"prettier": "^2.0.5",
"typescript": "^3.9.5"
},
"resolutions": {
"react": "~16.9.0",

View File

@@ -3,6 +3,97 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.6.0](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.12...react-navigation-animated-switch@0.6.0) (2020-06-25)
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/react-navigation/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
## [0.5.12](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.11...react-navigation-animated-switch@0.5.12) (2020-04-30)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.11](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.10...react-navigation-animated-switch@0.5.11) (2020-04-22)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.10](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.9...react-navigation-animated-switch@0.5.10) (2020-04-02)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.9](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.8...react-navigation-animated-switch@0.5.9) (2020-03-31)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.8](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.6...react-navigation-animated-switch@0.5.8) (2020-03-28)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.7](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.6...react-navigation-animated-switch@0.5.7) (2020-03-27)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.6](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.5...react-navigation-animated-switch@0.5.6) (2020-03-22)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.5](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.4...react-navigation-animated-switch@0.5.5) (2020-03-20)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.4](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.3...react-navigation-animated-switch@0.5.4) (2020-03-16)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.3](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.2...react-navigation-animated-switch@0.5.3) (2020-03-16)
**Note:** Version bump only for package react-navigation-animated-switch
## [0.5.2](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.5.1...react-navigation-animated-switch@0.5.2) (2020-02-26)
**Note:** Version bump only for package react-navigation-animated-switch

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation-animated-switch",
"version": "0.5.2",
"version": "0.6.0",
"description": "Animated switch for React Navigation",
"main": "lib/commonjs/index.js",
"react-native": "lib/module/index.js",
@@ -21,15 +21,15 @@
"access": "public"
},
"devDependencies": {
"@react-native-community/bob": "0.9.7",
"@types/react": "16.9.22",
"@types/react-native": "0.61.17",
"@react-native-community/bob": "0.10.0",
"@types/react": "16.9.23",
"@types/react-native": "0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-reanimated": "~1.7.0",
"react-navigation": "^4.2.2",
"typescript": "~3.7.5"
"react-navigation": "^4.4.0",
"typescript": "^3.9.5"
},
"peerDependencies": {
"react": "*",

View File

@@ -3,6 +3,84 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.7.6](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.5...@react-navigation/core@3.7.6) (2020-04-30)
### Bug Fixes
* change old docUrl to new docUrl due v5 ([e09906a](https://github.com/react-navigation/react-navigation-core/commit/e09906a4235a0fca09140923ebe7af34b50b491a))
## [3.7.5](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.4...@react-navigation/core@3.7.5) (2020-04-02)
### Bug Fixes
* emit refocus for child navigators ([66a4dbc](https://github.com/react-navigation/react-navigation-core/commit/66a4dbccd8e7b3cda51a1d9c7e9397dfc58d6b9e))
## [3.7.4](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.3...@react-navigation/core@3.7.4) (2020-03-31)
### Bug Fixes
* remove isTransitioning from SwitchRouter state ([3bec1c9](https://github.com/react-navigation/react-navigation-core/commit/3bec1c964a49136c0ead8e8ba8a8c66c556bbcba))
## [3.7.3](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.1...@react-navigation/core@3.7.3) (2020-03-28)
### Bug Fixes
* always emit didFocus/didBlur for root navigator ([ac98c0a](https://github.com/react-navigation/react-navigation-core/commit/ac98c0a668fe21200d0c6f62ae3043f92cc5aa7e))
* don't handle prune if there's only one route ([d2433f0](https://github.com/react-navigation/react-navigation-core/commit/d2433f0ab8f9791df8169de4ddfdeed9bc699e3e))
* emit didFocus and didBlur events based on parent's transition ([14a6538](https://github.com/react-navigation/react-navigation-core/commit/14a6538cc8e12c50d5d10722d75c9395a0a281ec))
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-core/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-core/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-core/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-core/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-core/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-core/issues/7749)
## [3.7.2](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.1...@react-navigation/core@3.7.2) (2020-03-27)
### Bug Fixes
* don't handle prune if there's only one route ([d2433f0](https://github.com/react-navigation/react-navigation-core/commit/d2433f0ab8f9791df8169de4ddfdeed9bc699e3e))
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-core/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-core/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-core/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-core/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-core/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-core/issues/7749)
## [3.7.1](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.0...@react-navigation/core@3.7.1) (2020-03-22)
**Note:** Version bump only for package @react-navigation/core
# [3.7.0](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.6.1...@react-navigation/core@3.7.0) (2020-03-16)
### Features
* add prune option to pop action to match v5 behaviour ([5927f42](https://github.com/react-navigation/react-navigation-core/commit/5927f4287f5e1ab106537865523daa1c03b14b47))
## [3.6.1](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.6.0...@react-navigation/core@3.6.1) (2020-02-24)

View File

@@ -1,6 +1,6 @@
{
"name": "@react-navigation/core",
"version": "3.6.1",
"version": "3.7.6",
"description": "Core utilities for the react-navigation framework",
"main": "lib/commonjs/index.js",
"react-native": "lib/module/index.js",
@@ -15,7 +15,8 @@
},
"sideEffects": false,
"publishConfig": {
"access": "public"
"access": "public",
"tag": "4.x"
},
"keywords": [
"react-navigation",
@@ -36,11 +37,11 @@
"dependencies": {
"hoist-non-react-statics": "^3.3.2",
"path-to-regexp": "^1.8.0",
"query-string": "^6.11.0",
"react-is": "^16.8.6"
"query-string": "^6.11.1",
"react-is": "^16.13.0"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.7",
"@react-native-community/bob": "^0.10.0",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",

View File

@@ -13,7 +13,7 @@ const StateUtils = {
* Gets a route by key. If the route isn't found, returns `null`.
*/
get(state, key) {
return state.routes.find(route => route.key === key) || null;
return state.routes.find((route) => route.key === key) || null;
},
/**
@@ -21,7 +21,7 @@ const StateUtils = {
* routes of the navigation state, or -1 if it is not present.
*/
indexOf(state, key) {
return state.routes.findIndex(route => route.key === key);
return state.routes.findIndex((route) => route.key === key);
},
/**
@@ -29,7 +29,7 @@ const StateUtils = {
* routes of the navigation state.
*/
has(state, key) {
return !!state.routes.some(route => route.key === key);
return !!state.routes.some((route) => route.key === key);
},
/**

View File

@@ -0,0 +1,148 @@
/* eslint-disable react/sort-comp */
import React from 'react';
import { NavigationActions, getNavigation, NavigationProvider } from '../index';
export default function createNavigationContainer(Component) {
class NavigationContainer extends React.Component {
static router = Component.router;
static navigationOptions = null;
constructor(props) {
super(props);
this._initialAction = NavigationActions.init();
this.state = {
nav: !props.loadNavigationState
? Component.router.getStateForAction(this._initialAction)
: null,
};
}
_actionEventSubscribers = new Set();
_onNavigationStateChange(prevNav, nav, action) {
if (typeof this.props.onNavigationStateChange === 'function') {
this.props.onNavigationStateChange(prevNav, nav, action);
}
}
componentDidUpdate() {
// Clear cached _navState every tick
if (this._navState === this.state.nav) {
this._navState = null;
}
}
async componentDidMount() {
// Initialize state. This must be done *after* any async code
// so we don't end up with a different value for this.state.nav
// due to changes while async function was resolving
let action = this._initialAction;
// eslint-disable-next-line react/no-access-state-in-setstate
let startupState = this.state.nav;
if (!startupState) {
startupState = Component.router.getStateForAction(action);
}
const dispatchActions = () =>
this._actionEventSubscribers.forEach((subscriber) =>
subscriber({
type: 'action',
action,
state: this.state.nav,
lastState: null,
})
);
if (startupState === this.state.nav) {
dispatchActions();
return;
}
// eslint-disable-next-line react/no-did-mount-set-state
this.setState({ nav: startupState }, () => {
dispatchActions();
});
}
dispatch = (action) => {
if (this.props.navigation) {
return this.props.navigation.dispatch(action);
}
// navState will have the most up-to-date value, because setState sometimes behaves asyncronously
this._navState = this._navState || this.state.nav;
const lastNavState = this._navState;
const reducedState = Component.router.getStateForAction(
action,
lastNavState
);
const navState = reducedState === null ? lastNavState : reducedState;
const dispatchActionEvents = () => {
this._actionEventSubscribers.forEach((subscriber) =>
subscriber({
type: 'action',
action,
state: navState,
lastState: lastNavState,
})
);
};
if (reducedState === null) {
// The router will return null when action has been handled and the state hasn't changed.
// dispatch returns true when something has been handled.
dispatchActionEvents();
return true;
}
if (navState !== lastNavState) {
// Cache updates to state.nav during the tick to ensure that subsequent calls will not discard this change
this._navState = navState;
this.setState({ nav: navState }, () => {
this._onNavigationStateChange(lastNavState, navState, action);
dispatchActionEvents();
});
return true;
}
dispatchActionEvents();
return false;
};
render() {
let navigation = this.props.navigation;
const navState = this.state.nav;
if (!navState) {
return null;
}
if (!this._navigation || this._navigation.state !== navState) {
this._navigation = getNavigation(
Component.router,
navState,
this.dispatch,
this._actionEventSubscribers,
this._getScreenProps,
() => this._navigation
);
}
navigation = this._navigation;
return (
<NavigationProvider value={navigation}>
<Component {...this.props} navigation={navigation} />
</NavigationProvider>
);
}
}
return NavigationContainer;
}

View File

@@ -0,0 +1,241 @@
import * as React from 'react';
import { render, act } from 'react-native-testing-library';
import { navigate } from '../NavigationActions';
import TabRouter from '../routers/TabRouter';
import createNavigator from '../navigators/createNavigator';
import createNavigationContainer from '../__fixtures__/createNavigationContainer';
it('fires focus and blur events in root navigator', async () => {
function createTestNavigator(routeConfigMap, config = {}) {
const router = TabRouter(routeConfigMap, config);
return createNavigator(
({ descriptors, navigation }) =>
navigation.state.routes.map((route) => {
const Comp = descriptors[route.key].getComponent();
return (
<Comp
key={route.key}
navigation={descriptors[route.key].navigation}
/>
);
}),
router,
config
);
}
const firstFocusCallback = jest.fn();
const firstBlurCallback = jest.fn();
const secondFocusCallback = jest.fn();
const secondBlurCallback = jest.fn();
const thirdFocusCallback = jest.fn();
const thirdBlurCallback = jest.fn();
const fourthFocusCallback = jest.fn();
const fourthBlurCallback = jest.fn();
const createComponent = (focusCallback, blurCallback) =>
class TestComponent extends React.Component {
componentDidMount() {
const { navigation } = this.props;
this.focusSub = navigation.addListener('willFocus', focusCallback);
this.blurSub = navigation.addListener('willBlur', blurCallback);
}
componentWillUnmount() {
this.focusSub?.remove();
this.blurSub?.remove();
}
render() {
return null;
}
};
const navigation = React.createRef();
const Navigator = createNavigationContainer(
createTestNavigator({
first: createComponent(firstFocusCallback, firstBlurCallback),
second: createComponent(secondFocusCallback, secondBlurCallback),
third: createComponent(thirdFocusCallback, thirdBlurCallback),
fourth: createComponent(fourthFocusCallback, fourthBlurCallback),
})
);
const element = <Navigator ref={navigation} />;
render(element);
expect(firstFocusCallback).toBeCalledTimes(1);
expect(firstBlurCallback).toBeCalledTimes(0);
expect(secondFocusCallback).toBeCalledTimes(0);
expect(secondBlurCallback).toBeCalledTimes(0);
expect(thirdFocusCallback).toBeCalledTimes(0);
expect(thirdBlurCallback).toBeCalledTimes(0);
expect(fourthFocusCallback).toBeCalledTimes(0);
expect(fourthBlurCallback).toBeCalledTimes(0);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'second' }));
});
expect(firstBlurCallback).toBeCalledTimes(1);
expect(secondFocusCallback).toBeCalledTimes(1);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'fourth' }));
});
expect(firstFocusCallback).toBeCalledTimes(1);
expect(firstBlurCallback).toBeCalledTimes(1);
expect(secondFocusCallback).toBeCalledTimes(1);
expect(secondBlurCallback).toBeCalledTimes(1);
expect(thirdFocusCallback).toBeCalledTimes(0);
expect(thirdBlurCallback).toBeCalledTimes(0);
expect(fourthFocusCallback).toBeCalledTimes(1);
expect(fourthBlurCallback).toBeCalledTimes(0);
});
it('fires focus and blur events in nested navigator', () => {
function createTestNavigator(routeConfigMap, config = {}) {
const router = TabRouter(routeConfigMap, config);
return createNavigator(
({ descriptors, navigation }) =>
navigation.state.routes.map((route) => {
const Comp = descriptors[route.key].getComponent();
return (
<Comp
key={route.key}
navigation={descriptors[route.key].navigation}
/>
);
}),
router,
config
);
}
const firstFocusCallback = jest.fn();
const firstBlurCallback = jest.fn();
const secondFocusCallback = jest.fn();
const secondBlurCallback = jest.fn();
const thirdFocusCallback = jest.fn();
const thirdBlurCallback = jest.fn();
const fourthFocusCallback = jest.fn();
const fourthBlurCallback = jest.fn();
const createComponent = (focusCallback, blurCallback) =>
class TestComponent extends React.Component {
componentDidMount() {
const { navigation } = this.props;
this.focusSub = navigation.addListener('willFocus', focusCallback);
this.blurSub = navigation.addListener('willBlur', blurCallback);
}
componentWillUnmount() {
this.focusSub?.remove();
this.blurSub?.remove();
}
render() {
return null;
}
};
const Navigator = createNavigationContainer(
createTestNavigator({
first: createComponent(firstFocusCallback, firstBlurCallback),
second: createComponent(secondFocusCallback, secondBlurCallback),
nested: createTestNavigator({
third: createComponent(thirdFocusCallback, thirdBlurCallback),
fourth: createComponent(fourthFocusCallback, fourthBlurCallback),
}),
})
);
const navigation = React.createRef();
const element = <Navigator ref={navigation} />;
render(element);
expect(thirdFocusCallback).toBeCalledTimes(0);
expect(firstFocusCallback).toBeCalledTimes(1);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'nested' }));
});
expect(firstFocusCallback).toBeCalledTimes(1);
expect(fourthFocusCallback).toBeCalledTimes(0);
expect(thirdFocusCallback).toBeCalledTimes(1);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'second' }));
});
expect(thirdFocusCallback).toBeCalledTimes(1);
expect(secondFocusCallback).toBeCalledTimes(1);
expect(fourthBlurCallback).toBeCalledTimes(0);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'nested' }));
});
expect(firstBlurCallback).toBeCalledTimes(1);
expect(secondBlurCallback).toBeCalledTimes(1);
expect(thirdFocusCallback).toBeCalledTimes(2);
expect(fourthFocusCallback).toBeCalledTimes(0);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'third' }));
});
expect(fourthBlurCallback).toBeCalledTimes(0);
expect(thirdFocusCallback).toBeCalledTimes(2);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'first' }));
});
expect(firstFocusCallback).toBeCalledTimes(2);
expect(thirdBlurCallback).toBeCalledTimes(2);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'fourth' }));
});
expect(fourthFocusCallback).toBeCalledTimes(1);
expect(thirdBlurCallback).toBeCalledTimes(2);
expect(firstBlurCallback).toBeCalledTimes(2);
act(() => {
navigation.current.dispatch(navigate({ routeName: 'third' }));
});
expect(thirdFocusCallback).toBeCalledTimes(3);
expect(fourthBlurCallback).toBeCalledTimes(1);
// Make sure nothing else has changed
expect(firstFocusCallback).toBeCalledTimes(2);
expect(firstBlurCallback).toBeCalledTimes(2);
expect(secondFocusCallback).toBeCalledTimes(1);
expect(secondBlurCallback).toBeCalledTimes(1);
expect(thirdFocusCallback).toBeCalledTimes(3);
expect(thirdBlurCallback).toBeCalledTimes(2);
expect(fourthFocusCallback).toBeCalledTimes(1);
expect(fourthBlurCallback).toBeCalledTimes(1);
});

View File

@@ -1,543 +0,0 @@
import getChildEventSubscriber from '../getChildEventSubscriber';
it('child action events only flow when focused', () => {
const parentSubscriber = jest.fn();
const emitParentAction = payload => {
parentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
parentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const testState = {
key: 'foo',
routeName: 'FooRoute',
routes: [{ key: 'key0' }, { key: 'key1' }],
index: 0,
isTransitioning: false,
};
const focusedTestState = {
...testState,
index: 1,
};
const childActionHandler = jest.fn();
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
childEventSubscriber('action', childActionHandler);
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
emitParentAction({
type: 'action',
state: focusedTestState,
lastState: testState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
emitParentAction({
type: 'action',
state: focusedTestState,
lastState: focusedTestState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(1);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
});
it('grandchildren subscription', () => {
const grandParentSubscriber = jest.fn();
const emitGrandParentAction = payload => {
grandParentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
grandParentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const parentSubscriber = getChildEventSubscriber(
grandParentSubscriber,
'parent'
).addListener;
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const parentBlurState = {
key: 'foo',
routeName: 'FooRoute',
routes: [
{ key: 'aunt' },
{
key: 'parent',
routes: [{ key: 'key0' }, { key: 'key1' }],
index: 1,
isTransitioning: false,
},
],
index: 0,
isTransitioning: false,
};
const parentTransitionState = {
...parentBlurState,
index: 1,
isTransitioning: true,
};
const parentFocusState = {
...parentTransitionState,
isTransitioning: false,
};
const childActionHandler = jest.fn();
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
childEventSubscriber('action', childActionHandler);
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
emitGrandParentAction({
type: 'action',
state: parentTransitionState,
lastState: parentBlurState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(0);
emitGrandParentAction({
type: 'action',
state: parentFocusState,
lastState: parentTransitionState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
});
it('grandchildren transitions', () => {
const grandParentSubscriber = jest.fn();
const emitGrandParentAction = payload => {
grandParentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
grandParentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const parentSubscriber = getChildEventSubscriber(
grandParentSubscriber,
'parent'
).addListener;
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const makeFakeState = (childIndex, childIsTransitioning) => ({
index: 1,
isTransitioning: false,
routes: [
{ key: 'nothing' },
{
key: 'parent',
index: childIndex,
isTransitioning: childIsTransitioning,
routes: [{ key: 'key0' }, { key: 'key1' }, { key: 'key2' }],
},
],
});
const blurredState = makeFakeState(0, false);
const transitionState = makeFakeState(1, true);
const focusState = makeFakeState(1, false);
const transition2State = makeFakeState(2, true);
const blurred2State = makeFakeState(2, false);
const childActionHandler = jest.fn();
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
const childWillBlurHandler = jest.fn();
const childDidBlurHandler = jest.fn();
childEventSubscriber('action', childActionHandler);
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
childEventSubscriber('willBlur', childWillBlurHandler);
childEventSubscriber('didBlur', childDidBlurHandler);
emitGrandParentAction({
type: 'action',
state: transitionState,
lastState: blurredState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(0);
emitGrandParentAction({
type: 'action',
state: focusState,
lastState: transitionState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: focusState,
lastState: focusState,
action: { type: 'TestAction' },
});
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
expect(childActionHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: transition2State,
lastState: focusState,
action: { type: 'CauseWillBlurAction' },
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
expect(childDidBlurHandler.mock.calls.length).toBe(0);
expect(childActionHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: blurred2State,
lastState: transition2State,
action: { type: 'CauseDidBlurAction' },
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
expect(childDidBlurHandler.mock.calls.length).toBe(1);
expect(childActionHandler.mock.calls.length).toBe(1);
});
it('grandchildren pass through transitions', () => {
const grandParentSubscriber = jest.fn();
const emitGrandParentAction = payload => {
grandParentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
grandParentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const parentSubscriber = getChildEventSubscriber(
grandParentSubscriber,
'parent'
).addListener;
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const makeFakeState = (childIndex, childIsTransitioning) => ({
index: childIndex,
isTransitioning: childIsTransitioning,
routes: [
{ key: 'nothing' },
{
key: 'parent',
index: 1,
isTransitioning: false,
routes: [{ key: 'key0' }, { key: 'key1' }, { key: 'key2' }],
},
].slice(0, childIndex + 1),
});
const blurredState = makeFakeState(0, false);
const transitionState = makeFakeState(1, true);
const focusState = makeFakeState(1, false);
const transition2State = makeFakeState(0, true);
const blurred2State = makeFakeState(0, false);
const childActionHandler = jest.fn();
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
const childWillBlurHandler = jest.fn();
const childDidBlurHandler = jest.fn();
childEventSubscriber('action', childActionHandler);
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
childEventSubscriber('willBlur', childWillBlurHandler);
childEventSubscriber('didBlur', childDidBlurHandler);
emitGrandParentAction({
type: 'action',
state: transitionState,
lastState: blurredState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(0);
emitGrandParentAction({
type: 'action',
state: focusState,
lastState: transitionState,
action: { type: 'FooAction' },
});
expect(childActionHandler.mock.calls.length).toBe(0);
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: focusState,
lastState: focusState,
action: { type: 'TestAction' },
});
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
expect(childActionHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: transition2State,
lastState: focusState,
action: { type: 'CauseWillBlurAction' },
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
expect(childDidBlurHandler.mock.calls.length).toBe(0);
expect(childActionHandler.mock.calls.length).toBe(1);
emitGrandParentAction({
type: 'action',
state: blurred2State,
lastState: transition2State,
action: { type: 'CauseDidBlurAction' },
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
expect(childDidBlurHandler.mock.calls.length).toBe(1);
expect(childActionHandler.mock.calls.length).toBe(1);
});
it('child focus with transition', () => {
const parentSubscriber = jest.fn();
const emitParentAction = payload => {
parentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
parentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const randomAction = { type: 'FooAction' };
const testState = {
key: 'foo',
routeName: 'FooRoute',
routes: [{ key: 'key0' }, { key: 'key1' }],
index: 0,
isTransitioning: false,
};
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
const childWillBlurHandler = jest.fn();
const childDidBlurHandler = jest.fn();
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
childEventSubscriber('willBlur', childWillBlurHandler);
childEventSubscriber('didBlur', childDidBlurHandler);
emitParentAction({
type: 'didFocus',
action: randomAction,
lastState: testState,
state: testState,
});
emitParentAction({
type: 'action',
action: randomAction,
lastState: testState,
state: {
...testState,
index: 1,
isTransitioning: true,
},
});
expect(childWillFocusHandler.mock.calls.length).toBe(1);
emitParentAction({
type: 'action',
action: randomAction,
lastState: {
...testState,
index: 1,
isTransitioning: true,
},
state: {
...testState,
index: 1,
isTransitioning: false,
},
});
expect(childDidFocusHandler.mock.calls.length).toBe(1);
emitParentAction({
type: 'action',
action: randomAction,
lastState: {
...testState,
index: 1,
isTransitioning: false,
},
state: {
...testState,
index: 0,
isTransitioning: true,
},
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
emitParentAction({
type: 'action',
action: randomAction,
lastState: {
...testState,
index: 0,
isTransitioning: true,
},
state: {
...testState,
index: 0,
isTransitioning: false,
},
});
expect(childDidBlurHandler.mock.calls.length).toBe(1);
});
it('child focus with immediate transition', () => {
const parentSubscriber = jest.fn();
const emitParentAction = payload => {
parentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
parentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const childEventSubscriber = getChildEventSubscriber(parentSubscriber, 'key1')
.addListener;
const randomAction = { type: 'FooAction' };
const testState = {
key: 'foo',
routeName: 'FooRoute',
routes: [{ key: 'key0' }, { key: 'key1' }],
index: 0,
isTransitioning: false,
};
const childWillFocusHandler = jest.fn();
const childDidFocusHandler = jest.fn();
const childWillBlurHandler = jest.fn();
const childDidBlurHandler = jest.fn();
childEventSubscriber('willFocus', childWillFocusHandler);
childEventSubscriber('didFocus', childDidFocusHandler);
childEventSubscriber('willBlur', childWillBlurHandler);
childEventSubscriber('didBlur', childDidBlurHandler);
emitParentAction({
type: 'didFocus',
action: randomAction,
lastState: testState,
state: testState,
});
emitParentAction({
type: 'action',
action: randomAction,
lastState: testState,
state: {
...testState,
index: 1,
},
});
expect(childWillFocusHandler.mock.calls.length).toBe(1);
expect(childDidFocusHandler.mock.calls.length).toBe(1);
emitParentAction({
type: 'action',
action: randomAction,
lastState: {
...testState,
index: 1,
},
state: {
...testState,
index: 0,
},
});
expect(childWillBlurHandler.mock.calls.length).toBe(1);
expect(childDidBlurHandler.mock.calls.length).toBe(1);
});
const setupEventTest = (subscriptionKey, initialLastFocusEvent) => {
const parentSubscriber = jest.fn();
const emitEvent = payload => {
parentSubscriber.mock.calls.forEach(subs => {
if (subs[0] === payload.type) {
subs[1](payload);
}
});
};
const subscriptionRemove = () => {};
parentSubscriber.mockReturnValueOnce({ remove: subscriptionRemove });
const evtProvider = getChildEventSubscriber(
parentSubscriber,
subscriptionKey,
initialLastFocusEvent
);
const handlers = {};
evtProvider.addListener('action', (handlers.action = jest.fn()));
evtProvider.addListener('willFocus', (handlers.willFocus = jest.fn()));
evtProvider.addListener('didFocus', (handlers.didFocus = jest.fn()));
evtProvider.addListener('willBlur', (handlers.willBlur = jest.fn()));
evtProvider.addListener('didBlur', (handlers.didBlur = jest.fn()));
return { emitEvent, handlers, evtProvider };
};
it('immediate back with uncompleted transition will focus first screen again', () => {
const { handlers, emitEvent } = setupEventTest('key0', 'didFocus');
emitEvent({
type: 'action',
state: {
index: 1,
routes: [{ key: 'key0' }, { key: 'key1' }],
isTransitioning: true,
},
lastState: {
index: 0,
routes: [{ key: 'key0' }],
isTransitioning: false,
},
action: { type: 'Any action, does not matter here' },
});
expect(handlers.willFocus.mock.calls.length).toBe(0);
expect(handlers.didFocus.mock.calls.length).toBe(0);
expect(handlers.willBlur.mock.calls.length).toBe(1);
expect(handlers.didBlur.mock.calls.length).toBe(0);
emitEvent({
type: 'action',
state: {
index: 0,
routes: [{ key: 'key0' }],
isTransitioning: true,
},
lastState: {
index: 1,
routes: [{ key: 'key0' }, { key: 'key1' }],
isTransitioning: true,
},
action: { type: 'Any action, does not matter here' },
});
expect(handlers.willFocus.mock.calls.length).toBe(1);
expect(handlers.didFocus.mock.calls.length).toBe(0);
expect(handlers.willBlur.mock.calls.length).toBe(1);
expect(handlers.didBlur.mock.calls.length).toBe(0);
emitEvent({
type: 'action',
state: {
index: 0,
routes: [{ key: 'key0' }],
isTransitioning: false,
},
lastState: {
index: 0,
routes: [{ key: 'key0' }],
isTransitioning: true,
},
action: { type: 'Any action, does not matter here' },
});
expect(handlers.willFocus.mock.calls.length).toBe(1);
expect(handlers.didFocus.mock.calls.length).toBe(1);
expect(handlers.willBlur.mock.calls.length).toBe(1);
expect(handlers.didBlur.mock.calls.length).toBe(0);
});

View File

@@ -30,7 +30,7 @@ it('getNavigation provides default action helpers', () => {
it.skip('getNavigation provides router action helpers', () => {
const router = {
getActionCreators: () => ({
foo: bar => ({ type: 'FooBarAction', bar }),
foo: (bar) => ({ type: 'FooBarAction', bar }),
}),
getStateForAction(action, lastState = {}) {
return lastState;

View File

@@ -1,196 +0,0 @@
/*
* This is used to extract one children's worth of events from a stream of navigation action events
*
* Based on the 'action' events that get fired for this navigation state, this utility will fire
* focus and blur events for this child
*/
export default function getChildEventSubscriber(
addListener,
key,
initialLastFocusEvent = 'didBlur'
) {
const actionSubscribers = new Set();
const willFocusSubscribers = new Set();
const didFocusSubscribers = new Set();
const willBlurSubscribers = new Set();
const didBlurSubscribers = new Set();
const refocusSubscribers = new Set();
const removeAll = () => {
[
actionSubscribers,
willFocusSubscribers,
didFocusSubscribers,
willBlurSubscribers,
didBlurSubscribers,
refocusSubscribers,
].forEach(set => set.clear());
upstreamSubscribers.forEach(subs => subs && subs.remove());
};
const getChildSubscribers = evtName => {
switch (evtName) {
case 'action':
return actionSubscribers;
case 'willFocus':
return willFocusSubscribers;
case 'didFocus':
return didFocusSubscribers;
case 'willBlur':
return willBlurSubscribers;
case 'didBlur':
return didBlurSubscribers;
case 'refocus':
return refocusSubscribers;
default:
return null;
}
};
const emit = (type, payload) => {
const payloadWithType = { ...payload, type };
const subscribers = getChildSubscribers(type);
subscribers &&
subscribers.forEach(subs => {
subs(payloadWithType);
});
};
// lastFocusEvent keeps track of focus state for one route. First we assume
// we are blurred. If we are focused on initialization, the first 'action'
// event will cause onFocus+willFocus events because we had previously been
// considered blurred
let lastFocusEvent = initialLastFocusEvent;
const upstreamEvents = [
'willFocus',
'didFocus',
'willBlur',
'didBlur',
'refocus',
'action',
];
const upstreamSubscribers = upstreamEvents.map(eventName =>
addListener(eventName, payload => {
if (eventName === 'refocus') {
emit(eventName, payload);
return;
}
const { state, lastState, action } = payload;
const lastRoutes = lastState && lastState.routes;
const routes = state && state.routes;
// const lastFocusKey =
// lastState && lastState.routes && lastState.routes[lastState.index].key;
const focusKey = routes && routes[state.index].key;
const isChildFocused = focusKey === key;
const lastRoute =
lastRoutes && lastRoutes.find(route => route.key === key);
const newRoute = routes && routes.find(route => route.key === key);
const childPayload = {
context: `${key}:${action.type}_${payload.context || 'Root'}`,
state: newRoute,
lastState: lastRoute,
action,
type: eventName,
};
const isTransitioning = !!state && state.isTransitioning;
const previouslylastFocusEvent = lastFocusEvent;
if (lastFocusEvent === 'didBlur') {
// The child is currently blurred. Look for willFocus conditions
if (eventName === 'willFocus' && isChildFocused) {
emit((lastFocusEvent = 'willFocus'), childPayload);
} else if (eventName === 'action' && isChildFocused) {
emit((lastFocusEvent = 'willFocus'), childPayload);
}
}
if (lastFocusEvent === 'willFocus') {
// We are currently mid-focus. Look for didFocus conditions.
// If state.isTransitioning is false, this child event happens immediately after willFocus
if (eventName === 'didFocus' && isChildFocused && !isTransitioning) {
emit((lastFocusEvent = 'didFocus'), childPayload);
} else if (
eventName === 'action' &&
isChildFocused &&
!isTransitioning
) {
emit((lastFocusEvent = 'didFocus'), childPayload);
}
}
if (lastFocusEvent === 'didFocus') {
// The child is currently focused. Look for blurring events
if (!isChildFocused) {
// The child is no longer focused within this navigation state
emit((lastFocusEvent = 'willBlur'), childPayload);
} else if (eventName === 'willBlur') {
// The parent is getting a willBlur event
emit((lastFocusEvent = 'willBlur'), childPayload);
} else if (
eventName === 'action' &&
previouslylastFocusEvent === 'didFocus'
) {
// While focused, pass action events to children for grandchildren focus
emit('action', childPayload);
}
}
if (lastFocusEvent === 'willBlur') {
// The child is mid-blur. Wait for transition to end
if (eventName === 'action' && !isChildFocused && !isTransitioning) {
// The child is done blurring because transitioning is over, or isTransitioning
// never began and didBlur fires immediately after willBlur
emit((lastFocusEvent = 'didBlur'), childPayload);
} else if (eventName === 'didBlur') {
// Pass through the parent didBlur event if it happens
emit((lastFocusEvent = 'didBlur'), childPayload);
} else if (
eventName === 'action' &&
isChildFocused &&
!isTransitioning
) {
emit((lastFocusEvent = 'didFocus'), childPayload);
} else if (
eventName === 'action' &&
isChildFocused &&
isTransitioning
) {
emit((lastFocusEvent = 'willFocus'), childPayload);
}
}
if (lastFocusEvent === 'didBlur' && !newRoute) {
removeAll();
}
})
);
return {
addListener(eventName, eventHandler) {
const subscribers = getChildSubscribers(eventName);
if (!subscribers) {
throw new Error(`Invalid event name "${eventName}"`);
}
subscribers.add(eventHandler);
const remove = () => {
subscribers.delete(eventHandler);
};
return { remove };
},
emit(eventName, payload) {
if (eventName !== 'refocus') {
console.error(
`navigation.emit only supports the 'refocus' event currently.`
);
return;
}
emit(eventName, payload);
},
};
}

View File

@@ -1,9 +1,9 @@
import getChildEventSubscriber from './getChildEventSubscriber';
import getChildRouter from './getChildRouter';
import getNavigationActionCreators from './routers/getNavigationActionCreators';
import getChildrenNavigationCache from './getChildrenNavigationCache';
import getEventManager from './getEventManager';
const createParamGetter = route => (paramName, defaultValue) => {
const createParamGetter = (route) => (paramName, defaultValue) => {
const params = route.params;
if (params && paramName in params) {
@@ -15,7 +15,7 @@ const createParamGetter = route => (paramName, defaultValue) => {
function getChildNavigation(navigation, childKey, getCurrentParentNavigation) {
const children = getChildrenNavigationCache(navigation);
const childRoute = navigation.state.routes.find(r => r.key === childKey);
const childRoute = navigation.state.routes.find((r) => r.key === childKey);
if (!childRoute) {
return null;
@@ -47,7 +47,7 @@ function getChildNavigation(navigation, childKey, getCurrentParentNavigation) {
};
const actionHelpers = {};
Object.keys(actionCreators).forEach(actionName => {
Object.keys(actionCreators).forEach((actionName) => {
actionHelpers[actionName] = (...args) => {
const actionCreator = actionCreators[actionName];
const action = actionCreator(...args);
@@ -78,10 +78,7 @@ function getChildNavigation(navigation, childKey, getCurrentParentNavigation) {
};
return children[childKey];
} else {
const childSubscriber = getChildEventSubscriber(
navigation.addListener,
childKey
);
const { addListener, emit } = getEventManager(childKey);
children[childKey] = {
...actionHelpers,
@@ -91,7 +88,7 @@ function getChildNavigation(navigation, childKey, getCurrentParentNavigation) {
actions: actionCreators,
getParam: createParamGetter(childRoute),
getChildNavigation: grandChildKey =>
getChildNavigation: (grandChildKey) =>
getChildNavigation(children[childKey], grandChildKey, () => {
const nav = getCurrentParentNavigation();
return nav && nav.getChildNavigation(childKey);
@@ -115,9 +112,10 @@ function getChildNavigation(navigation, childKey, getCurrentParentNavigation) {
dispatch: navigation.dispatch,
getScreenProps: navigation.getScreenProps,
dangerouslyGetParent: getCurrentParentNavigation,
addListener: childSubscriber.addListener,
emit: childSubscriber.emit,
addListener,
emit,
};
return children[childKey];
}
}

View File

@@ -5,8 +5,8 @@ export default function getChildrenNavigationCache(navigation) {
let childrenNavigationCache =
navigation._childrenNavigation || (navigation._childrenNavigation = {});
let childKeys = navigation.state.routes.map(route => route.key);
Object.keys(childrenNavigationCache).forEach(cacheKey => {
let childKeys = navigation.state.routes.map((route) => route.key);
Object.keys(childrenNavigationCache).forEach((cacheKey) => {
if (!childKeys.includes(cacheKey) && !navigation.state.isTransitioning) {
delete childrenNavigationCache[cacheKey];
}

View File

@@ -0,0 +1,61 @@
// @ts-check
/**
* @param {string} target
*/
export default function getEventManager(target) {
/**
* @type {Record<string, Record<string, ((e: any) => void)[]>>}
*/
const listeners = {};
/**
* @param {string} type
* @param {() => void} callback
*/
const removeListener = (type, callback) => {
const callbacks = listeners[type] ? listeners[type][target] : undefined;
if (!callbacks) {
return;
}
const index = callbacks.indexOf(callback);
callbacks.splice(index, 1);
};
/**
* @param {string} type
* @param {() => void} callback
*/
const addListener = (type, callback) => {
listeners[type] = listeners[type] || {};
listeners[type][target] = listeners[type][target] || [];
listeners[type][target].push(callback);
return {
remove: () => removeListener(type, callback),
};
};
return {
addListener,
/**
* @param {string} type
* @param {any} [data]
*/
emit: (type, data) => {
const items = listeners[type] || {};
/**
* Copy the current list of callbacks in case they are mutated during execution
* @type {((data: any) => void)[] | undefined}
*/
const callbacks = items[target] && items[target].slice();
callbacks?.forEach((cb) => cb(data));
},
};
}

View File

@@ -18,9 +18,9 @@ export default function getNavigation(
state,
dispatch,
getScreenProps,
getChildNavigation: childKey =>
getChildNavigation: (childKey) =>
getChildNavigation(navigation, childKey, getCurrentNavigation),
isFocused: childKey => {
isFocused: (childKey) => {
const { routes, index } = getCurrentNavigation().state;
if (childKey == null || routes[index].key === childKey) {
return true;
@@ -48,7 +48,7 @@ export default function getNavigation(
...actions,
};
Object.keys(actionCreators).forEach(actionName => {
Object.keys(actionCreators).forEach((actionName) => {
navigation[actionName] = (...args) =>
navigation.dispatch(actionCreators[actionName](...args));
});

View File

@@ -4,8 +4,8 @@ import { render, fireEvent } from 'react-native-testing-library';
import { createAppContainer } from '@react-navigation/native';
import createSwitchNavigator from '../createSwitchNavigator';
const getActiveRouteName = state => state.routes[state.index].routeName;
const createScreen = (routeName, nextRouteName) => props => (
const getActiveRouteName = (state) => state.routes[state.index].routeName;
const createScreen = (routeName, nextRouteName) => (props) => (
<View>
<Text testID="title">{routeName}</Text>
<Text testID={routeName + '-isFirstRoute'}>

View File

@@ -1,6 +1,7 @@
import React from 'react';
import * as React from 'react';
import invariant from '../utils/invariant';
import ThemeContext from '../views/ThemeContext';
import NavigationFocusEvents from '../views/NavigationFocusEvents';
function createNavigator(NavigatorView, router, navigationConfig) {
class Navigator extends React.Component {
@@ -78,13 +79,21 @@ function createNavigator(NavigatorView, router, navigationConfig) {
render() {
return (
<NavigatorView
{...this.props}
screenProps={this.state.screenProps}
navigation={this.props.navigation}
navigationConfig={navigationConfig}
descriptors={this.state.descriptors}
/>
<React.Fragment>
<NavigationFocusEvents
navigation={this.props.navigation}
onEvent={(target, type, data) => {
this.state.descriptors[target]?.navigation.emit(type, data);
}}
/>
<NavigatorView
{...this.props}
screenProps={this.state.screenProps}
navigation={this.props.navigation}
navigationConfig={navigationConfig}
descriptors={this.state.descriptors}
/>
</React.Fragment>
);
}
}

View File

@@ -5,33 +5,33 @@ export const RESET = 'Navigation/RESET';
export const REPLACE = 'Navigation/REPLACE';
export const COMPLETE_TRANSITION = 'Navigation/COMPLETE_TRANSITION';
export const pop = payload => ({
export const pop = (payload) => ({
type: POP,
...payload,
});
export const popToTop = payload => ({
export const popToTop = (payload) => ({
type: POP_TO_TOP,
...payload,
});
export const push = payload => ({
export const push = (payload) => ({
type: PUSH,
...payload,
});
export const reset = payload => ({
export const reset = (payload) => ({
type: RESET,
key: null,
...payload,
});
export const replace = payload => ({
export const replace = (payload) => ({
type: REPLACE,
...payload,
});
export const completeTransition = payload => ({
export const completeTransition = (payload) => ({
type: COMPLETE_TRANSITION,
preserveFocus: true,
...payload,

View File

@@ -29,7 +29,7 @@ export default (routeConfigs, stackConfig = {}) => {
const routeNames = Object.keys(routeConfigs);
// Loop through routes and find child routers
routeNames.forEach(routeName => {
routeNames.forEach((routeName) => {
// We're not using `getScreenForRouteName` here to preserve the lazy loading
// behaviour of routes. This means that routes with child routers must be
// defined using a component directly or with an object with a screen prop.
@@ -152,7 +152,7 @@ export default (routeConfigs, stackConfig = {}) => {
n,
...params,
}),
popToTop: params => StackActions.popToTop(params),
popToTop: (params) => StackActions.popToTop(params),
push: (routeName, params, action) =>
StackActions.push({
routeName,
@@ -280,7 +280,7 @@ export default (routeConfigs, stackConfig = {}) => {
// Before pushing a new route we first try to find one in the existing route stack
// More information on this: https://github.com/react-navigation/rfcs/blob/master/text/0004-less-pushy-navigate.md
const lastRouteIndex = state.routes.findIndex(r => {
const lastRouteIndex = state.routes.findIndex((r) => {
if (action.key) {
return r.key === action.key;
} else {
@@ -425,7 +425,7 @@ export default (routeConfigs, stackConfig = {}) => {
if (action.key === undefined && state.routes.length) {
routeIndex = state.routes.length - 1;
} else {
routeIndex = state.routes.findIndex(r => r.key === action.key);
routeIndex = state.routes.findIndex((r) => r.key === action.key);
}
// Only replace if the key matches one of our routes
@@ -467,7 +467,7 @@ export default (routeConfigs, stackConfig = {}) => {
if (action.type === NavigationActions.SET_PARAMS) {
const key = action.key;
const lastRoute = state.routes.find(route => route.key === key);
const lastRoute = state.routes.find((route) => route.key === key);
if (lastRoute) {
const params = {
...lastRoute.params,
@@ -496,7 +496,7 @@ export default (routeConfigs, stackConfig = {}) => {
return {
...state,
routes: newStackActions.map(newStackAction => {
routes: newStackActions.map((newStackAction) => {
const router = childRouters[newStackAction.routeName];
let childState = {};
@@ -532,24 +532,46 @@ export default (routeConfigs, stackConfig = {}) => {
action.type === NavigationActions.BACK ||
action.type === StackActions.POP
) {
const { key, n, immediate } = action;
let backRouteIndex = state.index;
if (action.type === StackActions.POP && n != null) {
// determine the index to go back *from*. In this case, n=1 means to go
// back from state.index, as if it were a normal "BACK" action
backRouteIndex = Math.max(1, state.index - n + 1);
} else if (key) {
const backRoute = state.routes.find(route => route.key === key);
backRouteIndex = state.routes.indexOf(backRoute);
}
const { key, n, immediate, prune } = action;
if (backRouteIndex > 0) {
return {
...state,
routes: state.routes.slice(0, backRouteIndex),
index: backRouteIndex - 1,
isTransitioning: immediate !== true,
};
if (action.type === StackActions.POP && prune === false && key) {
const index = state.routes.findIndex((r) => r.key === key);
if (index > 0) {
const count = Math.max(index - (n ?? 1) + 1, 1);
const routes = state.routes
.slice(0, count)
.concat(state.routes.slice(index + 1));
if (routes.length) {
return {
...state,
routes,
index: routes.length - 1,
isTransitioning: immediate !== true,
};
}
}
} else {
let backRouteIndex = state.index;
if (action.type === StackActions.POP && n != null) {
// determine the index to go back *from*. In this case, n=1 means to go
// back from state.index, as if it were a normal "BACK" action
backRouteIndex = Math.max(1, state.index - n + 1);
} else if (key) {
const backRoute = state.routes.find((route) => route.key === key);
backRouteIndex = state.routes.indexOf(backRoute);
}
if (backRouteIndex > 0) {
return {
...state,
routes: state.routes.slice(0, backRouteIndex),
index: backRouteIndex - 1,
isTransitioning: immediate !== true,
};
}
}
}

View File

@@ -30,12 +30,12 @@ export default (routeConfigs, config = {}) => {
if (initialRouteIndex === -1) {
throw new Error(
`Invalid initialRouteName '${initialRouteName}'.` +
`Should be one of ${order.map(n => `"${n}"`).join(', ')}`
`Should be one of ${order.map((n) => `"${n}"`).join(', ')}`
);
}
const childRouters = {};
order.forEach(routeName => {
order.forEach((routeName) => {
childRouters[routeName] = null;
const screen = getScreenForRouteName(routeConfigs, routeName);
if (screen.router) {
@@ -93,7 +93,7 @@ export default (routeConfigs, config = {}) => {
if (action.type === NavigationActions.NAVIGATE) {
nextRouteKeyHistory = [...nextRouteKeyHistory]; // copy
const keyToAdd = nextState.routes[nextState.index].key;
nextRouteKeyHistory = nextRouteKeyHistory.filter(k => k !== keyToAdd); // dedup
nextRouteKeyHistory = nextRouteKeyHistory.filter((k) => k !== keyToAdd); // dedup
nextRouteKeyHistory.push(keyToAdd);
} else if (action.type === NavigationActions.BACK) {
nextRouteKeyHistory = [...nextRouteKeyHistory]; // copy
@@ -128,8 +128,8 @@ export default (routeConfigs, config = {}) => {
const initialState = {
routes,
index: initialRouteIndex,
isTransitioning: false,
};
if (backBehavior === 'history') {
const initialKey = routes[initialRouteIndex].key;
initialState['routeKeyHistory'] = [initialKey];
@@ -156,7 +156,7 @@ export default (routeConfigs, config = {}) => {
// Merge any params from the action into all the child routes
const { params } = action;
if (params) {
state.routes = state.routes.map(route => ({
state.routes = state.routes.map((route) => ({
...route,
params: {
...route.params,
@@ -175,14 +175,14 @@ export default (routeConfigs, config = {}) => {
) {
const { params } = action;
const index = state.routes.findIndex(
route => route.routeName === action.routeName
(route) => route.routeName === action.routeName
);
if (index === -1) {
throw new Error(
`There is no route named '${action.routeName}' in the navigator with the key '${action.key}'.\n` +
`Must be one of: ${state.routes
.map(route => `'${route.routeName}'`)
.map((route) => `'${route.routeName}'`)
.join(',')}`
);
}
@@ -305,7 +305,7 @@ export default (routeConfigs, config = {}) => {
if (action.type === NavigationActions.SET_PARAMS) {
const key = action.key;
const lastRoute = state.routes.find(route => route.key === key);
const lastRoute = state.routes.find((route) => route.key === key);
if (lastRoute) {
const params = {
...lastRoute.params,

View File

@@ -12,7 +12,7 @@ beforeEach(() => {
_TESTING_ONLY_normalize_keys();
});
const performRouterTest = createTestRouter => {
const performRouterTest = (createTestRouter) => {
const ListScreen = () => <div />;
const ProfileNavigator = () => <div />;
@@ -584,7 +584,7 @@ it('Handles nested switch routers', () => {
expect(action.action.routeName).toEqual('B');
});
const performRouteNameAsPathDisabledTest = createTestRouter => {
const performRouteNameAsPathDisabledTest = (createTestRouter) => {
const BScreen = () => <div />;
const NestedNavigator = () => <div />;
NestedNavigator.router = createTestRouter({

View File

@@ -24,7 +24,7 @@ const dummyEventSubscriber = () => ({
remove: () => {},
});
Object.keys(ROUTERS).forEach(routerName => {
Object.keys(ROUTERS).forEach((routerName) => {
const Router = ROUTERS[routerName];
describe(`General router features - ${routerName}`, () => {
@@ -441,7 +441,7 @@ it('Inner actions are only unpacked if the current tab matches', () => {
routes: [screenApreState],
};
const comparable = state => {
const comparable = (state) => {
let result = {};
if (typeof state.routeName === 'string') {
result = { ...result, routeName: state.routeName };

View File

@@ -562,6 +562,31 @@ describe('StackRouter', () => {
expect(poppedState3.routes.length).toBe(1);
expect(poppedState3.index).toBe(0);
expect(poppedState3.isTransitioning).toBe(true);
const poppedState4 = TestRouter.getStateForAction(
StackActions.pop({ key: 'C', prune: false, immediate: true }),
state
);
expect(poppedState4.routes.length).toBe(3);
expect(poppedState4.index).toBe(2);
expect(poppedState4.isTransitioning).toBe(false);
expect(poppedState4.routes).toEqual([
{ key: 'A', routeName: 'foo' },
{ key: 'B', routeName: 'bar', params: { bazId: '321' } },
{ key: 'D', routeName: 'bar' },
]);
const poppedState5 = TestRouter.getStateForAction(
StackActions.pop({ n: 2, key: 'C', prune: false }),
state
);
expect(poppedState5.routes.length).toBe(2);
expect(poppedState5.index).toBe(1);
expect(poppedState5.isTransitioning).toBe(true);
expect(poppedState5.routes).toEqual([
{ key: 'A', routeName: 'foo' },
{ key: 'D', routeName: 'bar' },
]);
});
it('popToTop works as expected', () => {

View File

@@ -26,7 +26,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
],
isTransitioning: false,
};
expect(state).toEqual(expectedState);
const state2 = router.getStateForAction(
@@ -39,7 +38,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
],
isTransitioning: false,
};
expect(state2).toEqual(expectedState2);
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
@@ -65,7 +63,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
],
isTransitioning: false,
};
expect(state).toEqual(expectedState);
const state2 = router.getStateForAction(
@@ -78,7 +75,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
],
isTransitioning: false,
};
expect(state2).toEqual(expectedState2);
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
@@ -102,7 +98,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
],
isTransitioning: false,
});
});
@@ -118,7 +113,6 @@ describe('TabRouter', () => {
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar', params: { name: 'Qux' } },
],
isTransitioning: false,
});
});
@@ -230,7 +224,7 @@ describe('TabRouter', () => {
const state = router.getStateForAction(navAction);
expect(state).toEqual({
index: 1,
isTransitioning: false,
routes: [
{
key: 'Foo',
@@ -238,7 +232,7 @@ describe('TabRouter', () => {
},
{
index: 1,
isTransitioning: false,
key: 'Baz',
routeName: 'Baz',
params: { foo: '42' },
@@ -281,14 +275,14 @@ describe('TabRouter', () => {
let state = router.getStateForAction(navAction);
expect(state).toEqual({
index: 1,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{
index: 0,
key: 'Baz',
routeName: 'Baz',
isTransitioning: false,
routes: [
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Bar', routeName: 'Bar' },
@@ -308,7 +302,7 @@ describe('TabRouter', () => {
);
expect(state && state.routes[1]).toEqual({
index: 0,
isTransitioning: false,
key: 'Baz',
routeName: 'Baz',
routes: [
@@ -335,14 +329,14 @@ describe('TabRouter', () => {
});
expect(state).toEqual({
index: 1,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{
index: 1,
key: 'Baz',
routeName: 'Baz',
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
@@ -357,14 +351,14 @@ describe('TabRouter', () => {
);
expect(state2).toEqual({
index: 1,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{
index: 0,
key: 'Baz',
routeName: 'Baz',
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
@@ -403,19 +397,19 @@ describe('TabRouter', () => {
const state = router.getStateForAction(INIT_ACTION);
expect(state).toEqual({
index: 0,
isTransitioning: false,
routes: [
{
index: 0,
key: 'Foo',
routeName: 'Foo',
isTransitioning: false,
routes: [
{
index: 0,
key: 'Fee',
routeName: 'Fee',
isTransitioning: false,
routes: [
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Baz', routeName: 'Baz' },
@@ -425,7 +419,7 @@ describe('TabRouter', () => {
index: 0,
key: 'Bar',
routeName: 'Bar',
isTransitioning: false,
routes: [
{ key: 'Zoo', routeName: 'Zoo' },
{ key: 'Zap', routeName: 'Zap' },
@@ -442,19 +436,19 @@ describe('TabRouter', () => {
);
expect(state2).toEqual({
index: 0,
isTransitioning: false,
routes: [
{
index: 1,
key: 'Foo',
routeName: 'Foo',
isTransitioning: false,
routes: [
{
index: 0,
key: 'Fee',
routeName: 'Fee',
isTransitioning: false,
routes: [
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Baz', routeName: 'Baz' },
@@ -464,7 +458,7 @@ describe('TabRouter', () => {
index: 1,
key: 'Bar',
routeName: 'Bar',
isTransitioning: false,
routes: [
{ key: 'Zoo', routeName: 'Zoo' },
{ key: 'Zap', routeName: 'Zap' },
@@ -494,19 +488,19 @@ describe('TabRouter', () => {
});
expect(state4).toEqual({
index: 0,
isTransitioning: false,
routes: [
{
index: 1,
key: 'Foo',
routeName: 'Foo',
isTransitioning: false,
routes: [
{
index: 0,
key: 'Fee',
routeName: 'Fee',
isTransitioning: false,
routes: [
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Baz', routeName: 'Baz' },
@@ -516,7 +510,7 @@ describe('TabRouter', () => {
index: 1,
key: 'Bar',
routeName: 'Bar',
isTransitioning: false,
routes: [
{ key: 'Zoo', routeName: 'Zoo' },
{ key: 'Zap', routeName: 'Zap' },
@@ -557,7 +551,7 @@ describe('TabRouter', () => {
const state = router.getStateForAction({ type: NavigationActions.INIT });
const expectedState = {
index: 0,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo' },
{ key: 'Bar', routeName: 'Bar' },
@@ -567,7 +561,7 @@ describe('TabRouter', () => {
const state2 = router.getStateForAction(expectedAction, state);
const expectedState2 = {
index: 1,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo', params: undefined },
{
@@ -628,13 +622,13 @@ describe('TabRouter', () => {
const state = {
index: 0,
isTransitioning: false,
routes: [
{
index: 1,
key: 'Foo',
routeName: 'Foo',
isTransitioning: false,
routes: [
{ key: 'Boo', routeName: 'Boo' },
{ key: 'Baz', routeName: 'Baz' },
@@ -660,7 +654,7 @@ describe('TabRouter', () => {
expect(state0).toEqual({
index: 0,
isTransitioning: false,
routes: [
{ key: 'a', routeName: 'a' },
{ key: 'b', routeName: 'b' },
@@ -676,7 +670,7 @@ describe('TabRouter', () => {
expect(state1).toEqual({
index: 1,
isTransitioning: false,
routes: [
{ key: 'a', routeName: 'a' },
{ key: 'b', routeName: 'b', params },
@@ -765,17 +759,17 @@ describe('TabRouter', () => {
const screenApreState = {
index: 0,
key: 'Foo',
isTransitioning: false,
routeName: 'Foo',
routes: [{ key: 'Bar', routeName: 'Bar' }],
};
const preState = {
index: 0,
isTransitioning: false,
routes: [screenApreState],
};
const comparable = state => {
const comparable = (state) => {
let result = {};
if (typeof state.routeName === 'string') {
result = { ...result, routeName: state.routeName };

View File

@@ -17,7 +17,7 @@ export const getRouterTestHelper = (router, options = defaultOptions) => {
? undefined
: router.getStateForAction({ type: NavigationActions.INIT });
const applyAction = action => {
const applyAction = (action) => {
state = router.getStateForAction(action, state);
};
@@ -35,7 +35,7 @@ export const getRouterTestHelper = (router, options = defaultOptions) => {
...otherActionAttributes,
});
const back = key =>
const back = (key) =>
applyAction({
type: NavigationActions.BACK,
key,

View File

@@ -13,7 +13,7 @@ export default function getScreenForRouteName(routeConfigs, routeName) {
throw new Error(
`There is no route defined for key ${routeName}.\n` +
`Must be one of: ${Object.keys(routeConfigs)
.map(a => `'${a}'`)
.map((a) => `'${a}'`)
.join(',')}`
);
}

View File

@@ -36,7 +36,7 @@ export const getParamsFromPath = (inputParams, pathMatch, pathMatchKeys) => {
return params;
};
const getRestOfPath = (pathMatch, pathMatchKeys) => {
const rest = pathMatch[pathMatchKeys.findIndex(k => k.asterisk) + 1];
const rest = pathMatch[pathMatchKeys.findIndex((k) => k.asterisk) + 1];
return rest;
};
@@ -81,7 +81,7 @@ export const createPathParser = (
let paths = [];
// Build pathsByRouteNames, which includes a regex to match paths for each route. Keep in mind, the regex will pass for the route and all child routes. The code that uses pathsByRouteNames will need to also verify that the child router produces an action, in the case of isPathMatchable false (a null path).
Object.keys(childRouters).forEach(routeName => {
Object.keys(childRouters).forEach((routeName) => {
let pathPattern;
// First check for paths on the router, then check the route config
@@ -189,7 +189,7 @@ export const createPathParser = (
return null;
};
const getPathAndParamsForRoute = route => {
const getPathAndParamsForRoute = (route) => {
const { routeName, params } = route;
const childRouter = childRouters[routeName];
const { toPath, exactReKeys } = pathsByRouteNames[routeName];
@@ -197,8 +197,8 @@ export const createPathParser = (
const nonPathParams = {};
if (params) {
Object.keys(params)
.filter(paramName => !exactReKeys.find(k => k.name === paramName))
.forEach(paramName => {
.filter((paramName) => !exactReKeys.find((k) => k.name === paramName))
.forEach((paramName) => {
nonPathParams[paramName] = params[paramName];
});
}

View File

@@ -13,7 +13,7 @@ function validateRouteConfigMap(routeConfigs) {
'Please specify at least one route when configuring a navigator.'
);
routeNames.forEach(routeName => {
routeNames.forEach((routeName) => {
const routeConfig = routeConfigs[routeName];
const screenComponent = getScreenComponent(routeConfig);

View File

@@ -7,7 +7,7 @@ const deprecatedKeys = ['tabBar'];
export default (screenOptions, route) => {
const keys = Object.keys(screenOptions);
const deprecatedKey = keys.find(key => deprecatedKeys.includes(key));
const deprecatedKey = keys.find((key) => deprecatedKeys.includes(key));
if (typeof screenOptions.title === 'function') {
throw new Error(
@@ -54,7 +54,7 @@ export default (screenOptions, route) => {
'{',
` ${deprecatedKey}: {`,
...Object.keys(screenOptions[deprecatedKey]).map(
key => ` ${key}: ...,`
(key) => ` ${key}: ...,`
),
' },',
'}',
@@ -62,7 +62,7 @@ export default (screenOptions, route) => {
'with:',
'{',
...Object.keys(screenOptions[deprecatedKey]).map(
key =>
(key) =>
` ${deprecatedKey + key[0].toUpperCase() + key.slice(1)}: ...,`
),
'}',

View File

@@ -1,3 +1,3 @@
export default function docsUrl(path: string) {
return `https://reactnavigation.org/docs/${path}`;
return `https://reactnavigation.org/docs/4.x/${path}`;
}

View File

@@ -5,8 +5,10 @@ function getSceneIndicesForInterpolationInputRange(props) {
const isBack = !scenes[lastSceneIndexInScenes].isActive;
if (isBack) {
const currentSceneIndexInScenes = scenes.findIndex(item => item === scene);
const targetSceneIndexInScenes = scenes.findIndex(item => item.isActive);
const currentSceneIndexInScenes = scenes.findIndex(
(item) => item === scene
);
const targetSceneIndexInScenes = scenes.findIndex((item) => item.isActive);
const targetSceneIndex = scenes[targetSceneIndexInScenes].index;
const lastSceneIndex = scenes[lastSceneIndexInScenes].index;

View File

@@ -9,10 +9,10 @@
* will remain to ensure logic does not differ in production.
*/
let validateFormat: (format?: string) => void = function() {};
let validateFormat: (format?: string) => void = function () {};
if (process.env.NODE_ENV !== 'production') {
validateFormat = function(format?: string) {
validateFormat = function (format?: string) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}

View File

@@ -17,7 +17,7 @@ class NavigationEvents extends React.Component {
// We register all navigation listeners on mount to ensure listener stability across re-render
// A former implementation was replacing (removing/adding) listeners on all update (if prop provided)
// but there were issues (see https://github.com/react-navigation/react-navigation/issues/5058)
EventNames.forEach(eventName => {
EventNames.forEach((eventName) => {
this.subscriptions[eventName] = this.props.navigation.addListener(
eventName,
(...args) => {
@@ -29,12 +29,12 @@ class NavigationEvents extends React.Component {
}
componentWillUnmount() {
EventNames.forEach(eventName => {
EventNames.forEach((eventName) => {
this.subscriptions[eventName].remove();
});
}
getPropListener = eventName => this.props[EventNameToPropName[eventName]];
getPropListener = (eventName) => this.props[EventNameToPropName[eventName]];
render() {
return null;

View File

@@ -0,0 +1,360 @@
// @ts-check
import * as React from 'react';
/**
* @typedef {object} State
* @prop {number} index
* @prop {({ key: string } & (State | {}))[]} routes
* @prop {boolean} [isTransitioning]
*
* @typedef {object} ParentPayload
* @prop {string} type
* @prop {object} action
* @prop {State} state
* @prop {State | {key: string, routes?: undefined, index?: undefined, isTransitioning?: undefined} | undefined | null} lastState
* @prop {string} [context]
*
* @typedef {object} Payload
* @prop {string} type
* @prop {object} action
* @prop {State | {key: string}} state
* @prop {State | {key: string} | undefined | null} lastState
* @prop {string} [context]
*
* @typedef {object} Props
* @prop {object} navigation
* @prop {Function} navigation.addListener
* @prop {Function} navigation.removeListener
* @prop {() => boolean} navigation.isFocused
* @prop {() => object | undefined} navigation.dangerouslyGetParent
* @prop {State} navigation.state
* @prop {(target: string, type: string, data: any) => void} onEvent
*
* @extends {React.Component<Props>}
*/
export default class NavigationEventManager extends React.Component {
componentDidMount() {
const { navigation } = this.props;
this._actionSubscription = navigation.addListener(
'action',
this._handleAction
);
this._willFocusSubscription = navigation.addListener(
'willFocus',
this._handleWillFocus
);
this._willBlurSubscription = navigation.addListener(
'willBlur',
this._handleWillBlur
);
this._didFocusSubscription = navigation.addListener(
'didFocus',
this._handleDidFocus
);
this._didBlurSubscription = navigation.addListener(
'didBlur',
this._handleDidBlur
);
this._refocusSubscription = navigation.addListener(
'refocus',
this._handleRefocus
);
}
componentWillUnmount() {
this._actionSubscription?.remove();
this._willFocusSubscription?.remove();
this._willBlurSubscription?.remove();
this._didFocusSubscription?.remove();
this._didBlurSubscription?.remove();
this._refocusSubscription?.remove();
}
/**
* @type {{ remove(): void } | undefined}
*/
_actionSubscription;
/**
* @type {{ remove(): void } | undefined}
*/
_willFocusSubscription;
/**
* @type {{ remove(): void } | undefined}
*/
_willBlurSubscription;
/**
* @type {{ remove(): void } | undefined}
*/
_didFocusSubscription;
/**
* @type {{ remove(): void } | undefined}
*/
_didBlurSubscription;
/**
* @type {{ remove(): void } | undefined}
*/
_refocusSubscription;
/**
* @type {string | undefined}
*/
_lastWillBlurKey;
/**
* @type {string | undefined}
*/
_lastWillFocusKey;
/**
* @type {string | undefined}
*/
_lastDidBlurKey;
/**
* @type {string | undefined}
*/
_lastDidFocusKey;
/**
* The 'action' event will fire when navigation state changes.
* Detect if the focused route changed here and emit appropriate events.
*
* @param {ParentPayload} payload
*/
_handleAction = ({ state, lastState, action, type, context }) => {
const { navigation, onEvent } = this.props;
// We should only emit events when the navigator is focused
// When navigator is not focused, screens inside shouldn't receive focused status either
if (!navigation.isFocused()) {
return;
}
const previous = lastState
? lastState.routes?.[lastState.index]
: undefined;
const current = state.routes[state.index];
const payload = {
context: `${current.key}:${action.type}_${context || 'Root'}`,
state: current,
lastState: previous,
action,
type,
};
if (previous?.key !== current.key) {
this._emitWillFocus(current.key, payload);
if (previous?.key) {
this._emitWillBlur(previous.key, payload);
}
}
if (
lastState?.isTransitioning !== state.isTransitioning &&
state.isTransitioning === false
) {
if (this._lastWillBlurKey) {
this._emitDidBlur(this._lastWillBlurKey, payload);
}
if (this._lastWillFocusKey) {
this._emitDidFocus(this._lastWillFocusKey, payload);
}
}
onEvent(current.key, 'action', payload);
};
/**
* @param {ParentPayload} payload
*/
_handleWillFocus = ({ lastState, action, context, type }) => {
const { navigation } = this.props;
const route = navigation.state.routes[navigation.state.index];
this._emitWillFocus(route.key, {
context: `${route.key}:${action.type}_${context || 'Root'}`,
state: route,
lastState: lastState?.routes?.find((r) => r.key === route.key),
action,
type,
});
};
/**
* @param {ParentPayload} payload
*/
_handleWillBlur = ({ lastState, action, context, type }) => {
const { navigation } = this.props;
const route = navigation.state.routes[navigation.state.index];
this._emitWillBlur(route.key, {
context: `${route.key}:${action.type}_${context || 'Root'}`,
state: route,
lastState: lastState?.routes?.find((r) => r.key === route.key),
action,
type,
});
};
/**
* @param {ParentPayload} payload
*/
_handleDidFocus = ({ lastState, action, context, type }) => {
const { navigation } = this.props;
if (this._lastWillFocusKey) {
const route = navigation.state.routes.find(
(r) => r.key === this._lastWillFocusKey
);
if (route) {
this._emitDidFocus(route.key, {
context: `${route.key}:${action.type}_${context || 'Root'}`,
state: route,
lastState: lastState?.routes?.find((r) => r.key === route.key),
action,
type,
});
}
}
};
/**
* @param {ParentPayload} payload
*/
_handleDidBlur = ({ lastState, action, context, type }) => {
const { navigation } = this.props;
if (this._lastWillBlurKey) {
const route = navigation.state.routes.find(
(r) => r.key === this._lastWillBlurKey
);
if (route) {
this._emitDidBlur(route.key, {
context: `${route.key}:${action.type}_${context || 'Root'}`,
state: route,
lastState: lastState?.routes?.find((r) => r.key === route.key),
action,
type,
});
}
}
};
_handleRefocus = () => {
const { onEvent, navigation } = this.props;
const route = navigation.state.routes[navigation.state.index];
onEvent(route.key, 'refocus');
};
/**
* @param {string} target
* @param {Payload} payload
*/
_emitWillFocus = (target, payload) => {
if (this._lastWillBlurKey === target) {
this._lastWillBlurKey = undefined;
}
if (this._lastWillFocusKey === target) {
return;
}
this._lastDidFocusKey = undefined;
this._lastWillFocusKey = target;
const { navigation, onEvent } = this.props;
onEvent(target, 'willFocus', payload);
if (
typeof navigation.state.isTransitioning !== 'boolean' ||
(navigation.state.isTransitioning !== true &&
!navigation.dangerouslyGetParent())
) {
this._emitDidFocus(target, payload);
}
};
/**
* @param {string} target
* @param {Payload} payload
*/
_emitWillBlur = (target, payload) => {
if (this._lastWillFocusKey === target) {
this._lastWillFocusKey = undefined;
}
if (this._lastWillBlurKey === target) {
return;
}
this._lastDidBlurKey = undefined;
this._lastWillBlurKey = target;
const { navigation, onEvent } = this.props;
onEvent(target, 'willBlur', payload);
if (
typeof navigation.state.isTransitioning !== 'boolean' ||
(navigation.state.isTransitioning !== true &&
!navigation.dangerouslyGetParent())
) {
this._emitDidBlur(target, payload);
}
};
/**
* @param {string} target
* @param {Payload} payload
*/
_emitDidFocus = (target, payload) => {
if (this._lastWillFocusKey !== target || this._lastDidFocusKey === target) {
return;
}
this._lastDidFocusKey = target;
const { onEvent } = this.props;
onEvent(target, 'didFocus', payload);
};
/**
* @param {string} target
* @param {Payload} payload
*/
_emitDidBlur = (target, payload) => {
if (this._lastWillBlurKey !== target || this._lastDidBlurKey === target) {
return;
}
this._lastDidBlurKey = target;
const { onEvent } = this.props;
onEvent(target, 'didBlur', payload);
};
render() {
return null;
}
}

View File

@@ -26,13 +26,15 @@ const createTestNavigationAndHelpers = () => {
listeners[eventName].push(handler);
},
remove: (eventName, handler) => {
listeners[eventName] = listeners[eventName].filter(h => h !== handler);
listeners[eventName] = listeners[eventName].filter(
(h) => h !== handler
);
},
get: eventName => {
get: (eventName) => {
return listeners[eventName];
},
call: eventName => {
listeners[eventName].forEach(listener => listener());
call: (eventName) => {
listeners[eventName].forEach((listener) => listener());
},
};
})();

View File

@@ -8,14 +8,15 @@ export default function withNavigation(
config = { forwardRef: true }
) {
class ComponentWithNavigation extends React.Component {
static displayName = `withNavigation(${Component.displayName ||
Component.name})`;
static displayName = `withNavigation(${
Component.displayName || Component.name
})`;
render() {
const navigationProp = this.props.navigation;
return (
<NavigationContext.Consumer>
{navigationContext => {
{(navigationContext) => {
const navigation = navigationProp || navigationContext;
invariant(
!!navigation,

View File

@@ -4,28 +4,29 @@ import withNavigation from './withNavigation';
export default function withNavigationFocus(Component) {
class ComponentWithNavigationFocus extends React.Component {
static displayName = `withNavigationFocus(${Component.displayName ||
Component.name})`;
static displayName = `withNavigationFocus(${
Component.displayName || Component.name
})`;
constructor(props) {
super(props);
state = {
isFocused: this.props.navigation.isFocused(),
};
componentDidMount() {
const { navigation } = this.props;
this.subscriptions = [
props.navigation.addListener('didFocus', () =>
navigation.addListener('willFocus', () =>
this.setState({ isFocused: true })
),
props.navigation.addListener('willBlur', () =>
navigation.addListener('willBlur', () =>
this.setState({ isFocused: false })
),
];
this.state = {
isFocused: props.navigation ? props.navigation.isFocused() : false,
};
}
componentWillUnmount() {
this.subscriptions.forEach(sub => sub.remove());
this.subscriptions?.forEach((sub) => sub.remove());
}
render() {

View File

@@ -0,0 +1,6 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"allowJs": true
}
}

View File

@@ -3,6 +3,111 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.5.0](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.13...react-navigation-drawer@2.5.0) (2020-06-25)
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/drawer/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
## [2.4.13](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.12...react-navigation-drawer@2.4.13) (2020-04-30)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.12](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.11...react-navigation-drawer@2.4.12) (2020-04-22)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.11](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.10...react-navigation-drawer@2.4.11) (2020-04-02)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.10](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.9...react-navigation-drawer@2.4.10) (2020-03-31)
### Bug Fixes
* remove isTransitioning from SwitchRouter state ([3bec1c9](https://github.com/react-navigation/drawer/commit/3bec1c964a49136c0ead8e8ba8a8c66c556bbcba))
## [2.4.9](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.7...react-navigation-drawer@2.4.9) (2020-03-28)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.8](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.7...react-navigation-drawer@2.4.8) (2020-03-27)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.7](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.6...react-navigation-drawer@2.4.7) (2020-03-22)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.6](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.5...react-navigation-drawer@2.4.6) (2020-03-20)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.5](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.4...react-navigation-drawer@2.4.5) (2020-03-19)
### Bug Fixes
* don't use react-native-screens on web ([44c3900](https://github.com/react-navigation/drawer/commit/44c390075f7b76664e09fd9a1a7926645133ebec)), closes [#7485](https://github.com/react-navigation/drawer/issues/7485)
## [2.4.4](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.3...react-navigation-drawer@2.4.4) (2020-03-16)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.3](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.2...react-navigation-drawer@2.4.3) (2020-03-16)
**Note:** Version bump only for package react-navigation-drawer
## [2.4.2](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.4.1...react-navigation-drawer@2.4.2) (2020-02-26)
**Note:** Version bump only for package react-navigation-drawer

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation-drawer",
"version": "2.4.2",
"version": "2.5.0",
"description": "Drawer navigator component for React Navigation",
"main": "lib/commonjs/index.js",
"react-native": "lib/module/index.js",
@@ -38,26 +38,26 @@
},
"homepage": "https://github.com/react-navigation/drawer#readme",
"devDependencies": {
"@react-native-community/bob": "^0.9.7",
"@types/react": "^16.9.22",
"@types/react-native": "^0.61.17",
"@react-native-community/bob": "^0.10.0",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-lifecycles-compat": "^3.0.4",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.6.0",
"react-native-reanimated": "^1.2.0",
"react-native-screens": "^2.0.0-beta.10",
"react-native-screens": "^2.3.0",
"react-native-testing-library": "^1.12.0",
"react-navigation": "^4.2.2",
"typescript": "~3.7.5"
"react-navigation": "^4.4.0",
"typescript": "^3.9.5"
},
"peerDependencies": {
"react": "*",
"react-native": "*",
"react-native-gesture-handler": "^1.0.12",
"react-native-reanimated": "^1.0.0",
"react-native-screens": "^1.0.0 || ^1.0.0-alpha",
"react-native-screens": ">=1.0.0 || >= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0",
"react-navigation": "^4.1.1"
},
"@react-native-community/bob": {

View File

@@ -75,8 +75,11 @@ const DrawerNavigator = (
const drawerRouter = DrawerRouter(routeConfigs, mergedConfig);
// TODO: don't have time to fix it right now
// @ts-ignore
const navigator = createNavigator(DrawerView, drawerRouter, mergedConfig);
const navigator = createNavigator(
DrawerView as any,
drawerRouter,
mergedConfig
);
return navigator;
};

View File

@@ -18,7 +18,7 @@ it('handles basic drawer logic and fires close on switch', () => {
const state = router.getStateForAction(INIT_ACTION);
const expectedState = {
index: 0,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo', params: undefined },
{ key: 'Bar', routeName: 'Bar', params: undefined },
@@ -32,7 +32,7 @@ it('handles basic drawer logic and fires close on switch', () => {
);
const expectedState2 = {
index: 1,
isTransitioning: false,
routes: [
{ key: 'Foo', routeName: 'Foo', params: undefined },
{ key: 'Bar', routeName: 'Bar', params: undefined },
@@ -65,7 +65,7 @@ it('handles initial route navigation', () => {
expect(state).toEqual({
index: 0,
isDrawerOpen: false,
isTransitioning: false,
routes: [
{
key: 'Foo',

View File

@@ -160,10 +160,6 @@ export default class DrawerView extends React.PureComponent<Props, State> {
drawerOpenProgress={progress}
navigation={this.props.navigation}
descriptors={this.props.descriptors}
contentComponent={this.props.navigationConfig.contentComponent}
contentOptions={this.props.navigationConfig.contentOptions}
drawerPosition={this.props.navigationConfig.drawerPosition}
style={this.props.navigationConfig.style}
{...this.props.navigationConfig}
/>
);

View File

@@ -1,5 +1,3 @@
/* @flow */
import * as React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { Screen, screensEnabled } from 'react-native-screens';
@@ -10,21 +8,29 @@ type Props = {
style?: any;
};
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
export default class ResourceSavingScene extends React.Component<Props> {
render() {
if (screensEnabled?.()) {
// react-native-screens is buggy on web
if (screensEnabled?.() && Platform.OS !== 'web') {
const { isVisible, ...rest } = this.props;
// @ts-ignore
return <Screen active={isVisible ? 1 : 0} {...rest} />;
}
const { isVisible, children, style, ...rest } = this.props;
return (
<View
style={[styles.container, style]}
style={[
styles.container,
Platform.OS === 'web'
? { display: isVisible ? 'flex' : 'none' }
: null,
style,
]}
collapsable={false}
removeClippedSubviews={
// On iOS, set removeClippedSubviews to true only when not focused

View File

@@ -3,6 +3,97 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.3.0](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.12...react-navigation-material-bottom-tabs@2.3.0) (2020-06-25)
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/react-navigation-material-bottom-tabs/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
## [2.2.12](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.11...react-navigation-material-bottom-tabs@2.2.12) (2020-04-30)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.11](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.10...react-navigation-material-bottom-tabs@2.2.11) (2020-04-22)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.10](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.9...react-navigation-material-bottom-tabs@2.2.10) (2020-04-02)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.9](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.8...react-navigation-material-bottom-tabs@2.2.9) (2020-03-31)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.8](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.6...react-navigation-material-bottom-tabs@2.2.8) (2020-03-28)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.7](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.6...react-navigation-material-bottom-tabs@2.2.7) (2020-03-27)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.6](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.5...react-navigation-material-bottom-tabs@2.2.6) (2020-03-22)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.5](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.4...react-navigation-material-bottom-tabs@2.2.5) (2020-03-20)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.4](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.3...react-navigation-material-bottom-tabs@2.2.4) (2020-03-16)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.3](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.2...react-navigation-material-bottom-tabs@2.2.3) (2020-03-16)
**Note:** Version bump only for package react-navigation-material-bottom-tabs
## [2.2.2](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.2.1...react-navigation-material-bottom-tabs@2.2.2) (2020-02-26)
**Note:** Version bump only for package react-navigation-material-bottom-tabs

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation-material-bottom-tabs",
"version": "2.2.2",
"version": "2.3.0",
"description": "Material Bottom Tab Navigation component for React Navigation",
"main": "lib/commonjs/index.js",
"module": "lib/module/index.js",
@@ -38,18 +38,18 @@
},
"homepage": "https://github.com/react-navigation/react-navigation-material-bottom-tabs#readme",
"devDependencies": {
"@react-native-community/bob": "^0.9.7",
"@react-native-community/bob": "^0.10.0",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/react": "^16.9.22",
"@types/react-native": "^0.61.17",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.6.0",
"react-native-paper": "^3.1.1",
"react-native-reanimated": "^1.2.0",
"react-navigation": "^4.2.2",
"typescript": "~3.7.5"
"react-navigation": "^4.4.0",
"typescript": "^3.9.5"
},
"peerDependencies": {
"react": "*",

View File

@@ -3,6 +3,114 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [3.8.0](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.13...@react-navigation/native@3.8.0) (2020-06-25)
### Bug Fixes
* improve error message when installing wrong version ([442ca3e](https://github.com/react-navigation/react-navigation-native/commit/442ca3e700c5805cdc5cd02c68f49042887a5054))
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/react-navigation-native/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
## [3.7.13](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.12...@react-navigation/native@3.7.13) (2020-04-30)
**Note:** Version bump only for package @react-navigation/native
## [3.7.12](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.11...@react-navigation/native@3.7.12) (2020-04-22)
**Note:** Version bump only for package @react-navigation/native
## [3.7.11](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.10...@react-navigation/native@3.7.11) (2020-04-02)
**Note:** Version bump only for package @react-navigation/native
## [3.7.10](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.9...@react-navigation/native@3.7.10) (2020-03-31)
**Note:** Version bump only for package @react-navigation/native
## [3.7.9](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.7...@react-navigation/native@3.7.9) (2020-03-28)
### Bug Fixes
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-native/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-native/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-native/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-native/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-native/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-native/issues/7749)
## [3.7.8](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.7...@react-navigation/native@3.7.8) (2020-03-27)
### Bug Fixes
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-native/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-native/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-native/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-native/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-native/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-native/issues/7749)
## [3.7.7](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.6...@react-navigation/native@3.7.7) (2020-03-22)
**Note:** Version bump only for package @react-navigation/native
## [3.7.6](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.5...@react-navigation/native@3.7.6) (2020-03-20)
### Bug Fixes
* don't mix import and module.exports. closes [#7660](https://github.com/react-navigation/react-navigation-native/issues/7660) ([80c8c9d](https://github.com/react-navigation/react-navigation-native/commit/80c8c9d1dead57eab3b977a1eebf1e9f5f35cd1a))
## [3.7.5](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.4...@react-navigation/native@3.7.5) (2020-03-16)
### Bug Fixes
* downgrade react-native-safe-area-view ([cfc1bac](https://github.com/react-navigation/react-navigation-native/commit/cfc1bac4e153db4a4ba3f2a9033f77b53367fcbc)), closes [#7813](https://github.com/react-navigation/react-navigation-native/issues/7813)
## [3.7.4](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.3...@react-navigation/native@3.7.4) (2020-03-16)
**Note:** Version bump only for package @react-navigation/native
## [3.7.3](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.7.0...@react-navigation/native@3.7.3) (2020-02-24)
**Note:** Version bump only for package @react-navigation/native

View File

@@ -1,6 +1,6 @@
{
"name": "@react-navigation/native",
"version": "3.7.3",
"version": "3.8.0",
"description": "React Native support for React Navigation",
"main": "lib/commonjs/index.js",
"react-native": "lib/module/index.js",
@@ -15,7 +15,8 @@
},
"sideEffects": false,
"publishConfig": {
"access": "public"
"access": "public",
"tag": "4.x"
},
"keywords": [
"react-native",
@@ -35,17 +36,16 @@
"homepage": "https://github.com/react-navigation/react-navigation-native#readme",
"dependencies": {
"hoist-non-react-statics": "^3.3.2",
"react-native-safe-area-view": "^0.14.8"
"react-native-safe-area-view": "^0.14.9"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.7",
"@react-navigation/core": "^3.6.1",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/core": "^3.7.6",
"@types/react-test-renderer": "^16.9.2",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.6.0",
"react-native-screens": "^2.0.0-beta.10",
"react-test-renderer": "^16.9.2"
},
"@react-native-community/bob": {

View File

@@ -52,7 +52,7 @@ const WrappedFlatList = React.forwardRef((props, ref) => (
<FlatList
ref={ref}
{...props}
renderScrollComponent={props => (
renderScrollComponent={(props) => (
<WrappedScrollView {...propsMaybeWithRefreshControl(props)} />
)}
/>
@@ -62,15 +62,14 @@ const WrappedSectionList = React.forwardRef((props, ref) => (
<SectionList
ref={ref}
{...props}
renderScrollComponent={props => (
renderScrollComponent={(props) => (
<WrappedScrollView {...propsMaybeWithRefreshControl(props)} />
)}
/>
));
// eslint-disable-next-line import/no-commonjs
module.exports = {
ScrollView: WrappedScrollView,
FlatList: WrappedFlatList,
SectionList: WrappedSectionList,
export {
WrappedScrollView as ScrollView,
WrappedFlatList as FlatList,
WrappedSectionList as SectionList,
};

View File

@@ -274,7 +274,7 @@ describe('NavigationContainer', () => {
});
// https://github.com/facebook/jest/issues/2157#issuecomment-279171856
const flushPromises = () => new Promise(resolve => setImmediate(resolve));
const flushPromises = () => new Promise((resolve) => setImmediate(resolve));
describe('state persistence', () => {
async function createPersistenceEnabledContainer(

View File

@@ -266,7 +266,7 @@ export default function createNavigationContainer(Component) {
}
const dispatchActions = () =>
this._actionEventSubscribers.forEach(subscriber =>
this._actionEventSubscribers.forEach((subscriber) =>
subscriber({
type: 'action',
action,
@@ -316,7 +316,7 @@ export default function createNavigationContainer(Component) {
}
}
_persistNavigationState = async nav => {
_persistNavigationState = async (nav) => {
const { persistNavigationState } = this.props;
if (persistNavigationState) {
try {
@@ -341,7 +341,7 @@ export default function createNavigationContainer(Component) {
// Per-tick temporary storage for state.nav
dispatch = action => {
dispatch = (action) => {
if (this.props.navigation) {
return this.props.navigation.dispatch(action);
}
@@ -357,7 +357,7 @@ export default function createNavigationContainer(Component) {
const navState = reducedState === null ? lastNavState : reducedState;
const dispatchActionEvents = () => {
this._actionEventSubscribers.forEach(subscriber =>
this._actionEventSubscribers.forEach((subscriber) =>
subscriber({
type: 'action',
action,

View File

@@ -4,9 +4,10 @@ import { withNavigation } from '@react-navigation/core';
export default function createNavigationAwareScrollable(Component) {
const ComponentWithNavigationScrolling = withNavigation(
class extends React.PureComponent<any> {
static displayName = `withNavigationScrolling(${Component.displayName ||
Component.name})`;
class extends React.PureComponent {
static displayName = `withNavigationScrolling(${
Component.displayName || Component.name
})`;
componentDidMount() {
this._subscription = this.props.navigation.addListener(
@@ -49,7 +50,7 @@ export default function createNavigationAwareScrollable(Component) {
render() {
return (
<Component
ref={view => {
ref={(view) => {
this._scrollRef = view;
}}
{...this.props}
@@ -59,11 +60,12 @@ export default function createNavigationAwareScrollable(Component) {
}
);
class NavigationAwareScrollable extends React.PureComponent<any> {
static displayName = `NavigationAwareScrollable(${Component.displayName ||
Component.name})`;
class NavigationAwareScrollable extends React.PureComponent {
static displayName = `NavigationAwareScrollable(${
Component.displayName || Component.name
})`;
_captureRef = view => {
_captureRef = (view) => {
this._innerRef = view;
this.props.onRef && this.props.onRef(view);
};

View File

@@ -43,6 +43,24 @@ module.exports = {
get createNavigationFactory() {
return require('./throwIfWrongVersion').default;
},
get useNavigationBuilder() {
return require('./throwIfWrongVersion').default;
},
get useNavigation() {
return require('./throwIfWrongVersion').default;
},
get useRoute() {
return require('./throwIfWrongVersion').default;
},
get useFocusEffect() {
return require('./throwIfWrongVersion').default;
},
get useIsFocused() {
return require('./throwIfWrongVersion').default;
},
get useNavigationState() {
return require('./throwIfWrongVersion').default;
},
get NavigationContainer() {
return require('./throwIfWrongVersion').default;
},

View File

@@ -1,5 +1,5 @@
export default function() {
export default function () {
throw new Error(
"This version of '@react-navigation/native' is not compatible with React Navigation 5. Make sure you install 5.x version of '@react-navigation/native'."
'Looks like you are trying to use React Navigation 5 APIs, but have React Navigation 4 installed.\n\nMixing React Navigation 4 and 5 is not supported. See the documentation for installation instructions and usage guide for appropriate versions:\n\n- React Navigation 5: https://reactnavigation.org/docs/getting-started\n- React Navigation 4: https://reactnavigation.org/docs/4.x/getting-started'
);
}

View File

@@ -9,17 +9,17 @@
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function() {};
var validateFormat = function () {};
if (process.env.NODE_ENV !== 'production') {
validateFormat = function(format) {
validateFormat = function (format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
function invariant(condition, format, a, b, c, d, e, f) {
export default function invariant(condition, format, a, b, c, d, e, f) {
validateFormat(format);
if (!condition) {
@@ -32,7 +32,7 @@ function invariant(condition, format, a, b, c, d, e, f) {
var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(
format.replace(/%s/g, function() {
format.replace(/%s/g, function () {
return args[argIndex++];
})
);
@@ -43,6 +43,3 @@ function invariant(condition, format, a, b, c, d, e, f) {
throw error;
}
}
// eslint-disable-next-line import/no-commonjs
module.exports = invariant;

View File

@@ -4,7 +4,7 @@ import hoistNonReactStatic from 'hoist-non-react-statics';
export const isOrientationLandscape = ({ width, height }) => width > height;
export default function(WrappedComponent) {
export default function (WrappedComponent) {
class withOrientation extends React.Component {
constructor() {
super();

View File

@@ -3,6 +3,103 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [4.4.0](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.9...react-navigation@4.4.0) (2020-06-25)
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/react-navigation/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
## [4.3.9](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.8...react-navigation@4.3.9) (2020-04-30)
### Bug Fixes
* change old docUrl to new docUrl due v5 ([e09906a](https://github.com/react-navigation/react-navigation/commit/e09906a4235a0fca09140923ebe7af34b50b491a))
## [4.3.8](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.7...react-navigation@4.3.8) (2020-04-22)
**Note:** Version bump only for package react-navigation
## [4.3.7](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.6...react-navigation@4.3.7) (2020-04-02)
**Note:** Version bump only for package react-navigation
## [4.3.6](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.5...react-navigation@4.3.6) (2020-03-31)
**Note:** Version bump only for package react-navigation
## [4.3.5](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.3...react-navigation@4.3.5) (2020-03-28)
**Note:** Version bump only for package react-navigation
## [4.3.4](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.3...react-navigation@4.3.4) (2020-03-27)
**Note:** Version bump only for package react-navigation
## [4.3.3](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.2...react-navigation@4.3.3) (2020-03-22)
**Note:** Version bump only for package react-navigation
## [4.3.2](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.1...react-navigation@4.3.2) (2020-03-20)
**Note:** Version bump only for package react-navigation
## [4.3.1](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.3.0...react-navigation@4.3.1) (2020-03-16)
**Note:** Version bump only for package react-navigation
# [4.3.0](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.2.2...react-navigation@4.3.0) (2020-03-16)
### Features
* add prune option to pop action to match v5 behaviour ([5927f42](https://github.com/react-navigation/react-navigation/commit/5927f4287f5e1ab106537865523daa1c03b14b47))
## [4.2.2](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.2.1...react-navigation@4.2.2) (2020-02-26)

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation",
"version": "4.2.2",
"version": "4.4.0",
"description": "Routing and navigation for your React Native apps",
"main": "src/index.js",
"types": "typescript/react-navigation.d.ts",
@@ -24,16 +24,16 @@
"react-native": "*"
},
"dependencies": {
"@react-navigation/core": "^3.6.1",
"@react-navigation/native": "^3.7.3"
"@react-navigation/core": "^3.7.6",
"@react-navigation/native": "^3.8.0"
},
"devDependencies": {
"@types/react": "^16.9.22",
"@types/react-native": "^0.61.17",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"@types/react-test-renderer": "^16.9.2",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-test-renderer": "^16.9.2",
"typescript": "~3.7.5"
"typescript": "^3.9.5"
}
}

View File

@@ -1,3 +1,3 @@
export default function docsUrl(path) {
return `https://reactnavigation.org/docs/${path}`;
return `https://reactnavigation.org/docs/4.x/${path}`;
}

View File

@@ -328,6 +328,7 @@ export interface NavigationPopActionPayload {
// n: the number of routes to pop of the stack
n?: number;
immediate?: boolean;
prune?: boolean;
key?: string;
}
@@ -733,7 +734,9 @@ export namespace StackActions {
export const REPLACE: 'Navigation/REPLACE';
export const COMPLETE_TRANSITION: 'Navigation/COMPLETE_TRANSITION';
export function pop(options: NavigationPopActionPayload): NavigationPopAction;
export function pop(
options?: NavigationPopActionPayload
): NavigationPopAction;
export function popToTop(
options?: NavigationPopToTopActionPayload
): NavigationPopToTopAction;
@@ -809,17 +812,15 @@ export interface NavigationDescriptor<
getComponent: () => React.ComponentType;
}
export type NavigationView<
Options,
State,
ScreenProps = unknown
> = React.ComponentType<
{
descriptors: { [key: string]: NavigationDescriptor };
navigationConfig: Options;
screenProps?: ScreenProps;
} & NavigationInjectedProps
>;
export type NavigationView<Options, State, ScreenProps = unknown> =
| React.ComponentType<
{
descriptors: { [key: string]: NavigationDescriptor };
navigationConfig: Options;
screenProps?: ScreenProps;
} & NavigationInjectedProps
>
| React.ComponentType<any>;
export type CreateNavigatorConfig<
NavigatorConfig,

View File

@@ -3,6 +3,230 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.8.2](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.8.1...react-navigation-stack@2.8.2) (2020-06-25)
### Bug Fixes
* sync latest stack ([46b797d](https://github.com/react-navigation/react-navigation-stack/commit/46b797dd297f789e3c92ff6f5c4432fedc891767))
## [2.8.1](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.8.0...react-navigation-stack@2.8.1) (2020-06-25)
### Bug Fixes
* pop with correct key from nested stack ([2e7f4a6](https://github.com/react-navigation/react-navigation-stack/commit/2e7f4a6d10a00930bd5c53ef6f4bf964c9638db5))
# [2.8.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.7.0...react-navigation-stack@2.8.0) (2020-06-25)
### Features
* sync latest stack and upgrade typescript ([454e05b](https://github.com/react-navigation/react-navigation-stack/commit/454e05b02ec97f053b381fdc801df899d8c93cb6))
# [2.7.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.6.0...react-navigation-stack@2.7.0) (2020-06-08)
### Features
* sync latest stack ([ba6d7dc](https://github.com/react-navigation/react-navigation-stack/commit/ba6d7dcbedcfca774a53de32f92acc45140bb1fe))
# [2.6.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.5.1...react-navigation-stack@2.6.0) (2020-06-06)
### Features
* sync latest stack ([03f9f8c](https://github.com/react-navigation/react-navigation-stack/commit/03f9f8cd8ec3b5fe9dc2ed1ed2024e79dd06f854))
## [2.5.1](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.5.0...react-navigation-stack@2.5.1) (2020-05-15)
### Bug Fixes
* sync latest stack ([bc1313b](https://github.com/react-navigation/react-navigation-stack/commit/bc1313b61da6134255adff477ded2ed8f632bf4a))
# [2.5.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.4.0...react-navigation-stack@2.5.0) (2020-05-11)
### Features
* sync latest stack ([bb82d50](https://github.com/react-navigation/react-navigation-stack/commit/bb82d5000f6577f421cc7f72df8064eb4c2a0650))
# [2.4.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.13...react-navigation-stack@2.4.0) (2020-04-30)
### Features
* sync latest stack ([8b79e9b](https://github.com/react-navigation/react-navigation-stack/commit/8b79e9bee65c3ba6a788ca76771379319168f117))
## [2.3.13](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.12...react-navigation-stack@2.3.13) (2020-04-22)
**Note:** Version bump only for package react-navigation-stack
## [2.3.12](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.11...react-navigation-stack@2.3.12) (2020-04-17)
### Bug Fixes
* stack peer warnings ([4c4e66f](https://github.com/react-navigation/react-navigation-stack/commit/4c4e66f05cd4d694f512f4cc38827f3fbf0f70de))
## [2.3.11](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.10...react-navigation-stack@2.3.11) (2020-04-02)
**Note:** Version bump only for package react-navigation-stack
## [2.3.10](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.9...react-navigation-stack@2.3.10) (2020-03-31)
**Note:** Version bump only for package react-navigation-stack
## [2.3.9](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.7...react-navigation-stack@2.3.9) (2020-03-28)
### Bug Fixes
* emit didFocus and didBlur events based on parent's transition ([14a6538](https://github.com/react-navigation/react-navigation-stack/commit/14a6538cc8e12c50d5d10722d75c9395a0a281ec))
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-stack/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-stack/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-stack/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-stack/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-stack/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-stack/issues/7749)
## [2.3.8](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.7...react-navigation-stack@2.3.8) (2020-03-27)
### Bug Fixes
* rework focus and blur events to make them more reliable ([cd08338](https://github.com/react-navigation/react-navigation-stack/commit/cd083381866506a192f1ec842ac169f2b4277ca5)), closes [#4867](https://github.com/react-navigation/react-navigation-stack/issues/4867) [#6187](https://github.com/react-navigation/react-navigation-stack/issues/6187) [#6451](https://github.com/react-navigation/react-navigation-stack/issues/6451) [#7628](https://github.com/react-navigation/react-navigation-stack/issues/7628) [#7749](https://github.com/react-navigation/react-navigation-stack/issues/7749)
## [2.3.7](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.6...react-navigation-stack@2.3.7) (2020-03-27)
**Note:** Version bump only for package react-navigation-stack
## [2.3.6](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.5...react-navigation-stack@2.3.6) (2020-03-23)
**Note:** Version bump only for package react-navigation-stack
## [2.3.5](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.4...react-navigation-stack@2.3.5) (2020-03-22)
**Note:** Version bump only for package react-navigation-stack
## [2.3.4](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.3...react-navigation-stack@2.3.4) (2020-03-20)
**Note:** Version bump only for package react-navigation-stack
## [2.3.3](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.2...react-navigation-stack@2.3.3) (2020-03-20)
**Note:** Version bump only for package react-navigation-stack
## [2.3.2](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.1...react-navigation-stack@2.3.2) (2020-03-19)
**Note:** Version bump only for package react-navigation-stack
## [2.3.1](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.3.0...react-navigation-stack@2.3.1) (2020-03-16)
**Note:** Version bump only for package react-navigation-stack
# [2.3.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.2.3...react-navigation-stack@2.3.0) (2020-03-16)
### Features
* add prune option to pop action to match v5 behaviour ([5927f42](https://github.com/react-navigation/react-navigation-stack/commit/5927f4287f5e1ab106537865523daa1c03b14b47))
## [2.2.3](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.2.2...react-navigation-stack@2.2.3) (2020-03-04)
### Bug Fixes
* dispatch completeTransition on mount so focus event is emitted ([f5a3880](https://github.com/react-navigation/react-navigation-stack/commit/f5a3880969afad2df409b0606e249b3971361dca))
## [2.2.2](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.2.1...react-navigation-stack@2.2.2) (2020-02-26)

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation-stack",
"version": "2.2.2",
"version": "2.8.2",
"description": "Stack navigator component for React Navigation",
"main": "lib/commonjs/index.js",
"module": "lib/module/index.js",
@@ -43,30 +43,30 @@
"react-native-iphone-x-helper": "^1.2.1"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.7",
"@react-native-community/masked-view": "^0.1.6",
"@react-navigation/stack": "^5.0.9",
"@react-native-community/bob": "^0.10.0",
"@react-native-community/masked-view": "^0.1.7",
"@react-navigation/stack": "^5.6.1",
"@types/color": "^3.0.1",
"@types/react": "^16.9.22",
"@types/react-native": "^0.61.17",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"@types/react-test-renderer": "^16.9.2",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.4",
"react-native-gesture-handler": "^1.6.0",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.0.0-beta.10",
"react-navigation": "^4.2.2",
"react-native-screens": "^2.3.0",
"react-navigation": "^4.4.0",
"react-test-renderer": "~16.9.0",
"typescript": "~3.7.5"
"typescript": "^3.9.5"
},
"peerDependencies": {
"@react-native-community/masked-view": "^0.1.1",
"@react-native-community/masked-view": ">=0.1.0",
"react": "*",
"react-native": "*",
"react-native-gesture-handler": "^1.5.0",
"react-native-safe-area-context": "^0.6.0",
"react-native-screens": "^1.0.0 || ^1.0.0-alpha.0 || ^2.0.0-alpha.20",
"react-native-gesture-handler": ">= 1.5.0",
"react-native-safe-area-context": ">= 0.6.0",
"react-native-screens": ">=1.0.0 || >= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0",
"react-navigation": "^4.1.1"
},
"@react-native-community/bob": {

View File

@@ -1,6 +1,6 @@
diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/index.tsx
--- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/index.tsx 2020-02-24 11:58:26.000000000 +0100
--- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/index.tsx 2020-06-24 23:16:17.000000000 +0200
@@ -3,11 +3,6 @@
import * as TransitionSpecs from './TransitionConfigs/TransitionSpecs';
import * as TransitionPresets from './TransitionConfigs/TransitionPresets';
@@ -16,22 +16,23 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/i
@@ -49,9 +44,10 @@
* Types
*/
export {
export type {
- StackNavigationOptions,
- StackNavigationProp,
- StackHeaderProps,
- StackScreenProps,
+ NavigationStackState,
+ StackNavigationProp as NavigationStackProp,
+ StackNavigationOptions as NavigationStackOptions,
+ StackNavigationConfig as NavigationStackConfig,
StackHeaderProps,
StackHeaderLeftButtonProps,
StackHeaderTitleProps,
StackCardInterpolatedStyle,
diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx src/vendor/navigators/createStackNavigator.tsx
--- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-02-24 11:53:26.000000000 +0100
--- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/navigators/createStackNavigator.tsx 1970-01-01 01:00:00.000000000 +0100
@@ -1,79 +0,0 @@
@@ -1,96 +0,0 @@
-import * as React from 'react';
-import { Platform } from 'react-native';
-import {
- useNavigationBuilder,
- createNavigatorFactory,
@@ -43,7 +44,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
- StackActions,
-} from '@react-navigation/native';
-import StackView from '../views/Stack/StackView';
-import {
-import type {
- StackNavigationConfig,
- StackNavigationOptions,
- StackNavigationEventMap,
@@ -59,6 +60,11 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
- screenOptions,
- ...rest
-}: Props) {
- const defaultOptions = {
- gestureEnabled: Platform.OS === 'ios',
- animationEnabled: Platform.OS !== 'web',
- };
-
- const { state, descriptors, navigation } = useNavigationBuilder<
- StackNavigationState,
- StackRouterOptions,
@@ -67,13 +73,22 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
- >(StackRouter, {
- initialRouteName,
- children,
- screenOptions,
- screenOptions:
- typeof screenOptions === 'function'
- ? (...args) => ({
- ...defaultOptions,
- ...screenOptions(...args),
- })
- : {
- ...defaultOptions,
- ...screenOptions,
- },
- });
-
- React.useEffect(
- () =>
- navigation.addListener &&
- navigation.addListener('tabPress', e => {
- navigation.addListener('tabPress', (e) => {
- const isFocused = navigation.isFocused();
-
- // Run the operation in the next frame so we're sure all listeners have been run
@@ -107,16 +122,18 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
-}
-
-export default createNavigatorFactory<
- StackNavigationState,
- StackNavigationOptions,
- StackNavigationEventMap,
- typeof StackNavigator
->(StackNavigator);
diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/types.tsx
--- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/types.tsx 2020-02-24 12:05:09.000000000 +0100
@@ -7,13 +7,28 @@
--- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/types.tsx 2020-06-24 23:18:40.000000000 +0200
@@ -8,15 +8,28 @@
} from 'react-native';
import { EdgeInsets } from 'react-native-safe-area-context';
import {
import type { EdgeInsets } from 'react-native-safe-area-context';
import type {
+ NavigationRoute,
+ NavigationState,
+ NavigationScreenProp,
@@ -126,6 +143,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
- Route,
- NavigationHelpers,
- StackNavigationState,
- StackActionHelpers,
- RouteProp,
-} from '@react-navigation/native';
+ NavigationParams,
+ NavigationNavigateAction,
@@ -148,7 +167,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
export type StackNavigationEventMap = {
/**
@@ -26,42 +41,29 @@
@@ -29,29 +42,28 @@
transitionEnd: { data: { closing: boolean } };
};
@@ -156,8 +175,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
- ParamListBase,
- StackNavigationEventMap
->;
-
+export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
export type StackNavigationProp<
- ParamList extends ParamListBase,
- RouteName extends keyof ParamList = string
@@ -167,28 +186,15 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
- StackNavigationState,
- StackNavigationOptions,
- StackNavigationEventMap
-> & {
- /**
- * Push a new screen onto the stack.
- *
- * @param name Name of the route for the tab.
- * @param [params] Params object for the route.
- */
- push<RouteName extends keyof ParamList>(
- ...args: ParamList[RouteName] extends undefined | any
- ? [RouteName] | [RouteName, ParamList[RouteName]]
- : [RouteName, ParamList[RouteName]]
- ): void;
-> &
- StackActionHelpers<ParamList>;
-
- /**
- * Pop a screen from the stack.
- */
- pop(count?: number): void;
-
- /**
- * Pop to the first route in the stack, dismissing all other screens.
- */
- popToTop(): void;
-export type StackScreenProps<
- ParamList extends ParamListBase,
- RouteName extends keyof ParamList = string
-> = {
- navigation: StackNavigationProp<ParamList, RouteName>;
- route: RouteProp<ParamList, RouteName>;
+ State = NavigationRoute,
+ Params = NavigationParams
+> = NavigationScreenProp<State, Params> & {
@@ -212,7 +218,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
};
export type Layout = { width: number; height: number };
@@ -237,24 +239,27 @@
@@ -228,24 +240,27 @@
/**
* Navigation prop for the header.
*/
@@ -246,7 +252,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
export type StackNavigationOptions = StackHeaderOptions &
Partial<TransitionPreset> & {
/**
@@ -332,6 +337,8 @@
@@ -330,6 +345,8 @@
bottom?: number;
left?: number;
};
@@ -255,39 +261,40 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
};
export type StackNavigationConfig = {
diff -Naur ../../node_modules/@react-navigation/stack/src/views/BorderlessButton.tsx src/vendor/views/BorderlessButton.tsx
--- ../../node_modules/@react-navigation/stack/src/views/BorderlessButton.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/BorderlessButton.tsx 2020-02-24 12:50:48.000000000 +0100
@@ -39,6 +39,7 @@
const { children, style, enabled, ...rest } = this.props;
diff -Naur ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx src/vendor/utils/PreviousSceneContext.tsx
--- ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/utils/PreviousSceneContext.tsx 2020-06-24 23:26:38.000000000 +0200
@@ -1,6 +1,5 @@
import * as React from 'react';
-import type { Route } from '@react-navigation/native';
-import type { Scene } from '../types';
+import type { Route, Scene } from '../types';
return (
+ // @ts-ignore
<AnimatedBaseButton
{...rest}
onActiveStateChange={this.handleActiveStateChange}
const PreviousSceneContext = React.createContext<
Scene<Route<string>> | undefined
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx src/vendor/views/Header/Header.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/Header.tsx 2020-02-24 12:48:47.000000000 +0100
@@ -1,12 +1,14 @@
--- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/Header.tsx 2020-06-25 03:01:13.000000000 +0200
@@ -1,12 +1,15 @@
import * as React from 'react';
-import { StackActions } from '@react-navigation/native';
+import { Dimensions } from 'react-native';
+import { StackActions } from 'react-navigation';
+import { getStatusBarHeight } from 'react-native-iphone-x-helper';
+
+import HeaderSegment, { getDefaultHeaderHeight } from './HeaderSegment';
-import HeaderSegment from './HeaderSegment';
+import HeaderSegment, { getDefaultHeaderHeight } from './HeaderSegment';
import HeaderTitle from './HeaderTitle';
import debounce from '../../utils/debounce';
import { StackHeaderProps, StackHeaderTitleProps } from '../../types';
import type { StackHeaderProps, StackHeaderTitleProps } from '../../types';
-export default React.memo(function Header(props: StackHeaderProps) {
+const Header = React.memo(function Header(props: StackHeaderProps) {
const {
scene,
previous,
@@ -22,7 +24,7 @@
@@ -22,7 +25,7 @@
? options.headerTitle
: options.title !== undefined
? options.title
@@ -296,7 +303,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
let leftLabel;
@@ -38,17 +40,12 @@
@@ -38,17 +41,20 @@
? o.headerTitle
: o.title !== undefined
? o.title
@@ -304,19 +311,26 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
+ : previous.route.routeName;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
const goBack = React.useCallback(
debounce(() => {
- if (navigation.canGoBack()) {
- if (navigation.isFocused() && navigation.canGoBack()) {
- navigation.dispatch({
- ...StackActions.pop(),
- source: scene.route.key,
- });
- }
+ navigation.dispatch(StackActions.pop({ key: scene.route.key }));
+ const key = navigation.isFirstRouteInParent()
+ ? // If we're the first route, we're going back to a parent navigator
+ // So we need to get the key of the route we're nested in
+ navigation.dangerouslyGetParent()?.state.key
+ : scene.route.key;
+
+ if (key !== undefined) {
+ navigation.dispatch(StackActions.pop({ key }));
}
}, 50),
[navigation, scene.route.key]
);
@@ -63,7 +60,10 @@
@@ -64,7 +70,10 @@
leftLabel={leftLabel}
headerTitle={
typeof options.headerTitle !== 'function'
@@ -328,7 +342,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
: options.headerTitle
}
onGoBack={previous ? goBack : undefined}
@@ -71,3 +71,18 @@
@@ -72,3 +81,18 @@
/>
);
});
@@ -348,33 +362,34 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
+
+export default Header;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx src/vendor/views/Header/HeaderBackButton.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/HeaderBackButton.tsx 2020-02-24 11:58:32.000000000 +0100
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/HeaderBackButton.tsx 2020-06-24 23:21:49.000000000 +0200
@@ -8,9 +8,9 @@
StyleSheet,
LayoutChangeEvent,
} from 'react-native';
-import { useTheme } from '@react-navigation/native';
import MaskedView from '../MaskedView';
import TouchableItem from '../TouchableItem';
import { TouchableItem } from '../TouchableItem';
+import useTheme from '../../../utils/useTheme';
import { StackHeaderLeftButtonProps } from '../../types';
import type { StackHeaderLeftButtonProps } from '../../types';
type Props = StackHeaderLeftButtonProps;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx src/vendor/views/Header/HeaderBackground.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/HeaderBackground.tsx 2020-02-24 11:58:32.000000000 +0100
@@ -1,6 +1,6 @@
import * as React from 'react';
import { Animated, StyleSheet, Platform, ViewProps } from 'react-native';
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/HeaderBackground.tsx 2020-06-24 23:16:23.000000000 +0200
@@ -7,7 +7,7 @@
StyleProp,
ViewStyle,
} from 'react-native';
-import { useTheme } from '@react-navigation/native';
+import useTheme from '../../../utils/useTheme';
type Props = ViewProps & {
children?: React.ReactNode;
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx src/vendor/views/Header/HeaderContainer.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/HeaderContainer.tsx 2020-02-24 12:08:14.000000000 +0100
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/HeaderContainer.tsx 2020-06-24 23:21:29.000000000 +0200
@@ -1,11 +1,6 @@
import * as React from 'react';
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
@@ -385,18 +400,18 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
- ParamListBase,
-} from '@react-navigation/native';
+import { NavigationContext } from 'react-navigation';
import { EdgeInsets } from 'react-native-safe-area-context';
import type { EdgeInsets } from 'react-native-safe-area-context';
import Header from './Header';
@@ -16,6 +11,7 @@
forSlideRight,
} from '../../TransitionConfigs/HeaderStyleInterpolators';
import {
+ Route,
@@ -19,6 +14,7 @@
import PreviousSceneContext from '../../utils/PreviousSceneContext';
import type {
Layout,
+ Route,
Scene,
StackHeaderStyleInterpolator,
@@ -99,9 +95,7 @@
StackNavigationProp,
@@ -109,9 +105,7 @@
insets,
scene,
previous,
@@ -407,7 +422,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
styleInterpolator:
mode === 'float'
? isHeaderStatic
@@ -120,7 +114,7 @@
@@ -130,7 +124,7 @@
key={scene.route.key}
value={scene.descriptor.navigation}
>
@@ -416,9 +431,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
<View
onLayout={
onContentHeightChange
@@ -152,7 +146,7 @@
)
) : null}
@@ -156,7 +150,7 @@
>
{header !== undefined ? header(props) : <Header {...props} />}
</View>
- </NavigationRouteContext.Provider>
+ </>
@@ -426,14 +441,14 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
);
})}
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx src/vendor/views/Header/HeaderSegment.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/HeaderSegment.tsx 2020-02-24 11:58:32.000000000 +0100
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/HeaderSegment.tsx 2020-06-24 23:20:58.000000000 +0200
@@ -8,7 +8,7 @@
ViewStyle,
} from 'react-native';
import { EdgeInsets } from 'react-native-safe-area-context';
-import { Route } from '@react-navigation/native';
+import { NavigationRoute } from 'react-navigation';
import type { EdgeInsets } from 'react-native-safe-area-context';
-import type { Route } from '@react-navigation/native';
+import type { NavigationRoute } from 'react-navigation';
import HeaderBackButton from './HeaderBackButton';
import HeaderBackground from './HeaderBackground';
import memoize from '../../utils/memoize';
@@ -447,24 +462,20 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSeg
};
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx src/vendor/views/Header/HeaderTitle.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Header/HeaderTitle.tsx 2020-02-24 12:47:49.000000000 +0100
@@ -1,8 +1,8 @@
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Header/HeaderTitle.tsx 2020-06-24 23:16:23.000000000 +0200
@@ -1,6 +1,6 @@
import * as React from 'react';
-import { Animated, StyleSheet, Platform, TextProps } from 'react-native';
import { Animated, StyleSheet, Platform } from 'react-native';
-import { useTheme } from '@react-navigation/native';
+import { Animated, StyleSheet, Platform } from 'react-native';
+import useTheme from '../../../utils/useTheme';
-type Props = TextProps & {
+type Props = React.ComponentProps<typeof Animated.Text> & {
type Props = Omit<React.ComponentProps<typeof Animated.Text>, 'key'> & {
tintColor?: string;
children?: string;
};
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx src/vendor/views/Stack/Card.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Stack/Card.tsx 2020-02-24 11:58:32.000000000 +0100
@@ -133,7 +133,7 @@
--- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Stack/Card.tsx 2020-06-24 23:16:23.000000000 +0200
@@ -146,7 +146,7 @@
private interactionHandle: number | undefined;
@@ -473,102 +484,72 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx s
private animate = ({
closing,
@@ -507,7 +507,7 @@
) : null}
<View
ref={this.contentRef}
- style={[styles.content, contentStyle]}
+ style={[styles.content, contentStyle] as any}
>
<StackGestureRefContext.Provider value={this.gestureRef}>
<CardAnimationContext.Provider value={animationContext}>
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx src/vendor/views/Stack/CardContainer.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Stack/CardContainer.tsx 2020-02-24 11:58:32.000000000 +0100
@@ -1,10 +1,16 @@
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Stack/CardContainer.tsx 2020-06-24 23:20:38.000000000 +0200
@@ -1,12 +1,13 @@
import * as React from 'react';
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
-import { Route, useTheme } from '@react-navigation/native';
import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
import Card from './Card';
import HeaderHeightContext from '../../utils/HeaderHeightContext';
-import { Scene, Layout, StackHeaderMode, TransitionPreset } from '../../types';
import HeaderShownContext from '../../utils/HeaderShownContext';
import PreviousSceneContext from '../../utils/PreviousSceneContext';
+import useTheme from '../../../utils/useTheme';
+import {
import type {
+ Route,
+ Scene,
+ Layout,
+ StackHeaderMode,
+ TransitionPreset,
+} from '../../types';
type Props = TransitionPreset & {
index: number;
@@ -180,7 +186,7 @@
? { marginTop: headerHeight }
: null
}
- contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
+ contentStyle={[{ backgroundColor: colors.background }, cardStyle] as any}
style={StyleSheet.absoluteFill}
>
<View style={styles.container}>
Scene,
Layout,
StackHeaderMode,
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx src/vendor/views/Stack/CardStack.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Stack/CardStack.tsx 2020-02-24 12:09:38.000000000 +0100
@@ -9,9 +9,8 @@
ViewProps,
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Stack/CardStack.tsx 2020-06-24 23:20:16.000000000 +0200
@@ -7,7 +7,7 @@
Platform,
} from 'react-native';
import { EdgeInsets } from 'react-native-safe-area-context';
-// eslint-disable-next-line import/no-unresolved
import { ScreenContainer, Screen, screensEnabled } from 'react-native-screens'; // Import with * as to prevent getters being called
-import { Route, StackNavigationState } from '@react-navigation/native';
+import { NavigationState as StackNavigationState } from 'react-navigation';
import type { EdgeInsets } from 'react-native-safe-area-context';
-import type { Route, StackNavigationState } from '@react-navigation/native';
+import type { NavigationState as StackNavigationState } from 'react-navigation';
import { MaybeScreenContainer, MaybeScreen } from '../Screens';
import { getDefaultHeaderHeight } from '../Header/HeaderSegment';
import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
@@ -24,6 +23,7 @@
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
import getDistanceForDirection from '../../utils/getDistanceForDirection';
import {
+ Route,
@@ -25,6 +25,7 @@
Layout,
StackHeaderMode,
StackCardMode,
@@ -103,7 +103,7 @@
<View
collapsable={!enabled}
removeClippedSubviews={Platform.OS !== 'ios' && enabled}
- style={[style, { overflow: 'hidden' }]}
+ style={[style, { overflow: 'hidden' }] as any}
{...rest}
/>
);
+ Route,
Scene,
StackDescriptorMap,
StackNavigationOptions,
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx src/vendor/views/Stack/StackView.tsx
--- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-02-24 11:53:26.000000000 +0100
+++ src/vendor/views/Stack/StackView.tsx 2020-02-24 12:09:08.000000000 +0100
@@ -4,9 +4,9 @@
import { GestureHandlerRootView } from 'react-native-gesture-handler';
--- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-06-25 01:58:50.000000000 +0200
+++ src/vendor/views/Stack/StackView.tsx 2020-06-24 23:19:46.000000000 +0200
@@ -2,11 +2,11 @@
import { View, Platform, StyleSheet } from 'react-native';
import { SafeAreaConsumer, EdgeInsets } from 'react-native-safe-area-context';
import {
- NavigationHelpersContext,
StackActions,
- StackNavigationState,
- Route,
-} from '@react-navigation/native';
+ NavigationState as StackNavigationState,
+ NavigationActions,
+ SceneView,
+} from 'react-navigation';
import { GestureHandlerRootView } from '../GestureHandler';
import CardStack from './CardStack';
import KeyboardManager from '../KeyboardManager';
@@ -15,6 +15,7 @@
@@ -16,6 +16,7 @@
} from '../Header/HeaderContainer';
import SafeAreaProviderCompat from '../SafeAreaProviderCompat';
import {
import type {
+ Route,
StackNavigationHelpers,
StackNavigationConfig,
StackDescriptorMap,
@@ -24,6 +25,7 @@
@@ -25,6 +26,7 @@
state: StackNavigationState;
navigation: StackNavigationHelpers;
descriptors: StackDescriptorMap;
@@ -576,7 +557,18 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
};
type State = {
@@ -290,14 +292,31 @@
@@ -293,7 +295,9 @@
return false;
}
- return gestureEnabled !== false;
+ return gestureEnabled !== undefined
+ ? gestureEnabled
+ : Platform.OS !== 'android';
}
return false;
@@ -321,26 +325,49 @@
return null;
}
@@ -597,19 +589,39 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
return <HeaderContainer {...props} />;
};
+ private handleTransitionComplete = ({ route }: { route: Route<string> }) => {
+ // TODO: remove when the new event system lands
+ this.props.navigation.dispatch(
+ StackActions.completeTransition({ toChildKey: route.key })
+ );
+ private handleTransitionComplete = () => {
+ const { state, navigation } = this.props;
+
+ if (state.isTransitioning) {
+ navigation.dispatch(
+ StackActions.completeTransition({
+ key: navigation.state.key,
+ toChildKey: state.routes[state.index].key,
+ })
+ );
+ }
+ };
+
private handleOpenRoute = ({ route }: { route: Route<string> }) => {
+ this.handleTransitionComplete({ route });
this.setState(state => ({
routes: state.replacingRouteKeys.length
? state.routes.filter(r => !state.replacingRouteKeys.includes(r.key))
@@ -315,12 +334,17 @@
const { state, navigation } = this.props;
const { closingRouteKeys, replacingRouteKeys } = this.state;
+ this.handleTransitionComplete();
+
if (
closingRouteKeys.some((key) => key === route.key) &&
replacingRouteKeys.every((key) => key !== route.key) &&
- state.routeNames.includes(route.name) &&
!state.routes.some((r) => r.key === route.key)
) {
// If route isn't present in current state, but was closing, assume that a close animation was cancelled
// So we need to add this route back to the state
- navigation.navigate(route);
+ navigation.dispatch(NavigationActions.navigate(route));
} else {
this.setState((state) => ({
routes: state.replacingRouteKeys.length
@@ -366,12 +393,11 @@
// If a route exists in state, trigger a pop
// This will happen in when the route was closed from the card component
// e.g. When the close animation triggered from a gesture ends
@@ -619,20 +631,14 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
- target: state.key,
- });
+ // @ts-ignore
+ navigation.dispatch(StackActions.pop({ key: route.key }));
+ navigation.dispatch(StackActions.pop({ key: route.key, prune: false }));
} else {
+ // While closing route we need to point to the previous one assuming that
+ // this previous one in routes array
+ const index = this.state.routes.findIndex(r => r.key === route.key);
+
+ this.handleTransitionComplete({
+ route: this.state.routes[Math.max(index - 1, 0)],
+ });
+ this.handleTransitionComplete();
+
// We need to clean up any state tracking the route and pop it immediately
this.setState(state => ({
routes: state.routes.filter(r => r.key !== route.key),
@@ -337,22 +361,24 @@
this.setState((state) => ({
routes: state.routes.filter((r) => r.key !== route.key),
@@ -388,26 +414,29 @@
private handleTransitionStart = (
{ route }: { route: Route<string> },
closing: boolean
@@ -669,3 +675,26 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
render() {
const {
state,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
navigation,
keyboardHandlingEnabled,
mode = 'card',
@@ -427,7 +456,7 @@
} = this.state;
return (
- <NavigationHelpersContext.Provider value={navigation}>
+ <>
<GestureHandlerWrapper style={styles.container}>
<SafeAreaProviderCompat>
<SafeAreaConsumer>
@@ -460,7 +489,7 @@
</SafeAreaConsumer>
</SafeAreaProviderCompat>
</GestureHandlerWrapper>
- </NavigationHelpersContext.Provider>
+ </>
);
}
}

View File

@@ -8,7 +8,7 @@ export { default as createStackNavigator } from './navigators/createStackNavigat
/**
* Types
*/
export {
export type {
NavigationStackScreenComponent,
NavigationStackScreenProps,
} from './types';

View File

@@ -9,7 +9,7 @@ import createAppContainer, {
_TESTING_ONLY_reset_container_count,
// @ts-ignore
} from '../../../../native/src/createAppContainer';
import { StackNavigationProp } from '../../vendor/types';
import type { StackNavigationProp } from '../../vendor/types';
const NavigationTestUtils = {
resetInternalState: _TESTING_ONLY_reset_container_count,

View File

@@ -8,12 +8,119 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
}
}
>
<View
pointerEvents="box-none"
style={
Array [
Object {
"zIndex": 1,
},
false,
]
}
>
<View
accessibilityElementsHidden={false}
importantForAccessibility="auto"
onLayout={[Function]}
pointerEvents="box-none"
style={null}
>
<View
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
"zIndex": 0,
}
}
>
<View
style={
Object {
"backgroundColor": "#fff",
"borderBottomColor": "#a7a7aa",
"flex": 1,
"shadowColor": "#a7a7aa",
"shadowOffset": Object {
"height": 0.5,
"width": 0,
},
"shadowOpacity": 0.85,
"shadowRadius": 0,
}
}
/>
</View>
<View
pointerEvents="box-none"
style={
Object {
"height": 44,
"maxHeight": undefined,
"minHeight": undefined,
"opacity": undefined,
"transform": undefined,
}
}
>
<View
pointerEvents="none"
style={
Object {
"height": 0,
}
}
/>
<View
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"justifyContent": "center",
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"marginHorizontal": 16,
"opacity": 1,
}
}
>
<Text
accessibilityRole="header"
numberOfLines={1}
onLayout={[Function]}
style={
Object {
"color": "rgba(0, 0, 0, 0.9)",
"fontSize": 17,
"fontWeight": "600",
}
}
>
Sub
</Text>
</View>
</View>
</View>
</View>
</View>
<View
onLayout={[Function]}
style={
Object {
"flex": 1,
"overflow": "hidden",
}
}
>
@@ -29,6 +136,14 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
}
}
>
<View
collapsable={false}
style={
Object {
"opacity": 1,
}
}
/>
<View
accessibilityElementsHidden={false}
closing={false}
@@ -57,8 +172,8 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -68,8 +183,8 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -81,7 +196,6 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
style={
Object {
"flex": 1,
"marginTop": 44,
}
}
>
@@ -115,7 +229,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
pointerEvents="none"
style={
Object {
"backgroundColor": "#fff",
"backgroundColor": "rgb(242, 242, 242)",
"bottom": 0,
"left": 0,
"position": "absolute",
@@ -174,7 +288,6 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
style={
Object {
"flex": 1,
"overflow": "hidden",
}
}
>
@@ -190,6 +303,14 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
}
}
>
<View
collapsable={false}
style={
Object {
"opacity": 1,
}
}
/>
<View
accessibilityElementsHidden={false}
closing={false}
@@ -218,8 +339,8 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -229,8 +350,8 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -242,7 +363,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
style={
Object {
"flex": 1,
"marginTop": 44,
"marginTop": 0,
}
}
>
@@ -276,7 +397,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
pointerEvents="none"
style={
Object {
"backgroundColor": "#fff",
"backgroundColor": "rgb(242, 242, 242)",
"bottom": 0,
"left": 0,
"position": "absolute",
@@ -334,110 +455,19 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
<View
pointerEvents="box-none"
style={
Object {
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
Array [
Object {
"zIndex": 1,
},
Object {
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
]
}
>
<View
accessibilityElementsHidden={false}
importantForAccessibility="auto"
onLayout={[Function]}
pointerEvents="box-none"
style={null}
>
<View
pointerEvents="none"
style={
Object {
"bottom": 0,
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<View
style={
Object {
"backgroundColor": "#fff",
"borderBottomColor": "#a7a7aa",
"flex": 1,
"shadowColor": "#a7a7aa",
"shadowOffset": Object {
"height": 0.5,
"width": 0,
},
"shadowOpacity": 0.85,
"shadowRadius": 0,
}
}
/>
</View>
<View
pointerEvents="box-none"
style={
Object {
"height": 44,
"maxHeight": undefined,
"minHeight": undefined,
"opacity": undefined,
"transform": undefined,
}
}
>
<View
pointerEvents="none"
style={
Object {
"height": 0,
}
}
/>
<View
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"justifyContent": "center",
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"marginHorizontal": 18,
"opacity": 1,
}
}
>
<Text
accessibilityRole="header"
numberOfLines={1}
onLayout={[Function]}
style={
Object {
"color": "rgba(0, 0, 0, 0.9)",
"fontSize": 17,
"fontWeight": "600",
}
}
>
Home
</Text>
</View>
</View>
</View>
</View>
</View>
/>
</View>
</View>
</View>
@@ -448,113 +478,6 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
</View>
</View>
</View>
<View
pointerEvents="box-none"
style={
Object {
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<View
accessibilityElementsHidden={false}
importantForAccessibility="auto"
onLayout={[Function]}
pointerEvents="box-none"
style={null}
>
<View
pointerEvents="none"
style={
Object {
"bottom": 0,
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<View
style={
Object {
"backgroundColor": "#fff",
"borderBottomColor": "#a7a7aa",
"flex": 1,
"shadowColor": "#a7a7aa",
"shadowOffset": Object {
"height": 0.5,
"width": 0,
},
"shadowOpacity": 0.85,
"shadowRadius": 0,
}
}
/>
</View>
<View
pointerEvents="box-none"
style={
Object {
"height": 44,
"maxHeight": undefined,
"minHeight": undefined,
"opacity": undefined,
"transform": undefined,
}
}
>
<View
pointerEvents="none"
style={
Object {
"height": 0,
}
}
/>
<View
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"justifyContent": "center",
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"marginHorizontal": 18,
"opacity": 1,
}
}
>
<Text
accessibilityRole="header"
numberOfLines={1}
onLayout={[Function]}
style={
Object {
"color": "rgba(0, 0, 0, 0.9)",
"fontSize": 17,
"fontWeight": "600",
}
}
>
Sub
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
`;

View File

@@ -8,177 +8,15 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
}
}
>
<View
onLayout={[Function]}
style={
Object {
"flex": 1,
"overflow": "hidden",
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<View
accessibilityElementsHidden={false}
closing={false}
gestureVelocityImpact={0.3}
importantForAccessibility="auto"
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
transitionSpec={
Object {
"close": Object {
"animation": "spring",
"config": Object {
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"stiffness": 1000,
},
},
"open": Object {
"animation": "spring",
"config": Object {
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"stiffness": 1000,
},
},
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"flex": 1,
"marginTop": 44,
}
}
>
<PanGestureHandler
enabled={false}
hitSlop={
Object {
"right": -700,
}
}
maxDeltaY={20}
minOffsetX={5}
onHandlerStateChange={[Function]}
>
<View
style={
Object {
"flex": 1,
"transform": Array [
Object {
"translateX": 0,
},
Object {
"translateX": 0,
},
],
}
}
>
<View
pointerEvents="none"
style={
Object {
"backgroundColor": "#fff",
"bottom": 0,
"left": 0,
"position": "absolute",
"shadowColor": "#000",
"shadowOffset": Object {
"height": 1,
"width": -1,
},
"shadowOpacity": 0.3,
"shadowRadius": 5,
"top": 0,
"width": 3,
}
}
/>
<View
style={
Array [
Object {
"flex": 1,
"overflow": "hidden",
},
Array [
Object {
"backgroundColor": "rgb(242, 242, 242)",
},
undefined,
],
]
}
>
<View
style={
Object {
"flex": 1,
"flexDirection": "column-reverse",
}
}
>
<View
style={
Object {
"flex": 1,
}
}
/>
</View>
</View>
</View>
</PanGestureHandler>
</View>
</View>
</View>
</View>
<View
pointerEvents="box-none"
style={
Object {
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
Array [
Object {
"zIndex": 1,
},
false,
]
}
>
<View
@@ -189,7 +27,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
style={null}
>
<View
pointerEvents="none"
pointerEvents="box-none"
style={
Object {
"bottom": 0,
@@ -198,6 +36,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
"position": "absolute",
"right": 0,
"top": 0,
"zIndex": 0,
}
}
>
@@ -254,7 +93,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
pointerEvents="box-none"
style={
Object {
"marginHorizontal": 18,
"marginHorizontal": 16,
"opacity": 1,
}
}
@@ -294,23 +133,11 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
</View>
</View>
</View>
</View>
`;
exports[`StackNavigator renders successfully 1`] = `
<View
style={
Object {
"flex": 1,
}
}
>
<View
onLayout={[Function]}
style={
Object {
"flex": 1,
"overflow": "hidden",
}
}
>
@@ -326,6 +153,14 @@ exports[`StackNavigator renders successfully 1`] = `
}
}
>
<View
collapsable={false}
style={
Object {
"opacity": 1,
}
}
/>
<View
accessibilityElementsHidden={false}
closing={false}
@@ -354,8 +189,8 @@ exports[`StackNavigator renders successfully 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -365,8 +200,8 @@ exports[`StackNavigator renders successfully 1`] = `
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 0.01,
"restSpeedThreshold": 0.01,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
@@ -378,7 +213,6 @@ exports[`StackNavigator renders successfully 1`] = `
style={
Object {
"flex": 1,
"marginTop": 44,
}
}
>
@@ -412,7 +246,7 @@ exports[`StackNavigator renders successfully 1`] = `
pointerEvents="none"
style={
Object {
"backgroundColor": "#fff",
"backgroundColor": "rgb(242, 242, 242)",
"bottom": 0,
"left": 0,
"position": "absolute",
@@ -467,15 +301,26 @@ exports[`StackNavigator renders successfully 1`] = `
</View>
</View>
</View>
</View>
`;
exports[`StackNavigator renders successfully 1`] = `
<View
style={
Object {
"flex": 1,
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
Array [
Object {
"zIndex": 1,
},
false,
]
}
>
<View
@@ -486,7 +331,7 @@ exports[`StackNavigator renders successfully 1`] = `
style={null}
>
<View
pointerEvents="none"
pointerEvents="box-none"
style={
Object {
"bottom": 0,
@@ -495,6 +340,7 @@ exports[`StackNavigator renders successfully 1`] = `
"position": "absolute",
"right": 0,
"top": 0,
"zIndex": 0,
}
}
>
@@ -551,7 +397,7 @@ exports[`StackNavigator renders successfully 1`] = `
pointerEvents="box-none"
style={
Object {
"marginHorizontal": 18,
"marginHorizontal": 16,
"opacity": 1,
}
}
@@ -575,5 +421,173 @@ exports[`StackNavigator renders successfully 1`] = `
</View>
</View>
</View>
<View
onLayout={[Function]}
style={
Object {
"flex": 1,
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<View
collapsable={false}
style={
Object {
"opacity": 1,
}
}
/>
<View
accessibilityElementsHidden={false}
closing={false}
gestureVelocityImpact={0.3}
importantForAccessibility="auto"
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
transitionSpec={
Object {
"close": Object {
"animation": "spring",
"config": Object {
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
"open": Object {
"animation": "spring",
"config": Object {
"damping": 500,
"mass": 3,
"overshootClamping": true,
"restDisplacementThreshold": 10,
"restSpeedThreshold": 10,
"stiffness": 1000,
},
},
}
}
>
<View
pointerEvents="box-none"
style={
Object {
"flex": 1,
}
}
>
<PanGestureHandler
enabled={false}
hitSlop={
Object {
"right": -700,
}
}
maxDeltaY={20}
minOffsetX={5}
onHandlerStateChange={[Function]}
>
<View
style={
Object {
"flex": 1,
"transform": Array [
Object {
"translateX": 0,
},
Object {
"translateX": 0,
},
],
}
}
>
<View
pointerEvents="none"
style={
Object {
"backgroundColor": "rgb(242, 242, 242)",
"bottom": 0,
"left": 0,
"position": "absolute",
"shadowColor": "#000",
"shadowOffset": Object {
"height": 1,
"width": -1,
},
"shadowOpacity": 0.3,
"shadowRadius": 5,
"top": 0,
"width": 3,
}
}
/>
<View
style={
Array [
Object {
"flex": 1,
"overflow": "hidden",
},
Array [
Object {
"backgroundColor": "rgb(242, 242, 242)",
},
undefined,
],
]
}
>
<View
style={
Object {
"flex": 1,
"flexDirection": "column-reverse",
}
}
>
<View
style={
Object {
"flex": 1,
}
}
/>
</View>
</View>
</View>
</PanGestureHandler>
</View>
</View>
</View>
</View>
</View>
`;

View File

@@ -7,7 +7,7 @@ import {
CreateNavigatorConfig,
} from 'react-navigation';
import StackView from '../views/StackView';
import {
import type {
StackNavigationConfig,
StackNavigationOptions,
StackNavigationProp,
@@ -30,7 +30,7 @@ function createStackNavigator(
return createNavigator(
// TODO: don't have time to fix it right now
// @ts-ignore
navigatorProps => <StackView {...navigatorProps} />,
(navigatorProps) => <StackView {...navigatorProps} />,
router,
stackConfig
);

View File

@@ -1,10 +1,13 @@
import {
import type {
NavigationRoute,
NavigationParams,
NavigationScreenConfig,
SupportedThemes,
} from 'react-navigation';
import { StackNavigationProp, StackNavigationOptions } from './vendor/types';
import type {
StackNavigationProp,
StackNavigationOptions,
} from './vendor/types';
export type NavigationStackScreenProps<
Params = NavigationParams,

View File

@@ -1,5 +1,8 @@
import { StyleProp, ViewStyle } from 'react-native';
import { StackNavigationOptions, StackNavigationConfig } from '../vendor/types';
import type { StyleProp, ViewStyle } from 'react-native';
import type {
StackNavigationOptions,
StackNavigationConfig,
} from '../vendor/types';
type Validation = {
message: string;
@@ -58,7 +61,7 @@ export default function validateDeprecatedConfig(
) {
let result = options;
Object.keys(validations).forEach(name => {
Object.keys(validations).forEach((name) => {
if (name in config) {
const { compat, message } = validations[name];

View File

@@ -1,5 +1,5 @@
import { EdgeInsets } from 'react-native-safe-area-context';
import { StackNavigationOptions } from '../vendor/types';
import type { EdgeInsets } from 'react-native-safe-area-context';
import type { StackNavigationOptions } from '../vendor/types';
type Validation = {
check: (o: Record<string, any>) => boolean;
@@ -12,10 +12,10 @@ const shownWarnings: string[] = [];
const validations: Validation[] = [
{
check: o => typeof o.headerForceInset === 'object',
check: (o) => typeof o.headerForceInset === 'object',
deprecated: 'headerForceInset',
updated: 'safeAreaInsets',
compat: o => {
compat: (o) => {
const { headerForceInset, ...rest } = o;
let safeAreaInsets: Partial<EdgeInsets> | undefined = {
@@ -55,20 +55,20 @@ const validations: Validation[] = [
},
},
{
check: o => o.gesturesEnabled !== undefined,
check: (o) => o.gesturesEnabled !== undefined,
deprecated: 'gesturesEnabled',
updated: 'gestureEnabled',
compat: o => {
compat: (o) => {
const { gesturesEnabled, ...rest } = o;
return { ...rest, gestureEnabled: gesturesEnabled };
},
},
{
check: o => o.header === null,
check: (o) => o.header === null,
deprecated: 'header: null',
updated: 'headerShown: false',
compat: o => {
compat: (o) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { header, ...rest } = o;
@@ -76,26 +76,26 @@ const validations: Validation[] = [
},
},
{
check: o => o.header != null && typeof o.header !== 'function',
check: (o) => o.header != null && typeof o.header !== 'function',
deprecated: 'header: <SomeElement />',
updated: 'header: () => <SomeElement />',
compat: o => ({ ...o, header: () => o.header }),
compat: (o) => ({ ...o, header: () => o.header }),
},
{
check: o =>
check: (o) =>
o.headerTitle !== undefined &&
typeof o.headerTitle !== 'string' &&
typeof o.headerTitle !== 'function',
deprecated: 'headerTitle: <SomeElement />',
updated: 'headerTitle: () => <SomeElement />',
compat: o => ({ ...o, headerTitle: () => o.headerTitle }),
compat: (o) => ({ ...o, headerTitle: () => o.headerTitle }),
},
...['headerLeft', 'headerRight', 'headerBackground', 'headerBackImage'].map(
(p): Validation => ({
check: (o: any) => o[p] !== undefined && typeof o[p] !== 'function',
deprecated: `${p}: <SomeElement />`,
updated: `${p}: () => <SomeElement />`,
compat: o => ({ ...o, [p]: () => o[p] }),
compat: (o) => ({ ...o, [p]: () => o[p] }),
})
),
];
@@ -108,7 +108,7 @@ export default function validateDeprecatedOptions(
const warnings: Validation[] = [];
// Validate options to show warnings for deprecations
validations.forEach(v => {
validations.forEach((v) => {
if (v.check(options)) {
result = v.compat(result);
@@ -127,7 +127,7 @@ export default function validateDeprecatedOptions(
console.warn(
`Deprecation in 'navigationOptions':\n${warnings
.map(
v =>
(v) =>
`- '${v.deprecated}' will be removed in a future version. Use '${v.updated}' instead`
)
.join('\n')}`

View File

@@ -1,7 +1,7 @@
import { Animated } from 'react-native';
import { isIphoneX } from 'react-native-iphone-x-helper';
import conditional from '../utils/conditional';
import {
import type {
StackCardInterpolationProps,
StackCardInterpolatedStyle,
} from '../types';
@@ -164,6 +164,7 @@ export function forModalPresentationIOS({
borderTopLeftRadius: borderRadius,
borderTopRightRadius: borderRadius,
marginTop: index === 0 ? 0 : statusBarHeight,
marginBottom: index === 0 ? 0 : topOffset,
transform: [{ translateY }, { scale }],
},
overlayStyle: { opacity: overlayOpacity },

View File

@@ -1,5 +1,5 @@
import { Animated, I18nManager } from 'react-native';
import {
import type {
StackHeaderInterpolationProps,
StackHeaderInterpolatedStyle,
} from '../types';

View File

@@ -1,3 +1,4 @@
import { Platform } from 'react-native';
import {
forHorizontalIOS,
forVerticalIOS,
@@ -14,8 +15,7 @@ import {
FadeOutToBottomAndroidSpec,
FadeInFromBottomAndroidSpec,
} from './TransitionSpecs';
import { TransitionPreset } from '../types';
import { Platform } from 'react-native';
import type { TransitionPreset } from '../types';
const ANDROID_VERSION_PIE = 28;

View File

@@ -1,5 +1,5 @@
import { Easing } from 'react-native';
import { TransitionSpec } from '../types';
import type { TransitionSpec } from '../types';
/**
* Exact values from UINavigationController's animation configuration.
@@ -11,8 +11,8 @@ export const TransitionIOSSpec: TransitionSpec = {
damping: 500,
mass: 3,
overshootClamping: true,
restDisplacementThreshold: 0.01,
restSpeedThreshold: 0.01,
restDisplacementThreshold: 10,
restSpeedThreshold: 10,
},
};

View File

@@ -43,11 +43,12 @@ export { default as useGestureHandlerRef } from './utils/useGestureHandlerRef';
/**
* Types
*/
export {
export type {
NavigationStackState,
StackNavigationProp as NavigationStackProp,
StackNavigationOptions as NavigationStackOptions,
StackNavigationConfig as NavigationStackConfig,
StackHeaderProps,
StackHeaderLeftButtonProps,
StackHeaderTitleProps,
StackCardInterpolatedStyle,

View File

@@ -1,12 +1,13 @@
import {
import type * as React from 'react';
import type {
Animated,
StyleProp,
TextStyle,
ViewStyle,
LayoutChangeEvent,
} from 'react-native';
import { EdgeInsets } from 'react-native-safe-area-context';
import {
import type { EdgeInsets } from 'react-native-safe-area-context';
import type {
NavigationRoute,
NavigationState,
NavigationScreenProp,
@@ -42,7 +43,6 @@ export type StackNavigationEventMap = {
};
export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
export type StackNavigationProp<
State = NavigationRoute,
Params = NavigationParams
@@ -124,14 +124,14 @@ export type StackHeaderOptions = {
/**
* Style object for the title component.
*/
headerTitleStyle?: StyleProp<TextStyle>;
headerTitleStyle?: React.ComponentProps<typeof Animated.Text>['style'];
/**
* Style object for the container of the `headerTitle` component, for example to add padding.
* By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`.
* This may lead to white space or overlap between `headerLeft` and `headerTitle` if a customized `headerLeft` is used.
* It can be solved by adjusting `left` and `right` style in `headerTitleContainerStyle` and `marginHorizontal` in `headerTitleStyle`.
*/
headerTitleContainerStyle?: StyleProp<ViewStyle>;
headerTitleContainerStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
/**
* Tint color for the header.
*/
@@ -145,7 +145,8 @@ export type StackHeaderOptions = {
*/
headerBackAllowFontScaling?: boolean;
/**
* Title string used by the back button on iOS, or `null` to disable label. Defaults to the previous scene's `headerTitle`.
* Title string used by the back button on iOS. Defaults to the previous scene's `headerTitle`.
* Use `headerBackTitleVisible: false` to hide it.
*/
headerBackTitle?: string;
/**
@@ -169,7 +170,7 @@ export type StackHeaderOptions = {
/**
* Style object for the container of the `headerLeft` component, for example to add padding.
*/
headerLeftContainerStyle?: StyleProp<ViewStyle>;
headerLeftContainerStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
/**
* Function which returns a React Element to display on the right side of the header.
*/
@@ -177,7 +178,7 @@ export type StackHeaderOptions = {
/**
* Style object for the container of the `headerRight` component, for example to add padding.
*/
headerRightContainerStyle?: StyleProp<ViewStyle>;
headerRightContainerStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
/**
* Function which returns a React Element to display custom image in header's back button.
* It receives the `tintColor` in in the options object as an argument. object.
@@ -199,7 +200,7 @@ export type StackHeaderOptions = {
/**
* Style object for the header. You can specify a custom background color here, for example.
*/
headerStyle?: StyleProp<ViewStyle>;
headerStyle?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
/**
* Defaults to `false`. If `true`, the header will not have a background unless you explicitly provide it with `headerBackground`.
* The header will also float over the screen so that it overlaps the content underneath.
@@ -284,6 +285,10 @@ export type StackNavigationOptions = StackHeaderOptions &
* Defaults to `true` on Android and `false` on iOS.
*/
cardOverlayEnabled?: boolean;
/**
* Function that returns a React Element to display as a overlay for the card.
*/
cardOverlay?: (props: { style: StyleProp<ViewStyle> }) => React.ReactNode;
/**
* Style object for the card in stack.
* You can provide a custom background color to use instead of the default background here.
@@ -296,7 +301,8 @@ export type StackNavigationOptions = StackHeaderOptions &
cardStyle?: StyleProp<ViewStyle>;
/**
* Whether transition animation should be enabled the screen.
* If you set it to `false`, the screen won't animate when pushing or popping. Defaults to `true`.
* If you set it to `false`, the screen won't animate when pushing or popping.
* Defaults to `true` on Android and iOS, `false` on Web.
*/
animationEnabled?: boolean;
/**
@@ -306,10 +312,12 @@ export type StackNavigationOptions = StackHeaderOptions &
animationTypeForReplace?: 'push' | 'pop';
/**
* Whether you can use gestures to dismiss this screen. Defaults to `true` on iOS, `false` on Android.
* Not supported on Web.
*/
gestureEnabled?: boolean;
/**
* Object to override the distance of touch start from the edge of the screen to recognize gestures.
* Not supported on Web.
*/
gestureResponseDistance?: {
/**
@@ -322,8 +330,8 @@ export type StackNavigationOptions = StackHeaderOptions &
horizontal?: number;
};
/**
* Number which determines the relevance of velocity for the gesture.
* Defaults to 0.3.
* Number which determines the relevance of velocity for the gesture. Defaults to 0.3.
* Not supported on Web.
*/
gestureVelocityImpact?: number;
/**
@@ -390,7 +398,7 @@ export type StackHeaderLeftButtonProps = {
/**
* Style object for the label.
*/
labelStyle?: React.ComponentProps<typeof Animated.Text>['style'];
labelStyle?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
/**
* Whether label font should scale to respect Text Size accessibility settings.
*/
@@ -437,7 +445,7 @@ export type StackHeaderTitleProps = {
/**
* Style object for the title element.
*/
style?: StyleProp<TextStyle>;
style?: React.ComponentProps<typeof Animated.Text>['style'];
};
export type TransitionSpec =

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { StackCardInterpolationProps } from '../types';
import type { StackCardInterpolationProps } from '../types';
export default React.createContext<StackCardInterpolationProps | undefined>(
undefined

View File

@@ -1,6 +1,5 @@
import * as React from 'react';
import { PanGestureHandler } from 'react-native-gesture-handler';
export default React.createContext<React.Ref<PanGestureHandler> | undefined>(
undefined
);
export default React.createContext<React.Ref<
import('react-native-gesture-handler').PanGestureHandler
> | null>(null);

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
const HeaderShownContext = React.createContext(false);
export default HeaderShownContext;

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import type { Route, Scene } from '../types';
const PreviousSceneContext = React.createContext<
Scene<Route<string>> | undefined
>(undefined);
export default PreviousSceneContext;

Some files were not shown because too many files have changed in this diff Show More