Compare commits

..

47 Commits

Author SHA1 Message Date
Satyajit Sahoo
358d9e9feb chore: publish
- @react-navigation/bottom-tabs@5.2.1
 - @react-navigation/compat@5.1.3
 - @react-navigation/drawer@5.3.0
 - @react-navigation/material-bottom-tabs@5.1.3
 - @react-navigation/material-top-tabs@5.1.3
 - @react-navigation/native@5.1.0
 - @react-navigation/stack@5.2.1
2020-03-17 14:37:21 +01:00
Satyajit Sahoo
6a5d0a035a feat: add permanent drawer type (#7818)
Co-authored-by: NoemiRozpara <nrozpara@gmail.com>
2020-03-17 14:11:00 +01:00
Satyajit Sahoo
b75744abd5 chore: publish
- @react-navigation/bottom-tabs@5.2.0
 - @react-navigation/compat@5.1.2
 - @react-navigation/core@5.2.2
 - @react-navigation/drawer@5.2.0
 - @react-navigation/material-bottom-tabs@5.1.2
 - @react-navigation/material-top-tabs@5.1.2
 - @react-navigation/native@5.0.10
 - @react-navigation/routers@5.1.1
 - @react-navigation/stack@5.2.0
2020-03-16 14:29:25 +01:00
Satyajit Sahoo
6dbda1a0c2 chore: upgrade depenendecies 2020-03-16 14:28:10 +01:00
Michał Osadnik
70029d6c13 feat: add an option to change use a custom card overlay (#7809)
I find it sometimes useful to define overlay renderer on my own. Eg. I needed to replace the background with BlurView and with this API I find it quite easy

Co-authored-by: Satyajit Sahoo <satyajit.happy@gmail.com>
2020-03-16 14:28:10 +01:00
Tien Pham
469d0542c7 fix: fix back gesture cancellation (#7700)
The problem here is that when we scroll back really fast, even though velocity is negative, `Math.abs(translation + velocity * gestureVelocityImpact)` will end up bigger than `distance / 2`.

I removed the `Math.abs`, I think it's not necessary. When `translation + velocity * gestureVelocityImpact` is negative, it's also < `distance / 2` and we should just close the screen.

Closes #6782
2020-03-16 12:03:16 +01:00
Vojtech Novak
0dcaea3242 fix: fix android header title font weight (#7720)
the previously used fort weight of 500 would effectively be converted to `fontWeight: bold` because of https://github.com/facebook/react-native/pull/25341

this fixes the title appearance to look as customary
2020-03-16 11:05:02 +01:00
Satyajit Sahoo
646cbfb28e refactor: move action helper types to routers 2020-03-13 12:34:37 +01:00
Satyajit Sahoo
660cac3557 fix: don't handle action if no routes are present 2020-03-11 18:17:19 +01:00
Satyajit Sahoo
e637250a7e chore: add a triage action for feature requests 2020-03-11 03:19:49 +01:00
Satyajit Sahoo
82af7bed71 feat: add safeAreaInsets to bottom tabs 2020-03-09 22:21:04 +01:00
Michał Osadnik
cb46d0bca4 feat: make useIsDrawerOpen workable inside drawer content (#7746) 2020-03-06 15:46:13 +01:00
Mike Rogers
b3665a325d Correcting spelling 'Supress' > 'Suppress' (#7731) 2020-03-06 07:24:43 -03:00
Satyajit Sahoo
0cc7a12b9c chore: remove stale action coz it's not keeping issues open after reply 2020-03-04 13:53:42 +01:00
Satyajit Sahoo
90e417248d chore: fix typo in expo preview url 2020-03-03 18:38:20 +01:00
Satyajit Sahoo
e071a978e6 chore: publish
- @react-navigation/bottom-tabs@5.1.1
 - @react-navigation/compat@5.1.1
 - @react-navigation/core@5.2.1
 - @react-navigation/drawer@5.1.1
 - @react-navigation/material-bottom-tabs@5.1.1
 - @react-navigation/material-top-tabs@5.1.1
 - @react-navigation/native@5.0.9
 - @react-navigation/routers@5.1.0
 - @react-navigation/stack@5.1.1
2020-03-03 11:58:45 +01:00
Satyajit Sahoo
296c836064 fix: ignore back button press if screen isn't focused. closes #7673 2020-03-03 11:34:38 +01:00
Satyajit Sahoo
09f6808d7d feat: make reset bubble up 2020-03-01 02:45:08 +01:00
Satyajit Sahoo
5bb0f405ce fix: fix links for documentation 2020-02-28 17:12:18 +01:00
Satyajit Sahoo
2dfa4f3629 fix: move updating state to useEffect 2020-02-28 17:01:58 +01:00
Satyajit Sahoo
cf41288760 chore: run clean before release 2020-02-26 15:03:57 +01:00
Satyajit Sahoo
3677818f63 chore: publish
- @react-navigation/bottom-tabs@5.1.0
 - @react-navigation/compat@5.1.0
 - @react-navigation/core@5.2.0
 - @react-navigation/drawer@5.1.0
 - @react-navigation/material-bottom-tabs@5.1.0
 - @react-navigation/material-top-tabs@5.1.0
 - @react-navigation/native@5.0.8
 - @react-navigation/routers@5.0.3
 - @react-navigation/stack@5.1.0
2020-02-26 13:57:42 +01:00
Satyajit Sahoo
162410843c feat: add ability add listeners with listeners prop
This adds ability to listen to events from the component where the navigator is defined, even if the screen is not rendered.

```js
<Tabs.Screen
  name="Chat"
  component={Chat}
  options={{ title: 'Chat' }}
  listeners={{
    tabPress: e => console.log('Tab press', e.target),
  }}
/>
```

Closes #6756
2020-02-26 13:02:22 +01:00
Satyajit Sahoo
028c2887c6 refactor: tweak error messages more 2020-02-25 20:58:14 +01:00
Satyajit Sahoo
7a44cda136 refactor: tweak error messages 2020-02-25 17:58:09 +01:00
Satyajit Sahoo
a046db536f chore: publish
- @react-navigation/stack@5.0.9
2020-02-24 14:45:00 +01:00
Satyajit Sahoo
d115787b1c chore: mark yarn script as binary 2020-02-24 14:44:29 +01:00
Michał Osadnik
80a337024a fix: enhance border radius in modals on new iPhones (#6945)
Co-authored-by: Satyajit Sahoo <satyajit.happy@gmail.com>
2020-02-24 14:44:20 +01:00
Satyajit Sahoo
c19da31240 refactor: enable screens only for last screen
This will avoid issues such as https://github.com/react-navigation/react-navigation/issues/6909
2020-02-24 11:37:25 +01:00
Satyajit Sahoo
85e9376302 chore: publish
- @react-navigation/stack@5.0.8
2020-02-21 20:09:06 +01:00
Satyajit Sahoo
a67b49477e fix: fix transparent header on Android 2020-02-21 20:07:38 +01:00
Satyajit Sahoo
225cb298b6 chore: publish
- @react-navigation/bottom-tabs@5.0.7
 - @react-navigation/compat@5.0.7
 - @react-navigation/core@5.1.6
 - @react-navigation/drawer@5.0.7
 - @react-navigation/material-bottom-tabs@5.0.7
 - @react-navigation/material-top-tabs@5.0.7
 - @react-navigation/native@5.0.7
 - @react-navigation/routers@5.0.2
 - @react-navigation/stack@5.0.7
2020-02-21 19:18:56 +01:00
Satyajit Sahoo
c8ea4199f4 fix: tweak error message for navigate 2020-02-21 19:13:11 +01:00
Satyajit Sahoo
f16700812f fix: avoid emitting focus events twice
fixes #6749
2020-02-21 18:56:06 +01:00
Satyajit Sahoo
240ce01822 fix: make sure header is visibile to accessibility tools on iOS 2020-02-21 16:30:05 +01:00
Satyajit Sahoo
c7dd3a58b1 fix: debounce back button by default in stack header 2020-02-21 15:31:50 +01:00
Satyajit Sahoo
125bd70e49 fix: preserve screen order with numeric names
fixes #6900
2020-02-21 05:43:32 +01:00
Satyajit Sahoo
4578849ebf chore: publish
- @react-navigation/bottom-tabs@5.0.6
 - @react-navigation/compat@5.0.6
 - @react-navigation/core@5.1.5
 - @react-navigation/drawer@5.0.6
 - @react-navigation/material-bottom-tabs@5.0.6
 - @react-navigation/material-top-tabs@5.0.6
 - @react-navigation/native@5.0.6
 - @react-navigation/stack@5.0.6
2020-02-19 23:34:10 +01:00
Satyajit Sahoo
c084517d7b chore: add release script 2020-02-19 23:30:12 +01:00
Satyajit Sahoo
22c85ff6a9 chore: remove native-stack from the repo
it's now moved to https://github.com/kmagiera/react-native-screens
2020-02-19 23:18:11 +01:00
Satyajit Sahoo
bf76075e0f fix: add accessibilityLabel prop to back button
fixes #6895
2020-02-19 23:09:00 +01:00
Satyajit Sahoo
d69b0db604 fix: add NavigationEvents
See https://github.com/react-navigation/react-navigation/issues/6821#issuecomment-588268512
2020-02-19 23:04:14 +01:00
Satyajit Sahoo
cdb2fed43d chore: update .gitignore 2020-02-18 21:03:18 +01:00
Satyajit Sahoo
bb0226e26d chore: tweak error message 2020-02-18 18:59:39 +01:00
Satyajit Sahoo
1a28c299b5 fix: show descriptive error for invalid return for useFocusEffect 2020-02-15 20:02:39 +01:00
Satyajit Sahoo
e0c3298e64 fix: delay showing drawer by one frame after layout 2020-02-15 19:17:20 +01:00
Satyajit Sahoo
040f5dbb9d refactor: drop use of performTransaction 2020-02-15 19:05:50 +01:00
103 changed files with 2640 additions and 2528 deletions

View File

@@ -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
View File

@@ -0,0 +1 @@
yarn-*.js binary

View File

@@ -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 |

View File

@@ -44,7 +44,7 @@ jobs:
- name: Get expo link
id: expo
run: echo "::set-output name=path::@react-navigation/react-react-navigationample?release-channel=pr-${{ github.event.number }}"
run: echo "::set-output name=path::@react-navigation/react-navigation-example?release-channel=pr-${{ github.event.number }}"
- name: Comment on PR
uses: unsplash/comment-on-pr@master

View File

@@ -1,20 +0,0 @@
name: "Close stale issues and pull requests"
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Hello 👋, this issue has been open for more than 3 months with no activity on it. If the issue is still present in the latest version, please leave a comment within 7 days to keep it open, otherwise it will be closed automatically. If you found a solution on workaround for the issue, please comment here for others to find. If this issue is critical for you, please consider sending a pull request to fix the issue.'
stale-pr-message: 'Hello 👋, this pull request has been open for more than 3 months with no activity on it. If you think this is still necessary with the latest version, please comment and ping a maintainer to get this reviewed, otherwise it will be closed automatically in 7 days.'
days-before-stale: 90
days-before-close: 7
stale-issue-label: 'stale'
stale-pr-label: 'stale'
exempt-issue-label: 'keep open'
exempt-pr-label: 'keep open'

View File

@@ -36,3 +36,14 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: comment "Hey! Thanks for opening the issue. The issue tracker is intended for only tracking bug reports. This helps us prioritize fixing bugs in the library. Seems you have a usage question. Please ask the question on [StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation) instead using the `react-navigation` label. You can also chat with other community members on [Reactiflux Discord server](https://www.reactiflux.com/) in the `#react-navigation` channel."
feature-request:
runs-on: ubuntu-latest
if: github.event.label.name == 'feature-request'
steps:
- uses: actions/checkout@master
- uses: actions/github@v1.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: comment "Hey! Thanks for opening the issue. The issue tracker is intended for only tracking bug reports. Seems you have a feature request. Please post the feature request on [Canny](https://react-navigation.canny.io/feature-requests). This lets other users upvote your feature request and helps us prioritize the most requested features."

3
.gitignore vendored
View File

@@ -4,6 +4,9 @@
.idea
.expo
.gradle
.project
.settings
.history
local.properties

View File

@@ -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.

View File

@@ -12,7 +12,7 @@
},
"dependencies": {
"@expo/vector-icons": "^10.0.0",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/masked-view": "0.1.7",
"@types/react-native-restart": "^0.0.0",
"color": "^3.1.2",
"expo": "^36.0.2",
@@ -21,22 +21,22 @@
"react": "~16.9.0",
"react-dom": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.5.6",
"react-native-gesture-handler": "^1.6.0",
"react-native-paper": "^3.6.0",
"react-native-reanimated": "^1.7.0",
"react-native-restart": "^0.0.13",
"react-native-safe-area-context": "^0.7.2",
"react-native-screens": "^2.0.0-beta.2",
"react-native-restart": "^0.0.14",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.3.0",
"react-native-tab-view": "2.13.0",
"react-native-unimodules": "^0.7.0",
"react-native-web": "^0.11.7"
},
"devDependencies": {
"@expo/webpack-config": "^0.10.12",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@expo/webpack-config": "^0.11.7",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"babel-preset-expo": "^8.0.0",
"expo-cli": "^3.11.9",
"expo-cli": "^3.13.8",
"typescript": "^3.7.5"
}
}

View File

@@ -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&apos;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 &quot;de Finibus Bonorum et Malorum&quot; (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, &quot;Lorem ipsum dolor sit amet..&quot;, 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 &quot;de
Finibus Bonorum et Malorum&quot; 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 &quot;Content here, content here&quot;,
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 &quot;lorem ipsum&quot; 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&apos;t look even slightly believable. If you
are going to use a passage of Lorem Ipsum, you need to be sure there
isn&apos;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,
},
});

View File

@@ -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',
},
});

View File

@@ -6,8 +6,14 @@ import {
Platform,
StatusBar,
I18nManager,
Dimensions,
ScaledSize,
} 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 +23,6 @@ import {
List,
Divider,
} from 'react-native-paper';
import { Asset } from 'expo-asset';
import {
InitialState,
useLinking,
@@ -39,7 +44,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 +54,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 +72,6 @@ type RootStackParamList = {
const SCREENS = {
SimpleStack: { title: 'Simple Stack', component: SimpleStack },
NativeStack: { title: 'Native Stack', component: NativeStack },
ModalPresentationStack: {
title: 'Modal Presentation Stack',
component: ModalPresentationStack,
@@ -194,10 +198,24 @@ export default function App() {
};
}, [theme.colors, theme.dark]);
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
React.useEffect(() => {
const onDimensionsChange = ({ window }: { window: ScaledSize }) => {
setDimensions(window);
};
Dimensions.addEventListener('change', onDimensionsChange);
return () => Dimensions.removeEventListener('change', onDimensionsChange);
}, []);
if (!isReady) {
return null;
}
const isLargeScreen = dimensions.width > 900;
return (
<PaperProvider theme={paperTheme}>
{Platform.OS === 'ios' && (
@@ -214,7 +232,7 @@ export default function App() {
}
theme={theme}
>
<Drawer.Navigator>
<Drawer.Navigator drawerType={isLargeScreen ? 'permanent' : undefined}>
<Drawer.Screen
name="Root"
options={{
@@ -238,13 +256,15 @@ export default function App() {
name="Home"
options={{
title: 'Examples',
headerLeft: () => (
<Appbar.Action
color={theme.colors.text}
icon="menu"
onPress={() => navigation.toggleDrawer()}
/>
),
headerLeft: isLargeScreen
? undefined
: () => (
<Appbar.Action
color={theme.colors.text}
icon="menu"
onPress={() => navigation.toggleDrawer()}
/>
),
}}
>
{({

View File

@@ -1,7 +1,7 @@
const error = console.error;
console.error = (...args) =>
// Supress error messages regarding error boundary in tests
// Suppress error messages regarding error boundary in tests
/(Consider adding an error boundary to your tree to customize error handling behavior|React will try to recreate this component tree from scratch using the error boundary you provided|Error boundaries should implement getDerivedStateFromError)/m.test(
args[0]
)

View File

@@ -20,25 +20,27 @@
"lint": "eslint --ext '.js,.ts,.tsx' .",
"typescript": "tsc --noEmit",
"test": "jest",
"prerelease": "lerna run clean",
"release": "lerna publish",
"example": "yarn --cwd example"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"@babel/preset-env": "^7.8.7",
"@babel/preset-flow": "^7.8.3",
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@babel/runtime": "^7.8.4",
"@babel/runtime": "^7.8.7",
"@commitlint/config-conventional": "^8.3.4",
"@types/jest": "^25.1.2",
"@types/jest": "^25.1.4",
"codecov": "^3.6.5",
"commitlint": "^8.3.5",
"core-js": "^3.6.4",
"detox": "^15.1.4",
"detox": "^16.0.0",
"eslint": "^6.8.0",
"eslint-config-satya164": "^3.1.5",
"husky": "^4.2.1",
"husky": "^4.2.3",
"jest": "^25.1.0",
"lerna": "^3.20.2",
"prettier": "^1.19.1",

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.0...@react-navigation/bottom-tabs@5.2.1) (2020-03-17)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.1.1...@react-navigation/bottom-tabs@5.2.0) (2020-03-16)
### Features
* add safeAreaInsets to bottom tabs ([82af7be](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/82af7bed7135e42e24693b48cf7f1c6f9f5a6981))
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.1.0...@react-navigation/bottom-tabs@5.1.1) (2020-03-03)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [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

View File

@@ -1,6 +1,7 @@
{
"name": "@react-navigation/bottom-tabs",
"description": "Bottom tab navigator following iOS design guidelines",
"version": "5.2.1",
"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",
@@ -34,22 +34,24 @@
"react-native-iphone-x-helper": "^1.2.1"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.4",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.0",
"@types/color": "^3.0.1",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-safe-area-context": "^0.7.2",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.3.0",
"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"
"react-native-safe-area-context": ">= 0.6.0",
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
},
"@react-native-community/bob": {
"source": "src",

View File

@@ -48,6 +48,8 @@ function BottomTabNavigator({
}
export default createNavigatorFactory<
TabNavigationState,
BottomTabNavigationOptions,
BottomTabNavigationEventMap,
typeof BottomTabNavigator
>(BottomTabNavigator);

View File

@@ -11,6 +11,7 @@ import {
ParamListBase,
Descriptor,
TabNavigationState,
TabActionHelpers,
} from '@react-navigation/native';
export type BottomTabNavigationEventMap = {
@@ -40,19 +41,8 @@ export type BottomTabNavigationProp<
TabNavigationState,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
> & {
/**
* Jump to an existing tab.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
};
> &
TabActionHelpers<ParamList>;
export type BottomTabNavigationOptions = {
/**
@@ -184,6 +174,16 @@ export type BottomTabBarOptions = {
* Whether the label position should adapt to the orientation.
*/
adaptive?: boolean;
/**
* Safe area insets for the tab bar. This is used to avoid elements like the navigation bar on Android and bottom safe area on iOS.
* By default, the device's safe area insets are automatically detected. You can override the behavior with this option.
*/
safeAreaInsets?: {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
/**
* Style object for the tab bar container.
*/

View File

@@ -15,7 +15,7 @@ import {
CommonActions,
useTheme,
} from '@react-navigation/native';
import { SafeAreaConsumer } from 'react-native-safe-area-context';
import { useSafeArea } from 'react-native-safe-area-context';
import BottomTabItem from './BottomTabItem';
import { BottomTabBarProps } from '../types';
@@ -43,6 +43,7 @@ export default function BottomTabBar({
keyboardHidesTabBar = false,
labelPosition,
labelStyle,
safeAreaInsets,
showIcon,
showLabel,
style,
@@ -158,116 +159,122 @@ export default function BottomTabBar({
}
};
const defaultInsets = useSafeArea();
const insets = {
top: safeAreaInsets?.top ?? defaultInsets.top,
right: safeAreaInsets?.right ?? defaultInsets.right,
bottom: safeAreaInsets?.bottom ?? defaultInsets.bottom,
left: safeAreaInsets?.left ?? defaultInsets.left,
};
return (
<SafeAreaConsumer>
{insets => (
<Animated.View
style={[
styles.tabBar,
{
backgroundColor: colors.card,
borderTopColor: colors.border,
},
keyboardHidesTabBar
? {
// When the keyboard is shown, slide down the tab bar
transform: [
{
translateY: visible.interpolate({
inputRange: [0, 1],
outputRange: [layout.height, 0],
}),
},
],
// Absolutely position the tab bar so that the content is below it
// This is needed to avoid gap at bottom when the tab bar is hidden
position: keyboardShown ? 'absolute' : null,
}
: null,
{
height: DEFAULT_TABBAR_HEIGHT + (insets ? insets.bottom : 0),
paddingBottom: insets ? insets.bottom : 0,
},
style,
]}
pointerEvents={keyboardHidesTabBar && keyboardShown ? 'none' : 'auto'}
>
<View style={styles.content} onLayout={handleLayout}>
{routes.map((route, index) => {
const focused = index === state.index;
const { options } = descriptors[route.key];
<Animated.View
style={[
styles.tabBar,
{
backgroundColor: colors.card,
borderTopColor: colors.border,
},
keyboardHidesTabBar
? {
// When the keyboard is shown, slide down the tab bar
transform: [
{
translateY: visible.interpolate({
inputRange: [0, 1],
outputRange: [layout.height, 0],
}),
},
],
// Absolutely position the tab bar so that the content is below it
// This is needed to avoid gap at bottom when the tab bar is hidden
position: keyboardShown ? 'absolute' : null,
}
: null,
{
height: DEFAULT_TABBAR_HEIGHT + insets.bottom,
paddingBottom: insets.bottom,
paddingHorizontal: Math.max(insets.left, insets.right),
},
style,
]}
pointerEvents={keyboardHidesTabBar && keyboardShown ? 'none' : 'auto'}
>
<View style={styles.content} onLayout={handleLayout}>
{routes.map((route, index) => {
const focused = index === state.index;
const { options } = descriptors[route.key];
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!focused && !event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(route.name),
target: state.key,
});
}
};
if (!focused && !event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(route.name),
target: state.key,
});
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const accessibilityLabel =
options.tabBarAccessibilityLabel !== undefined
? options.tabBarAccessibilityLabel
: typeof label === 'string'
? `${label}, tab, ${index + 1} of ${routes.length}`
: undefined;
const accessibilityLabel =
options.tabBarAccessibilityLabel !== undefined
? options.tabBarAccessibilityLabel
: typeof label === 'string'
? `${label}, tab, ${index + 1} of ${routes.length}`
: undefined;
return (
<NavigationContext.Provider
key={route.key}
value={descriptors[route.key].navigation}
>
<NavigationRouteContext.Provider value={route}>
<BottomTabItem
route={route}
focused={focused}
horizontal={shouldUseHorizontalLabels()}
onPress={onPress}
onLongPress={onLongPress}
accessibilityLabel={accessibilityLabel}
testID={options.tabBarTestID}
allowFontScaling={allowFontScaling}
activeTintColor={activeTintColor}
inactiveTintColor={inactiveTintColor}
activeBackgroundColor={activeBackgroundColor}
inactiveBackgroundColor={inactiveBackgroundColor}
button={options.tabBarButton}
icon={options.tabBarIcon}
label={label}
showIcon={showIcon}
showLabel={showLabel}
labelStyle={labelStyle}
style={tabStyle}
/>
</NavigationRouteContext.Provider>
</NavigationContext.Provider>
);
})}
</View>
</Animated.View>
)}
</SafeAreaConsumer>
return (
<NavigationContext.Provider
key={route.key}
value={descriptors[route.key].navigation}
>
<NavigationRouteContext.Provider value={route}>
<BottomTabItem
route={route}
focused={focused}
horizontal={shouldUseHorizontalLabels()}
onPress={onPress}
onLongPress={onLongPress}
accessibilityLabel={accessibilityLabel}
testID={options.tabBarTestID}
allowFontScaling={allowFontScaling}
activeTintColor={activeTintColor}
inactiveTintColor={inactiveTintColor}
activeBackgroundColor={activeBackgroundColor}
inactiveBackgroundColor={inactiveBackgroundColor}
button={options.tabBarButton}
icon={options.tabBarIcon}
label={label}
showIcon={showIcon}
showLabel={showLabel}
labelStyle={labelStyle}
style={tabStyle}
/>
</NavigationRouteContext.Provider>
</NavigationContext.Provider>
);
})}
</View>
</Animated.View>
);
}

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.2...@react-navigation/compat@5.1.3) (2020-03-17)
**Note:** Version bump only for package @react-navigation/compat
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.1...@react-navigation/compat@5.1.2) (2020-03-16)
**Note:** Version bump only for package @react-navigation/compat
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.0...@react-navigation/compat@5.1.1) (2020-03-03)
**Note:** Version bump only for package @react-navigation/compat
# [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

View File

@@ -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.3",
"license": "MIT",
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
"bugs": {
@@ -25,14 +25,14 @@
"clean": "del lib"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.4",
"@types/react": "^16.9.19",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.0",
"@types/react": "^16.9.23",
"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": {

View 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;
}

View File

@@ -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) {

View File

@@ -22,5 +22,7 @@ function SwitchNavigator(props: Props) {
}
export default createCompatNavigatorFactory(
createNavigatorFactory<{}, typeof SwitchNavigator>(SwitchNavigator)
createNavigatorFactory<TabNavigationState, {}, {}, typeof SwitchNavigator>(
SwitchNavigator
)
);

View File

@@ -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';

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.1...@react-navigation/core@5.2.2) (2020-03-16)
**Note:** Version bump only for package @react-navigation/core
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.0...@react-navigation/core@5.2.1) (2020-03-03)
### Bug Fixes
* fix links for documentation ([5bb0f40](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/5bb0f405ceb5755d39a0b5b1f2e4ecee0da051bc))
* move updating state to useEffect ([2dfa4f3](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/2dfa4f36293a2acb718814f6b2fa79d7c7ddf09c))
# [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)

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/core",
"description": "Core utilities for building navigators",
"version": "5.1.3",
"version": "5.2.2",
"keywords": [
"react",
"react-native",
@@ -29,23 +29,23 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.1",
"@react-navigation/routers": "^5.1.1",
"escape-string-regexp": "^2.0.0",
"query-string": "^6.10.1",
"react-is": "^16.12.0",
"query-string": "^6.11.1",
"react-is": "^16.13.0",
"shortid": "^2.2.15",
"use-subscription": "^1.3.0"
"use-subscription": "^1.4.0"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@types/react": "^16.9.19",
"@react-native-community/bob": "^0.10.0",
"@types/react": "^16.9.23",
"@types/react-is": "^16.7.1",
"@types/shortid": "^0.0.29",
"@types/use-subscription": "^1.0.0",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native-testing-library": "^1.12.0",
"react-test-renderer": "~16.12.0",
"react-test-renderer": "~16.9.0",
"typescript": "^3.7.5"
},
"peerDependencies": {

View File

@@ -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 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#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#i-get-the-warning-non-serializable-values-were-found-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}>

View File

@@ -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 for a guide on nesting.`;
export const SingleNavigatorContext = React.createContext<
| {

View File

@@ -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 (

View File

@@ -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;
}

View File

@@ -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'?"
);
});

View File

@@ -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."
);
});

View File

@@ -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);

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 for migration guide."
);
}

View File

@@ -48,6 +48,7 @@ export type EventArg<
* Type of the event (e.g. `focus`, `blur`)
*/
readonly type: EventName;
readonly target?: string;
} & (CanPreventDefault extends true
? {
/**
@@ -167,18 +168,6 @@ type NavigationHelpersCommon<
| { name: RouteName; key?: string; params: ParamList[RouteName] }
): void;
/**
* Replace the current route with a new one.
*
* @param name Route name of the new route.
* @param [params] Params object for the new route.
*/
replace<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends undefined
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
/**
* Reset the navigation state to the provided state.
*
@@ -360,7 +349,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 +368,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 +421,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 +454,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;
};

View File

@@ -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`

View File

@@ -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;

View File

@@ -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';
} 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]);
}

View File

@@ -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]);
}

View File

@@ -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?"
);
}

View File

@@ -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<
@@ -312,14 +333,14 @@ export default function useNavigationBuilder<
: state;
}
if (state !== nextState) {
// 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(() => {
const shouldUpdate = state !== nextState;
React.useEffect(() => {
if (shouldUpdate) {
// If the state needs to be updated, we'll schedule an update with React
setState(nextState);
});
}
}
}, [nextState, setState, shouldUpdate]);
// The up-to-date state will come in next render, but we don't need to wait for it
// We can't use the outdated state since the screens have changed, which will cause error due to mismatched config
@@ -331,11 +352,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 +367,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 +451,7 @@ export default function useNavigationBuilder<
getStateForRoute,
});
const descriptors = useDescriptors<State, ScreenOptions>({
const descriptors = useDescriptors<State, ScreenOptions, EventMap>({
state,
screens,
navigation,

View File

@@ -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#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 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]);
}

View File

@@ -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?"
);
}

View 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;
}

View File

@@ -3,6 +3,66 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.2.0...@react-navigation/drawer@5.3.0) (2020-03-17)
### Features
* add permanent drawer type ([#7818](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7818)) ([6a5d0a0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/6a5d0a035afae60d91aef78401ec8826295746fe))
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.1.1...@react-navigation/drawer@5.2.0) (2020-03-16)
### Features
* make useIsDrawerOpen workable inside drawer content ([#7746](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7746)) ([cb46d0b](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/cb46d0bca4e17e847fff46ac94276213ac9697bf))
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.1.0...@react-navigation/drawer@5.1.1) (2020-03-03)
**Note:** Version bump only for package @react-navigation/drawer
# [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

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/drawer",
"description": "Drawer navigator component with animated transitions and gesturess",
"version": "5.0.4",
"version": "5.3.0",
"keywords": [
"react-native-component",
"react-component",
@@ -39,27 +39,27 @@
"react-native-iphone-x-helper": "^1.2.1"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.4",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.0",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.5.6",
"react-native-gesture-handler": "^1.6.0",
"react-native-reanimated": "^1.7.0",
"react-native-safe-area-context": "^0.7.2",
"react-native-screens": "^2.0.0-beta.2",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.3.0",
"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",
"react-native-reanimated": ">= 1.0.0",
"react-native-safe-area-context": ">= 0.6.0",
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0"
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
},
"@react-native-community/bob": {
"source": "src",

View File

@@ -49,6 +49,8 @@ function DrawerNavigator({
}
export default createNavigatorFactory<
DrawerNavigationState,
DrawerNavigationOptions,
DrawerNavigationEventMap,
typeof DrawerNavigator
>(DrawerNavigator);

View File

@@ -7,6 +7,7 @@ import {
Descriptor,
NavigationHelpers,
DrawerNavigationState,
DrawerActionHelpers,
} from '@react-navigation/native';
import { PanGestureHandler } from 'react-native-gesture-handler';
@@ -26,8 +27,9 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
* - `front`: Traditional drawer which covers the screen with a overlay behind it.
* - `back`: The drawer is revealed behind the screen on swipe.
* - `slide`: Both the screen and the drawer slide on swipe to reveal the drawer.
* - `permanent`: A permanent drawer is shown as a sidebar.
*/
drawerType?: 'front' | 'back' | 'slide';
drawerType?: 'front' | 'back' | 'slide' | 'permanent';
/**
* How far from the edge of the screen the swipe gesture should activate.
*/
@@ -190,22 +192,8 @@ export type DrawerNavigationProp<
DrawerNavigationState,
DrawerNavigationOptions,
DrawerNavigationEventMap
> & {
/**
* Open the drawer sidebar.
*/
openDrawer(): void;
/**
* Close the drawer sidebar.
*/
closeDrawer(): void;
/**
* Open the drawer sidebar if closed, or close if opened.
*/
toggleDrawer(): void;
};
> &
DrawerActionHelpers<ParamList>;
export type DrawerDescriptor = Descriptor<
ParamListBase,

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import { useNavigation, ParamListBase } from '@react-navigation/native';
import { DrawerNavigationProp } from '../types';
import DrawerOpenContext from '../views/DrawerOpenContext';
/**
* Hook to detect if the drawer is open in a parent navigator.
@@ -10,6 +11,8 @@ export default function useIsDrawerOpen() {
let drawer = navigation as DrawerNavigationProp<ParamListBase>;
const drawerOpenContext = React.useContext(DrawerOpenContext);
// The screen might be inside another navigator such as stack nested in drawer
// We need to find the closest drawer navigator and add the listener there
while (drawer && drawer.dangerouslyGetState().type !== 'drawer') {
@@ -34,5 +37,9 @@ export default function useIsDrawerOpen() {
return unsubscribe;
}, [drawer, isDrawerOpen]);
if (drawerOpenContext !== null) {
return drawerOpenContext;
}
return isDrawerOpen;
}

View File

@@ -18,6 +18,7 @@ import {
} from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
import Overlay from './Overlay';
import DrawerOpenContext from './DrawerOpenContext';
const {
Clock,
@@ -68,6 +69,8 @@ const SPRING_CONFIG = {
restSpeedThreshold: 0.01,
};
const ANIMATED_ONE = new Animated.Value(1);
type Binary = 0 | 1;
type Renderer = (props: { progress: Animated.Node<number> }) => React.ReactNode;
@@ -79,7 +82,7 @@ type Props = {
onGestureRef?: (ref: PanGestureHandler | null) => void;
gestureEnabled: boolean;
drawerPosition: 'left' | 'right';
drawerType: 'front' | 'back' | 'slide';
drawerType: 'front' | 'back' | 'slide' | 'permanent';
keyboardDismissMode: 'none' | 'on-drag';
swipeEdgeWidth: number;
swipeDistanceThreshold?: number;
@@ -504,7 +507,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) => {
@@ -542,6 +547,7 @@ export default class DrawerView extends React.PureComponent<Props> {
gestureHandlerProps,
} = this.props;
const isOpen = drawerType === 'permanent' ? true : open;
const isRight = drawerPosition === 'right';
const contentTranslateX = drawerType === 'front' ? 0 : this.translateX;
@@ -567,8 +573,10 @@ export default class DrawerView extends React.PureComponent<Props> {
const hitSlop = isRight
? // Extend hitSlop to the side of the screen when drawer is closed
// This lets the user drag the drawer from the side of the screen
{ right: 0, width: open ? undefined : swipeEdgeWidth }
: { left: 0, width: open ? undefined : swipeEdgeWidth };
{ right: 0, width: isOpen ? undefined : swipeEdgeWidth }
: { left: 0, width: isOpen ? undefined : swipeEdgeWidth };
const progress = drawerType === 'permanent' ? ANIMATED_ONE : this.progress;
return (
<PanGestureHandler
@@ -578,62 +586,84 @@ export default class DrawerView extends React.PureComponent<Props> {
onGestureEvent={this.handleGestureEvent}
onHandlerStateChange={this.handleGestureStateChange}
hitSlop={hitSlop}
enabled={gestureEnabled}
enabled={drawerType !== 'permanent' && gestureEnabled}
{...gestureHandlerProps}
>
<Animated.View
onLayout={this.handleContainerLayout}
style={styles.main}
style={[
styles.main,
drawerType === 'permanent' && {
flexDirection: 'row-reverse',
},
]}
>
<Animated.View
style={[
styles.content,
{
drawerType !== 'permanent' && {
transform: [{ translateX: contentTranslateX }],
},
sceneContainerStyle as any,
]}
>
<View
accessibilityElementsHidden={open}
importantForAccessibility={open ? 'no-hide-descendants' : 'auto'}
accessibilityElementsHidden={isOpen}
importantForAccessibility={
isOpen ? 'no-hide-descendants' : 'auto'
}
style={styles.content}
>
{renderSceneContent({ progress: this.progress })}
{renderSceneContent({ progress })}
</View>
<TapGestureHandler
enabled={gestureEnabled}
onHandlerStateChange={this.handleTapStateChange}
>
<Overlay progress={this.progress} style={overlayStyle} />
</TapGestureHandler>
{// Disable overlay if sidebar is permanent
drawerType === 'permanent' ? null : (
<TapGestureHandler
enabled={gestureEnabled}
onHandlerStateChange={this.handleTapStateChange}
>
<Overlay progress={progress} style={overlayStyle} />
</TapGestureHandler>
)}
</Animated.View>
<Animated.Code
exec={block([
onChange(this.manuallyTriggerSpring, [
cond(eq(this.manuallyTriggerSpring, TRUE), [
set(this.nextIsOpen, FALSE),
call([], () => (this.currentOpenValue = false)),
{drawerType === 'permanent' ? null : (
<Animated.Code
exec={block([
onChange(this.manuallyTriggerSpring, [
cond(eq(this.manuallyTriggerSpring, TRUE), [
set(this.nextIsOpen, FALSE),
call([], () => (this.currentOpenValue = false)),
]),
]),
]),
])}
/>
])}
/>
)}
<Animated.View
accessibilityViewIsModal={open}
accessibilityViewIsModal={isOpen}
removeClippedSubviews={Platform.OS !== 'ios'}
onLayout={this.handleDrawerLayout}
style={[
styles.container,
isRight ? { right: offset } : { left: offset },
{
transform: [{ translateX: drawerTranslateX }],
opacity: this.drawerOpacity,
zIndex: drawerType === 'back' ? -1 : 0,
},
drawerType === 'permanent'
? // Without this, the `left`/`right` values don't get reset
isRight
? { right: 0 }
: { left: 0 }
: [
styles.nonPermanent,
{
transform: [{ translateX: drawerTranslateX }],
opacity: this.drawerOpacity,
},
isRight ? { right: offset } : { left: offset },
{ zIndex: drawerType === 'back' ? -1 : 0 },
],
drawerStyle as any,
]}
>
{renderDrawerContent({ progress: this.progress })}
<DrawerOpenContext.Provider value={isOpen}>
{renderDrawerContent({ progress })}
</DrawerOpenContext.Provider>
</Animated.View>
</Animated.View>
</PanGestureHandler>
@@ -644,11 +674,13 @@ export default class DrawerView extends React.PureComponent<Props> {
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
maxWidth: '100%',
},
nonPermanent: {
position: 'absolute',
top: 0,
bottom: 0,
width: '80%',
maxWidth: '100%',
},
content: {
flex: 1,

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
const DrawerOpenContext = React.createContext<boolean | null>(null);
export default DrawerOpenContext;

View File

@@ -221,6 +221,10 @@ export default function DrawerView({
]}
drawerStyle={[
{ width: drawerWidth, backgroundColor: colors.card },
drawerType === 'permanent' && {
borderRightColor: colors.border,
borderRightWidth: StyleSheet.hairlineWidth,
},
drawerStyle,
]}
overlayStyle={{ backgroundColor: overlayColor }}

View File

@@ -3,6 +3,57 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.2...@react-navigation/material-bottom-tabs@5.1.3) (2020-03-17)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.1...@react-navigation/material-bottom-tabs@5.1.2) (2020-03-16)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.0...@react-navigation/material-bottom-tabs@5.1.1) (2020-03-03)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [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

View File

@@ -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.3",
"keywords": [
"react-native-component",
"react-component",
@@ -35,10 +35,10 @@
"clean": "del lib"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.4",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.0",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"@types/react-native-vector-icons": "^6.4.5",
"del-cli": "^3.0.0",
"react": "~16.9.0",
@@ -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",

View File

@@ -49,6 +49,8 @@ function MaterialBottomTabNavigator({
}
export default createNavigatorFactory<
TabNavigationState,
MaterialBottomTabNavigationOptions,
MaterialBottomTabNavigationEventMap,
typeof MaterialBottomTabNavigator
>(MaterialBottomTabNavigator);

View File

@@ -5,6 +5,7 @@ import {
NavigationProp,
NavigationHelpers,
TabNavigationState,
TabActionHelpers,
} from '@react-navigation/native';
export type MaterialBottomTabNavigationEventMap = {
@@ -28,19 +29,8 @@ export type MaterialBottomTabNavigationProp<
TabNavigationState,
MaterialBottomTabNavigationOptions,
MaterialBottomTabNavigationEventMap
> & {
/**
* Jump to an existing tab.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
};
> &
TabActionHelpers<ParamList>;
export type MaterialBottomTabNavigationOptions = {
/**

View File

@@ -3,6 +3,57 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.2...@react-navigation/material-top-tabs@5.1.3) (2020-03-17)
**Note:** Version bump only for package @react-navigation/material-top-tabs
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.1...@react-navigation/material-top-tabs@5.1.2) (2020-03-16)
**Note:** Version bump only for package @react-navigation/material-top-tabs
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.0...@react-navigation/material-top-tabs@5.1.1) (2020-03-03)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [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

View File

@@ -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.3",
"keywords": [
"react-native-component",
"react-component",
@@ -38,20 +38,20 @@
"color": "^3.1.2"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.4",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@react-native-community/bob": "^0.10.0",
"@react-navigation/native": "^5.1.0",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.5.6",
"react-native-gesture-handler": "^1.6.0",
"react-native-reanimated": "^1.7.0",
"react-native-tab-view": "^2.13.0",
"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",

View File

@@ -48,6 +48,8 @@ function MaterialTopTabNavigator({
}
export default createNavigatorFactory<
TabNavigationState,
MaterialTopTabNavigationOptions,
MaterialTopTabNavigationEventMap,
typeof MaterialTopTabNavigator
>(MaterialTopTabNavigator);

View File

@@ -7,6 +7,7 @@ import {
Route,
NavigationProp,
TabNavigationState,
TabActionHelpers,
} from '@react-navigation/native';
export type MaterialTopTabNavigationEventMap = {
@@ -42,19 +43,8 @@ export type MaterialTopTabNavigationProp<
TabNavigationState,
MaterialTopTabNavigationOptions,
MaterialTopTabNavigationEventMap
> & {
/**
* Jump to an existing tab.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
};
> &
TabActionHelpers<ParamList>;
export type MaterialTopTabNavigationOptions = {
/**

View File

@@ -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))

View File

@@ -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.

View File

@@ -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).

View File

@@ -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"
}
]
]
}
}

View File

@@ -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';

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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>
);
}

View File

@@ -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,
},
});

View File

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

View File

@@ -1,11 +0,0 @@
{
"extends": "../../tsconfig",
"references": [
{ "path": "../core" },
{ "path": "../routers" },
{ "path": "../native" }
],
"compilerOptions": {
"outDir": "./lib/typescript"
}
}

View File

@@ -3,6 +3,57 @@
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/native/compare/@react-navigation/native@5.0.10...@react-navigation/native@5.1.0) (2020-03-17)
### Features
* add permanent drawer type ([#7818](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/7818)) ([6a5d0a0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/6a5d0a035afae60d91aef78401ec8826295746fe))
## [5.0.10](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.9...@react-navigation/native@5.0.10) (2020-03-16)
**Note:** Version bump only for package @react-navigation/native
## [5.0.9](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.8...@react-navigation/native@5.0.9) (2020-03-03)
**Note:** Version bump only for package @react-navigation/native
## [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

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/native",
"description": "React Native integration for React Navigation",
"version": "5.0.4",
"version": "5.1.0",
"keywords": [
"react-native",
"react-navigation",
@@ -31,12 +31,12 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.1.3"
"@react-navigation/core": "^5.2.2"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@react-native-community/bob": "^0.10.0",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",

View File

@@ -7,7 +7,7 @@ const DefaultTheme: Theme = {
background: 'rgb(242, 242, 242)',
card: 'rgb(255, 255, 255)',
text: 'rgb(28, 28, 30)',
border: 'rgb(199, 199, 204)',
border: 'rgb(224, 224, 224)',
},
};

View File

@@ -6,11 +6,11 @@ type ScrollOptions = { y?: number; animated?: boolean };
type ScrollableView =
| { scrollToTop(): void }
| { scrollTo(options: ScrollOptions): void }
| { scrollToOffset(options: ScrollOptions): void }
| { scrollToOffset(options: { offset?: number; animated?: boolean }): void }
| { scrollResponderScrollTo(options: ScrollOptions): void };
type ScrollableWrapper =
| { getScrollResponder(): ScrollableView }
| { getScrollResponder(): React.ReactNode }
| { getNode(): ScrollableView }
| ScrollableView;
@@ -79,7 +79,7 @@ export default function useScrollToTop(
// 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(() => {
const scrollable = getScrollableNode(ref);
const scrollable = getScrollableNode(ref) as ScrollableWrapper;
if (isFocused && isFirst && scrollable && !e.defaultPrevented) {
if ('scrollToTop' in scrollable) {
@@ -87,7 +87,7 @@ export default function useScrollToTop(
} else if ('scrollTo' in scrollable) {
scrollable.scrollTo({ y: 0, animated: true });
} else if ('scrollToOffset' in scrollable) {
scrollable.scrollToOffset({ y: 0, animated: true });
scrollable.scrollToOffset({ offset: 0, animated: true });
} else if ('scrollResponderScrollTo' in scrollable) {
scrollable.scrollResponderScrollTo({ y: 0, animated: true });
}

View File

@@ -3,6 +3,52 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.1.0...@react-navigation/routers@5.1.1) (2020-03-16)
### Bug Fixes
* don't handle action if no routes are present ([660cac3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/660cac3557bce8978812ce2750e961e7ada92d13))
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.3...@react-navigation/routers@5.1.0) (2020-03-03)
### Bug Fixes
* fix links for documentation ([5bb0f40](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/5bb0f405ceb5755d39a0b5b1f2e4ecee0da051bc))
### Features
* make reset bubble up ([09f6808](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/09f6808d7d43c70b2c502151f9f20fad03972886))
## [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)

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/routers",
"description": "Routers to help build custom navigators",
"version": "5.0.1",
"version": "5.1.1",
"keywords": [
"react",
"react-native",
@@ -33,7 +33,7 @@
"shortid": "^2.2.15"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-native-community/bob": "^0.10.0",
"del-cli": "^3.0.0",
"typescript": "^3.7.5"
},

View File

@@ -29,8 +29,29 @@ const BaseRouter = {
};
}
case 'RESET':
return action.payload as PartialState<State>;
case 'RESET': {
const nextState = action.payload as State | PartialState<State>;
if (nextState.stale === false) {
if (
state.routeNames.length !== nextState.routeNames.length ||
nextState.routeNames.some(name => !state.routeNames.includes(name))
) {
return null;
}
}
if (
nextState.routes.length === 0 ||
nextState.routes.some(
(route: { name: string }) => !state.routeNames.includes(route.name)
)
) {
return null;
}
return nextState;
}
default:
return null;

View File

@@ -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#navigate for usage.'
);
}

View File

@@ -1,10 +1,16 @@
import shortid from 'shortid';
import { PartialState, CommonNavigationAction, Router } from './types';
import {
PartialState,
CommonNavigationAction,
Router,
ParamListBase,
} from './types';
import TabRouter, {
TabActions,
TabActionType,
TabRouterOptions,
TabNavigationState,
TabActionHelpers,
} from './TabRouter';
export type DrawerActionType =
@@ -31,6 +37,25 @@ export type DrawerNavigationState = Omit<
history: ({ type: 'route'; key: string } | { type: 'drawer' })[];
};
export type DrawerActionHelpers<
ParamList extends ParamListBase
> = TabActionHelpers<ParamList> & {
/**
* Open the drawer sidebar.
*/
openDrawer(): void;
/**
* Close the drawer sidebar.
*/
closeDrawer(): void;
/**
* Open the drawer sidebar if closed, or close if opened.
*/
toggleDrawer(): void;
};
export const DrawerActions = {
...TabActions,
openDrawer(): DrawerActionType {

View File

@@ -6,6 +6,7 @@ import {
Router,
DefaultRouterOptions,
Route,
ParamListBase,
} from './types';
export type StackActionType =
@@ -42,6 +43,42 @@ export type StackNavigationState = NavigationState & {
type: 'stack';
};
export type StackActionHelpers<ParamList extends ParamListBase> = {
/**
* Replace the current route with a new one.
*
* @param name Route name of the new route.
* @param [params] Params object for the new route.
*/
replace<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends undefined
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
/**
* 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 const StackActions = {
replace(name: string, params?: object): StackActionType {
return { type: 'REPLACE', payload: { name, params } };

View File

@@ -7,6 +7,7 @@ import {
Router,
DefaultRouterOptions,
Route,
ParamListBase,
} from './types';
export type TabActionType = {
@@ -33,6 +34,20 @@ export type TabNavigationState = Omit<NavigationState, 'history'> & {
history: { type: 'route'; key: string }[];
};
export type TabActionHelpers<ParamList extends ParamListBase> = {
/**
* Jump to an existing tab.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
};
const TYPE_ROUTE = 'route' as const;
export const TabActions = {

View File

@@ -83,3 +83,46 @@ it('resets state to new state with RESET', () => {
expect(result).toEqual({ index: 0, routes });
});
it("doesn't handle RESET if routes don't match routeNames", () => {
const routes = [
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'baz', name: 'baz' },
{ key: 'qux', name: 'quz' },
];
const result = BaseRouter.getStateForAction(
STATE,
CommonActions.reset({
index: 0,
routes,
})
);
expect(result).toEqual(null);
});
it("doesn't handle RESET if routeNames don't match", () => {
const result = BaseRouter.getStateForAction(
STATE,
CommonActions.reset({
...STATE,
// @ts-ignore
routeNames: ['ten'],
})
);
expect(result).toEqual(null);
});
it("doesn't handle RESET if there are no routes", () => {
const result = BaseRouter.getStateForAction(
STATE,
CommonActions.reset({
index: 0,
routes: [],
})
);
expect(result).toEqual(null);
});

View File

@@ -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.'
);
});

View File

@@ -7,6 +7,7 @@ export { default as BaseRouter } from './BaseRouter';
export {
default as StackRouter,
StackActions,
StackActionHelpers,
StackActionType,
StackRouterOptions,
StackNavigationState,
@@ -15,6 +16,7 @@ export {
export {
default as TabRouter,
TabActions,
TabActionHelpers,
TabActionType,
TabRouterOptions,
TabNavigationState,
@@ -23,6 +25,7 @@ export {
export {
default as DrawerRouter,
DrawerActions,
DrawerActionHelpers,
DrawerActionType,
DrawerRouterOptions,
DrawerNavigationState,

View File

@@ -3,6 +3,98 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.0...@react-navigation/stack@5.2.1) (2020-03-17)
**Note:** Version bump only for package @react-navigation/stack
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.1.1...@react-navigation/stack@5.2.0) (2020-03-16)
### Bug Fixes
* fix android header title font weight ([#7720](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7720)) ([0dcaea3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/0dcaea32428484cdc9b4d56f7bf38f9f1bdf1dee))
* fix back gesture cancellation ([#7700](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7700)) ([469d054](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/469d0542c7341dc524a597d70216ba743602a51e)), closes [#6782](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6782)
### Features
* add an option to change use a custom card overlay ([#7809](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7809)) ([70029d6](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/70029d6c130f0f47de94b6a6c4cbee6afa12b405))
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.1.0...@react-navigation/stack@5.1.1) (2020-03-03)
### Bug Fixes
* ignore back button press if screen isn't focused. closes [#7673](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7673) ([296c836](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/296c836064447e055a88e43cfbbf5f9de93838f0))
# [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

View File

@@ -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.2.1",
"keywords": [
"react-native-component",
"react-component",
@@ -38,28 +38,28 @@
"react-native-iphone-x-helper": "^1.2.1"
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-native-community/masked-view": "^0.1.6",
"@react-navigation/native": "^5.0.4",
"@react-native-community/bob": "^0.10.0",
"@react-native-community/masked-view": "^0.1.7",
"@react-navigation/native": "^5.1.0",
"@types/color": "^3.0.1",
"@types/react": "^16.9.19",
"@types/react-native": "^0.60.30",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
"del-cli": "^3.0.0",
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.5.6",
"react-native-safe-area-context": "^0.7.2",
"react-native-screens": "^2.0.0-beta.2",
"react-native-gesture-handler": "^1.6.0",
"react-native-safe-area-context": "^0.7.3",
"react-native-screens": "^2.3.0",
"typescript": "^3.7.5"
},
"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",
"react-native-safe-area-context": ">= 0.6.0",
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0"
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
},
"@react-native-community/bob": {
"source": "src",

View File

@@ -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;

View File

@@ -74,6 +74,8 @@ function StackNavigator({
}
export default createNavigatorFactory<
StackNavigationState,
StackNavigationOptions,
StackNavigationEventMap,
typeof StackNavigator
>(StackNavigator);

View File

@@ -1,3 +1,4 @@
import * as React from 'react';
import {
Animated,
StyleProp,
@@ -13,6 +14,7 @@ import {
Route,
NavigationHelpers,
StackNavigationState,
StackActionHelpers,
} from '@react-navigation/native';
export type StackNavigationEventMap = {
@@ -40,29 +42,8 @@ export type StackNavigationProp<
StackNavigationState,
StackNavigationOptions,
StackNavigationEventMap
> & {
/**
* Push a new screen onto the stack.
*
* @param name Name of the route for the tab.
* @param [params] Params object for the route.
*/
push<RouteName extends keyof ParamList>(
...args: ParamList[RouteName] extends undefined | any
? [RouteName] | [RouteName, ParamList[RouteName]]
: [RouteName, ParamList[RouteName]]
): void;
/**
* Pop a screen from the stack.
*/
pop(count?: number): void;
/**
* Pop to the first route in the stack, dismissing all other screens.
*/
popToTop(): void;
};
> &
StackActionHelpers<ParamList>;
export type Layout = { width: number; height: number };
@@ -122,7 +103,7 @@ export type StackHeaderOptions = {
/**
* Style object for the title component.
*/
headerTitleStyle?: StyleProp<TextStyle>;
headerTitleStyle?: React.ComponentProps<typeof Animated.Text>['style'];
/**
* Style object for the container of the `headerTitle` component, for example to add padding.
* By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`.
@@ -279,6 +260,10 @@ export type StackNavigationOptions = StackHeaderOptions &
* Defaults to `true` on Android and `false` on iOS.
*/
cardOverlayEnabled?: boolean;
/**
* Function that returns a React Element to display as a overlay for the card.
*/
cardOverlay?: (props: { style: StyleProp<ViewStyle> }) => React.ReactNode;
/**
* Style object for the card in stack.
* You can provide a custom background color to use instead of the default background here.
@@ -404,6 +389,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 = {
@@ -426,7 +415,7 @@ export type StackHeaderTitleProps = {
/**
* Style object for the title element.
*/
style?: StyleProp<TextStyle>;
style?: React.ComponentProps<typeof Animated.Text>['style'];
};
export type TransitionSpec =

View File

@@ -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;
}

View File

@@ -32,13 +32,14 @@ export default class BorderlessButton extends React.Component<Props> {
}).start();
}
this.props.onActiveStateChange && this.props.onActiveStateChange(active);
this.props.onActiveStateChange?.(active);
};
render() {
const { children, style, enabled, ...rest } = this.props;
return (
// @ts-ignore
<AnimatedBaseButton
{...rest}
onActiveStateChange={this.handleActiveStateChange}

View File

@@ -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.isFocused() && 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}
/>
);

View File

@@ -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}

View File

@@ -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
}

View File

@@ -1,8 +1,8 @@
import * as React from 'react';
import { Animated, StyleSheet, Platform, TextProps } from 'react-native';
import { Animated, StyleSheet, Platform } from 'react-native';
import { useTheme } from '@react-navigation/native';
type Props = TextProps & {
type Props = React.ComponentProps<typeof Animated.Text> & {
tintColor?: string;
children?: string;
};
@@ -32,7 +32,8 @@ const styles = StyleSheet.create({
},
android: {
fontSize: 20,
fontWeight: '500',
fontFamily: 'sans-serif-medium',
fontWeight: 'normal',
},
default: {
fontSize: 18,

View File

@@ -44,6 +44,7 @@ type Props = ViewProps & {
onGestureCanceled?: () => void;
onGestureEnd?: () => void;
children: React.ReactNode;
overlay: (props: { style: StyleProp<ViewStyle> }) => React.ReactNode;
overlayEnabled: boolean;
shadowEnabled: boolean;
gestureEnabled: boolean;
@@ -80,6 +81,10 @@ export default class Card extends React.Component<Props> {
shadowEnabled: true,
gestureEnabled: true,
gestureVelocityImpact: GESTURE_VELOCITY_IMPACT,
overlay: ({ style }: { style: StyleProp<ViewStyle> }) =>
style ? (
<Animated.View pointerEvents="none" style={[styles.overlay, style]} />
) : null,
};
componentDidMount() {
@@ -267,8 +272,7 @@ export default class Card extends React.Component<Props> {
}
const closing =
Math.abs(translation + velocity * gestureVelocityImpact) >
distance / 2
translation + velocity * gestureVelocityImpact > distance / 2
? velocity !== 0 || translation !== 0
: false;
@@ -409,6 +413,7 @@ export default class Card extends React.Component<Props> {
next,
layout,
insets,
overlay,
overlayEnabled,
shadowEnabled,
gestureEnabled,
@@ -470,55 +475,54 @@ export default class Card extends React.Component<Props> {
: false;
return (
<View pointerEvents="box-none" {...rest}>
{overlayEnabled && overlayStyle ? (
<CardAnimationContext.Provider value={animationContext}>
<View pointerEvents="box-none" {...rest}>
{overlayEnabled ? (
<View style={StyleSheet.absoluteFill}>
{overlay({ style: overlayStyle })}
</View>
) : null}
<Animated.View
pointerEvents="none"
style={[styles.overlay, overlayStyle]}
/>
) : null}
<Animated.View
style={[styles.container, containerStyle, customContainerStyle]}
pointerEvents="box-none"
>
<PanGestureHandler
ref={this.gestureRef}
enabled={layout.width !== 0 && gestureEnabled}
onGestureEvent={handleGestureEvent}
onHandlerStateChange={this.handleGestureStateChange}
{...this.gestureActivationCriteria()}
style={[styles.container, containerStyle, customContainerStyle]}
pointerEvents="box-none"
>
<Animated.View style={[styles.container, cardStyle]}>
{shadowEnabled && shadowStyle && !isTransparent ? (
<Animated.View
style={[
styles.shadow,
gestureDirection === 'horizontal'
? [styles.shadowHorizontal, styles.shadowLeft]
: gestureDirection === 'horizontal-inverted'
? [styles.shadowHorizontal, styles.shadowRight]
: gestureDirection === 'vertical'
? [styles.shadowVertical, styles.shadowTop]
: [styles.shadowVertical, styles.shadowBottom],
shadowStyle,
]}
pointerEvents="none"
/>
) : null}
<View
ref={this.contentRef}
style={[styles.content, contentStyle]}
>
<StackGestureRefContext.Provider value={this.gestureRef}>
<CardAnimationContext.Provider value={animationContext}>
<PanGestureHandler
ref={this.gestureRef}
enabled={layout.width !== 0 && gestureEnabled}
onGestureEvent={handleGestureEvent}
onHandlerStateChange={this.handleGestureStateChange}
{...this.gestureActivationCriteria()}
>
<Animated.View style={[styles.container, cardStyle]}>
{shadowEnabled && shadowStyle && !isTransparent ? (
<Animated.View
style={[
styles.shadow,
gestureDirection === 'horizontal'
? [styles.shadowHorizontal, styles.shadowLeft]
: gestureDirection === 'horizontal-inverted'
? [styles.shadowHorizontal, styles.shadowRight]
: gestureDirection === 'vertical'
? [styles.shadowVertical, styles.shadowTop]
: [styles.shadowVertical, styles.shadowBottom],
shadowStyle,
]}
pointerEvents="none"
/>
) : null}
<View
ref={this.contentRef}
style={[styles.content, contentStyle]}
>
<StackGestureRefContext.Provider value={this.gestureRef}>
{children}
</CardAnimationContext.Provider>
</StackGestureRefContext.Provider>
</View>
</Animated.View>
</PanGestureHandler>
</Animated.View>
</View>
</StackGestureRefContext.Provider>
</View>
</Animated.View>
</PanGestureHandler>
</Animated.View>
</View>
</CardAnimationContext.Provider>
);
}
}
@@ -532,7 +536,7 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
overlay: {
...StyleSheet.absoluteFillObject,
flex: 1,
backgroundColor: '#000',
},
shadow: {

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