mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-13 09:30:30 +08:00
Compare commits
26 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3677818f63 | ||
|
|
162410843c | ||
|
|
028c2887c6 | ||
|
|
7a44cda136 | ||
|
|
a046db536f | ||
|
|
d115787b1c | ||
|
|
80a337024a | ||
|
|
c19da31240 | ||
|
|
85e9376302 | ||
|
|
a67b49477e | ||
|
|
225cb298b6 | ||
|
|
c8ea4199f4 | ||
|
|
f16700812f | ||
|
|
240ce01822 | ||
|
|
c7dd3a58b1 | ||
|
|
125bd70e49 | ||
|
|
4578849ebf | ||
|
|
c084517d7b | ||
|
|
22c85ff6a9 | ||
|
|
bf76075e0f | ||
|
|
d69b0db604 | ||
|
|
cdb2fed43d | ||
|
|
bb0226e26d | ||
|
|
1a28c299b5 | ||
|
|
e0c3298e64 | ||
|
|
040f5dbb9d |
@@ -8,7 +8,6 @@
|
||||
"@react-navigation/routers",
|
||||
"@react-navigation/compat",
|
||||
"@react-navigation/stack",
|
||||
"@react-navigation/native-stack",
|
||||
"@react-navigation/drawer",
|
||||
"@react-navigation/bottom-tabs",
|
||||
"@react-navigation/material-top-tabs",
|
||||
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
yarn-*.js binary
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
name: Native Stack Navigator
|
||||
about: Report an issue with Native Stack Navigator (@react-navigation/native-stack)
|
||||
title: ''
|
||||
labels: bug, package:native-stack
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**Current Behavior**
|
||||
|
||||
- What code are you running and what is happening?
|
||||
- Include a screenshot or video if it makes sense.
|
||||
|
||||
**Expected Behavior**
|
||||
|
||||
- What do you expect should be happening?
|
||||
- Include a screenshot or video if it makes sense.
|
||||
|
||||
**How to reproduce**
|
||||
|
||||
- You must provide a way to reproduce the problem. If you are having an issue with your machine or build tools, the issue belongs on another repository as that is outside of the scope of React Navigation.
|
||||
- Either re-create the bug on [Snack](https://snack.expo.io) or link to a GitHub repository with code that reproduces the bug.
|
||||
- Explain how to run the example app and any steps that we need to take to reproduce the issue from the example app.
|
||||
- Keep the repro code as simple as possible, with the minimum amount of code required to repro the issue.
|
||||
- Before reporting an issue, make sure you are on latest version of the package.
|
||||
|
||||
**Your Environment**
|
||||
|
||||
| software | version |
|
||||
| ------------------------------ | ------- |
|
||||
| iOS or Android |
|
||||
| @react-navigation/native |
|
||||
| @react-navigation/native-stack |
|
||||
| react-native-screens |
|
||||
| react-native |
|
||||
| expo |
|
||||
| node |
|
||||
| npm or yarn |
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,6 +4,8 @@
|
||||
.idea
|
||||
.expo
|
||||
.gradle
|
||||
.project
|
||||
.settings
|
||||
|
||||
local.properties
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ When you're sending a pull request:
|
||||
Maintainers with write access to the GitHub repo and the npm organization can publish new versions. To publish a new version, first, you need to export a `GH_TOKEN` environment variable as mentioned [here](https://github.com/lerna/lerna/tree/master/commands/version#--create-release-type). Then run:
|
||||
|
||||
```sh
|
||||
yarn lerna publish
|
||||
yarn release
|
||||
```
|
||||
|
||||
This will automatically bump the version and publish the packages. It'll also publish the changelogs on GitHub for each package.
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, ScrollView, StyleSheet } from 'react-native';
|
||||
import { Button } from 'react-native-paper';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { enableScreens } from 'react-native-screens';
|
||||
import {
|
||||
RouteProp,
|
||||
ParamListBase,
|
||||
useFocusEffect,
|
||||
useTheme,
|
||||
} from '@react-navigation/native';
|
||||
import { DrawerNavigationProp } from '@react-navigation/drawer';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
} from '@react-navigation/native-stack';
|
||||
import Albums from '../Shared/Albums';
|
||||
|
||||
type NativeStackParams = {
|
||||
Article: { author: string };
|
||||
Album: undefined;
|
||||
};
|
||||
|
||||
type NativeStackNavigation = NativeStackNavigationProp<NativeStackParams>;
|
||||
|
||||
const Title = ({ children }: { children: React.ReactNode }) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return <Text style={[styles.title, { color: colors.text }]}>{children}</Text>;
|
||||
};
|
||||
|
||||
const Paragraph = ({ children }: { children: React.ReactNode }) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<Text style={[styles.paragraph, { color: colors.text }]}>{children}</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const ArticleScreen = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: NativeStackNavigation;
|
||||
route: RouteProp<NativeStackParams, 'Article'>;
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={{ backgroundColor: colors.card }}
|
||||
contentContainerStyle={styles.content}
|
||||
>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('Album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
</Button>
|
||||
<Button
|
||||
mode="outlined"
|
||||
onPress={() => navigation.goBack()}
|
||||
style={styles.button}
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
</View>
|
||||
<Title>What is Lorem Ipsum?</Title>
|
||||
<Paragraph>
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting
|
||||
industry. Lorem Ipsum has been the industry's standard dummy text
|
||||
ever since the 1500s, when an unknown printer took a galley of type and
|
||||
scrambled it to make a type specimen book. It has survived not only five
|
||||
centuries, but also the leap into electronic typesetting, remaining
|
||||
essentially unchanged. It was popularised in the 1960s with the release
|
||||
of Letraset sheets containing Lorem Ipsum passages, and more recently
|
||||
with desktop publishing software like Aldus PageMaker including versions
|
||||
of Lorem Ipsum.
|
||||
</Paragraph>
|
||||
<Title>Where does it come from?</Title>
|
||||
<Paragraph>
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It
|
||||
has roots in a piece of classical Latin literature from 45 BC, making it
|
||||
over 2000 years old. Richard McClintock, a Latin professor at
|
||||
Hampden-Sydney College in Virginia, looked up one of the more obscure
|
||||
Latin words, consectetur, from a Lorem Ipsum passage, and going through
|
||||
the cites of the word in classical literature, discovered the
|
||||
undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33
|
||||
of "de Finibus Bonorum et Malorum" (The Extremes of Good and
|
||||
Evil) by Cicero, written in 45 BC. This book is a treatise on the theory
|
||||
of ethics, very popular during the Renaissance. The first line of Lorem
|
||||
Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in
|
||||
section 1.10.32.
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
The standard chunk of Lorem Ipsum used since the 1500s is reproduced
|
||||
below for those interested. Sections 1.10.32 and 1.10.33 from "de
|
||||
Finibus Bonorum et Malorum" by Cicero are also reproduced in their
|
||||
exact original form, accompanied by English versions from the 1914
|
||||
translation by H. Rackham.
|
||||
</Paragraph>
|
||||
<Title>Why do we use it?</Title>
|
||||
<Paragraph>
|
||||
It is a long established fact that a reader will be distracted by the
|
||||
readable content of a page when looking at its layout. The point of
|
||||
using Lorem Ipsum is that it has a more-or-less normal distribution of
|
||||
letters, as opposed to using "Content here, content here",
|
||||
making it look like readable English. Many desktop publishing packages
|
||||
and web page editors now use Lorem Ipsum as their default model text,
|
||||
and a search for "lorem ipsum" will uncover many web sites
|
||||
still in their infancy. Various versions have evolved over the years,
|
||||
sometimes by accident, sometimes on purpose (injected humour and the
|
||||
like).
|
||||
</Paragraph>
|
||||
<Title>Where can I get some?</Title>
|
||||
<Paragraph>
|
||||
There are many variations of passages of Lorem Ipsum available, but the
|
||||
majority have suffered alteration in some form, by injected humour, or
|
||||
randomised words which don't look even slightly believable. If you
|
||||
are going to use a passage of Lorem Ipsum, you need to be sure there
|
||||
isn't anything embarrassing hidden in the middle of text. All the
|
||||
Lorem Ipsum generators on the Internet tend to repeat predefined chunks
|
||||
as necessary, making this the first true generator on the Internet. It
|
||||
uses a dictionary of over 200 Latin words, combined with a handful of
|
||||
model sentence structures, to generate Lorem Ipsum which looks
|
||||
reasonable. The generated Lorem Ipsum is therefore always free from
|
||||
repetition, injected humour, or non-characteristic words etc.
|
||||
</Paragraph>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
const AlbumsScreen = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: NativeStackNavigation;
|
||||
}) => (
|
||||
<ScrollView>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('Article', { author: 'Babel fish' })}
|
||||
style={styles.button}
|
||||
>
|
||||
Push article
|
||||
</Button>
|
||||
<Button
|
||||
mode="outlined"
|
||||
onPress={() => navigation.goBack()}
|
||||
style={styles.button}
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
</View>
|
||||
<Albums scrollEnabled={false} />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const NativeStack = createNativeStackNavigator<NativeStackParams>();
|
||||
|
||||
type Props = {
|
||||
navigation: StackNavigationProp<ParamListBase>;
|
||||
};
|
||||
|
||||
export default function NativeStackScreen({ navigation }: Props) {
|
||||
navigation.setOptions({
|
||||
headerShown: false,
|
||||
});
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
const drawer = navigation.dangerouslyGetParent() as DrawerNavigationProp<
|
||||
ParamListBase
|
||||
>;
|
||||
|
||||
navigation.setOptions({ gestureEnabled: false });
|
||||
drawer.setOptions({ gestureEnabled: false });
|
||||
|
||||
return () => {
|
||||
navigation.setOptions({ gestureEnabled: true });
|
||||
drawer.setOptions({ gestureEnabled: true });
|
||||
};
|
||||
}, [navigation])
|
||||
);
|
||||
|
||||
return (
|
||||
<NativeStack.Navigator>
|
||||
<NativeStack.Screen
|
||||
name="Article"
|
||||
component={ArticleScreen}
|
||||
options={{
|
||||
title: 'Lorem Ipsum',
|
||||
headerLargeTitle: true,
|
||||
headerHideShadow: true,
|
||||
}}
|
||||
/>
|
||||
<NativeStack.Screen
|
||||
name="Album"
|
||||
component={AlbumsScreen}
|
||||
options={{ title: 'Album' }}
|
||||
/>
|
||||
</NativeStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
enableScreens(true);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttons: {
|
||||
flexDirection: 'row',
|
||||
padding: 8,
|
||||
},
|
||||
button: {
|
||||
margin: 8,
|
||||
},
|
||||
content: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 24,
|
||||
marginVertical: 8,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
paragraph: {
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginVertical: 8,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
|
||||
export default function NativeStack() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>Not supported on Web :(</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#eceff1',
|
||||
},
|
||||
text: {
|
||||
fontSize: 16,
|
||||
color: '#999',
|
||||
},
|
||||
});
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
StatusBar,
|
||||
I18nManager,
|
||||
} from 'react-native';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { enableScreens } from 'react-native-screens';
|
||||
import RNRestart from 'react-native-restart';
|
||||
import { Updates } from 'expo';
|
||||
import { Asset } from 'expo-asset';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
import {
|
||||
Provider as PaperProvider,
|
||||
@@ -17,7 +21,6 @@ import {
|
||||
List,
|
||||
Divider,
|
||||
} from 'react-native-paper';
|
||||
import { Asset } from 'expo-asset';
|
||||
import {
|
||||
InitialState,
|
||||
useLinking,
|
||||
@@ -39,7 +42,6 @@ import {
|
||||
|
||||
import LinkingPrefixes from './LinkingPrefixes';
|
||||
import SimpleStack from './Screens/SimpleStack';
|
||||
import NativeStack from './Screens/NativeStack';
|
||||
import ModalPresentationStack from './Screens/ModalPresentationStack';
|
||||
import StackTransparent from './Screens/StackTransparent';
|
||||
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
|
||||
@@ -50,10 +52,11 @@ import DynamicTabs from './Screens/DynamicTabs';
|
||||
import AuthFlow from './Screens/AuthFlow';
|
||||
import CompatAPI from './Screens/CompatAPI';
|
||||
import SettingsItem from './Shared/SettingsItem';
|
||||
import { Updates } from 'expo';
|
||||
|
||||
YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']);
|
||||
|
||||
enableScreens();
|
||||
|
||||
type RootDrawerParamList = {
|
||||
Root: undefined;
|
||||
Another: undefined;
|
||||
@@ -67,7 +70,6 @@ type RootStackParamList = {
|
||||
|
||||
const SCREENS = {
|
||||
SimpleStack: { title: 'Simple Stack', component: SimpleStack },
|
||||
NativeStack: { title: 'Native Stack', component: NativeStack },
|
||||
ModalPresentationStack: {
|
||||
title: 'Modal Presentation Stack',
|
||||
component: ModalPresentationStack,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"lint": "eslint --ext '.js,.ts,.tsx' .",
|
||||
"typescript": "tsc --noEmit",
|
||||
"test": "jest",
|
||||
"release": "lerna publish",
|
||||
"example": "yarn --cwd example"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.7...@react-navigation/bottom-tabs@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.6...@react-navigation/bottom-tabs@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.5...@react-navigation/bottom-tabs@5.0.6) (2020-02-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.4...@react-navigation/bottom-tabs@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/bottom-tabs",
|
||||
"description": "Bottom tab navigator following iOS design guidelines",
|
||||
"version": "5.1.0",
|
||||
"keywords": [
|
||||
"react-native-component",
|
||||
"react-component",
|
||||
@@ -10,7 +11,6 @@
|
||||
"android",
|
||||
"tab"
|
||||
],
|
||||
"version": "5.0.4",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs",
|
||||
"main": "lib/commonjs/index.js",
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/color": "^3.0.1",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-native": "^0.60.30",
|
||||
@@ -46,7 +46,7 @@
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 0.6.0"
|
||||
|
||||
@@ -48,6 +48,8 @@ function BottomTabNavigator({
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
TabNavigationState,
|
||||
BottomTabNavigationOptions,
|
||||
BottomTabNavigationEventMap,
|
||||
typeof BottomTabNavigator
|
||||
>(BottomTabNavigator);
|
||||
|
||||
@@ -3,6 +3,36 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.7...@react-navigation/compat@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.6...@react-navigation/compat@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/compat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.5...@react-navigation/compat@5.0.6) (2020-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add NavigationEvents ([d69b0db](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/commit/d69b0db60455b8789276822ba73f5349db8842d7)), closes [/github.com/react-navigation/react-navigation/issues/6821#issuecomment-588268512](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/issues/issuecomment-588268512)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.4...@react-navigation/compat@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/compat
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/compat",
|
||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
|
||||
"bugs": {
|
||||
@@ -26,13 +26,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/react": "^16.9.19",
|
||||
"react": "~16.9.0",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
|
||||
45
packages/compat/src/NavigationEvents.tsx
Normal file
45
packages/compat/src/NavigationEvents.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
type Props = {
|
||||
onWillFocus?: () => void;
|
||||
onDidFocus?: () => void;
|
||||
onWillBlur?: () => void;
|
||||
onDidBlur?: () => void;
|
||||
};
|
||||
|
||||
export default function NavigationEvents(props: Props) {
|
||||
const navigation = useNavigation();
|
||||
const propsRef = React.useRef(props);
|
||||
|
||||
React.useEffect(() => {
|
||||
propsRef.current = props;
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const unsubFocus = navigation.addListener('focus', () => {
|
||||
propsRef.current.onWillFocus?.();
|
||||
});
|
||||
|
||||
const unsubBlur = navigation.addListener('blur', () => {
|
||||
propsRef.current.onWillBlur?.();
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
const unsubTransitionEnd = navigation.addListener('transitionEnd', () => {
|
||||
if (navigation.isFocused()) {
|
||||
propsRef.current.onDidFocus?.();
|
||||
} else {
|
||||
propsRef.current.onDidBlur?.();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubFocus();
|
||||
unsubBlur();
|
||||
unsubTransitionEnd();
|
||||
};
|
||||
}, [navigation]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
TypedNavigator,
|
||||
NavigationProp,
|
||||
RouteProp,
|
||||
EventMapBase,
|
||||
} from '@react-navigation/native';
|
||||
import CompatScreen from './CompatScreen';
|
||||
import ScreenPropsContext from './ScreenPropsContext';
|
||||
@@ -15,7 +16,9 @@ import { CompatScreenType, CompatRouteConfig } from './types';
|
||||
export default function createCompatNavigatorFactory<
|
||||
CreateNavigator extends () => TypedNavigator<
|
||||
ParamListBase,
|
||||
NavigationState,
|
||||
{},
|
||||
EventMapBase,
|
||||
React.ComponentType<any>
|
||||
>
|
||||
>(createNavigator: CreateNavigator) {
|
||||
|
||||
@@ -22,5 +22,7 @@ function SwitchNavigator(props: Props) {
|
||||
}
|
||||
|
||||
export default createCompatNavigatorFactory(
|
||||
createNavigatorFactory<{}, typeof SwitchNavigator>(SwitchNavigator)
|
||||
createNavigatorFactory<TabNavigationState, {}, {}, typeof SwitchNavigator>(
|
||||
SwitchNavigator
|
||||
)
|
||||
);
|
||||
|
||||
@@ -14,4 +14,6 @@ export { default as createSwitchNavigator } from './createSwitchNavigator';
|
||||
export { default as withNavigation } from './withNavigation';
|
||||
export { default as withNavigationFocus } from './withNavigationFocus';
|
||||
|
||||
export { default as NavigationEvents } from './NavigationEvents';
|
||||
|
||||
export * from './types';
|
||||
|
||||
@@ -3,6 +3,40 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.6...@react-navigation/core@5.2.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.5...@react-navigation/core@5.1.6) (2020-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* avoid emitting focus events twice ([f167008](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/f16700812f3757713b04ca3a860209795b4a6c44)), closes [#6749](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/6749)
|
||||
* preserve screen order with numeric names ([125bd70](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/125bd70e49b708d936a2eee72ba5cb92eacf26a9)), closes [#6900](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/6900)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.1.5](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.4...@react-navigation/core@5.1.5) (2020-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* show descriptive error for invalid return for useFocusEffect ([1a28c29](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/1a28c299b5e3f0805eb6e9ea3cf5e9cc90c7a280))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.1.4](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.3...@react-navigation/core@5.1.4) (2020-02-14)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/core",
|
||||
"description": "Core utilities for building navigators",
|
||||
"version": "5.1.3",
|
||||
"version": "5.2.0",
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-native",
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.1",
|
||||
"@react-navigation/routers": "^5.0.3",
|
||||
"escape-string-regexp": "^2.0.0",
|
||||
"query-string": "^6.10.1",
|
||||
"react-is": "^16.12.0",
|
||||
|
||||
@@ -16,14 +16,15 @@ import isSerializable from './isSerializable';
|
||||
|
||||
import { NavigationContainerRef, NavigationContainerProps } from './types';
|
||||
import useEventEmitter from './useEventEmitter';
|
||||
import useSyncState from './useSyncState';
|
||||
|
||||
type State = NavigationState | PartialState<NavigationState> | undefined;
|
||||
|
||||
const MISSING_CONTEXT_ERROR =
|
||||
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/en/getting-started.html for setup instructions.";
|
||||
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started.html for setup instructions.";
|
||||
|
||||
const NOT_INITIALIZED_ERROR =
|
||||
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. You can ensure that all navigators have mounted after the callback to 'useEffect' is called in your root component. See https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html#handling-initialization for more details.";
|
||||
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop.html#handling-initialization for more details.";
|
||||
|
||||
export const NavigationStateContext = React.createContext<{
|
||||
isDefault?: true;
|
||||
@@ -34,7 +35,6 @@ export const NavigationStateContext = React.createContext<{
|
||||
setState: (
|
||||
state: NavigationState | PartialState<NavigationState> | undefined
|
||||
) => void;
|
||||
performTransaction: (action: () => void) => void;
|
||||
}>({
|
||||
isDefault: true,
|
||||
|
||||
@@ -50,9 +50,6 @@ export const NavigationStateContext = React.createContext<{
|
||||
get setState(): any {
|
||||
throw new Error(MISSING_CONTEXT_ERROR);
|
||||
},
|
||||
get performTransaction(): any {
|
||||
throw new Error(MISSING_CONTEXT_ERROR);
|
||||
},
|
||||
});
|
||||
|
||||
let hasWarnedForSerialization = false;
|
||||
@@ -115,13 +112,10 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
);
|
||||
}
|
||||
|
||||
const [state, setNavigationState] = React.useState<State>(() =>
|
||||
const [state, getState, setState] = useSyncState<State>(() =>
|
||||
getPartialState(initialState == null ? undefined : initialState)
|
||||
);
|
||||
|
||||
const navigationStateRef = React.useRef<State>();
|
||||
const transactionStateRef = React.useRef<State | null>(null);
|
||||
const isTransactionActiveRef = React.useRef<boolean>(false);
|
||||
const isFirstMountRef = React.useRef<boolean>(true);
|
||||
const skipTrackingRef = React.useRef<boolean>(false);
|
||||
|
||||
@@ -133,53 +127,12 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
navigatorKeyRef.current = key;
|
||||
}, []);
|
||||
|
||||
const performTransaction = React.useCallback((callback: () => void) => {
|
||||
if (isTransactionActiveRef.current) {
|
||||
throw new Error(
|
||||
"Only one transaction can be active at a time. Did you accidentally nest 'performTransaction'?"
|
||||
);
|
||||
}
|
||||
|
||||
setNavigationState((navigationState: State) => {
|
||||
isTransactionActiveRef.current = true;
|
||||
transactionStateRef.current = navigationState;
|
||||
|
||||
try {
|
||||
callback();
|
||||
} finally {
|
||||
isTransactionActiveRef.current = false;
|
||||
}
|
||||
|
||||
return transactionStateRef.current;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getState = React.useCallback(
|
||||
() =>
|
||||
transactionStateRef.current !== null
|
||||
? transactionStateRef.current
|
||||
: navigationStateRef.current,
|
||||
[]
|
||||
);
|
||||
|
||||
const setState = React.useCallback((navigationState: State) => {
|
||||
if (transactionStateRef.current === null) {
|
||||
throw new Error(
|
||||
"Any 'setState' calls need to be done inside 'performTransaction'"
|
||||
);
|
||||
}
|
||||
|
||||
transactionStateRef.current = navigationState;
|
||||
}, []);
|
||||
|
||||
const reset = React.useCallback(
|
||||
(state: NavigationState) => {
|
||||
performTransaction(() => {
|
||||
skipTrackingRef.current = true;
|
||||
setState(state);
|
||||
});
|
||||
skipTrackingRef.current = true;
|
||||
setState(state);
|
||||
},
|
||||
[performTransaction, setState]
|
||||
[setState]
|
||||
);
|
||||
|
||||
const { trackState, trackAction } = useDevTools({
|
||||
@@ -223,12 +176,10 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
|
||||
const resetRoot = React.useCallback(
|
||||
(state?: PartialState<NavigationState> | NavigationState) => {
|
||||
performTransaction(() => {
|
||||
trackAction('@@RESET_ROOT');
|
||||
setState(state);
|
||||
});
|
||||
trackAction('@@RESET_ROOT');
|
||||
setState(state);
|
||||
},
|
||||
[performTransaction, setState, trackAction]
|
||||
[setState, trackAction]
|
||||
);
|
||||
|
||||
const getRootState = React.useCallback(() => {
|
||||
@@ -269,13 +220,12 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
const context = React.useMemo(
|
||||
() => ({
|
||||
state,
|
||||
performTransaction,
|
||||
getState,
|
||||
setState,
|
||||
getKey,
|
||||
setKey,
|
||||
}),
|
||||
[getKey, getState, performTransaction, setKey, setState, state]
|
||||
[getKey, getState, setKey, setState, state]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -288,7 +238,7 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
hasWarnedForSerialization = true;
|
||||
|
||||
console.warn(
|
||||
"We found non-serializable values in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/en/troubleshooting.html#i-get-the-warning-we-found-non-serializable-values-in-the-navigation-state for more details."
|
||||
"Non-serializable values were found in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting.html#i-get-the-warning-we-found-non-serializable-values-in-the-navigation-state for more details."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -304,15 +254,12 @@ const BaseNavigationContainer = React.forwardRef(
|
||||
trackState(getRootState);
|
||||
}
|
||||
|
||||
navigationStateRef.current = state;
|
||||
transactionStateRef.current = null;
|
||||
|
||||
if (!isFirstMountRef.current && onStateChange) {
|
||||
onStateChange(getRootState());
|
||||
}
|
||||
|
||||
isFirstMountRef.current = false;
|
||||
}, [state, onStateChange, trackState, getRootState, emitter]);
|
||||
}, [onStateChange, trackState, getRootState, emitter, state]);
|
||||
|
||||
return (
|
||||
<NavigationBuilderContext.Provider value={builderContext}>
|
||||
|
||||
@@ -4,7 +4,7 @@ type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/en/nesting-navigators.html for a guide on nesting.`;
|
||||
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators.html for a guide on nesting.`;
|
||||
|
||||
export const SingleNavigatorContext = React.createContext<
|
||||
| {
|
||||
|
||||
@@ -10,10 +10,14 @@ import NavigationContext from './NavigationContext';
|
||||
import NavigationRouteContext from './NavigationRouteContext';
|
||||
import StaticContainer from './StaticContainer';
|
||||
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
||||
import { NavigationProp, RouteConfig } from './types';
|
||||
import { NavigationProp, RouteConfig, EventMapBase } from './types';
|
||||
|
||||
type Props<State extends NavigationState, ScreenOptions extends object> = {
|
||||
screen: RouteConfig<ParamListBase, string, ScreenOptions>;
|
||||
type Props<
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
> = {
|
||||
screen: RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>;
|
||||
navigation: NavigationProp<ParamListBase, string, State, ScreenOptions>;
|
||||
route: Route<string> & {
|
||||
state?: NavigationState | PartialState<NavigationState>;
|
||||
@@ -28,16 +32,15 @@ type Props<State extends NavigationState, ScreenOptions extends object> = {
|
||||
*/
|
||||
export default function SceneView<
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
>({
|
||||
screen,
|
||||
route,
|
||||
navigation,
|
||||
getState,
|
||||
setState,
|
||||
}: Props<State, ScreenOptions>) {
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
}: Props<State, ScreenOptions, EventMap>) {
|
||||
const navigatorKeyRef = React.useRef<string | undefined>();
|
||||
|
||||
const getKey = React.useCallback(() => navigatorKeyRef.current, []);
|
||||
@@ -72,18 +75,10 @@ export default function SceneView<
|
||||
state: route.state,
|
||||
getState: getCurrentState,
|
||||
setState: setCurrentState,
|
||||
performTransaction,
|
||||
getKey,
|
||||
setKey,
|
||||
}),
|
||||
[
|
||||
getCurrentState,
|
||||
getKey,
|
||||
performTransaction,
|
||||
route.state,
|
||||
setCurrentState,
|
||||
setKey,
|
||||
]
|
||||
[getCurrentState, getKey, route.state, setCurrentState, setKey]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ParamListBase } from '@react-navigation/routers';
|
||||
import { RouteConfig } from './types';
|
||||
import { ParamListBase, NavigationState } from '@react-navigation/routers';
|
||||
import { RouteConfig, EventMapBase } from './types';
|
||||
|
||||
/**
|
||||
* Empty component used for specifying route configuration.
|
||||
@@ -7,8 +7,10 @@ import { RouteConfig } from './types';
|
||||
export default function Screen<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList,
|
||||
ScreenOptions extends object
|
||||
>(_: RouteConfig<ParamList, RouteName, ScreenOptions>) {
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
>(_: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>) {
|
||||
/* istanbul ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ it('throws when getState is accessed without a container', () => {
|
||||
const element = <Test />;
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
|
||||
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -47,78 +47,7 @@ it('throws when setState is accessed without a container', () => {
|
||||
const element = <Test />;
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when performTransaction is accessed without a container', () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const Test = () => {
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
// eslint-disable-next-line babel/no-unused-expressions
|
||||
performTransaction;
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const element = <Test />;
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when setState is called outside performTransaction', () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const Test = () => {
|
||||
const { setState } = React.useContext(NavigationStateContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
setState(undefined);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const element = (
|
||||
<BaseNavigationContainer>
|
||||
<Test />
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"Any 'setState' calls need to be done inside 'performTransaction'"
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when nesting performTransaction', () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const Test = () => {
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
React.useEffect(() => {
|
||||
performTransaction(() => {
|
||||
performTransaction(() => {});
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const element = (
|
||||
<BaseNavigationContainer>
|
||||
<Test />
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"Only one transaction can be active at a time. Did you accidentally nest 'performTransaction'?"
|
||||
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ it("doesn't update state if action wasn't handled", () => {
|
||||
expect(onStateChange).toBeCalledTimes(0);
|
||||
|
||||
expect(spy.mock.calls[0][0]).toMatch(
|
||||
"The action 'INVALID' with payload 'undefined' was not handled by any navigator."
|
||||
"The action 'INVALID' was not handled by any navigator."
|
||||
);
|
||||
|
||||
spy.mockRestore();
|
||||
@@ -772,6 +772,60 @@ it('gives access to internal state', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves order of screens in state with non-numeric names', () => {
|
||||
const TestNavigator = (props: any): any => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
return null;
|
||||
};
|
||||
|
||||
const navigation = React.createRef<NavigationContainerRef>();
|
||||
|
||||
const root = (
|
||||
<BaseNavigationContainer ref={navigation}>
|
||||
<TestNavigator>
|
||||
<Screen name="foo" component={jest.fn()} />
|
||||
<Screen name="bar" component={jest.fn()} />
|
||||
<Screen name="baz" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
render(root);
|
||||
|
||||
expect(navigation.current?.getRootState().routeNames).toEqual([
|
||||
'foo',
|
||||
'bar',
|
||||
'baz',
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves order of screens in state with numeric names', () => {
|
||||
const TestNavigator = (props: any): any => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
return null;
|
||||
};
|
||||
|
||||
const navigation = React.createRef<NavigationContainerRef>();
|
||||
|
||||
const root = (
|
||||
<BaseNavigationContainer ref={navigation}>
|
||||
<TestNavigator>
|
||||
<Screen name="4" component={jest.fn()} />
|
||||
<Screen name="7" component={jest.fn()} />
|
||||
<Screen name="1" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
render(root);
|
||||
|
||||
expect(navigation.current?.getRootState().routeNames).toEqual([
|
||||
'4',
|
||||
'7',
|
||||
'1',
|
||||
]);
|
||||
});
|
||||
|
||||
it("throws if navigator doesn't have any screens", () => {
|
||||
const TestNavigator = (props: any) => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
@@ -1031,7 +1085,7 @@ it('throws descriptive error for invalid screen component', () => {
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
"Got an invalid value for 'component' prop for the screen 'foo'. It must be a a valid React Component."
|
||||
"Got an invalid value for 'component' prop for the screen 'foo'. It must be a valid React Component."
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -188,10 +188,12 @@ it('fires focus and blur events in nested navigator', () => {
|
||||
|
||||
expect(thirdFocusCallback).toBeCalledTimes(0);
|
||||
expect(secondFocusCallback).toBeCalledTimes(1);
|
||||
expect(fourthBlurCallback).toBeCalledTimes(0);
|
||||
|
||||
act(() => parent.current.navigate('nested'));
|
||||
|
||||
expect(firstBlurCallback).toBeCalledTimes(1);
|
||||
expect(secondBlurCallback).toBeCalledTimes(1);
|
||||
expect(thirdFocusCallback).toBeCalledTimes(0);
|
||||
expect(fourthFocusCallback).toBeCalledTimes(1);
|
||||
|
||||
@@ -199,6 +201,35 @@ it('fires focus and blur events in nested navigator', () => {
|
||||
|
||||
expect(fourthBlurCallback).toBeCalledTimes(1);
|
||||
expect(thirdFocusCallback).toBeCalledTimes(1);
|
||||
|
||||
act(() => parent.current.navigate('first'));
|
||||
|
||||
expect(firstFocusCallback).toBeCalledTimes(2);
|
||||
expect(thirdBlurCallback).toBeCalledTimes(1);
|
||||
|
||||
act(() => parent.current.navigate('nested', { screen: 'fourth' }));
|
||||
|
||||
expect(fourthFocusCallback).toBeCalledTimes(2);
|
||||
expect(thirdBlurCallback).toBeCalledTimes(1);
|
||||
expect(firstBlurCallback).toBeCalledTimes(2);
|
||||
|
||||
act(() => parent.current.navigate('nested', { screen: 'third' }));
|
||||
|
||||
expect(thirdFocusCallback).toBeCalledTimes(2);
|
||||
expect(fourthBlurCallback).toBeCalledTimes(2);
|
||||
|
||||
// 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(2);
|
||||
expect(thirdBlurCallback).toBeCalledTimes(1);
|
||||
|
||||
expect(fourthFocusCallback).toBeCalledTimes(2);
|
||||
expect(fourthBlurCallback).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it('fires blur event when a route is removed with a delay', async () => {
|
||||
@@ -331,7 +362,7 @@ it('fires blur event when a route is removed with a delay', async () => {
|
||||
expect(blurCallback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('fires custom events', () => {
|
||||
it('fires custom events added with addListener', () => {
|
||||
const eventName = 'someSuperCoolEvent';
|
||||
|
||||
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
|
||||
@@ -378,10 +409,13 @@ it('fires custom events', () => {
|
||||
expect(secondCallback).toBeCalledTimes(0);
|
||||
expect(thirdCallback).toBeCalledTimes(0);
|
||||
|
||||
const target =
|
||||
ref.current.state.routes[ref.current.state.routes.length - 1].key;
|
||||
|
||||
act(() => {
|
||||
ref.current.navigation.emit({
|
||||
type: eventName,
|
||||
target: ref.current.state.routes[ref.current.state.routes.length - 1].key,
|
||||
target,
|
||||
data: 42,
|
||||
});
|
||||
});
|
||||
@@ -391,6 +425,7 @@ it('fires custom events', () => {
|
||||
expect(thirdCallback).toBeCalledTimes(1);
|
||||
expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent');
|
||||
expect(thirdCallback.mock.calls[0][0].data).toBe(42);
|
||||
expect(thirdCallback.mock.calls[0][0].target).toBe(target);
|
||||
expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined);
|
||||
expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined);
|
||||
|
||||
@@ -398,11 +433,197 @@ it('fires custom events', () => {
|
||||
ref.current.navigation.emit({ type: eventName });
|
||||
});
|
||||
|
||||
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
|
||||
expect(secondCallback.mock.calls[0][0].target).toBe(undefined);
|
||||
expect(thirdCallback.mock.calls[1][0].target).toBe(undefined);
|
||||
|
||||
expect(firstCallback).toBeCalledTimes(1);
|
||||
expect(secondCallback).toBeCalledTimes(1);
|
||||
expect(thirdCallback).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it("doesn't call same listener multiple times with addListener", () => {
|
||||
const eventName = 'someSuperCoolEvent';
|
||||
|
||||
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
|
||||
const { state, navigation, descriptors } = useNavigationBuilder(
|
||||
MockRouter,
|
||||
props
|
||||
);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({ navigation, state }), [
|
||||
navigation,
|
||||
state,
|
||||
]);
|
||||
|
||||
return state.routes.map(route => descriptors[route.key].render());
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
|
||||
const Test = ({ navigation }: any) => {
|
||||
React.useEffect(() => navigation.addListener(eventName, callback), [
|
||||
navigation,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const ref = React.createRef<any>();
|
||||
|
||||
const element = (
|
||||
<BaseNavigationContainer>
|
||||
<TestNavigator ref={ref}>
|
||||
<Screen name="first" component={Test} />
|
||||
<Screen name="second" component={Test} />
|
||||
<Screen name="third" component={Test} />
|
||||
</TestNavigator>
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
render(element);
|
||||
|
||||
expect(callback).toBeCalledTimes(0);
|
||||
|
||||
act(() => {
|
||||
ref.current.navigation.emit({ type: eventName });
|
||||
});
|
||||
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('fires custom events added with listeners prop', () => {
|
||||
const eventName = 'someSuperCoolEvent';
|
||||
|
||||
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
|
||||
const { state, navigation } = useNavigationBuilder(MockRouter, props);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({ navigation, state }), [
|
||||
navigation,
|
||||
state,
|
||||
]);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const firstCallback = jest.fn();
|
||||
const secondCallback = jest.fn();
|
||||
const thirdCallback = jest.fn();
|
||||
|
||||
const ref = React.createRef<any>();
|
||||
|
||||
const element = (
|
||||
<BaseNavigationContainer>
|
||||
<TestNavigator ref={ref}>
|
||||
<Screen
|
||||
name="first"
|
||||
listeners={{ someSuperCoolEvent: firstCallback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
<Screen
|
||||
name="second"
|
||||
listeners={{ someSuperCoolEvent: secondCallback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
<Screen
|
||||
name="third"
|
||||
listeners={{ someSuperCoolEvent: thirdCallback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
</TestNavigator>
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
render(element);
|
||||
|
||||
expect(firstCallback).toBeCalledTimes(0);
|
||||
expect(secondCallback).toBeCalledTimes(0);
|
||||
expect(thirdCallback).toBeCalledTimes(0);
|
||||
|
||||
const target =
|
||||
ref.current.state.routes[ref.current.state.routes.length - 1].key;
|
||||
|
||||
act(() => {
|
||||
ref.current.navigation.emit({
|
||||
type: eventName,
|
||||
target,
|
||||
data: 42,
|
||||
});
|
||||
});
|
||||
|
||||
expect(firstCallback).toBeCalledTimes(0);
|
||||
expect(secondCallback).toBeCalledTimes(0);
|
||||
expect(thirdCallback).toBeCalledTimes(1);
|
||||
expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent');
|
||||
expect(thirdCallback.mock.calls[0][0].data).toBe(42);
|
||||
expect(thirdCallback.mock.calls[0][0].target).toBe(target);
|
||||
expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined);
|
||||
expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined);
|
||||
|
||||
act(() => {
|
||||
ref.current.navigation.emit({ type: eventName });
|
||||
});
|
||||
|
||||
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
|
||||
expect(secondCallback.mock.calls[0][0].target).toBe(undefined);
|
||||
expect(thirdCallback.mock.calls[1][0].target).toBe(undefined);
|
||||
|
||||
expect(firstCallback).toBeCalledTimes(1);
|
||||
expect(secondCallback).toBeCalledTimes(1);
|
||||
expect(thirdCallback).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it("doesn't call same listener multiple times with listeners", () => {
|
||||
const eventName = 'someSuperCoolEvent';
|
||||
|
||||
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
|
||||
const { state, navigation } = useNavigationBuilder(MockRouter, props);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({ navigation, state }), [
|
||||
navigation,
|
||||
state,
|
||||
]);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
|
||||
const ref = React.createRef<any>();
|
||||
|
||||
const element = (
|
||||
<BaseNavigationContainer>
|
||||
<TestNavigator ref={ref}>
|
||||
<Screen
|
||||
name="first"
|
||||
listeners={{ someSuperCoolEvent: callback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
<Screen
|
||||
name="second"
|
||||
listeners={{ someSuperCoolEvent: callback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
<Screen
|
||||
name="third"
|
||||
listeners={{ someSuperCoolEvent: callback }}
|
||||
component={jest.fn()}
|
||||
/>
|
||||
</TestNavigator>
|
||||
</BaseNavigationContainer>
|
||||
);
|
||||
|
||||
render(element);
|
||||
|
||||
expect(callback).toBeCalledTimes(0);
|
||||
|
||||
act(() => {
|
||||
ref.current.navigation.emit({ type: eventName });
|
||||
});
|
||||
|
||||
expect(callback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('has option to prevent default', () => {
|
||||
expect.assertions(5);
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ it('throws if called outside a navigation context', () => {
|
||||
const Test = () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
expect(() => useNavigation()).toThrow(
|
||||
"We couldn't find a navigation object. Is your component inside a screen in a navigator?"
|
||||
"Couldn't find a navigation object. Is your component inside a screen in a navigator?"
|
||||
);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -374,7 +374,7 @@ it('logs error if no navigator handled the action', () => {
|
||||
render(element).update(element);
|
||||
|
||||
expect(spy.mock.calls[0][0]).toMatch(
|
||||
"The action 'UNKNOWN' with payload 'undefined' was not handled by any navigator."
|
||||
"The action 'UNKNOWN' was not handled by any navigator."
|
||||
);
|
||||
|
||||
spy.mockRestore();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { ParamListBase } from '@react-navigation/routers';
|
||||
import { ParamListBase, NavigationState } from '@react-navigation/routers';
|
||||
import Screen from './Screen';
|
||||
import { TypedNavigator } from './types';
|
||||
import { TypedNavigator, EventMapBase } from './types';
|
||||
|
||||
/**
|
||||
* Higher order component to create a `Navigator` and `Screen` pair.
|
||||
@@ -11,17 +11,21 @@ import { TypedNavigator } from './types';
|
||||
* @returns Factory method to create a `Navigator` and `Screen` pair.
|
||||
*/
|
||||
export default function createNavigatorFactory<
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase,
|
||||
NavigatorComponent extends React.ComponentType<any>
|
||||
>(Navigator: NavigatorComponent) {
|
||||
return function<ParamList extends ParamListBase>(): TypedNavigator<
|
||||
ParamList,
|
||||
State,
|
||||
ScreenOptions,
|
||||
EventMap,
|
||||
typeof Navigator
|
||||
> {
|
||||
if (arguments[0] !== undefined) {
|
||||
throw new Error(
|
||||
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/en/upgrading-from-4.x.html for migration guide."
|
||||
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/upgrading-from-4.x.html for migration guide."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ export type EventArg<
|
||||
* Type of the event (e.g. `focus`, `blur`)
|
||||
*/
|
||||
readonly type: EventName;
|
||||
readonly target?: string;
|
||||
} & (CanPreventDefault extends true
|
||||
? {
|
||||
/**
|
||||
@@ -360,7 +361,9 @@ export type Descriptor<
|
||||
export type RouteConfig<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList,
|
||||
ScreenOptions extends object
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
> = {
|
||||
/**
|
||||
* Route name of this screen.
|
||||
@@ -377,6 +380,16 @@ export type RouteConfig<
|
||||
navigation: any;
|
||||
}) => ScreenOptions);
|
||||
|
||||
/**
|
||||
* Event listeners for this screen.
|
||||
*/
|
||||
listeners?: Partial<
|
||||
{
|
||||
[EventName in keyof (EventMap &
|
||||
EventMapCore<State>)]: EventListenerCallback<EventMap, EventName>;
|
||||
}
|
||||
>;
|
||||
|
||||
/**
|
||||
* Initial params object for the route.
|
||||
*/
|
||||
@@ -420,7 +433,9 @@ export type NavigationContainerRef =
|
||||
|
||||
export type TypedNavigator<
|
||||
ParamList extends ParamListBase,
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase,
|
||||
Navigator extends React.ComponentType<any>
|
||||
> = {
|
||||
/**
|
||||
@@ -451,6 +466,6 @@ export type TypedNavigator<
|
||||
* Component used for specifying route configuration.
|
||||
*/
|
||||
Screen: <RouteName extends keyof ParamList>(
|
||||
_: RouteConfig<ParamList, RouteName, ScreenOptions>
|
||||
_: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>
|
||||
) => null;
|
||||
};
|
||||
|
||||
@@ -13,11 +13,24 @@ import NavigationBuilderContext, {
|
||||
} from './NavigationBuilderContext';
|
||||
import { NavigationEventEmitter } from './useEventEmitter';
|
||||
import useNavigationCache from './useNavigationCache';
|
||||
import { Descriptor, NavigationHelpers, RouteConfig, RouteProp } from './types';
|
||||
import {
|
||||
Descriptor,
|
||||
NavigationHelpers,
|
||||
RouteConfig,
|
||||
RouteProp,
|
||||
EventMapBase,
|
||||
} from './types';
|
||||
|
||||
type Options<State extends NavigationState, ScreenOptions extends object> = {
|
||||
type Options<
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
> = {
|
||||
state: State;
|
||||
screens: Record<string, RouteConfig<ParamListBase, string, ScreenOptions>>;
|
||||
screens: Record<
|
||||
string,
|
||||
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
|
||||
>;
|
||||
navigation: NavigationHelpers<ParamListBase>;
|
||||
screenOptions?:
|
||||
| ScreenOptions
|
||||
@@ -49,7 +62,8 @@ type Options<State extends NavigationState, ScreenOptions extends object> = {
|
||||
*/
|
||||
export default function useDescriptors<
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
>({
|
||||
state,
|
||||
screens,
|
||||
@@ -64,7 +78,7 @@ export default function useDescriptors<
|
||||
onRouteFocus,
|
||||
router,
|
||||
emitter,
|
||||
}: Options<State, ScreenOptions>) {
|
||||
}: Options<State, ScreenOptions, EventMap>) {
|
||||
const [options, setOptions] = React.useState<Record<string, object>>({});
|
||||
const { trackAction } = React.useContext(NavigationBuilderContext);
|
||||
|
||||
@@ -133,6 +147,7 @@ export default function useDescriptors<
|
||||
: screen.options({
|
||||
// @ts-ignore
|
||||
route,
|
||||
// @ts-ignore
|
||||
navigation,
|
||||
})),
|
||||
// The options set via `navigation.setOptions`
|
||||
|
||||
@@ -5,12 +5,20 @@ export type NavigationEventEmitter = EventEmitter<Record<string, any>> & {
|
||||
create: (target: string) => EventConsumer<Record<string, any>>;
|
||||
};
|
||||
|
||||
type Listeners = ((data: any) => void)[];
|
||||
type Listeners = ((e: any) => void)[];
|
||||
|
||||
/**
|
||||
* Hook to manage the event system used by the navigator to notify screens of various events.
|
||||
*/
|
||||
export default function useEventEmitter(): NavigationEventEmitter {
|
||||
export default function useEventEmitter(
|
||||
listen?: (e: any) => void
|
||||
): NavigationEventEmitter {
|
||||
const listenRef = React.useRef(listen);
|
||||
|
||||
React.useEffect(() => {
|
||||
listenRef.current = listen;
|
||||
});
|
||||
|
||||
const listeners = React.useRef<Record<string, Record<string, Listeners>>>({});
|
||||
|
||||
const create = React.useCallback((target: string) => {
|
||||
@@ -60,7 +68,9 @@ export default function useEventEmitter(): NavigationEventEmitter {
|
||||
const callbacks =
|
||||
target !== undefined
|
||||
? items[target] && items[target].slice()
|
||||
: ([] as Listeners).concat(...Object.keys(items).map(t => items[t]));
|
||||
: ([] as Listeners)
|
||||
.concat(...Object.keys(items).map(t => items[t]))
|
||||
.filter((cb, i, self) => self.lastIndexOf(cb) === i);
|
||||
|
||||
const event: EventArg<any, any, any> = {
|
||||
get type() {
|
||||
@@ -68,8 +78,18 @@ export default function useEventEmitter(): NavigationEventEmitter {
|
||||
},
|
||||
};
|
||||
|
||||
if (target !== undefined) {
|
||||
Object.defineProperty(event, 'target', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return target;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (data !== undefined) {
|
||||
Object.defineProperty(event, 'data', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return data;
|
||||
},
|
||||
@@ -81,11 +101,13 @@ export default function useEventEmitter(): NavigationEventEmitter {
|
||||
|
||||
Object.defineProperties(event, {
|
||||
defaultPrevented: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return defaultPrevented;
|
||||
},
|
||||
},
|
||||
preventDefault: {
|
||||
enumerable: true,
|
||||
value() {
|
||||
defaultPrevented = true;
|
||||
},
|
||||
@@ -93,6 +115,8 @@ export default function useEventEmitter(): NavigationEventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
listenRef.current?.(event);
|
||||
|
||||
callbacks?.forEach(cb => cb(event));
|
||||
|
||||
return event as any;
|
||||
|
||||
@@ -10,13 +10,51 @@ type EffectCallback = () => undefined | void | (() => void);
|
||||
*
|
||||
* @param callback Memoized callback containing the effect, should optionally return a cleanup function.
|
||||
*/
|
||||
export default function useFocusEffect(callback: EffectCallback) {
|
||||
export default function useFocusEffect(effect: EffectCallback) {
|
||||
const navigation = useNavigation();
|
||||
|
||||
React.useEffect(() => {
|
||||
let isFocused = false;
|
||||
let cleanup: undefined | void | (() => void);
|
||||
|
||||
const callback = () => {
|
||||
const destroy = effect();
|
||||
|
||||
if (destroy === undefined || typeof destroy === 'function') {
|
||||
return destroy;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
let message =
|
||||
'An effect function must not return anything besides a function, which is used for clean-up.';
|
||||
|
||||
if (destroy === null) {
|
||||
message +=
|
||||
" You returned 'null'. If your effect does not require clean-up, return 'undefined' (or nothing).";
|
||||
} else if (typeof (destroy as any).then === 'function') {
|
||||
message +=
|
||||
"\n\nIt looks like you wrote 'useFocusEffect(async () => ...)' or returned a Promise. " +
|
||||
'Instead, write the async function inside your effect ' +
|
||||
'and call it immediately:\n\n' +
|
||||
'useFocusEffect(\n' +
|
||||
' React.useCallback() => {\n' +
|
||||
' async function fetchData() {\n' +
|
||||
' // You can await here\n' +
|
||||
' const response = await MyAPI.getData(someId);\n' +
|
||||
' // ...\n' +
|
||||
' }\n\n' +
|
||||
' fetchData();\n' +
|
||||
' }, [someId])\n' +
|
||||
'};\n\n' +
|
||||
'See usage guide: https://reactnavigation.org/docs/use-focus-effect.html';
|
||||
} else {
|
||||
message += ` You returned: '${JSON.stringify(destroy)}'`;
|
||||
}
|
||||
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
// We need to run the effect on intial render/dep changes if the screen is focused
|
||||
if (navigation.isFocused()) {
|
||||
cleanup = callback();
|
||||
@@ -55,5 +93,5 @@ export default function useFocusEffect(callback: EffectCallback) {
|
||||
unsubscribeFocus();
|
||||
unsubscribeBlur();
|
||||
};
|
||||
}, [callback, navigation]);
|
||||
}, [effect, navigation]);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,19 @@ export default function useFocusEvents({ state, emitter }: Options) {
|
||||
// Coz the child screen can't be focused if the parent screen is out of focus
|
||||
React.useEffect(
|
||||
() =>
|
||||
navigation?.addListener('focus', () =>
|
||||
emitter.emit({ type: 'focus', target: currentFocusedKey })
|
||||
),
|
||||
navigation?.addListener('focus', () => {
|
||||
lastFocusedKeyRef.current = currentFocusedKey;
|
||||
emitter.emit({ type: 'focus', target: currentFocusedKey });
|
||||
}),
|
||||
[currentFocusedKey, emitter, navigation]
|
||||
);
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
navigation?.addListener('blur', () =>
|
||||
emitter.emit({ type: 'blur', target: currentFocusedKey })
|
||||
),
|
||||
navigation?.addListener('blur', () => {
|
||||
lastFocusedKeyRef.current = undefined;
|
||||
emitter.emit({ type: 'blur', target: currentFocusedKey });
|
||||
}),
|
||||
[currentFocusedKey, emitter, navigation]
|
||||
);
|
||||
|
||||
@@ -60,14 +62,7 @@ export default function useFocusEvents({ state, emitter }: Options) {
|
||||
return;
|
||||
}
|
||||
|
||||
emitter.emit({
|
||||
type: 'focus',
|
||||
target: currentFocusedKey,
|
||||
});
|
||||
|
||||
emitter.emit({
|
||||
type: 'blur',
|
||||
target: lastFocusedKey,
|
||||
});
|
||||
emitter.emit({ type: 'focus', target: currentFocusedKey });
|
||||
emitter.emit({ type: 'blur', target: lastFocusedKey });
|
||||
}, [currentFocusedKey, emitter, navigation]);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function useNavigation<
|
||||
|
||||
if (navigation === undefined) {
|
||||
throw new Error(
|
||||
"We couldn't find a navigation object. Is your component inside a screen in a navigator?"
|
||||
"Couldn't find a navigation object. Is your component inside a screen in a navigator?"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
DefaultNavigatorOptions,
|
||||
RouteConfig,
|
||||
PrivateValueStore,
|
||||
EventMapBase,
|
||||
} from './types';
|
||||
import useStateGetters from './useStateGetters';
|
||||
import useOnGetState from './useOnGetState';
|
||||
@@ -55,18 +56,28 @@ const isArrayEqual = (a: any[], b: any[]) =>
|
||||
*
|
||||
* @param children React Elements to extract the config from.
|
||||
*/
|
||||
const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
||||
const getRouteConfigsFromChildren = <
|
||||
State extends NavigationState,
|
||||
ScreenOptions extends object,
|
||||
EventMap extends EventMapBase
|
||||
>(
|
||||
children: React.ReactNode
|
||||
) => {
|
||||
const configs = React.Children.toArray(children).reduce<
|
||||
RouteConfig<ParamListBase, string, ScreenOptions>[]
|
||||
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>[]
|
||||
>((acc, child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
if (child.type === Screen) {
|
||||
// We can only extract the config from `Screen` elements
|
||||
// If something else was rendered, it's probably a bug
|
||||
acc.push(
|
||||
child.props as RouteConfig<ParamListBase, string, ScreenOptions>
|
||||
child.props as RouteConfig<
|
||||
ParamListBase,
|
||||
string,
|
||||
State,
|
||||
ScreenOptions,
|
||||
EventMap
|
||||
>
|
||||
);
|
||||
return acc;
|
||||
}
|
||||
@@ -75,7 +86,9 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
||||
// When we encounter a fragment, we need to dive into its children to extract the configs
|
||||
// This is handy to conditionally define a group of screens
|
||||
acc.push(
|
||||
...getRouteConfigsFromChildren<ScreenOptions>(child.props.children)
|
||||
...getRouteConfigsFromChildren<State, ScreenOptions, EventMap>(
|
||||
child.props.children
|
||||
)
|
||||
);
|
||||
return acc;
|
||||
}
|
||||
@@ -116,7 +129,7 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
||||
|
||||
if (component !== undefined && !isValidElementType(component)) {
|
||||
throw new Error(
|
||||
`Got an invalid value for 'component' prop for the screen '${name}'. It must be a a valid React Component.`
|
||||
`Got an invalid value for 'component' prop for the screen '${name}'. It must be a valid React Component.`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,20 +190,29 @@ export default function useNavigationBuilder<
|
||||
})
|
||||
);
|
||||
|
||||
const screens = getRouteConfigsFromChildren<ScreenOptions>(children).reduce<
|
||||
Record<string, RouteConfig<ParamListBase, string, ScreenOptions>>
|
||||
>((acc, curr) => {
|
||||
if (curr.name in acc) {
|
||||
const routeConfigs = getRouteConfigsFromChildren<
|
||||
State,
|
||||
ScreenOptions,
|
||||
EventMap
|
||||
>(children);
|
||||
|
||||
const screens = routeConfigs.reduce<
|
||||
Record<
|
||||
string,
|
||||
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
|
||||
>
|
||||
>((acc, config) => {
|
||||
if (config.name in acc) {
|
||||
throw new Error(
|
||||
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${curr.name}')`
|
||||
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${config.name}')`
|
||||
);
|
||||
}
|
||||
|
||||
acc[curr.name] = curr;
|
||||
acc[config.name] = config;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const routeNames = Object.keys(screens);
|
||||
const routeNames = routeConfigs.map(config => config.name);
|
||||
const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
|
||||
(acc, curr) => {
|
||||
const { initialParams } = screens[curr];
|
||||
@@ -235,7 +257,6 @@ export default function useNavigationBuilder<
|
||||
setState,
|
||||
setKey,
|
||||
getKey,
|
||||
performTransaction,
|
||||
} = React.useContext(NavigationStateContext);
|
||||
|
||||
const previousStateRef = React.useRef<
|
||||
@@ -316,9 +337,7 @@ export default function useNavigationBuilder<
|
||||
// If the state needs to be updated, we'll schedule an update with React
|
||||
// setState in render seems hacky, but that's how React docs implement getDerivedPropsFromState
|
||||
// https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops
|
||||
performTransaction(() => {
|
||||
setState(nextState);
|
||||
});
|
||||
setState(nextState);
|
||||
}
|
||||
|
||||
// The up-to-date state will come in next render, but we don't need to wait for it
|
||||
@@ -331,11 +350,9 @@ export default function useNavigationBuilder<
|
||||
|
||||
return () => {
|
||||
// We need to clean up state for this navigator on unmount
|
||||
performTransaction(() => {
|
||||
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
||||
setState(undefined);
|
||||
}
|
||||
});
|
||||
if (getCurrentState() !== undefined && getKey() === navigatorKey) {
|
||||
setState(undefined);
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
@@ -348,7 +365,35 @@ export default function useNavigationBuilder<
|
||||
: (initializedStateRef.current as State);
|
||||
}, [getCurrentState, isStateInitialized]);
|
||||
|
||||
const emitter = useEventEmitter();
|
||||
const emitter = useEventEmitter(e => {
|
||||
let routeNames = [];
|
||||
|
||||
if (e.target) {
|
||||
const name = state.routes.find(route => route.key === e.target)?.name;
|
||||
|
||||
if (name) {
|
||||
routeNames.push(name);
|
||||
}
|
||||
} else {
|
||||
routeNames.push(...Object.keys(screens));
|
||||
}
|
||||
|
||||
const listeners = ([] as (((e: any) => void) | undefined)[])
|
||||
.concat(
|
||||
...routeNames.map(name => {
|
||||
const { listeners } = screens[name];
|
||||
|
||||
return listeners
|
||||
? Object.keys(listeners)
|
||||
.filter(type => type === e.type)
|
||||
.map(type => listeners[type])
|
||||
: undefined;
|
||||
})
|
||||
)
|
||||
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
||||
|
||||
listeners.forEach(listener => listener?.(e));
|
||||
});
|
||||
|
||||
useFocusEvents({ state, emitter });
|
||||
|
||||
@@ -404,7 +449,7 @@ export default function useNavigationBuilder<
|
||||
getStateForRoute,
|
||||
});
|
||||
|
||||
const descriptors = useDescriptors<State, ScreenOptions>({
|
||||
const descriptors = useDescriptors<State, ScreenOptions, EventMap>({
|
||||
state,
|
||||
screens,
|
||||
navigation,
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
Router,
|
||||
} from '@react-navigation/routers';
|
||||
import NavigationContext from './NavigationContext';
|
||||
import { NavigationStateContext } from './BaseNavigationContainer';
|
||||
import { NavigationEventEmitter } from './useEventEmitter';
|
||||
import { NavigationHelpers, NavigationProp, PrivateValueStore } from './types';
|
||||
|
||||
@@ -35,24 +34,48 @@ export default function useNavigationHelpers<
|
||||
EventMap extends Record<string, any>
|
||||
>({ onAction, getState, emitter, router }: Options<State, Action>) {
|
||||
const parentNavigationHelpers = React.useContext(NavigationContext);
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
return React.useMemo(() => {
|
||||
const dispatch = (action: Action | ((state: State) => Action)) => {
|
||||
performTransaction(() => {
|
||||
const payload =
|
||||
typeof action === 'function' ? action(getState()) : action;
|
||||
const dispatch = (op: Action | ((state: State) => Action)) => {
|
||||
const action = typeof op === 'function' ? op(getState()) : op;
|
||||
|
||||
const handled = onAction(payload);
|
||||
const handled = onAction(action);
|
||||
|
||||
if (!handled && process.env.NODE_ENV !== 'production') {
|
||||
console.error(
|
||||
`The action '${payload.type}' with payload '${JSON.stringify(
|
||||
payload.payload
|
||||
)}' was not handled by any navigator. If you are trying to navigate to a screen, check if the screen exists in your navigator. If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/en/nesting-navigators.html#navigating-to-a-screen-in-a-nested-navigator.`
|
||||
);
|
||||
if (!handled && process.env.NODE_ENV !== 'production') {
|
||||
const payload: Record<string, any> | undefined = action.payload;
|
||||
|
||||
let message = `The action '${action.type}'${
|
||||
payload ? ` with payload ${JSON.stringify(action.payload)}` : ''
|
||||
} was not handled by any navigator.`;
|
||||
|
||||
switch (action.type) {
|
||||
case 'NAVIGATE':
|
||||
case 'PUSH':
|
||||
case 'REPLACE':
|
||||
case 'JUMP_TO':
|
||||
if (payload?.name) {
|
||||
message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators.html#navigating-to-a-screen-in-a-nested-navigator.`;
|
||||
} else {
|
||||
message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions.html for usage.`;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'GO_BACK':
|
||||
case 'POP':
|
||||
case 'POP_TO_TOP':
|
||||
message += `\n\nIs there any screen to go back to?`;
|
||||
break;
|
||||
case 'OPEN_DRAWER':
|
||||
case 'CLOSE_DRAWER':
|
||||
case 'TOGGLE_DRAWER':
|
||||
message += `\n\nIs your screen inside a Drawer navigator?`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
message += `\n\nThis is a development-only warning and won't be shown in production.`;
|
||||
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
@@ -91,12 +114,5 @@ export default function useNavigationHelpers<
|
||||
},
|
||||
} as NavigationHelpers<ParamListBase, EventMap> &
|
||||
(NavigationProp<ParamListBase, string, any, any, any> | undefined);
|
||||
}, [
|
||||
router,
|
||||
getState,
|
||||
parentNavigationHelpers,
|
||||
emitter.emit,
|
||||
performTransaction,
|
||||
onAction,
|
||||
]);
|
||||
}, [router, getState, parentNavigationHelpers, emitter.emit, onAction]);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function useRoute<
|
||||
|
||||
if (route === undefined) {
|
||||
throw new Error(
|
||||
"We couldn't find a route object. Is your component inside a screen in a navigator?"
|
||||
"Couldn't find a route object. Is your component inside a screen in a navigator?"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
28
packages/core/src/useSyncState.tsx
Normal file
28
packages/core/src/useSyncState.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
|
||||
const UNINTIALIZED_STATE = {};
|
||||
|
||||
export default function useSyncState<T>(initialState?: (() => T) | T) {
|
||||
const stateRef = React.useRef<T>(UNINTIALIZED_STATE as any);
|
||||
|
||||
if (stateRef.current === UNINTIALIZED_STATE) {
|
||||
stateRef.current =
|
||||
// @ts-ignore
|
||||
typeof initialState === 'function' ? initialState() : initialState;
|
||||
}
|
||||
|
||||
const [state, setTrackingState] = React.useState(stateRef.current);
|
||||
|
||||
const getState = React.useCallback(() => stateRef.current, []);
|
||||
|
||||
const setState = React.useCallback((state: T) => {
|
||||
if (state === stateRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
stateRef.current = state;
|
||||
setTrackingState(state);
|
||||
}, []);
|
||||
|
||||
return [state, getState, setState] as const;
|
||||
}
|
||||
@@ -3,6 +3,36 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.7...@react-navigation/drawer@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.6...@react-navigation/drawer@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/drawer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.5...@react-navigation/drawer@5.0.6) (2020-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* delay showing drawer by one frame after layout ([e0c3298](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/e0c3298e64970dc01a61401cfbd7a623eb0fd735))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.4...@react-navigation/drawer@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/drawer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/drawer",
|
||||
"description": "Drawer navigator component with animated transitions and gesturess",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"keywords": [
|
||||
"react-native-component",
|
||||
"react-component",
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-native": "^0.60.30",
|
||||
"del-cli": "^3.0.0",
|
||||
@@ -53,7 +53,7 @@
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": ">= 1.0.0",
|
||||
|
||||
@@ -49,6 +49,8 @@ function DrawerNavigator({
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
DrawerNavigationState,
|
||||
DrawerNavigationOptions,
|
||||
DrawerNavigationEventMap,
|
||||
typeof DrawerNavigator
|
||||
>(DrawerNavigator);
|
||||
|
||||
@@ -504,7 +504,9 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
// Until layout is available, drawer is hidden with opacity: 0 by default
|
||||
// Show it in the next frame when layout is available
|
||||
// If we don't delay it until the next frame, there's a visible flicker
|
||||
requestAnimationFrame(() => this.drawerOpacity.setValue(1));
|
||||
requestAnimationFrame(() =>
|
||||
requestAnimationFrame(() => this.drawerOpacity.setValue(1))
|
||||
);
|
||||
};
|
||||
|
||||
private toggleDrawer = (open: boolean) => {
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.7...@react-navigation/material-bottom-tabs@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.6...@react-navigation/material-bottom-tabs@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.5...@react-navigation/material-bottom-tabs@5.0.6) (2020-02-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.4...@react-navigation/material-bottom-tabs@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/material-bottom-tabs",
|
||||
"description": "Integration for bottom navigation component from react-native-paper",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"keywords": [
|
||||
"react-native-component",
|
||||
"react-component",
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-native": "^0.60.30",
|
||||
"@types/react-native-vector-icons": "^6.4.5",
|
||||
@@ -48,7 +48,7 @@
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-paper": ">= 3.0.0",
|
||||
|
||||
@@ -49,6 +49,8 @@ function MaterialBottomTabNavigator({
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
TabNavigationState,
|
||||
MaterialBottomTabNavigationOptions,
|
||||
MaterialBottomTabNavigationEventMap,
|
||||
typeof MaterialBottomTabNavigator
|
||||
>(MaterialBottomTabNavigator);
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.7...@react-navigation/material-top-tabs@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.6...@react-navigation/material-top-tabs@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.5...@react-navigation/material-top-tabs@5.0.6) (2020-02-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.4...@react-navigation/material-top-tabs@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/material-top-tabs",
|
||||
"description": "Integration for the animated tab view component from react-native-tab-view",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"keywords": [
|
||||
"react-native-component",
|
||||
"react-component",
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-native": "^0.60.30",
|
||||
"del-cli": "^3.0.0",
|
||||
@@ -51,7 +51,7 @@
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": ">= 1.0.0",
|
||||
|
||||
@@ -48,6 +48,8 @@ function MaterialTopTabNavigator({
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
TabNavigationState,
|
||||
MaterialTopTabNavigationOptions,
|
||||
MaterialTopTabNavigationEventMap,
|
||||
typeof MaterialTopTabNavigator
|
||||
>(MaterialTopTabNavigator);
|
||||
|
||||
@@ -1,367 +0,0 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.4...@react-navigation/native-stack@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.4](https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.3...@react-navigation/native-stack@5.0.4) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.3](https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.2...@react-navigation/native-stack@5.0.3) (2020-02-12)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.2](https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.1...@react-navigation/native-stack@5.0.2) (2020-02-11)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.1](https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.35...@react-navigation/native-stack@5.0.1) (2020-02-10)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.34...@react-navigation/native-stack@5.0.0-alpha.35) (2020-02-04)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.34](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.33...@react-navigation/native-stack@5.0.0-alpha.34) (2020-02-04)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.33](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.32...@react-navigation/native-stack@5.0.0-alpha.33) (2020-02-03)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.29...@react-navigation/native-stack@5.0.0-alpha.32) (2020-02-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||
* screens integration on Android ([#294](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/issues/294)) ([9bfb295](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/9bfb29562020c61b4d5c9bee278bcb1c7bdb8b67))
|
||||
* update screens for native stack ([5411816](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/54118161885738a6d20b062c7e6679f3bace8424))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.29...@react-navigation/native-stack@5.0.0-alpha.30) (2020-02-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||
* screens integration on Android ([#294](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/issues/294)) ([9bfb295](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/9bfb29562020c61b4d5c9bee278bcb1c7bdb8b67))
|
||||
* update screens for native stack ([5411816](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/54118161885738a6d20b062c7e6679f3bace8424))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.28...@react-navigation/native-stack@5.0.0-alpha.29) (2020-01-24)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.27...@react-navigation/native-stack@5.0.0-alpha.28) (2020-01-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix types for native stack ([1da4a64](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/1da4a6437f4607c1d4547d26dd5068615631982e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* emit appear and dismiss events for native stack ([f1df4a0](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/f1df4a080877b3642e748a41a5ffc2da8c449a8c))
|
||||
* let the navigator specify if default can be prevented ([da67e13](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/da67e134d2157201360427d3c10da24f24cae7aa))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.26...@react-navigation/native-stack@5.0.0-alpha.27) (2020-01-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.26](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.25...@react-navigation/native-stack@5.0.0-alpha.26) (2020-01-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* make sure paths aren't aliased when building definitions ([65a5dac](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/commit/65a5dac2bf887f4ba081ab15bd4c9870bb15697f)), closes [#265](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/issues/265)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.25](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.24...@react-navigation/native-stack@5.0.0-alpha.25) (2020-01-13)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.24](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.22...@react-navigation/native-stack@5.0.0-alpha.24) (2020-01-09)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.23](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.22...@react-navigation/native-stack@5.0.0-alpha.23) (2020-01-09)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.22](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.21...@react-navigation/native-stack@5.0.0-alpha.22) (2020-01-05)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.20...@react-navigation/native-stack@5.0.0-alpha.21) (2020-01-03)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.19...@react-navigation/native-stack@5.0.0-alpha.20) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.18...@react-navigation/native-stack@5.0.0-alpha.19) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.17...@react-navigation/native-stack@5.0.0-alpha.18) (2019-12-16)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.16...@react-navigation/native-stack@5.0.0-alpha.17) (2019-12-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add custom theme support ([#211](https://github.com/react-navigation/navigation-ex/issues/211)) ([00fc616](https://github.com/react-navigation/navigation-ex/commit/00fc616de0572bade8aa85052cdc8290360b1d7f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.15...@react-navigation/native-stack@5.0.0-alpha.16) (2019-12-11)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.15](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.14...@react-navigation/native-stack@5.0.0-alpha.15) (2019-12-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* export underlying views used to build navigators ([#191](https://github.com/react-navigation/navigation-ex/issues/191)) ([d618ab3](https://github.com/react-navigation/navigation-ex/commit/d618ab382ecc5eccbcd5faa89e76f9ed2d75f405))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.14](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.13...@react-navigation/native-stack@5.0.0-alpha.14) (2019-11-20)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.13](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.12...@react-navigation/native-stack@5.0.0-alpha.13) (2019-11-17)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.12](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.11...@react-navigation/native-stack@5.0.0-alpha.12) (2019-11-10)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.11](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.10...@react-navigation/native-stack@5.0.0-alpha.11) (2019-11-08)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.9...@react-navigation/native-stack@5.0.0-alpha.10) (2019-11-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* popToTop on tab press in native stack ([301c35e](https://github.com/react-navigation/navigation-ex/commit/301c35e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.8...@react-navigation/native-stack@5.0.0-alpha.9) (2019-11-04)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.7...@react-navigation/native-stack@5.0.0-alpha.8) (2019-11-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add headerBackTitleVisible to navigation options in native stack ([77f29d3](https://github.com/react-navigation/navigation-ex/commit/77f29d3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.7](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.6...@react-navigation/native-stack@5.0.0-alpha.7) (2019-11-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove top margin from screen in native stack on Android ([5cd6940](https://github.com/react-navigation/navigation-ex/commit/5cd6940))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.6](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.5...@react-navigation/native-stack@5.0.0-alpha.6) (2019-10-30)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.5](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.4...@react-navigation/native-stack@5.0.0-alpha.5) (2019-10-29)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.4](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.3...@react-navigation/native-stack@5.0.0-alpha.4) (2019-10-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **native-stack:** add support for large title attributes ([#135](https://github.com/react-navigation/navigation-ex/issues/135)) ([6cf1a04](https://github.com/react-navigation/navigation-ex/commit/6cf1a04))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.3](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.2...@react-navigation/native-stack@5.0.0-alpha.3) (2019-10-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove top margin when header is hidden in native stack. fixes [#131](https://github.com/react-navigation/navigation-ex/issues/131) ([fb726ee](https://github.com/react-navigation/navigation-ex/commit/fb726ee))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.2](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.1...@react-navigation/native-stack@5.0.0-alpha.2) (2019-10-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix header font size config in native stack ([#128](https://github.com/react-navigation/navigation-ex/issues/128)) ([477c088](https://github.com/react-navigation/navigation-ex/commit/477c088))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 5.0.0-alpha.1 (2019-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* increase hitSlop of back button on Android ([c7da1e4](https://github.com/react-navigation/navigation-ex/commit/c7da1e4))
|
||||
* update supported options for native stack ([b71f4e5](https://github.com/react-navigation/navigation-ex/commit/b71f4e5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* initial version of native stack ([#102](https://github.com/react-navigation/navigation-ex/issues/102)) ([ba3f718](https://github.com/react-navigation/navigation-ex/commit/ba3f718))
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 React Navigation Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,5 +0,0 @@
|
||||
# `@react-navigation/native-stack`
|
||||
|
||||
Stack navigator for React Native using native primitives for navigation. Uses [`react-native-screens`](https://github.com/kmagiera/react-native-screens) under the hood.
|
||||
|
||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/native-stack-navigator.html).
|
||||
@@ -1,59 +0,0 @@
|
||||
{
|
||||
"name": "@react-navigation/native-stack",
|
||||
"description": "Native stack navigator component for iOS and Android",
|
||||
"version": "5.0.4",
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-native",
|
||||
"react-navigation"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/native-stack",
|
||||
"bugs": {
|
||||
"url": "https://github.com/react-navigation/react-navigation/issues"
|
||||
},
|
||||
"homepage": "https://reactnavigation.org/docs/native-stack-navigator.html",
|
||||
"main": "lib/commonjs/index.js",
|
||||
"react-native": "src/index.tsx",
|
||||
"module": "lib/module/index.js",
|
||||
"types": "lib/typescript/src/index.d.ts",
|
||||
"files": [
|
||||
"src",
|
||||
"lib"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "bob build",
|
||||
"clean": "del lib"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"del-cli": "^3.0.0",
|
||||
"react-native-screens": "^2.0.0-beta.2",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": ">= 5.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
"output": "lib",
|
||||
"targets": [
|
||||
"commonjs",
|
||||
"module",
|
||||
[
|
||||
"typescript",
|
||||
{
|
||||
"project": "tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Navigators
|
||||
*/
|
||||
export { default as createNativeStackNavigator } from './navigators/createNativeStackNavigator';
|
||||
|
||||
/**
|
||||
* Views
|
||||
*/
|
||||
export { default as NativeStackView } from './views/NativeStackView';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
export {
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationProp,
|
||||
} from './types';
|
||||
@@ -1,81 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
createNavigatorFactory,
|
||||
useNavigationBuilder,
|
||||
EventArg,
|
||||
StackRouter,
|
||||
StackNavigationState,
|
||||
StackRouterOptions,
|
||||
StackActions,
|
||||
} from '@react-navigation/native';
|
||||
|
||||
import {
|
||||
screensEnabled,
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
} from 'react-native-screens';
|
||||
import NativeStackView from '../views/NativeStackView';
|
||||
import {
|
||||
NativeStackNavigatorProps,
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationEventMap,
|
||||
} from '../types';
|
||||
|
||||
function NativeStackNavigator(props: NativeStackNavigatorProps) {
|
||||
if (!screensEnabled()) {
|
||||
throw new Error(
|
||||
'Native stack is only available if React Native Screens is enabled.'
|
||||
);
|
||||
}
|
||||
|
||||
const { initialRouteName, children, screenOptions, ...rest } = props;
|
||||
const { state, descriptors, navigation } = useNavigationBuilder<
|
||||
StackNavigationState,
|
||||
StackRouterOptions,
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationEventMap
|
||||
>(StackRouter, {
|
||||
initialRouteName,
|
||||
children,
|
||||
screenOptions,
|
||||
});
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
navigation.addListener &&
|
||||
navigation.addListener('tabPress', e => {
|
||||
const isFocused = navigation.isFocused();
|
||||
|
||||
// Run the operation in the next frame so we're sure all listeners have been run
|
||||
// This is necessary to know if preventDefault() has been called
|
||||
requestAnimationFrame(() => {
|
||||
if (
|
||||
state.index > 0 &&
|
||||
isFocused &&
|
||||
!(e as EventArg<'tabPress', true>).defaultPrevented
|
||||
) {
|
||||
// When user taps on already focused tab and we're inside the tab,
|
||||
// reset the stack to replicate native behaviour
|
||||
navigation.dispatch({
|
||||
...StackActions.popToTop(),
|
||||
target: state.key,
|
||||
});
|
||||
}
|
||||
});
|
||||
}),
|
||||
[navigation, state.index, state.key]
|
||||
);
|
||||
|
||||
return (
|
||||
<NativeStackView
|
||||
{...rest}
|
||||
state={state}
|
||||
navigation={navigation}
|
||||
descriptors={descriptors}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
NativeStackNavigationOptions,
|
||||
typeof NativeStackNavigator
|
||||
>(NativeStackNavigator);
|
||||
@@ -1,217 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { StyleProp, ViewStyle } from 'react-native';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { ScreenProps } from 'react-native-screens';
|
||||
import {
|
||||
DefaultNavigatorOptions,
|
||||
Descriptor,
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
ParamListBase,
|
||||
StackNavigationState,
|
||||
StackRouterOptions,
|
||||
} from '@react-navigation/native';
|
||||
|
||||
export type NativeStackNavigationEventMap = {
|
||||
/**
|
||||
* Event which fires when the screen appears.
|
||||
*/
|
||||
appear: { data: undefined };
|
||||
/**
|
||||
* Event which fires when the current screen is dismissed by hardware back (on Android) or dismiss gesture (swipe back or down).
|
||||
*/
|
||||
dismiss: { data: undefined };
|
||||
};
|
||||
|
||||
export type NativeStackNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<
|
||||
ParamList,
|
||||
RouteName,
|
||||
StackNavigationState,
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationEventMap
|
||||
> & {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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 NativeStackNavigationHelpers = NavigationHelpers<
|
||||
ParamListBase,
|
||||
NativeStackNavigationEventMap
|
||||
>;
|
||||
|
||||
export type NativeStackNavigationConfig = {};
|
||||
|
||||
export type NativeStackNavigationOptions = {
|
||||
/**
|
||||
* String that can be displayed in the header as a fallback for `headerTitle`.
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* String to display in the header as title. Defaults to scene `title`.
|
||||
*/
|
||||
headerTitle?: string;
|
||||
/**
|
||||
* Title to display in the back button.
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerBackTitle?: string;
|
||||
/**
|
||||
* Whether the back button title should be visible or not. Defaults to `true`.
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerBackTitleVisible?: boolean;
|
||||
/**
|
||||
* Whether to show the header.
|
||||
*/
|
||||
headerShown?: boolean;
|
||||
/**
|
||||
* Boolean indicating whether the navigation bar is translucent.
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerTranslucent?: boolean;
|
||||
/**
|
||||
* Boolean to set native property to prefer large title header (like in iOS setting).
|
||||
* For large title to collapse on scroll, the content of the screen should be wrapped in a scrollable view such as `ScrollView` or `FlatList`.
|
||||
* If the scrollable area doesn't fill the screen, the large title won't collapse on scroll.
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerLargeTitle?: boolean;
|
||||
/**
|
||||
* Function which returns a React Element to display on the right side of the header.
|
||||
*/
|
||||
headerRight?: () => React.ReactNode;
|
||||
/**
|
||||
* Tint color for the header. Changes the color of back button and title.
|
||||
*/
|
||||
headerTintColor?: string;
|
||||
/**
|
||||
* Boolean indicating whether to hide the back button in header.
|
||||
* Only supported on Android.
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
headerHideBackButton?: boolean;
|
||||
/**
|
||||
* Boolean indicating whether to hide the elevation shadow or the bottom border on the header.
|
||||
*/
|
||||
headerHideShadow?: boolean;
|
||||
/**
|
||||
* Style object for header title. Supported properties:
|
||||
* - backgroundColor
|
||||
*/
|
||||
headerStyle?: {
|
||||
backgroundColor?: string;
|
||||
};
|
||||
/**
|
||||
* Style object for header title. Supported properties:
|
||||
* - fontFamily
|
||||
* - fontSize
|
||||
* - color
|
||||
*/
|
||||
headerTitleStyle?: {
|
||||
fontFamily?: string;
|
||||
fontSize?: number;
|
||||
color?: string;
|
||||
};
|
||||
/**
|
||||
* Style object for header large title. Supported properties:
|
||||
* - fontFamily
|
||||
* - fontSize
|
||||
*
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerLargeTitleStyle?: {
|
||||
fontFamily?: string;
|
||||
fontSize?: number;
|
||||
};
|
||||
/**
|
||||
* Style object for header back title. Supported properties:
|
||||
* - fontFamily
|
||||
* - fontSize
|
||||
*
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
headerBackTitleStyle?: {
|
||||
fontFamily?: string;
|
||||
fontSize?: number;
|
||||
};
|
||||
/**
|
||||
* Style object for the scene content.
|
||||
*/
|
||||
contentStyle?: StyleProp<ViewStyle>;
|
||||
/**
|
||||
* Whether you can use gestures to dismiss this screen. Defaults to `true`.
|
||||
* Only supported on iOS.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
gestureEnabled?: boolean;
|
||||
/**
|
||||
* How should the screen be presented.
|
||||
* The following values are currently supported:
|
||||
* - "push" – the new screen will be pushed onto a stack which on iOS means that the default animation will be slide from the side, the animation on Android may vary depending on the OS version and theme.
|
||||
* - "modal" – the new screen will be presented modally. In addition this allow for a nested stack to be rendered inside such screens
|
||||
* - "transparentModal" – the new screen will be presented modally but in addition the second to last screen will remain attached to the stack container such that if the top screen is non opaque the content below can still be seen. If "modal" is used instead the below screen will get unmounted as soon as the transition ends.
|
||||
*/
|
||||
stackPresentation?: ScreenProps['stackPresentation'];
|
||||
/**
|
||||
* How the screen should appear/disappear when pushed or popped at the top of the stack.
|
||||
* The following values are currently supported:
|
||||
* - "default" – uses a platform default animation
|
||||
* - "fade" – fades screen in or out
|
||||
* - "flip" – flips the screen, requires stackPresentation: "modal" (iOS only)
|
||||
* - "none" – the screen appears/dissapears without an animation
|
||||
*/
|
||||
stackAnimation?: ScreenProps['stackAnimation'];
|
||||
};
|
||||
|
||||
export type NativeStackNavigatorProps = DefaultNavigatorOptions<
|
||||
NativeStackNavigationOptions
|
||||
> &
|
||||
StackRouterOptions &
|
||||
NativeStackNavigationConfig;
|
||||
|
||||
export type NativeStackDescriptor = Descriptor<
|
||||
ParamListBase,
|
||||
string,
|
||||
StackNavigationState,
|
||||
NativeStackNavigationOptions
|
||||
>;
|
||||
|
||||
export type NativeStackDescriptorMap = {
|
||||
[key: string]: NativeStackDescriptor;
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
ScreenStackHeaderConfig,
|
||||
ScreenStackHeaderRightView,
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
} from 'react-native-screens';
|
||||
import { Route, useTheme } from '@react-navigation/native';
|
||||
import { NativeStackNavigationOptions } from '../types';
|
||||
|
||||
type Props = NativeStackNavigationOptions & {
|
||||
route: Route<string>;
|
||||
};
|
||||
|
||||
export default function HeaderConfig(props: Props) {
|
||||
const { colors } = useTheme();
|
||||
const {
|
||||
route,
|
||||
title,
|
||||
headerRight,
|
||||
headerTitle,
|
||||
headerBackTitle,
|
||||
headerBackTitleVisible = true,
|
||||
headerHideBackButton,
|
||||
headerHideShadow,
|
||||
headerTintColor,
|
||||
headerLargeTitle,
|
||||
headerTranslucent,
|
||||
headerStyle = {},
|
||||
headerTitleStyle = {},
|
||||
headerLargeTitleStyle = {},
|
||||
headerBackTitleStyle = {},
|
||||
headerShown,
|
||||
gestureEnabled,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<ScreenStackHeaderConfig
|
||||
hidden={headerShown === false}
|
||||
translucent={headerTranslucent === true}
|
||||
hideShadow={headerHideShadow}
|
||||
hideBackButton={headerHideBackButton}
|
||||
title={
|
||||
headerTitle !== undefined
|
||||
? headerTitle
|
||||
: title !== undefined
|
||||
? title
|
||||
: route.name
|
||||
}
|
||||
titleFontFamily={headerTitleStyle.fontFamily}
|
||||
titleFontSize={headerTitleStyle.fontSize}
|
||||
titleColor={
|
||||
headerTitleStyle.color !== undefined
|
||||
? headerTitleStyle.color
|
||||
: headerTintColor !== undefined
|
||||
? headerTintColor
|
||||
: colors.text
|
||||
}
|
||||
backTitle={headerBackTitleVisible ? headerBackTitle : ' '}
|
||||
backTitleFontFamily={headerBackTitleStyle.fontFamily}
|
||||
backTitleFontSize={headerBackTitleStyle.fontSize}
|
||||
color={headerTintColor !== undefined ? headerTintColor : colors.primary}
|
||||
// Keep this temporarily for compatibility with old versions of screens
|
||||
// @ts-ignore
|
||||
gestureEnabled={gestureEnabled}
|
||||
largeTitle={headerLargeTitle}
|
||||
largeTitleFontFamily={headerLargeTitleStyle.fontFamily}
|
||||
largeTitleFontSize={headerLargeTitleStyle.fontSize}
|
||||
backgroundColor={
|
||||
headerStyle.backgroundColor !== undefined
|
||||
? headerStyle.backgroundColor
|
||||
: colors.card
|
||||
}
|
||||
>
|
||||
{headerRight !== undefined ? (
|
||||
<ScreenStackHeaderRightView>{headerRight()}</ScreenStackHeaderRightView>
|
||||
) : null}
|
||||
</ScreenStackHeaderConfig>
|
||||
);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import {
|
||||
ScreenStack,
|
||||
Screen as ScreenComponent,
|
||||
ScreenProps,
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
} from 'react-native-screens';
|
||||
import {
|
||||
StackNavigationState,
|
||||
StackActions,
|
||||
useTheme,
|
||||
} from '@react-navigation/native';
|
||||
import HeaderConfig from './HeaderConfig';
|
||||
import {
|
||||
NativeStackNavigationHelpers,
|
||||
NativeStackDescriptorMap,
|
||||
} from '../types';
|
||||
|
||||
const Screen = (ScreenComponent as unknown) as React.ComponentType<ScreenProps>;
|
||||
|
||||
type Props = {
|
||||
state: StackNavigationState;
|
||||
navigation: NativeStackNavigationHelpers;
|
||||
descriptors: NativeStackDescriptorMap;
|
||||
};
|
||||
|
||||
export default function NativeStackView({
|
||||
state,
|
||||
navigation,
|
||||
descriptors,
|
||||
}: Props) {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<ScreenStack style={styles.container}>
|
||||
{state.routes.map(route => {
|
||||
const { options, render: renderScene } = descriptors[route.key];
|
||||
const {
|
||||
gestureEnabled,
|
||||
stackPresentation = 'push',
|
||||
stackAnimation,
|
||||
contentStyle,
|
||||
} = options;
|
||||
|
||||
return (
|
||||
<Screen
|
||||
key={route.key}
|
||||
style={StyleSheet.absoluteFill}
|
||||
gestureEnabled={gestureEnabled}
|
||||
stackPresentation={stackPresentation}
|
||||
stackAnimation={stackAnimation}
|
||||
onAppear={() => {
|
||||
navigation.emit({
|
||||
type: 'appear',
|
||||
target: route.key,
|
||||
});
|
||||
}}
|
||||
onDismissed={() => {
|
||||
navigation.emit({
|
||||
type: 'dismiss',
|
||||
target: route.key,
|
||||
});
|
||||
|
||||
navigation.dispatch({
|
||||
...StackActions.pop(),
|
||||
source: route.key,
|
||||
target: state.key,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<HeaderConfig {...options} route={route} />
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: colors.background },
|
||||
contentStyle,
|
||||
]}
|
||||
>
|
||||
{renderScene()}
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
})}
|
||||
</ScreenStack>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig",
|
||||
"compilerOptions": {
|
||||
"paths": {}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"references": [
|
||||
{ "path": "../core" },
|
||||
{ "path": "../routers" },
|
||||
{ "path": "../native" }
|
||||
],
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib/typescript"
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [5.0.8](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.7...@react-navigation/native@5.0.8) (2020-02-26)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.6...@react-navigation/native@5.0.7) (2020-02-21)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.5...@react-navigation/native@5.0.6) (2020-02-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.4...@react-navigation/native@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/native",
|
||||
"description": "React Native integration for React Navigation",
|
||||
"version": "5.0.4",
|
||||
"version": "5.0.8",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
"react-navigation",
|
||||
@@ -31,7 +31,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^5.1.3"
|
||||
"@react-navigation/core": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [5.0.3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.2...@react-navigation/routers@5.0.3) (2020-02-26)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/routers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.2](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.1...@react-navigation/routers@5.0.2) (2020-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* tweak error message for navigate ([c8ea419](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/c8ea4199f4b19a58d5e409cfcc96e587fe354a9a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.1](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.33...@react-navigation/routers@5.0.1) (2020-02-10)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/routers",
|
||||
"description": "Routers to help build custom navigators",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.3",
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-native",
|
||||
|
||||
@@ -41,11 +41,11 @@ export function navigate(...args: any): Action {
|
||||
if (typeof args[0] === 'string') {
|
||||
return { type: 'NAVIGATE', payload: { name: args[0], params: args[1] } };
|
||||
} else {
|
||||
const payload = args[0];
|
||||
const payload = args[0] || {};
|
||||
|
||||
if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) {
|
||||
throw new Error(
|
||||
'While calling navigate with an object as the argument, you need to specify name or key'
|
||||
'You need to specify name or key when calling navigate with an object as the argument. See https://reactnavigation.org/docs/navigation-actions.html#navigate for usage.'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@ import * as CommonActions from '../CommonActions';
|
||||
it('throws if NAVIGATE is called without key or name', () => {
|
||||
// @ts-ignore
|
||||
expect(() => CommonActions.navigate({})).toThrowError(
|
||||
'While calling navigate with an object as the argument, you need to specify name or key'
|
||||
'You need to specify name or key when calling navigate with an object as the argument.'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,62 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.9...@react-navigation/stack@5.1.0) (2020-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6756)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.9](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.8...@react-navigation/stack@5.0.9) (2020-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* enhance border radius in modals on new iPhones ([#6945](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6945)) ([80a3370](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/80a337024abc53537ff4a63916cea38bb4f374bf))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.8](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.7...@react-navigation/stack@5.0.8) (2020-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix transparent header on Android ([a67b494](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/a67b49477eb500c81fedcd73bbd8102901a95170))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.6...@react-navigation/stack@5.0.7) (2020-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* debounce back button by default in stack header ([c7dd3a5](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/c7dd3a58b18d7a267d94009d459944c251ea74c1))
|
||||
* make sure header is visibile to accessibility tools on iOS ([240ce01](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/240ce01822febac2c1aa324c01e43fdc88a235a0))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.6](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.5...@react-navigation/stack@5.0.6) (2020-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add accessibilityLabel prop to back button ([bf76075](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/bf76075e0fbf51961e81e9337ef194e43cc6b986)), closes [#6895](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6895)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.0.5](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.4...@react-navigation/stack@5.0.5) (2020-02-14)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/stack
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/stack",
|
||||
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
||||
"version": "5.0.4",
|
||||
"version": "5.1.0",
|
||||
"keywords": [
|
||||
"react-native-component",
|
||||
"react-component",
|
||||
@@ -40,7 +40,7 @@
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.9.3",
|
||||
"@react-native-community/masked-view": "^0.1.6",
|
||||
"@react-navigation/native": "^5.0.4",
|
||||
"@react-navigation/native": "^5.0.8",
|
||||
"@types/color": "^3.0.1",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-native": "^0.60.30",
|
||||
@@ -54,7 +54,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-community/masked-view": ">= 0.1.0",
|
||||
"@react-navigation/native": "^5.0.0",
|
||||
"@react-navigation/native": "^5.0.5",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": ">= 1.0.0",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Animated } from 'react-native';
|
||||
import { isIphoneX } from 'react-native-iphone-x-helper';
|
||||
import conditional from '../utils/conditional';
|
||||
import {
|
||||
StackCardInterpolationProps,
|
||||
@@ -152,8 +153,8 @@ export function forModalPresentationIOS({
|
||||
? 0
|
||||
: index === 0
|
||||
? progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [0, 0, 10],
|
||||
inputRange: [0, 1, 1.0001, 2],
|
||||
outputRange: [0, 0, isIphoneX() ? 38 : 0, 10],
|
||||
})
|
||||
: 10;
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ function StackNavigator({
|
||||
}
|
||||
|
||||
export default createNavigatorFactory<
|
||||
StackNavigationState,
|
||||
StackNavigationOptions,
|
||||
StackNavigationEventMap,
|
||||
typeof StackNavigator
|
||||
>(StackNavigator);
|
||||
|
||||
@@ -404,6 +404,10 @@ export type StackHeaderLeftButtonProps = {
|
||||
* Whether it's possible to navigate back in stack.
|
||||
*/
|
||||
canGoBack?: boolean;
|
||||
/**
|
||||
* Accessibility label for the button for screen readers.
|
||||
*/
|
||||
accessibilityLabel?: string;
|
||||
};
|
||||
|
||||
export type StackHeaderTitleProps = {
|
||||
|
||||
17
packages/stack/src/utils/debounce.tsx
Normal file
17
packages/stack/src/utils/debounce.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
export default function debounce<T extends (...args: any[]) => void>(
|
||||
func: T,
|
||||
duration: number
|
||||
): T {
|
||||
let timeout: NodeJS.Timeout | number | undefined;
|
||||
|
||||
return function(this: any, ...args) {
|
||||
if (!timeout) {
|
||||
// eslint-disable-next-line babel/no-invalid-this
|
||||
func.apply(this, args);
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
timeout = undefined;
|
||||
}, duration);
|
||||
}
|
||||
} as T;
|
||||
}
|
||||
@@ -2,8 +2,9 @@ import * as React from 'react';
|
||||
import { StackActions } from '@react-navigation/native';
|
||||
|
||||
import HeaderSegment from './HeaderSegment';
|
||||
import { StackHeaderProps, StackHeaderTitleProps } from '../../types';
|
||||
import HeaderTitle from './HeaderTitle';
|
||||
import debounce from '../../utils/debounce';
|
||||
import { StackHeaderProps, StackHeaderTitleProps } from '../../types';
|
||||
|
||||
export default React.memo(function Header(props: StackHeaderProps) {
|
||||
const {
|
||||
@@ -40,6 +41,18 @@ export default React.memo(function Header(props: StackHeaderProps) {
|
||||
: previous.route.name;
|
||||
}
|
||||
|
||||
const goBack = React.useCallback(
|
||||
debounce(() => {
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.dispatch({
|
||||
...StackActions.pop(),
|
||||
source: scene.route.key,
|
||||
});
|
||||
}
|
||||
}, 50),
|
||||
[navigation, scene.route.key]
|
||||
);
|
||||
|
||||
return (
|
||||
<HeaderSegment
|
||||
{...options}
|
||||
@@ -53,18 +66,7 @@ export default React.memo(function Header(props: StackHeaderProps) {
|
||||
? (props: StackHeaderTitleProps) => <HeaderTitle {...props} />
|
||||
: options.headerTitle
|
||||
}
|
||||
onGoBack={
|
||||
previous
|
||||
? () => {
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.dispatch({
|
||||
...StackActions.pop(),
|
||||
source: scene.route.key,
|
||||
});
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onGoBack={previous ? goBack : undefined}
|
||||
styleInterpolator={styleInterpolator}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -29,6 +29,7 @@ export default function HeaderBackButton({
|
||||
tintColor: customTintColor,
|
||||
titleLayout,
|
||||
truncatedLabel = 'Back',
|
||||
accessibilityLabel = label && label !== 'Back' ? `${label}, back` : 'Go back',
|
||||
}: Props) {
|
||||
const { dark, colors } = useTheme();
|
||||
|
||||
@@ -153,9 +154,7 @@ export default function HeaderBackButton({
|
||||
accessible
|
||||
accessibilityRole="button"
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel={
|
||||
label && label !== 'Back' ? `${label}, back` : 'Go back'
|
||||
}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityTraits="button"
|
||||
testID="header-back"
|
||||
delayPressIn={0}
|
||||
|
||||
@@ -137,7 +137,9 @@ export default function HeaderContainer({
|
||||
isFocused ? 'auto' : 'no-hide-descendants'
|
||||
}
|
||||
style={
|
||||
mode === 'float' || options.headerTransparent
|
||||
// Avoid positioning the focused header absolutely
|
||||
// Otherwise accessibility tools don't seem to be able to find it
|
||||
(mode === 'float' && !isFocused) || options.headerTransparent
|
||||
? styles.header
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -37,14 +37,6 @@ type GestureValues = {
|
||||
[key: string]: Animated.Value;
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
const maybeExpoVersion = global.Expo?.Constants.manifest.sdkVersion.split(
|
||||
'.'
|
||||
)[0];
|
||||
const isInsufficientExpoVersion = maybeExpoVersion
|
||||
? Number(maybeExpoVersion) <= 36
|
||||
: maybeExpoVersion === 'UNVERSIONED';
|
||||
|
||||
type Props = {
|
||||
mode: StackCardMode;
|
||||
insets: EdgeInsets;
|
||||
@@ -82,37 +74,27 @@ type State = {
|
||||
};
|
||||
|
||||
const EPSILON = 0.01;
|
||||
const FAR_FAR_AWAY = 9000;
|
||||
|
||||
const dimensions = Dimensions.get('window');
|
||||
const layout = { width: dimensions.width, height: dimensions.height };
|
||||
|
||||
const MaybeScreenContainer = ({
|
||||
enabled,
|
||||
style,
|
||||
...rest
|
||||
}: ViewProps & {
|
||||
enabled: boolean;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
if (enabled && screensEnabled()) {
|
||||
return <ScreenContainer style={style} {...rest} />;
|
||||
return <ScreenContainer {...rest} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
collapsable={!enabled}
|
||||
removeClippedSubviews={Platform.OS !== 'ios' && enabled}
|
||||
style={[style, { overflow: 'hidden' }]}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
return <View {...rest} />;
|
||||
};
|
||||
|
||||
const MaybeScreen = ({
|
||||
enabled,
|
||||
active,
|
||||
style,
|
||||
...rest
|
||||
}: ViewProps & {
|
||||
enabled: boolean;
|
||||
@@ -121,39 +103,10 @@ const MaybeScreen = ({
|
||||
}) => {
|
||||
if (enabled && screensEnabled()) {
|
||||
// @ts-ignore
|
||||
return <Screen active={active} style={style} {...rest} />;
|
||||
return <Screen active={active} {...rest} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
style,
|
||||
{
|
||||
overflow: 'hidden',
|
||||
// Position the screen offscreen to take advantage of offscreen perf optimization
|
||||
// https://facebook.github.io/react-native/docs/view#removeclippedsubviews
|
||||
// This can be useful if screens is not enabled
|
||||
// It's buggy on iOS, so we don't enable it there
|
||||
top:
|
||||
enabled && typeof active === 'number' && !active ? FAR_FAR_AWAY : 0,
|
||||
transform: [
|
||||
{
|
||||
// If the `active` prop is animated node, we can't use the `left` property due to native driver
|
||||
// So we use `translateY` instead
|
||||
translateY:
|
||||
enabled && typeof active !== 'number'
|
||||
? active.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [FAR_FAR_AWAY, 0],
|
||||
})
|
||||
: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
return <View {...rest} />;
|
||||
};
|
||||
|
||||
const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
|
||||
@@ -450,9 +403,7 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
|
||||
// Screens is buggy on iOS, so we don't enable it there
|
||||
// For modals, usually we want the screen underneath to be visible, so also disable it there
|
||||
const isScreensEnabled =
|
||||
Platform.OS !== 'ios' &&
|
||||
(isInsufficientExpoVersion ? mode !== 'modal' : true);
|
||||
const isScreensEnabled = Platform.OS !== 'ios' && mode !== 'modal';
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -466,26 +417,13 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
const gesture = gestures[route.key];
|
||||
const scene = scenes[index];
|
||||
|
||||
// Display current screen and a screen beneath.
|
||||
let isScreenActive: Animated.AnimatedInterpolation | 0 | 1 =
|
||||
index >= self.length - 2 ? 1 : 0;
|
||||
|
||||
if (isInsufficientExpoVersion) {
|
||||
isScreenActive =
|
||||
index === self.length - 1
|
||||
? 1
|
||||
: Platform.OS === 'android'
|
||||
? scene.progress.next
|
||||
? scene.progress.next.interpolate({
|
||||
inputRange: [0, 1 - EPSILON, 1],
|
||||
outputRange: [1, 1, 0],
|
||||
extrapolate: 'clamp',
|
||||
})
|
||||
: 1
|
||||
: index === self.length - 2
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
const isScreenActive = scene.progress.next
|
||||
? scene.progress.next.interpolate({
|
||||
inputRange: [0, 1 - EPSILON, 1],
|
||||
outputRange: [1, 1, 0],
|
||||
extrapolate: 'clamp',
|
||||
})
|
||||
: 1;
|
||||
|
||||
const {
|
||||
safeAreaInsets,
|
||||
|
||||
Reference in New Issue
Block a user