Compare commits

..

4 Commits

Author SHA1 Message Date
Brent Vatne
f9fbffbfa0 Release 1.1.0 2018-02-19 18:15:37 -08:00
Brent Vatne
1b8422d77d Fix TabRouter to support shorthand route config 2018-02-19 18:13:22 -08:00
Brent Vatne
e27afea7ab Release 1.1.0-rc.5 2018-02-19 14:46:39 -08:00
Brent Vatne
ca6cd89118 Fix regression in modular back button 2018-02-19 14:46:25 -08:00
28 changed files with 526 additions and 687 deletions

View File

@@ -15,26 +15,9 @@ jobs:
- v3-react-navigation-master
- run: yarn # install root deps
- run: ./scripts/test.sh # run tests
- setup_remote_docker
- deploy:
command: |
set -x
VER="17.03.0-ce"
curl -L -o /tmp/docker-$VER.tgz https://get.docker.com/builds/Linux/x86_64/docker-$VER.tgz
tar -xz -C /tmp -f /tmp/docker-$VER.tgz
mv /tmp/docker/* /usr/bin
yarn global add exp
set +x
exp login -u "$EXPO_USERNAME" -p "$EXPO_PASSWORD"
set -x
cd examples/NavigationPlayground && yarn && exp publish --release-channel "${CIRCLE_SHA1}"
- save_cache:
key: v3-react-navigation-{{ .Branch }}-{{ checksum "package.json" }}
paths:
- ~/.cache/yarn
- ~/react-navigation/examples/NavigationPlayground/node_modules
- ~/react-navigation/examples/ReduxExample/node_modules
notify:
webhooks:
- url: https://react-navigation-ci.now.sh

View File

@@ -45,8 +45,8 @@ This library is a community effort: it can only be great if we all help out in o
* Creating public example repositories or [Snacks](https://snack.expo.io/) of navigation problems you have solved and sharing the links in [Community Resources](https://github.com/react-navigation/react-navigation/blob/master/COMMUNITY_RESOURCES.md).
* Answering questions on [Stack Overflow](https://stackoverflow.com/search?q=react-navigation).
* Answering questions in our [Reactiflux](https://www.reactiflux.com/) channel.
* Providing feedback on the open [PRs](https://github.com/react-navigation/react-navigation/pulls).
* Providing feedback on the open [RFCs](https://github.com/react-navigation/rfcs).
* Providing feedback on the open [PRs](https://github.com/react-community/react-navigation/pulls).
* Providing feedback on the open [RFCs](https://github.com/react-community/rfcs/pulls).
* Improving the [website](https://github.com/react-navigation/react-navigation.github.io).
If you would like to submit a pull request, please follow the [Contributors guide](https://reactnavigation.org/docs/contributing.html) to find out how. If you don't know where to start, check the ones with the label [`good first issue`](https://github.com/react-community/react-navigation/labels/good%20first%20issue) - even [fixing a typo in the documentation](https://github.com/react-community/react-navigation/pull/2727) is a worthy contribution!
@@ -57,7 +57,7 @@ Certainly not! There other libraries - which, depending on your needs, can be be
#### Can I use this library for web?
Web support was [not a priority for the 1.0 release](https://github.com/react-community/react-navigation/issues/2585#issuecomment-330338793), but the architecture of this library allows for it (and it has worked in the past). If you would like to lead this charge, please reach out with your ideas for how to move forward on the [RFCs repository](https://github.com/react-navigation/rfcs) and we would be happy to discuss.
Currently this is [not a priority](https://github.com/react-community/react-navigation/issues/2585#issuecomment-330338793), but the architecture of this library allows for it (and it has worked in the past). If you would like to lead this charge, please reach out with your ideas for how to move forward on the [RFCs repository](https://github.com/react-navigation/rfcs) and we would be happy to discuss.
## Code of conduct

View File

@@ -65,13 +65,11 @@ module.file_ext=.jsx
module.file_ext=.json
module.file_ext=.native.js
suppress_type=$FlowIgnore
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy

View File

@@ -29,7 +29,6 @@ import StacksOverTabs from './StacksOverTabs';
import StacksWithKeys from './StacksWithKeys';
import SimpleStack from './SimpleStack';
import StackWithHeaderPreset from './StackWithHeaderPreset';
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
import SimpleTabs from './SimpleTabs';
import TabAnimations from './TabAnimations';
import TabsWithNavigationFocus from './TabsWithNavigationFocus';
@@ -51,14 +50,6 @@ const ExampleInfo = {
name: 'UIKit-style Header Transitions',
description: 'Masked back button and sliding header items. iOS only.',
},
StackWithHeaderPreset: {
name: 'UIKit-style Header Transitions',
description: 'Masked back button and sliding header items. iOS only.',
},
StackWithTranslucentHeader: {
name: 'Translucent Header',
description: 'Render arbitrary translucent content in header background.',
},
// MultipleDrawer: {
// name: 'Multiple Drawer Example',
// description: 'Add any drawer you need',
@@ -123,7 +114,6 @@ const ExampleRoutes = {
// screen: MultipleDrawer,
// },
StackWithHeaderPreset: StackWithHeaderPreset,
StackWithTranslucentHeader: StackWithTranslucentHeader,
TabsInDrawer: TabsInDrawer,
CustomTabs: CustomTabs,
CustomTransitioner: CustomTransitioner,

View File

@@ -178,18 +178,20 @@ MyProfileScreen.navigationOptions = props => {
};
};
const SimpleStack = StackNavigator({
Home: {
screen: MyHomeScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
});
const SimpleStack = StackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
}
);
export default SimpleStack;

View File

@@ -1,234 +0,0 @@
/**
* @flow
*/
import type {
NavigationScreenProp,
NavigationEventSubscription,
} from 'react-navigation';
import { isIphoneX } from 'react-native-iphone-x-helper';
import * as React from 'react';
import { BlurView, Constants } from 'expo';
import {
Button,
Dimensions,
Platform,
ScrollView,
StatusBar,
View,
} from 'react-native';
import { Header, StackNavigator } from 'react-navigation';
import SampleText from './SampleText';
type MyNavScreenProps = {
navigation: NavigationScreenProp<*>,
banner: React.Node,
};
class MyNavScreen extends React.Component<MyNavScreenProps> {
render() {
const { navigation, banner } = this.props;
return (
<ScrollView style={{ flex: 1 }} {...this.getHeaderInset()}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.push('Profile', { name: 'Jane' })}
title="Push a profile screen"
/>
<Button
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
title="Navigate to a photos screen"
/>
<Button
onPress={() => navigation.replace('Profile', { name: 'Lucy' })}
title="Replace with profile"
/>
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</ScrollView>
);
}
// Inset to compensate for navigation bar being transparent.
// And improved abstraction for this will be built in to react-navigation
// at some point.
getHeaderInset() {
const NOTCH_HEIGHT = isIphoneX() ? 25 : 0;
// $FlowIgnore: we will remove the HEIGHT static soon enough
const BASE_HEADER_HEIGHT = Header.HEIGHT;
const HEADER_HEIGHT =
Platform.OS === 'ios'
? BASE_HEADER_HEIGHT + NOTCH_HEIGHT
: BASE_HEADER_HEIGHT + Constants.statusBarHeight;
return Platform.select({
ios: {
contentInset: { top: HEADER_HEIGHT },
contentOffset: { y: -HEADER_HEIGHT },
},
android: {
contentContainerStyle: {
paddingTop: HEADER_HEIGHT,
},
},
});
}
}
type MyHomeScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
static navigationOptions = {
title: 'Welcome',
};
_s0: NavigationEventSubscription;
_s1: NavigationEventSubscription;
_s2: NavigationEventSubscription;
_s3: NavigationEventSubscription;
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onWF = a => {
console.log('_willFocus HomeScreen', a);
};
_onDF = a => {
console.log('_didFocus HomeScreen', a);
};
_onWB = a => {
console.log('_willBlur HomeScreen', a);
};
_onDB = a => {
console.log('_didBlur HomeScreen', a);
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
}
}
type MyPhotosScreenProps = {
navigation: NavigationScreenProp<*>,
};
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
static navigationOptions = {
title: 'Photos',
};
_s0: NavigationEventSubscription;
_s1: NavigationEventSubscription;
_s2: NavigationEventSubscription;
_s3: NavigationEventSubscription;
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onWF = a => {
console.log('_willFocus PhotosScreen', a);
};
_onDF = a => {
console.log('_didFocus PhotosScreen', a);
};
_onWB = a => {
console.log('_willBlur PhotosScreen', a);
};
_onDB = a => {
console.log('_didBlur PhotosScreen', a);
};
render() {
const { navigation } = this.props;
return (
<MyNavScreen
banner={`${navigation.state.params.name}'s Photos`}
navigation={navigation}
/>
);
}
}
const MyProfileScreen = ({ navigation }) => (
<MyNavScreen
banner={`${navigation.state.params.mode === 'edit' ? 'Now Editing ' : ''}${
navigation.state.params.name
}'s Profile`}
navigation={navigation}
/>
);
MyProfileScreen.navigationOptions = props => {
const { navigation } = props;
const { state, setParams } = navigation;
const { params } = state;
return {
headerBackImage: params.headerBackImage,
headerTitle: `${params.name}'s Profile!`,
// Render a button on the right side of the header.
// When pressed switches the screen to edit mode.
headerRight: (
<Button
title={params.mode === 'edit' ? 'Done' : 'Edit'}
onPress={() =>
setParams({ mode: params.mode === 'edit' ? '' : 'edit' })
}
/>
),
};
};
const StackWithTranslucentHeader = StackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
},
{
headerTransitionPreset: 'uikit',
navigationOptions: {
headerTransparent: true,
headerBackground: Platform.select({
ios: <BlurView style={{ flex: 1 }} intensity={98} />,
android: (
<View style={{ flex: 1, backgroundColor: 'rgba(255,255,255,0.7)' }} />
),
}),
},
}
);
export default StackWithTranslucentHeader;

View File

@@ -14,12 +14,11 @@
"expo": "^25.0.0",
"react": "16.2.0",
"react-native": "^0.52.0",
"react-native-iphone-x-helper": "^1.0.2",
"react-navigation": "link:../.."
},
"devDependencies": {
"babel-jest": "^21.0.0",
"babel-plugin-transform-remove-console": "^6.9.0",
"babel-jest": "^21.0.0",
"flow-bin": "^0.61.0",
"jest": "^21.0.1",
"jest-expo": "^25.1.0",

View File

@@ -5173,17 +5173,13 @@ react-native-gesture-handler@1.0.0-alpha.39:
invariant "^2.2.2"
prop-types "^15.5.10"
react-native-iphone-x-helper@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.0.2.tgz#7dbca530930f7c1ce8633cc8fd13ba94102992e1"
react-native-maps@0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.19.0.tgz#ce94fad1cf360e335cb4338a68c95f791e869074"
react-native-safe-area-view@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz#38f5ab9368d6ef9e5d18ab64212938af3ec39421"
react-native-safe-area-view@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.6.0.tgz#ce01eb27905a77780219537e0f53fe9c783a8b3d"
dependencies:
hoist-non-react-statics "^2.3.1"

View File

@@ -71,11 +71,25 @@ declare module 'react-navigation' {
key?: string,
|};
declare type DeprecatedNavigationNavigateAction = {|
type: 'Navigate',
routeName: string,
params?: NavigationParams,
// The action to run inside the sub-router
action?: NavigationNavigateAction | DeprecatedNavigationNavigateAction,
|};
declare export type NavigationBackAction = {|
type: 'Navigation/BACK',
key?: ?string,
|};
declare type DeprecatedNavigationBackAction = {|
type: 'Back',
key?: ?string,
|};
declare export type NavigationSetParamsAction = {|
type: 'Navigation/SET_PARAMS',
@@ -86,11 +100,26 @@ declare module 'react-navigation' {
params: NavigationParams,
|};
declare type DeprecatedNavigationSetParamsAction = {|
type: 'SetParams',
// The key of the route where the params should be set
key: string,
// The new params to merge into the existing route params
params: NavigationParams,
|};
declare export type NavigationInitAction = {|
type: 'Navigation/INIT',
params?: NavigationParams,
|};
declare type DeprecatedNavigationInitAction = {|
type: 'Init',
params?: NavigationParams,
|};
declare export type NavigationResetAction = {|
type: 'Navigation/RESET',
index: number,
@@ -98,11 +127,25 @@ declare module 'react-navigation' {
actions: Array<NavigationNavigateAction>,
|};
declare type DeprecatedNavigationResetAction = {|
type: 'Reset',
index: number,
key?: ?string,
actions: Array<
NavigationNavigateAction | DeprecatedNavigationNavigateAction
>,
|};
declare export type NavigationUriAction = {|
type: 'Navigation/URI',
uri: string,
|};
declare type DeprecatedNavigationUriAction = {|
type: 'Uri',
uri: string,
|};
declare export type NavigationReplaceAction = {|
+type: 'Navigation/REPLACE',
+key: string,
@@ -138,6 +181,17 @@ declare module 'react-navigation' {
| NavigationSetParamsAction
| NavigationResetAction;
declare type DeprecatedNavigationAction =
| DeprecatedNavigationInitAction
| DeprecatedNavigationNavigateAction
| DeprecatedNavigationBackAction
| DeprecatedNavigationSetParamsAction
| DeprecatedNavigationResetAction;
declare export type PossiblyDeprecatedNavigationAction =
| NavigationAction
| DeprecatedNavigationAction;
/**
* NavigationState is a tree of routes for a single navigator, where each
* child route may either be a NavigationScreenRoute or a
@@ -327,7 +381,6 @@ declare module 'react-navigation' {
declare export type NavigationStackScreenOptions = NavigationScreenOptions & {
header?: ?(React$Node | (HeaderProps => React$Node)),
headerTransparent?: boolean,
headerTitle?: string | React$Node | React$ElementType,
headerTitleStyle?: AnimatedTextStyleProp,
headerTitleAllowFontScaling?: boolean,
@@ -340,7 +393,6 @@ declare module 'react-navigation' {
headerPressColorAndroid?: string,
headerRight?: React$Node,
headerStyle?: ViewStyleProp,
headerBackground?: React$Node | React$ElementType,
gesturesEnabled?: boolean,
gestureResponseDistance?: { vertical?: number, horizontal?: number },
gestureDirection?: 'default' | 'inverted',
@@ -428,7 +480,7 @@ declare module 'react-navigation' {
*/
declare export type NavigationDispatch = (
action: NavigationAction
action: PossiblyDeprecatedNavigationAction
) => boolean;
declare export type NavigationProp<S> = {
@@ -705,7 +757,7 @@ declare module 'react-navigation' {
toString: () => string,
},
init: {
(payload?: { params?: NavigationParams }): NavigationInitAction,
(payload: { params?: NavigationParams }): NavigationInitAction,
toString: () => string,
},
navigate: {
@@ -735,6 +787,9 @@ declare module 'react-navigation' {
(payload: { uri: string }): NavigationUriAction,
toString: () => string,
},
mapDeprecatedActionAndWarn: (
action: PossiblyDeprecatedNavigationAction
) => NavigationAction,
};
declare type _RouterProp<S: NavigationState, O: {}> = {

View File

@@ -1,6 +1,6 @@
{
"name": "react-navigation",
"version": "1.2.1",
"version": "1.1.0",
"description": "Routing and navigation for your React Native apps",
"main": "src/react-navigation.js",
"repository": {
@@ -33,7 +33,7 @@
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.10",
"react-native-drawer-layout-polyfill": "^1.3.2",
"react-native-safe-area-view": "^0.7.0",
"react-native-safe-area-view": "^0.6.0",
"react-native-tab-view": "^0.0.74"
},
"devDependencies": {

View File

@@ -57,7 +57,6 @@ const pop = createAction(POP, payload => ({
const popToTop = createAction(POP_TO_TOP, payload => ({
type: POP_TO_TOP,
immediate: payload && payload.immediate,
key: payload && payload.key,
}));
const push = createAction(PUSH, payload => {
@@ -107,6 +106,59 @@ const completeTransition = createAction(COMPLETE_TRANSITION, payload => ({
key: payload && payload.key,
}));
const mapDeprecatedNavigateAction = action => {
if (action.type === 'Navigate') {
const payload = {
routeName: action.routeName,
params: action.params,
};
if (action.action) {
payload.action = mapDeprecatedNavigateAction(action.action);
}
return navigate(payload);
}
return action;
};
const mapDeprecatedAction = action => {
if (action.type === 'Back') {
return back(action);
} else if (action.type === 'Init') {
return init(action);
} else if (action.type === 'Navigate') {
return mapDeprecatedNavigateAction(action);
} else if (action.type === 'Reset') {
return reset({
index: action.index,
key: action.key,
actions: action.actions.map(mapDeprecatedNavigateAction),
});
} else if (action.type === 'SetParams') {
return setParams(action);
}
return action;
};
const mapDeprecatedActionAndWarn = action => {
const newAction = mapDeprecatedAction(action);
if (newAction !== action) {
const oldType = action.type;
const newType = newAction.type;
console.warn(
[
`The action type '${oldType}' has been renamed to '${newType}'.`,
`'${oldType}' will continue to work while in beta but will be removed`,
'in the first major release. Moving forward, you should use the',
'action constants and action creators exported by this library in',
"the 'actions' object.",
'See https://github.com/react-community/react-navigation/pull/120 for',
'more details.',
].join(' ')
);
}
return newAction;
};
export default {
// Action constants
BACK,
@@ -133,4 +185,7 @@ export default {
setParams,
uri,
completeTransition,
// TODO: Remove once old actions are deprecated
mapDeprecatedActionAndWarn,
};

View File

@@ -1,9 +1,8 @@
import {
BackAndroid as DeprecatedBackAndroid,
BackHandler as ModernBackHandler,
MaskedViewIOS,
} from 'react-native';
const BackHandler = ModernBackHandler || DeprecatedBackAndroid;
export { BackHandler, MaskedViewIOS };
export { BackHandler };

View File

@@ -1,6 +1,3 @@
import React from 'react';
import { BackHandler, View } from 'react-native';
import { BackHandler } from 'react-native';
const MaskedViewIOS = () => <View>{this.props.children}</View>;
export { BackHandler, MaskedViewIOS };
export { BackHandler };

View File

@@ -166,7 +166,8 @@ export default function createNavigationContainer(Component) {
// Per-tick temporary storage for state.nav
dispatch = action => {
dispatch = inputAction => {
const action = NavigationActions.mapDeprecatedActionAndWarn(inputAction);
if (!this._isStateful()) {
return false;
}

View File

@@ -1,22 +1,15 @@
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { View } from 'react-native';
import renderer from 'react-test-renderer';
import StackNavigator from '../StackNavigator';
const styles = StyleSheet.create({
header: {
opacity: 0.5,
},
});
class HomeScreen extends Component {
static navigationOptions = ({ navigation }) => ({
title: `Welcome ${
navigation.state.params ? navigation.state.params.user : 'anonymous'
}`,
gesturesEnabled: true,
headerStyle: [{ backgroundColor: 'red' }, styles.header],
});
render() {

View File

@@ -48,7 +48,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
pointerEvents="auto"
style={
Object {
"backgroundColor": "#EFEFF4",
"backgroundColor": "#E9E9EF",
"bottom": 0,
"left": 0,
"opacity": 1,
@@ -75,108 +75,163 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
/>
</View>
<View
cardStyle={undefined}
collapsable={undefined}
onLayout={[Function]}
pointerEvents="box-none"
style={
getScreenDetails={[Function]}
headerMode={undefined}
headerTransitionPreset={undefined}
index={0}
layout={
Object {
"backgroundColor": "#F7F7F7",
"borderBottomColor": "#A7A7AA",
"borderBottomWidth": 0.5,
"height": 64,
"paddingBottom": 0,
"paddingLeft": 0,
"paddingRight": 0,
"paddingTop": 20,
"height": 0,
"initHeight": 0,
"initWidth": 0,
"isMeasured": false,
"width": 0,
}
}
leftButtonInterpolator={[Function]}
leftInterpolator={[Function]}
leftLabelInterpolator={[Function]}
mode="float"
navigation={
Object {
"addListener": [Function],
"dispatch": [Function],
"getParam": [Function],
"goBack": [Function],
"navigate": [Function],
"pop": [Function],
"popToTop": [Function],
"push": [Function],
"replace": [Function],
"setParams": [Function],
"state": Object {
"index": 0,
"isTransitioning": false,
"key": "StackRouterRoot",
"routes": Array [
Object {
"key": "id-0-1",
"routeName": "Home",
},
],
},
}
}
rightInterpolator={[Function]}
router={
Object {
"getActionForPathAndParams": [Function],
"getComponentForRouteName": [Function],
"getComponentForState": [Function],
"getPathAndParamsForState": [Function],
"getScreenConfig": [Function],
"getScreenOptions": [Function],
"getStateForAction": [Function],
}
}
titleFromLeftInterpolator={[Function]}
titleInterpolator={[Function]}
transitionConfig={undefined}
transitionPreset="fade-in-place"
>
<View
collapsable={undefined}
onLayout={[Function]}
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
<View
style={
Object {
"flex": 1,
"backgroundColor": "#F7F7F7",
"borderBottomColor": "rgba(0, 0, 0, .3)",
"borderBottomWidth": 0.5,
"height": 64,
"paddingBottom": 0,
"paddingLeft": 0,
"paddingRight": 0,
"paddingTop": 20,
}
}
>
<View
style={
Object {
"bottom": 0,
"flexDirection": "row",
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
"flex": 1,
}
}
>
<View
collapsable={undefined}
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"flexDirection": "row",
"justifyContent": "center",
"left": 70,
"opacity": 1,
"position": "absolute",
"right": 70,
"top": 0,
}
Array [
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
Object {
"flexDirection": "row",
},
]
}
>
<Text
accessibilityTraits="header"
accessible={true}
allowFontScaling={true}
<View
collapsable={undefined}
ellipsizeMode="tail"
numberOfLines={1}
onLayout={[Function]}
pointerEvents="box-none"
style={
Object {
"color": "rgba(0, 0, 0, .9)",
"fontSize": 17,
"fontWeight": "700",
"marginHorizontal": 16,
"textAlign": "center",
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"justifyContent": "center",
"left": 70,
"opacity": 1,
"position": "absolute",
"right": 70,
"top": 0,
}
}
>
Welcome anonymous
</Text>
</View>
<View
collapsable={undefined}
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"flexDirection": "row",
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
<Text
accessibilityTraits="header"
accessible={true}
allowFontScaling={true}
collapsable={undefined}
ellipsizeMode="tail"
numberOfLines={1}
onLayout={[Function]}
style={
Object {
"color": "rgba(0, 0, 0, .9)",
"fontSize": 17,
"fontWeight": "700",
"marginHorizontal": 16,
"textAlign": "center",
}
}
>
Welcome anonymous
</Text>
</View>
<View
collapsable={undefined}
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"justifyContent": "center",
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
}
}
}
>
<View />
>
<View />
</View>
</View>
</View>
</View>
@@ -233,7 +288,7 @@ exports[`StackNavigator renders successfully 1`] = `
pointerEvents="auto"
style={
Object {
"backgroundColor": "#EFEFF4",
"backgroundColor": "#E9E9EF",
"bottom": 0,
"left": 0,
"opacity": 1,
@@ -260,90 +315,145 @@ exports[`StackNavigator renders successfully 1`] = `
/>
</View>
<View
cardStyle={undefined}
collapsable={undefined}
onLayout={[Function]}
pointerEvents="box-none"
style={
getScreenDetails={[Function]}
headerMode={undefined}
headerTransitionPreset={undefined}
index={0}
layout={
Object {
"backgroundColor": "#F7F7F7",
"borderBottomColor": "#A7A7AA",
"borderBottomWidth": 0.5,
"height": 64,
"paddingBottom": 0,
"paddingLeft": 0,
"paddingRight": 0,
"paddingTop": 20,
"height": 0,
"initHeight": 0,
"initWidth": 0,
"isMeasured": false,
"width": 0,
}
}
leftButtonInterpolator={[Function]}
leftInterpolator={[Function]}
leftLabelInterpolator={[Function]}
mode="float"
navigation={
Object {
"addListener": [Function],
"dispatch": [Function],
"getParam": [Function],
"goBack": [Function],
"navigate": [Function],
"pop": [Function],
"popToTop": [Function],
"push": [Function],
"replace": [Function],
"setParams": [Function],
"state": Object {
"index": 0,
"isTransitioning": false,
"key": "StackRouterRoot",
"routes": Array [
Object {
"key": "id-0-0",
"routeName": "Home",
},
],
},
}
}
rightInterpolator={[Function]}
router={
Object {
"getActionForPathAndParams": [Function],
"getComponentForRouteName": [Function],
"getComponentForState": [Function],
"getPathAndParamsForState": [Function],
"getScreenConfig": [Function],
"getScreenOptions": [Function],
"getStateForAction": [Function],
}
}
titleFromLeftInterpolator={[Function]}
titleInterpolator={[Function]}
transitionConfig={undefined}
transitionPreset="fade-in-place"
>
<View
collapsable={undefined}
onLayout={[Function]}
pointerEvents="box-none"
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
<View
style={
Object {
"flex": 1,
"backgroundColor": "#F7F7F7",
"borderBottomColor": "rgba(0, 0, 0, .3)",
"borderBottomWidth": 0.5,
"height": 64,
"paddingBottom": 0,
"paddingLeft": 0,
"paddingRight": 0,
"paddingTop": 20,
}
}
>
<View
style={
Object {
"bottom": 0,
"flexDirection": "row",
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
"flex": 1,
}
}
>
<View
collapsable={undefined}
pointerEvents="box-none"
style={
Object {
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"flexDirection": "row",
"justifyContent": "center",
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
}
Array [
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
Object {
"flexDirection": "row",
},
]
}
>
<Text
accessibilityTraits="header"
accessible={true}
allowFontScaling={true}
<View
collapsable={undefined}
ellipsizeMode="tail"
numberOfLines={1}
onLayout={[Function]}
pointerEvents="box-none"
style={
Object {
"color": "rgba(0, 0, 0, .9)",
"fontSize": 17,
"fontWeight": "700",
"marginHorizontal": 16,
"textAlign": "center",
"alignItems": "center",
"backgroundColor": "transparent",
"bottom": 0,
"justifyContent": "center",
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
Welcome anonymous
</Text>
<Text
accessibilityTraits="header"
accessible={true}
allowFontScaling={true}
collapsable={undefined}
ellipsizeMode="tail"
numberOfLines={1}
onLayout={[Function]}
style={
Object {
"color": "rgba(0, 0, 0, .9)",
"fontSize": 17,
"fontWeight": "700",
"marginHorizontal": 16,
"textAlign": "center",
}
}
>
Welcome anonymous
</Text>
</View>
</View>
</View>
</View>

View File

@@ -305,12 +305,6 @@ export default (routeConfigs, stackConfig = {}) => {
// Handle pop-to-top behavior. Make sure this happens after children have had a chance to handle the action, so that the inner stack pops to top first.
if (action.type === NavigationActions.POP_TO_TOP) {
// Refuse to handle pop to top if a key is given that doesn't correspond
// to this router
if (action.key && state.key !== action.key) {
return state;
}
// If we're already at the top, then we return the state with a new
// identity so that the action is handled by this router.
if (state.index === 0) {
@@ -392,28 +386,21 @@ export default (routeConfigs, stackConfig = {}) => {
// undefined on either the state or the action
return state;
}
const newStackActions = action.actions;
const resetAction = action;
return {
...state,
routes: newStackActions.map(newStackAction => {
const router = childRouters[newStackAction.routeName];
routes: resetAction.actions.map(childAction => {
const router = childRouters[childAction.routeName];
let childState = {};
if (router) {
const childAction =
newStackAction.action ||
NavigationActions.init({ params: newStackAction.params });
childState = router.getStateForAction(childAction);
}
return {
params: newStackAction.params,
params: childAction.params,
...childState,
routeName: newStackAction.routeName,
key: newStackAction.key || generateKey(),
routeName: childAction.routeName,
key: childAction.key || generateKey(),
};
}),
index: action.index,

View File

@@ -240,7 +240,7 @@ export default (routeConfigs, config = {}) => {
},
getComponentForState(state) {
const routeName = state.routes[state.index].routeName;
const routeName = order[state.index];
invariant(
routeName,
`There is no route defined for index ${state.index}. Check that

View File

@@ -457,35 +457,6 @@ describe('StackRouter', () => {
expect(state3 && state3.routes[1].index).toEqual(0);
});
test('popToTop targets StackRouter by key if specified', () => {
const ChildNavigator = () => <div />;
ChildNavigator.router = StackRouter({
Baz: { screen: () => <div /> },
Qux: { screen: () => <div /> },
});
const router = StackRouter({
Foo: { screen: () => <div /> },
Bar: { screen: ChildNavigator },
});
const state = router.getStateForAction({ type: NavigationActions.INIT });
const state2 = router.getStateForAction(
{
type: NavigationActions.NAVIGATE,
routeName: 'Bar',
},
state
);
const barKey = state2.routes[1].routes[0].key;
const state3 = router.getStateForAction(
{
type: NavigationActions.POP_TO_TOP,
key: state2.key,
},
state2
);
expect(state3 && state3.index).toEqual(0);
});
test('popToTop works as expected', () => {
const TestRouter = StackRouter({
foo: { screen: () => <div /> },
@@ -1535,6 +1506,40 @@ describe('StackRouter', () => {
}
});
test('Maps old actions (uses "Handles the reset action" test)', () => {
global.console.warn = jest.fn();
const router = StackRouter({
Foo: {
screen: () => <div />,
},
Bar: {
screen: () => <div />,
},
});
const initAction = NavigationActions.mapDeprecatedActionAndWarn({
type: 'Init',
});
const state = router.getStateForAction(initAction);
const resetAction = NavigationActions.mapDeprecatedActionAndWarn({
type: 'Reset',
actions: [
{ type: 'Navigate', routeName: 'Foo', params: { bar: '42' } },
{ type: 'Navigate', routeName: 'Bar' },
],
index: 1,
});
const state2 = router.getStateForAction(resetAction, state);
expect(state2 && state2.index).toEqual(1);
expect(state2 && state2.routes[0].params).toEqual({ bar: '42' });
expect(state2 && state2.routes[0].routeName).toEqual('Foo');
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
expect(console.warn).toBeCalledWith(
expect.stringContaining(
"The action type 'Init' has been renamed to 'Navigation/INIT'"
)
);
});
test('URI encoded string get passed to deep link', () => {
const uri = 'people/2018%2F02%2F07';
const action = TestStackRouter.getActionForPathAndParams(uri);

View File

@@ -593,6 +593,29 @@ describe('TabRouter', () => {
expect(path).toEqual('f/Baz');
});
test('Maps old actions (uses "getStateForAction returns null when navigating to same tab" test)', () => {
global.console.warn = jest.fn();
const router = TabRouter(
{ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig },
{ initialRouteName: 'Bar' }
);
const initAction = NavigationActions.mapDeprecatedActionAndWarn({
type: 'Init',
});
const state = router.getStateForAction(initAction);
const navigateAction = NavigationActions.mapDeprecatedActionAndWarn({
type: 'Navigate',
routeName: 'Bar',
});
const state2 = router.getStateForAction(navigateAction, state);
expect(state2).toEqual(null);
expect(console.warn).toBeCalledWith(
expect.stringContaining(
"The action type 'Init' has been renamed to 'Navigation/INIT'"
)
);
});
test('Can navigate to other tab (no router) with params', () => {
const ScreenA = () => <div />;
const ScreenB = () => <div />;

View File

@@ -22,7 +22,7 @@ class Card extends React.Component {
const styles = StyleSheet.create({
main: {
backgroundColor: '#EFEFF4',
backgroundColor: '#E9E9EF',
bottom: 0,
left: 0,
position: 'absolute',

View File

@@ -19,7 +19,6 @@ import getChildEventSubscriber from '../../getChildEventSubscriber';
import SceneView from '../SceneView';
import TransitionConfigs from './TransitionConfigs';
import * as ReactNativeFeatures from '../../utils/ReactNativeFeatures';
const emptyFunction = () => {};
@@ -86,7 +85,7 @@ class CardStack extends React.Component {
if (props.screenProps !== this.props.screenProps) {
this._screenDetails = {};
}
props.transitionProps.scenes.forEach(newScene => {
props.scenes.forEach(newScene => {
if (
this._screenDetails[newScene.key] &&
this._screenDetails[newScene.key].state !== newScene.route
@@ -97,7 +96,7 @@ class CardStack extends React.Component {
}
_getScreenDetails = scene => {
const { screenProps, transitionProps: { navigation }, router } = this.props;
const { screenProps, navigation, router } = this.props;
let screenDetails = this._screenDetails[scene.key];
if (!screenDetails || screenDetails.state !== scene.route) {
const screenNavigation = addNavigationHelpers({
@@ -132,16 +131,10 @@ class CardStack extends React.Component {
headerRightInterpolator,
} = this._getTransitionConfig();
const {
mode,
transitionProps,
prevTransitionProps,
...passProps
} = this.props;
const { mode, ...passProps } = this.props;
return renderHeader({
...passProps,
...transitionProps,
scene,
mode: headerMode,
transitionPreset: this._getHeaderTransitionPreset(),
@@ -161,42 +154,34 @@ class CardStack extends React.Component {
// when we'd do that with the current structure we have. `stopAnimation` callback
// is also broken with native animated values that have no listeners so if we
// want to remove this we have to fix this too.
animatedSubscribeValue(props.transitionProps.layout.width);
animatedSubscribeValue(props.transitionProps.layout.height);
animatedSubscribeValue(props.transitionProps.position);
animatedSubscribeValue(props.layout.width);
animatedSubscribeValue(props.layout.height);
animatedSubscribeValue(props.position);
}
_reset(resetToIndex, duration) {
if (
Platform.OS === 'ios' &&
ReactNativeFeatures.supportsImprovedSpringAnimation()
) {
Animated.spring(this.props.transitionProps.position, {
toValue: resetToIndex,
stiffness: 5000,
damping: 600,
mass: 3,
useNativeDriver: this.props.transitionProps.position.__isNative,
}).start();
} else {
Animated.timing(this.props.transitionProps.position, {
toValue: resetToIndex,
duration,
easing: EaseInOut,
useNativeDriver: this.props.transitionProps.position.__isNative,
}).start();
}
Animated.timing(this.props.position, {
toValue: resetToIndex,
duration,
easing: EaseInOut,
useNativeDriver: this.props.position.__isNative,
}).start();
}
_goBack(backFromIndex, duration) {
const { navigation, position, scenes } = this.props.transitionProps;
const { navigation, position, scenes } = this.props;
const toValue = Math.max(backFromIndex - 1, 0);
// set temporary index for gesture handler to respect until the action is
// dispatched at the end of the transition.
this._immediateIndex = toValue;
const onCompleteAnimation = () => {
Animated.timing(position, {
toValue,
duration,
easing: EaseInOut,
useNativeDriver: position.__isNative,
}).start(() => {
this._immediateIndex = null;
const backFromScene = scenes.find(s => s.index === toValue + 1);
if (!this._isResponding && backFromScene) {
@@ -207,42 +192,16 @@ class CardStack extends React.Component {
})
);
}
};
if (
Platform.OS === 'ios' &&
ReactNativeFeatures.supportsImprovedSpringAnimation()
) {
Animated.spring(position, {
toValue,
stiffness: 5000,
damping: 600,
mass: 3,
useNativeDriver: position.__isNative,
}).start(onCompleteAnimation);
} else {
Animated.timing(position, {
toValue,
duration,
easing: EaseInOut,
useNativeDriver: position.__isNative,
}).start(onCompleteAnimation);
}
});
}
render() {
let floatingHeader = null;
const headerMode = this._getHeaderMode();
if (headerMode === 'float') {
floatingHeader = this._renderHeader(
this.props.transitionProps.scene,
headerMode
);
floatingHeader = this._renderHeader(this.props.scene, headerMode);
}
const {
transitionProps: { navigation, position, layout, scene, scenes },
mode,
} = this.props;
const { navigation, position, layout, scene, scenes, mode } = this.props;
const { index } = navigation.state;
const isVertical = mode === 'modal';
const { options } = this._getScreenDetails(scene);
@@ -452,8 +411,8 @@ class CardStack extends React.Component {
return TransitionConfigs.getTransitionConfig(
this.props.transitionConfig,
this.props.transitionProps,
this.props.prevTransitionProps,
{},
{},
isModal
);
};
@@ -461,19 +420,15 @@ class CardStack extends React.Component {
_renderCard = scene => {
const { screenInterpolator } = this._getTransitionConfig();
const style =
screenInterpolator &&
screenInterpolator({ ...this.props.transitionProps, scene });
screenInterpolator && screenInterpolator({ ...this.props, scene });
const SceneComponent = this.props.router.getComponentForRouteName(
scene.route.routeName
);
const { transitionProps, ...props } = this.props;
return (
<Card
{...props}
{...transitionProps}
{...this.props}
key={`card_${scene.key}`}
style={[style, this.props.cardStyle]}
scene={scene}

View File

@@ -53,7 +53,7 @@ class CardStackTransitioner extends React.Component {
return transitionSpec;
};
_render = (props, prevProps) => {
_render = props => {
const {
screenProps,
headerMode,
@@ -72,8 +72,7 @@ class CardStackTransitioner extends React.Component {
router={router}
cardStyle={cardStyle}
transitionConfig={transitionConfig}
transitionProps={props}
prevTransitionProps={prevProps}
{...props}
/>
);
};

View File

@@ -6,10 +6,10 @@ import {
Image,
Platform,
StyleSheet,
MaskedViewIOS,
View,
ViewPropTypes,
} from 'react-native';
import { MaskedViewIOS } from '../../PlatformHelpers';
import SafeAreaView from 'react-native-safe-area-view';
import HeaderTitle from './HeaderTitle';
@@ -373,18 +373,18 @@ class Header extends React.PureComponent {
hasRightComponent: !!right,
});
const { isLandscape, transitionPreset } = this.props;
const { options } = this.props.getScreenDetails(props.scene);
const wrapperProps = {
style: styles.header,
style: [StyleSheet.absoluteFill, styles.header],
key: `scene_${props.scene.key}`,
};
const { isLandscape, transitionPreset } = this.props;
const { options } = this.props.getScreenDetails(props.scene);
if (
options.headerLeft ||
options.headerBackImage ||
Platform.OS !== 'ios' ||
Platform.OS === 'android' ||
transitionPreset !== 'uikit'
) {
return (
@@ -418,9 +418,8 @@ class Header extends React.PureComponent {
render() {
let appBar;
const { mode, scene, isLandscape } = this.props;
if (mode === 'float') {
if (this.props.mode === 'float') {
const scenesByIndex = {};
this.props.scenes.forEach(scene => {
scenesByIndex[scene.index] = scene;
@@ -439,59 +438,37 @@ class Header extends React.PureComponent {
});
}
const { options } = this.props.getScreenDetails(scene);
const { headerStyle = {} } = options;
const headerStyleObj = StyleSheet.flatten(headerStyle);
const appBarHeight = getAppBarHeight(isLandscape);
// eslint-disable-next-line no-unused-vars
const {
alignItems,
justifyContent,
flex,
flexDirection,
flexGrow,
flexShrink,
flexBasis,
flexWrap,
...safeHeaderStyle
} = headerStyleObj;
scenes,
scene,
position,
screenProps,
progress,
isLandscape,
...rest
} = this.props;
if (__DEV__) {
warnIfHeaderStyleDefined(alignItems, 'alignItems');
warnIfHeaderStyleDefined(justifyContent, 'justifyContent');
warnIfHeaderStyleDefined(flex, 'flex');
warnIfHeaderStyleDefined(flexDirection, 'flexDirection');
warnIfHeaderStyleDefined(flexGrow, 'flexGrow');
warnIfHeaderStyleDefined(flexShrink, 'flexShrink');
warnIfHeaderStyleDefined(flexBasis, 'flexBasis');
warnIfHeaderStyleDefined(flexWrap, 'flexWrap');
}
// TODO: warn if any unsafe styles are provided
const { options } = this.props.getScreenDetails(scene);
const { headerStyle } = options;
const appBarHeight = getAppBarHeight(isLandscape);
const containerStyles = [
options.headerTransparent
? styles.transparentContainer
: styles.container,
{ height: appBarHeight },
safeHeaderStyle,
styles.container,
{
height: appBarHeight,
},
headerStyle,
];
return (
<SafeAreaView
forceInset={{ top: 'always', bottom: 'never' }}
style={containerStyles}
>
<View style={StyleSheet.absoluteFill}>{options.headerBackground}</View>
<View style={{ flex: 1 }}>{appBar}</View>
</SafeAreaView>
);
}
}
function warnIfHeaderStyleDefined(value, styleProp) {
if (value !== undefined) {
console.warn(
`${styleProp} was given a value of ${value}, this has no effect on headerStyle.`
<Animated.View {...rest}>
<SafeAreaView
style={containerStyles}
forceInset={{ top: 'always', bottom: 'never' }}
>
<View style={styles.appBar}>{appBar}</View>
</SafeAreaView>
</Animated.View>
);
}
}
@@ -500,7 +477,7 @@ let platformContainerStyles;
if (Platform.OS === 'ios') {
platformContainerStyles = {
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#A7A7AA',
borderBottomColor: 'rgba(0, 0, 0, .3)',
};
} else {
platformContainerStyles = {
@@ -519,18 +496,15 @@ const styles = StyleSheet.create({
backgroundColor: Platform.OS === 'ios' ? '#F7F7F7' : '#FFF',
...platformContainerStyles,
},
transparentContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
...platformContainerStyles,
appBar: {
flex: 1,
},
header: {
...StyleSheet.absoluteFillObject,
flexDirection: 'row',
},
item: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
iconMaskContainer: {
@@ -554,29 +528,23 @@ const styles = StyleSheet.create({
},
title: {
bottom: 0,
top: 0,
left: TITLE_OFFSET,
right: TITLE_OFFSET,
top: 0,
position: 'absolute',
alignItems: 'center',
flexDirection: 'row',
justifyContent: Platform.OS === 'ios' ? 'center' : 'flex-start',
alignItems: Platform.OS === 'ios' ? 'center' : 'flex-start',
},
left: {
left: 0,
bottom: 0,
top: 0,
position: 'absolute',
alignItems: 'center',
flexDirection: 'row',
},
right: {
right: 0,
bottom: 0,
top: 0,
position: 'absolute',
flexDirection: 'row',
alignItems: 'center',
},
});

View File

@@ -2,8 +2,8 @@ import { Dimensions, I18nManager } from 'react-native';
import getSceneIndicesForInterpolationInputRange from '../../utils/getSceneIndicesForInterpolationInputRange';
const crossFadeInterpolation = (first, index, last) => ({
inputRange: [first, index - 0.9, index - 0.2, index, last],
outputRange: [0, 0, 0.3, 1, 0],
inputRange: [first, index - 0.75, index - 0.5, index, index + 0.5, last],
outputRange: [0, 0, 0.2, 1, 0.5, 0],
});
/**

View File

@@ -10,7 +10,6 @@ import {
import SafeAreaView from 'react-native-safe-area-view';
import TabBarIcon from './TabBarIcon';
import NavigationActions from '../../NavigationActions';
import withOrientation from '../withOrientation';
const majorVersion = parseInt(Platform.Version, 10);
@@ -177,24 +176,6 @@ class TabBarBottom extends React.PureComponent {
}
}
_handleTabPress = index => {
const { jumpToIndex, navigation } = this.props;
const currentIndex = navigation.state.index;
if (currentIndex === index) {
let childRoute = navigation.state.routes[index];
if (childRoute.hasOwnProperty('index') && childRoute.index > 0) {
navigation.dispatch(
NavigationActions.popToTop({ key: childRoute.key })
);
} else {
// TODO: do something to scroll to top
}
} else {
jumpToIndex(index);
}
};
render() {
const {
position,
@@ -254,13 +235,8 @@ class TabBarBottom extends React.PureComponent {
accessibilityLabel={accessibilityLabel}
onPress={() =>
onPress
? onPress({
previousScene,
scene,
jumpToIndex,
defaultHandler: this._handleTabPress,
})
: this._handleTabPress(index)
? onPress({ previousScene, scene, jumpToIndex })
: jumpToIndex(index)
}
>
<Animated.View style={[styles.tab, { backgroundColor }]}>

View File

@@ -91,15 +91,7 @@ export default class TabBarTop extends React.PureComponent {
const onPress = getOnPress(previousScene, scene);
if (onPress) {
// To maintain the same API as `TabbarBottom`, we pass in a `defaultHandler`
// even though I don't believe in this case it should be any different
// than `jumpToIndex`.
onPress({
previousScene,
scene,
jumpToIndex,
defaultHandler: jumpToIndex,
});
onPress({ previousScene, scene, jumpToIndex });
} else {
jumpToIndex(scene.index);
}

View File

@@ -179,19 +179,9 @@ class Transitioner extends React.Component {
const prevTransitionProps = this._prevTransitionProps;
this._prevTransitionProps = null;
const scenes = this.state.scenes.filter(isSceneNotStale);
const nextState = {
...this.state,
/**
* Array.prototype.filter creates a new instance of an array
* even if there were no elements removed. There are cases when
* `this.state.scenes` will have no stale scenes (typically when
* pushing a new route). As a result, components that rely on this prop
* might enter an unnecessary render cycle.
*/
scenes:
this.state.scenes.length === scenes.length ? this.state.scenes : scenes,
scenes: this.state.scenes.filter(isSceneNotStale),
};
this._transitionProps = buildTransitionProps(this.props, nextState);