mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-25 05:18:15 +08:00
Compare commits
1 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41736641c1 |
@@ -2,6 +2,5 @@ module.exports = function (api) {
|
|||||||
api.cache(true);
|
api.cache(true);
|
||||||
return {
|
return {
|
||||||
presets: ['babel-preset-expo'],
|
presets: ['babel-preset-expo'],
|
||||||
plugins: ['react-native-reanimated/plugin'],
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -13,51 +13,50 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^12.0.0",
|
"@expo/vector-icons": "^12.0.3",
|
||||||
"@react-native-async-storage/async-storage": "^1.13.0",
|
"@react-native-masked-view/masked-view": "0.2.0",
|
||||||
"@react-native-masked-view/masked-view": "0.2.3",
|
|
||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
"expo": "^41.0.0-beta.2",
|
"expo": "^40.0.1",
|
||||||
"expo-asset": "~8.3.1",
|
"expo-asset": "~8.2.2",
|
||||||
"expo-blur": "~9.0.3",
|
"expo-blur": "~9.0.0",
|
||||||
"expo-linking": "~2.2.1",
|
"expo-linking": "~2.1.1",
|
||||||
"expo-updates": "~0.5.3",
|
"expo-updates": "~0.4.2",
|
||||||
"koa": "^2.13.0",
|
"koa": "^2.13.0",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
"react-dom": "16.13.1",
|
"react-dom": "16.13.1",
|
||||||
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
|
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
|
||||||
"react-native-appearance": "~0.3.3",
|
"react-native-appearance": "~0.3.3",
|
||||||
"react-native-gesture-handler": "~1.10.2",
|
"react-native-gesture-handler": "~1.8.0",
|
||||||
"react-native-pager-view": "~5.0.12",
|
"react-native-pager-view": "^4.2.4",
|
||||||
"react-native-paper": "^4.7.2",
|
"react-native-paper": "^4.7.2",
|
||||||
"react-native-reanimated": "~2.1.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-native-safe-area-context": "~3.2.0",
|
"react-native-safe-area-context": "3.1.9",
|
||||||
"react-native-screens": "~3.0.0",
|
"react-native-screens": "~2.15.0",
|
||||||
"react-native-tab-view": "^3.0.1",
|
"react-native-tab-view": "^3.0.0",
|
||||||
"react-native-vector-icons": "^8.1.0",
|
"react-native-vector-icons": "^8.1.0",
|
||||||
"react-native-web": "~0.15.0"
|
"react-native-web": "~0.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/node": "^7.13.13",
|
"@babel/node": "^7.13.0",
|
||||||
"@expo/webpack-config": "~0.12.63",
|
"@expo/webpack-config": "~0.12.60",
|
||||||
"@types/cheerio": "^0.22.28",
|
"@types/cheerio": "^0.22.24",
|
||||||
"@types/jest-dev-server": "^4.2.0",
|
"@types/jest-dev-server": "^4.2.0",
|
||||||
"@types/koa": "^2.13.1",
|
"@types/koa": "^2.13.1",
|
||||||
"@types/node-fetch": "^2.5.9",
|
"@types/node-fetch": "^2.5.8",
|
||||||
"@types/react": "~16.9.35",
|
"@types/react": "~16.9.35",
|
||||||
"@types/react-dom": "~16.9.8",
|
"@types/react-dom": "~16.9.8",
|
||||||
"@types/react-native": "~0.63.2",
|
"@types/react-native": "~0.63.51",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"babel-plugin-module-resolver": "^4.0.0",
|
"babel-plugin-module-resolver": "^4.0.0",
|
||||||
"babel-preset-expo": "8.3.0",
|
"babel-preset-expo": "8.3.0",
|
||||||
"cheerio": "^1.0.0-rc.3",
|
"cheerio": "^1.0.0-rc.3",
|
||||||
"expo-cli": "^4.3.4",
|
"expo-cli": "^4.2.1",
|
||||||
"jest": "^26.6.3",
|
"jest": "^26.6.3",
|
||||||
"jest-dev-server": "^4.4.0",
|
"jest-dev-server": "^4.4.0",
|
||||||
"mock-require-assets": "^0.0.1",
|
"mock-require-assets": "^0.0.1",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"nodemon": "^2.0.6",
|
"nodemon": "^2.0.6",
|
||||||
"playwright": "^1.10.0",
|
"playwright": "^1.9.1",
|
||||||
"serve": "^11.3.0",
|
"serve": "^11.3.0",
|
||||||
"typescript": "~4.2.3"
|
"typescript": "~4.2.3"
|
||||||
}
|
}
|
||||||
|
|||||||
2
example/src/LinkingPrefixes.expo.ts
Normal file
2
example/src/LinkingPrefixes.expo.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import * as Linking from 'expo-linking';
|
||||||
|
export default [Linking.makeUrl('/')];
|
||||||
1
example/src/LinkingPrefixes.ts
Normal file
1
example/src/LinkingPrefixes.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default ['rne://127.0.0.1:19000/--/'];
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { View, Platform, StyleSheet, ScrollView } from 'react-native';
|
|
||||||
import { Button } from 'react-native-paper';
|
|
||||||
import type { ParamListBase } from '@react-navigation/native';
|
|
||||||
import {
|
|
||||||
createStackNavigator,
|
|
||||||
StackScreenProps,
|
|
||||||
TransitionPresets,
|
|
||||||
HeaderStyleInterpolators,
|
|
||||||
} from '@react-navigation/stack';
|
|
||||||
import Article from '../Shared/Article';
|
|
||||||
import Albums from '../Shared/Albums';
|
|
||||||
import NewsFeed from '../Shared/NewsFeed';
|
|
||||||
|
|
||||||
export type SimpleStackParams = {
|
|
||||||
Article: { author: string } | undefined;
|
|
||||||
NewsFeed: { date: number };
|
|
||||||
Albums: undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const scrollEnabled = Platform.select({ web: true, default: false });
|
|
||||||
|
|
||||||
const ArticleScreen = ({
|
|
||||||
navigation,
|
|
||||||
route,
|
|
||||||
}: StackScreenProps<SimpleStackParams, 'Article'>) => {
|
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<View style={styles.buttons}>
|
|
||||||
<Button
|
|
||||||
mode="contained"
|
|
||||||
onPress={() => navigation.push('NewsFeed', { date: Date.now() })}
|
|
||||||
style={styles.button}
|
|
||||||
>
|
|
||||||
Push feed
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
mode="outlined"
|
|
||||||
onPress={() => navigation.pop()}
|
|
||||||
style={styles.button}
|
|
||||||
>
|
|
||||||
Pop screen
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
<Article
|
|
||||||
author={{ name: route.params?.author ?? 'Unknown' }}
|
|
||||||
scrollEnabled={scrollEnabled}
|
|
||||||
/>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const NewsFeedScreen = ({
|
|
||||||
route,
|
|
||||||
navigation,
|
|
||||||
}: StackScreenProps<SimpleStackParams, 'NewsFeed'>) => {
|
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<View style={styles.buttons}>
|
|
||||||
<Button
|
|
||||||
mode="contained"
|
|
||||||
onPress={() => navigation.push('Albums')}
|
|
||||||
style={styles.button}
|
|
||||||
>
|
|
||||||
Navigate to album
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
mode="outlined"
|
|
||||||
onPress={() => navigation.pop()}
|
|
||||||
style={styles.button}
|
|
||||||
>
|
|
||||||
Pop screen
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
<NewsFeed scrollEnabled={scrollEnabled} date={route.params.date} />
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const AlbumsScreen = ({
|
|
||||||
navigation,
|
|
||||||
}: StackScreenProps<SimpleStackParams, 'Albums'>) => {
|
|
||||||
return (
|
|
||||||
<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.pop()}
|
|
||||||
style={styles.button}
|
|
||||||
>
|
|
||||||
Pop screen
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
<Albums scrollEnabled={scrollEnabled} />
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const SimpleStack = createStackNavigator<SimpleStackParams>();
|
|
||||||
|
|
||||||
export default function SimpleStackScreen({
|
|
||||||
navigation,
|
|
||||||
}: StackScreenProps<ParamListBase>) {
|
|
||||||
React.useLayoutEffect(() => {
|
|
||||||
navigation.setOptions({
|
|
||||||
headerShown: false,
|
|
||||||
});
|
|
||||||
}, [navigation]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SimpleStack.Navigator
|
|
||||||
screenOptions={{
|
|
||||||
...TransitionPresets.SlideFromRightIOS,
|
|
||||||
headerMode: 'float',
|
|
||||||
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SimpleStack.Screen
|
|
||||||
name="Article"
|
|
||||||
component={ArticleScreen}
|
|
||||||
options={({ route }) => ({
|
|
||||||
title: `Article by ${route.params?.author ?? 'Unknown'}`,
|
|
||||||
})}
|
|
||||||
initialParams={{ author: 'Gandalf' }}
|
|
||||||
/>
|
|
||||||
<SimpleStack.Screen
|
|
||||||
name="NewsFeed"
|
|
||||||
component={NewsFeedScreen}
|
|
||||||
options={{ title: 'Feed' }}
|
|
||||||
/>
|
|
||||||
<SimpleStack.Screen
|
|
||||||
name="Albums"
|
|
||||||
component={AlbumsScreen}
|
|
||||||
options={{
|
|
||||||
...TransitionPresets.ModalSlideFromBottomIOS,
|
|
||||||
headerMode: 'screen',
|
|
||||||
title: 'Albums',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SimpleStack.Navigator>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
buttons: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
padding: 8,
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
margin: 8,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -86,7 +86,8 @@ const AlbumsScreen = ({ navigation }: StackScreenProps<SimpleStackParams>) => {
|
|||||||
|
|
||||||
const SimpleStack = createStackNavigator<SimpleStackParams>();
|
const SimpleStack = createStackNavigator<SimpleStackParams>();
|
||||||
|
|
||||||
type Props = StackScreenProps<ParamListBase>;
|
type Props = Partial<React.ComponentProps<typeof SimpleStack.Navigator>> &
|
||||||
|
StackScreenProps<ParamListBase>;
|
||||||
|
|
||||||
function CustomHeader(props: StackHeaderProps) {
|
function CustomHeader(props: StackHeaderProps) {
|
||||||
const { current, next } = props.progress;
|
const { current, next } = props.progress;
|
||||||
@@ -107,7 +108,7 @@ function CustomHeader(props: StackHeaderProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HeaderCustomizationScreen({ navigation }: Props) {
|
export default function SimpleStackScreen({ navigation, ...rest }: Props) {
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
@@ -118,13 +119,13 @@ export default function HeaderCustomizationScreen({ navigation }: Props) {
|
|||||||
const [headerTitleCentered, setHeaderTitleCentered] = React.useState(true);
|
const [headerTitleCentered, setHeaderTitleCentered] = React.useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleStack.Navigator screenOptions={{ headerMode: 'float' }}>
|
<SimpleStack.Navigator {...rest}>
|
||||||
<SimpleStack.Screen
|
<SimpleStack.Screen
|
||||||
name="Article"
|
name="Article"
|
||||||
component={ArticleScreen}
|
component={ArticleScreen}
|
||||||
options={({ route }) => ({
|
options={({ route }) => ({
|
||||||
title: `Article by ${route.params?.author}`,
|
title: `Article by ${route.params?.author}`,
|
||||||
header: (props) => <CustomHeader {...props} />,
|
header: CustomHeader,
|
||||||
headerTintColor: '#fff',
|
headerTintColor: '#fff',
|
||||||
headerStyle: { backgroundColor: '#ff005d' },
|
headerStyle: { backgroundColor: '#ff005d' },
|
||||||
headerBackTitleVisible: false,
|
headerBackTitleVisible: false,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
|
AsyncStorage,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
Platform,
|
Platform,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
@@ -20,8 +21,6 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
Text,
|
Text,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import { createURL } from 'expo-linking';
|
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
||||||
import {
|
import {
|
||||||
InitialState,
|
InitialState,
|
||||||
NavigationContainer,
|
NavigationContainer,
|
||||||
@@ -39,10 +38,10 @@ import {
|
|||||||
import { useReduxDevToolsExtension } from '@react-navigation/devtools';
|
import { useReduxDevToolsExtension } from '@react-navigation/devtools';
|
||||||
|
|
||||||
import { restartApp } from './Restart';
|
import { restartApp } from './Restart';
|
||||||
|
import LinkingPrefixes from './LinkingPrefixes';
|
||||||
import SettingsItem from './Shared/SettingsItem';
|
import SettingsItem from './Shared/SettingsItem';
|
||||||
import SimpleStack from './Screens/SimpleStack';
|
import SimpleStack from './Screens/SimpleStack';
|
||||||
import ModalStack from './Screens/ModalStack';
|
import ModalStack from './Screens/ModalStack';
|
||||||
import MixedHeaderMode from './Screens/MixedHeaderMode';
|
|
||||||
import StackTransparent from './Screens/StackTransparent';
|
import StackTransparent from './Screens/StackTransparent';
|
||||||
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
|
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
|
||||||
import BottomTabs from './Screens/BottomTabs';
|
import BottomTabs from './Screens/BottomTabs';
|
||||||
@@ -71,10 +70,6 @@ const SCREENS = {
|
|||||||
title: 'Modal Stack',
|
title: 'Modal Stack',
|
||||||
component: ModalStack,
|
component: ModalStack,
|
||||||
},
|
},
|
||||||
MixedHeaderMode: {
|
|
||||||
title: 'Float + Screen Header Stack',
|
|
||||||
component: MixedHeaderMode,
|
|
||||||
},
|
|
||||||
StackTransparent: {
|
StackTransparent: {
|
||||||
title: 'Transparent Stack',
|
title: 'Transparent Stack',
|
||||||
component: StackTransparent,
|
component: StackTransparent,
|
||||||
@@ -225,7 +220,7 @@ export default function App() {
|
|||||||
// Android (bare): adb shell am start -a android.intent.action.VIEW -d "rne://127.0.0.1:19000/--/simple-stack"
|
// Android (bare): adb shell am start -a android.intent.action.VIEW -d "rne://127.0.0.1:19000/--/simple-stack"
|
||||||
// iOS (bare): xcrun simctl openurl booted rne://127.0.0.1:19000/--/simple-stack
|
// iOS (bare): xcrun simctl openurl booted rne://127.0.0.1:19000/--/simple-stack
|
||||||
// The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
|
// The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
|
||||||
prefixes: [createURL('/')],
|
prefixes: LinkingPrefixes,
|
||||||
config: {
|
config: {
|
||||||
initialRouteName: 'Home',
|
initialRouteName: 'Home',
|
||||||
screens: Object.keys(SCREENS).reduce<PathConfigMap>(
|
screens: Object.keys(SCREENS).reduce<PathConfigMap>(
|
||||||
|
|||||||
@@ -8,10 +8,9 @@
|
|||||||
"version": "independent",
|
"version": "independent",
|
||||||
"command": {
|
"command": {
|
||||||
"publish": {
|
"publish": {
|
||||||
"allowBranch": "main",
|
"allowBranch": "6.x",
|
||||||
"conventionalCommits": true,
|
"conventionalCommits": true,
|
||||||
"createRelease": "github",
|
"createRelease": "github",
|
||||||
"distTag": "next",
|
|
||||||
"message": "chore: publish",
|
"message": "chore: publish",
|
||||||
"ignoreChanges": [
|
"ignoreChanges": [
|
||||||
"**/__fixtures__/**",
|
"**/__fixtures__/**",
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -8,7 +8,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -25,13 +26,13 @@
|
|||||||
"example": "yarn --cwd example"
|
"example": "yarn --cwd example"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/config-conventional": "^12.1.1",
|
"@commitlint/config-conventional": "^12.0.1",
|
||||||
"@types/jest": "^26.0.22",
|
"@types/jest": "^26.0.19",
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
"codecov": "^3.8.1",
|
"codecov": "^3.8.1",
|
||||||
"commitlint": "^12.1.1",
|
"commitlint": "^12.0.1",
|
||||||
"eslint": "^7.23.0",
|
"eslint": "^7.21.0",
|
||||||
"eslint-config-satya164": "^3.1.10",
|
"eslint-config-satya164": "^3.1.9",
|
||||||
"husky": "^4.3.6",
|
"husky": "^4.3.6",
|
||||||
"jest": "^26.6.3",
|
"jest": "^26.6.3",
|
||||||
"lerna": "^4.0.0",
|
"lerna": "^4.0.0",
|
||||||
|
|||||||
@@ -3,52 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.3...@react-navigation/bottom-tabs@6.0.0-next.4) (2021-04-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* remove calls to removed Keyboard.removeListener in useIsKeyboardShown ([#9457](https://github.com/react-navigation/react-navigation/issues/9457)) ([d87857e](https://github.com/react-navigation/react-navigation/commit/d87857e5d93c19ebee2fd84eb4910e36001ec2a3))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.2...@react-navigation/bottom-tabs@6.0.0-next.3) (2021-03-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* use tab role on Android for accessibility ([de805a3](https://github.com/react-navigation/react-navigation/commit/de805a3ebf35db81cb7b7bcbf5cfd4a03e69c567))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add a Background component ([cbaabc1](https://github.com/react-navigation/react-navigation/commit/cbaabc1288e780698e499a00b9ca06ab9746a0da))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.1...@react-navigation/bottom-tabs@6.0.0-next.2) (2021-03-12)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0...@react-navigation/bottom-tabs@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.11.1...@react-navigation/bottom-tabs@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@5.11.1...@react-navigation/bottom-tabs@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Bottom tab navigator for React Navigation following iOS design guidelines.
|
Bottom tab navigator for React Navigation following iOS design guidelines.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/bottom-tab-navigator/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/bottom-tab-navigator/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/bottom-tabs",
|
"name": "@react-navigation/bottom-tabs",
|
||||||
"description": "Bottom tab navigator following iOS design guidelines",
|
"description": "Bottom tab navigator following iOS design guidelines",
|
||||||
"version": "6.0.0-next.4",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -29,37 +29,38 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/elements": "^1.0.0-next.4",
|
"@react-navigation/elements": "^1.0.0",
|
||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
"warn-once": "^0.0.1"
|
"warn-once": "^0.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-native-safe-area-context": "~3.2.0",
|
"react-native-safe-area-context": "3.1.9",
|
||||||
"react-native-screens": "~3.0.0",
|
"react-native-screens": "~2.15.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-safe-area-context": ">= 3.0.0",
|
"react-native-safe-area-context": ">= 3.0.0",
|
||||||
"react-native-screens": ">= 3.0.0"
|
"react-native-screens": ">= 2.15.0"
|
||||||
},
|
},
|
||||||
"react-native-builder-bob": {
|
"react-native-builder-bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Keyboard, Platform, EmitterSubscription } from 'react-native';
|
import { Keyboard, Platform } from 'react-native';
|
||||||
|
|
||||||
export default function useIsKeyboardShown() {
|
export default function useIsKeyboardShown() {
|
||||||
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
|
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
|
||||||
@@ -8,22 +8,22 @@ export default function useIsKeyboardShown() {
|
|||||||
const handleKeyboardShow = () => setIsKeyboardShown(true);
|
const handleKeyboardShow = () => setIsKeyboardShown(true);
|
||||||
const handleKeyboardHide = () => setIsKeyboardShown(false);
|
const handleKeyboardHide = () => setIsKeyboardShown(false);
|
||||||
|
|
||||||
let subscriptions: EmitterSubscription[];
|
|
||||||
|
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
subscriptions = [
|
Keyboard.addListener('keyboardWillShow', handleKeyboardShow);
|
||||||
Keyboard.addListener('keyboardWillShow', handleKeyboardShow),
|
Keyboard.addListener('keyboardWillHide', handleKeyboardHide);
|
||||||
Keyboard.addListener('keyboardWillHide', handleKeyboardHide),
|
|
||||||
];
|
|
||||||
} else {
|
} else {
|
||||||
subscriptions = [
|
Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
|
||||||
Keyboard.addListener('keyboardDidShow', handleKeyboardShow),
|
Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
|
||||||
Keyboard.addListener('keyboardDidHide', handleKeyboardHide),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
subscriptions.forEach((s) => s.remove());
|
if (Platform.OS === 'ios') {
|
||||||
|
Keyboard.removeListener('keyboardWillShow', handleKeyboardShow);
|
||||||
|
Keyboard.removeListener('keyboardWillHide', handleKeyboardHide);
|
||||||
|
} else {
|
||||||
|
Keyboard.removeListener('keyboardDidShow', handleKeyboardShow);
|
||||||
|
Keyboard.removeListener('keyboardDidHide', handleKeyboardHide);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -285,11 +285,7 @@ export default function BottomTabBar({
|
|||||||
]}
|
]}
|
||||||
pointerEvents={isTabBarHidden ? 'none' : 'auto'}
|
pointerEvents={isTabBarHidden ? 'none' : 'auto'}
|
||||||
>
|
>
|
||||||
<View
|
<View style={styles.content} onLayout={handleLayout}>
|
||||||
accessibilityRole="tablist"
|
|
||||||
style={styles.content}
|
|
||||||
onLayout={handleLayout}
|
|
||||||
>
|
|
||||||
{routes.map((route, index) => {
|
{routes.map((route, index) => {
|
||||||
const focused = index === state.index;
|
const focused = index === state.index;
|
||||||
const { options } = descriptors[route.key];
|
const { options } = descriptors[route.key];
|
||||||
@@ -326,7 +322,7 @@ export default function BottomTabBar({
|
|||||||
const accessibilityLabel =
|
const accessibilityLabel =
|
||||||
options.tabBarAccessibilityLabel !== undefined
|
options.tabBarAccessibilityLabel !== undefined
|
||||||
? options.tabBarAccessibilityLabel
|
? options.tabBarAccessibilityLabel
|
||||||
: typeof label === 'string' && Platform.OS === 'ios'
|
: typeof label === 'string'
|
||||||
? `${label}, tab, ${index + 1} of ${routes.length}`
|
? `${label}, tab, ${index + 1} of ${routes.length}`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -263,8 +263,7 @@ export default function BottomTabBarItem({
|
|||||||
onLongPress,
|
onLongPress,
|
||||||
testID,
|
testID,
|
||||||
accessibilityLabel,
|
accessibilityLabel,
|
||||||
// FIXME: accessibilityRole: 'tab' doesn't seem to work as expected on iOS
|
accessibilityRole: 'button',
|
||||||
accessibilityRole: Platform.select({ ios: 'button', default: 'tab' }),
|
|
||||||
accessibilityState: { selected: focused },
|
accessibilityState: { selected: focused },
|
||||||
// @ts-expect-error: keep for compatibility with older React Native versions
|
// @ts-expect-error: keep for compatibility with older React Native versions
|
||||||
accessibilityStates: focused ? ['selected'] : [],
|
accessibilityStates: focused ? ['selected'] : [],
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { StyleSheet } from 'react-native';
|
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||||
import { ScreenContainer } from 'react-native-screens';
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
|
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
|
||||||
import {
|
import {
|
||||||
NavigationHelpersContext,
|
NavigationHelpersContext,
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
|
useTheme,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import {
|
import {
|
||||||
Header,
|
Header,
|
||||||
@@ -33,6 +34,28 @@ type Props = BottomTabNavigationConfig & {
|
|||||||
descriptors: BottomTabDescriptorMap;
|
descriptors: BottomTabDescriptorMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function SceneContent({
|
||||||
|
isFocused,
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
}: {
|
||||||
|
isFocused: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
}) {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
accessibilityElementsHidden={!isFocused}
|
||||||
|
importantForAccessibility={isFocused ? 'auto' : 'no-hide-descendants'}
|
||||||
|
style={[styles.content, { backgroundColor: colors.background }, style]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function BottomTabView(props: Props) {
|
export default function BottomTabView(props: Props) {
|
||||||
const {
|
const {
|
||||||
tabBar = (props: BottomTabBarProps) => <BottomTabBar {...props} />,
|
tabBar = (props: BottomTabBarProps) => <BottomTabBar {...props} />,
|
||||||
@@ -127,26 +150,26 @@ export default function BottomTabView(props: Props) {
|
|||||||
visible={isFocused}
|
visible={isFocused}
|
||||||
enabled={detachInactiveScreens}
|
enabled={detachInactiveScreens}
|
||||||
>
|
>
|
||||||
<BottomTabBarHeightContext.Provider value={tabBarHeight}>
|
<SceneContent isFocused={isFocused} style={sceneContainerStyle}>
|
||||||
<Screen
|
<BottomTabBarHeightContext.Provider value={tabBarHeight}>
|
||||||
focused={isFocused}
|
<Screen
|
||||||
route={descriptor.route}
|
route={descriptor.route}
|
||||||
navigation={descriptor.navigation}
|
navigation={descriptor.navigation}
|
||||||
headerShown={descriptor.options.headerShown}
|
headerShown={descriptor.options.headerShown}
|
||||||
headerStatusBarHeight={
|
headerStatusBarHeight={
|
||||||
descriptor.options.headerStatusBarHeight
|
descriptor.options.headerStatusBarHeight
|
||||||
}
|
}
|
||||||
header={header({
|
header={header({
|
||||||
layout: dimensions,
|
layout: dimensions,
|
||||||
route: descriptor.route,
|
route: descriptor.route,
|
||||||
navigation: descriptor.navigation as BottomTabNavigationProp<ParamListBase>,
|
navigation: descriptor.navigation as BottomTabNavigationProp<ParamListBase>,
|
||||||
options: descriptor.options,
|
options: descriptor.options,
|
||||||
})}
|
})}
|
||||||
style={sceneContainerStyle}
|
>
|
||||||
>
|
{descriptor.render()}
|
||||||
{descriptor.render()}
|
</Screen>
|
||||||
</Screen>
|
</BottomTabBarHeightContext.Provider>
|
||||||
</BottomTabBarHeightContext.Provider>
|
</SceneContent>
|
||||||
</ScreenFallback>
|
</ScreenFallback>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -164,4 +187,7 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
shouldUseActivityState,
|
shouldUseActivityState,
|
||||||
} from 'react-native-screens';
|
} from 'react-native-screens';
|
||||||
import { ResourceSavingView } from '@react-navigation/elements';
|
import { ResourceSavingScene } from '@react-navigation/elements';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -34,8 +34,8 @@ export default function ScreenFallback({ visible, children, ...rest }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResourceSavingView visible={visible} {...rest}>
|
<ResourceSavingScene visible={visible} {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</ResourceSavingView>
|
</ResourceSavingScene>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,30 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.1...@react-navigation/core@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* properly resolve initialRouteNames ([c38906a](https://github.com/react-navigation/react-navigation/commit/c38906a7a09b997f37ce56734ea823c75ea744db))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* improve useNavigationState typing ([#9464](https://github.com/react-navigation/react-navigation/issues/9464)) ([84020a0](https://github.com/react-navigation/react-navigation/commit/84020a0b27ebae50d3037438a51d95eb31b02424))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0...@react-navigation/core@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/core
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.3...@react-navigation/core@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@5.14.3...@react-navigation/core@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/core",
|
"name": "@react-navigation/core",
|
||||||
"description": "Core utilities for building navigators",
|
"description": "Core utilities for building navigators",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -28,17 +28,18 @@
|
|||||||
"!**/__tests__"
|
"!**/__tests__"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^6.0.0-next.2",
|
"@react-navigation/routers": "^6.0.0-next.0",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"nanoid": "^3.1.22",
|
"nanoid": "^3.1.20",
|
||||||
"query-string": "^7.0.0",
|
"query-string": "^6.14.1",
|
||||||
"react-is": "^16.13.0"
|
"react-is": "^16.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-is": "^16.7.1",
|
"@types/react-is": "^16.7.1",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"immer": "^9.0.1",
|
"immer": "^8.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-test-renderer": "~16.13.1",
|
"react-test-renderer": "~16.13.1",
|
||||||
|
|||||||
@@ -2303,119 +2303,3 @@ it('throws if two screens map to the same pattern', () => {
|
|||||||
})
|
})
|
||||||
).not.toThrow();
|
).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correctly applies initialRouteName for config with similar route names', () => {
|
|
||||||
const path = '/weekly-earnings';
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
screens: {
|
|
||||||
RootTabs: {
|
|
||||||
screens: {
|
|
||||||
HomeTab: {
|
|
||||||
screens: {
|
|
||||||
Home: '',
|
|
||||||
WeeklyEarnings: 'weekly-earnings',
|
|
||||||
EventDetails: 'event-details/:eventId',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EarningsTab: {
|
|
||||||
initialRouteName: 'Earnings',
|
|
||||||
path: 'earnings',
|
|
||||||
screens: {
|
|
||||||
Earnings: '',
|
|
||||||
WeeklyEarnings: 'weekly-earnings',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'RootTabs',
|
|
||||||
state: {
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'HomeTab',
|
|
||||||
state: {
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'WeeklyEarnings',
|
|
||||||
path,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(getStateFromPath(path, config)).toEqual(state);
|
|
||||||
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
|
||||||
state
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly applies initialRouteName for config with similar route names v2', () => {
|
|
||||||
const path = '/earnings/weekly-earnings';
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
screens: {
|
|
||||||
RootTabs: {
|
|
||||||
screens: {
|
|
||||||
HomeTab: {
|
|
||||||
initialRouteName: 'Home',
|
|
||||||
screens: {
|
|
||||||
Home: '',
|
|
||||||
WeeklyEarnings: 'weekly-earnings',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EarningsTab: {
|
|
||||||
initialRouteName: 'Earnings',
|
|
||||||
path: 'earnings',
|
|
||||||
screens: {
|
|
||||||
Earnings: '',
|
|
||||||
WeeklyEarnings: 'weekly-earnings',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'RootTabs',
|
|
||||||
state: {
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'EarningsTab',
|
|
||||||
state: {
|
|
||||||
index: 1,
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: 'Earnings',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'WeeklyEarnings',
|
|
||||||
path,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(getStateFromPath(path, config)).toEqual(state);
|
|
||||||
expect(getStateFromPath(getPathFromState(state, config), config)).toEqual(
|
|
||||||
state
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type RouteConfig = {
|
|||||||
|
|
||||||
type InitialRouteConfig = {
|
type InitialRouteConfig = {
|
||||||
initialRouteName: string;
|
initialRouteName: string;
|
||||||
parentScreens: string[];
|
connectedRoutes: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ResultState = PartialState<NavigationState> & {
|
type ResultState = PartialState<NavigationState> & {
|
||||||
@@ -69,7 +69,7 @@ export default function getStateFromPath(
|
|||||||
if (options?.initialRouteName) {
|
if (options?.initialRouteName) {
|
||||||
initialRoutes.push({
|
initialRoutes.push({
|
||||||
initialRouteName: options.initialRouteName,
|
initialRouteName: options.initialRouteName,
|
||||||
parentScreens: [],
|
connectedRoutes: Object.keys(options.screens),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,8 +108,7 @@ export default function getStateFromPath(
|
|||||||
key,
|
key,
|
||||||
screens as PathConfigMap,
|
screens as PathConfigMap,
|
||||||
[],
|
[],
|
||||||
initialRoutes,
|
initialRoutes
|
||||||
[]
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -310,15 +309,12 @@ const createNormalizedConfigs = (
|
|||||||
routeConfig: PathConfigMap,
|
routeConfig: PathConfigMap,
|
||||||
routeNames: string[] = [],
|
routeNames: string[] = [],
|
||||||
initials: InitialRouteConfig[],
|
initials: InitialRouteConfig[],
|
||||||
parentScreens: string[],
|
|
||||||
parentPattern?: string
|
parentPattern?: string
|
||||||
): RouteConfig[] => {
|
): RouteConfig[] => {
|
||||||
const configs: RouteConfig[] = [];
|
const configs: RouteConfig[] = [];
|
||||||
|
|
||||||
routeNames.push(screen);
|
routeNames.push(screen);
|
||||||
|
|
||||||
parentScreens.push(screen);
|
|
||||||
|
|
||||||
const config = routeConfig[screen];
|
const config = routeConfig[screen];
|
||||||
|
|
||||||
if (typeof config === 'string') {
|
if (typeof config === 'string') {
|
||||||
@@ -354,7 +350,7 @@ const createNormalizedConfigs = (
|
|||||||
if (config.initialRouteName) {
|
if (config.initialRouteName) {
|
||||||
initials.push({
|
initials.push({
|
||||||
initialRouteName: config.initialRouteName,
|
initialRouteName: config.initialRouteName,
|
||||||
parentScreens,
|
connectedRoutes: Object.keys(config.screens),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +360,6 @@ const createNormalizedConfigs = (
|
|||||||
config.screens as PathConfigMap,
|
config.screens as PathConfigMap,
|
||||||
routeNames,
|
routeNames,
|
||||||
initials,
|
initials,
|
||||||
[...parentScreens],
|
|
||||||
pattern ?? parentPattern
|
pattern ?? parentPattern
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -430,23 +425,13 @@ const findParseConfigForRoute = (
|
|||||||
// Try to find an initial route connected with the one passed
|
// Try to find an initial route connected with the one passed
|
||||||
const findInitialRoute = (
|
const findInitialRoute = (
|
||||||
routeName: string,
|
routeName: string,
|
||||||
parentScreens: string[],
|
|
||||||
initialRoutes: InitialRouteConfig[]
|
initialRoutes: InitialRouteConfig[]
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
for (const config of initialRoutes) {
|
for (const config of initialRoutes) {
|
||||||
if (parentScreens.length === config.parentScreens.length) {
|
if (config.connectedRoutes.includes(routeName)) {
|
||||||
let sameParents = true;
|
return config.initialRouteName === routeName
|
||||||
for (let i = 0; i < parentScreens.length; i++) {
|
? undefined
|
||||||
if (parentScreens[i].localeCompare(config.parentScreens[i]) !== 0) {
|
: config.initialRouteName;
|
||||||
sameParents = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sameParents) {
|
|
||||||
return routeName !== config.initialRouteName
|
|
||||||
? config.initialRouteName
|
|
||||||
: undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -492,11 +477,7 @@ const createNestedStateObject = (
|
|||||||
) => {
|
) => {
|
||||||
let state: InitialState;
|
let state: InitialState;
|
||||||
let route = routes.shift() as ParsedRoute;
|
let route = routes.shift() as ParsedRoute;
|
||||||
const parentScreens: string[] = [];
|
let initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
|
|
||||||
let initialRoute = findInitialRoute(route.name, parentScreens, initialRoutes);
|
|
||||||
|
|
||||||
parentScreens.push(route.name);
|
|
||||||
|
|
||||||
state = createStateObject(initialRoute, route, routes.length === 0);
|
state = createStateObject(initialRoute, route, routes.length === 0);
|
||||||
|
|
||||||
@@ -504,7 +485,7 @@ const createNestedStateObject = (
|
|||||||
let nestedState = state;
|
let nestedState = state;
|
||||||
|
|
||||||
while ((route = routes.shift() as ParsedRoute)) {
|
while ((route = routes.shift() as ParsedRoute)) {
|
||||||
initialRoute = findInitialRoute(route.name, parentScreens, initialRoutes);
|
initialRoute = findInitialRoute(route.name, initialRoutes);
|
||||||
|
|
||||||
const nestedStateIndex =
|
const nestedStateIndex =
|
||||||
nestedState.index || nestedState.routes.length - 1;
|
nestedState.index || nestedState.routes.length - 1;
|
||||||
@@ -519,8 +500,6 @@ const createNestedStateObject = (
|
|||||||
nestedState = nestedState.routes[nestedStateIndex]
|
nestedState = nestedState.routes[nestedStateIndex]
|
||||||
.state as InitialState;
|
.state as InitialState;
|
||||||
}
|
}
|
||||||
|
|
||||||
parentScreens.push(route.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
|
import type { NavigationState } from '@react-navigation/routers';
|
||||||
import useNavigation from './useNavigation';
|
import useNavigation from './useNavigation';
|
||||||
import type { NavigationProp } from './types';
|
|
||||||
|
|
||||||
type Selector<ParamList extends ParamListBase, T> = (
|
type Selector<T> = (state: NavigationState) => T;
|
||||||
state: NavigationState<ParamList>
|
|
||||||
) => T;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to get a value from the current navigation state using a selector.
|
* Hook to get a value from the current navigation state using a selector.
|
||||||
*
|
*
|
||||||
* @param selector Selector function to get a value from the state.
|
* @param selector Selector function to get a value from the state.
|
||||||
*/
|
*/
|
||||||
export default function useNavigationState<ParamList extends ParamListBase, T>(
|
export default function useNavigationState<T>(selector: Selector<T>): T {
|
||||||
selector: Selector<ParamList, T>
|
const navigation = useNavigation();
|
||||||
): T {
|
|
||||||
const navigation = useNavigation<NavigationProp<ParamList>>();
|
|
||||||
|
|
||||||
// We don't care about the state value, we run the selector again at the end
|
// We don't care about the state value, we run the selector again at the end
|
||||||
// The state is only to make sure that there's a re-render when we have a new value
|
// The state is only to make sure that there's a re-render when we have a new value
|
||||||
|
|||||||
@@ -3,22 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@6.0.0-next.1...@react-navigation/devtools@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/devtools
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@6.0.0...@react-navigation/devtools@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/devtools
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.17...@react-navigation/devtools@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/devtools@5.1.17...@react-navigation/devtools@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/devtools
|
**Note:** Version bump only for package @react-navigation/devtools
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Developer tools for React Navigation.
|
Developer tools for React Navigation.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/devtools).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/devtools).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/devtools",
|
"name": "@react-navigation/devtools",
|
||||||
"description": "Developer tools for React Navigation",
|
"description": "Developer tools for React Navigation",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -29,14 +29,15 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^6.0.0-next.2",
|
"@react-navigation/core": "^6.0.0-next.0",
|
||||||
"deep-equal": "^2.0.5"
|
"deep-equal": "^2.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -3,52 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@6.0.0-next.3...@react-navigation/drawer@6.0.0-next.4) (2021-04-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* don't handle back button with permanent drawer ([b893968](https://github.com/react-navigation/react-navigation/commit/b89396888f46ba79af3cfd84be55fba79d8387d2))
|
|
||||||
* fix drawer overlay on web ([3241190](https://github.com/react-navigation/react-navigation/commit/3241190b19946c1cd0a744fb09a19d79ba683d74))
|
|
||||||
* only handle back button in drawer when focused ([5ae0bad](https://github.com/react-navigation/react-navigation/commit/5ae0badc44b576d464f8841822a911b18a698403))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@6.0.0-next.2...@react-navigation/drawer@6.0.0-next.3) (2021-03-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add a Background component ([cbaabc1](https://github.com/react-navigation/react-navigation/commit/cbaabc1288e780698e499a00b9ca06ab9746a0da))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@6.0.0-next.1...@react-navigation/drawer@6.0.0-next.2) (2021-03-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* export drawer button ([2c8401d](https://github.com/react-navigation/react-navigation/commit/2c8401d5cb347d37c96e5b30f8ad05c17fd22ea4))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@6.0.0...@react-navigation/drawer@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.2...@react-navigation/drawer@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/drawer@5.11.2...@react-navigation/drawer@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# `@react-navigation/drawer`
|
# `@react-navigation/drawer`
|
||||||
|
|
||||||
Drawer navigator for React Navigation following Material Design guidelines.
|
Drawer navigator for React Navigation following Material Design guidelines.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/drawer-navigator/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/drawer-navigator/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/drawer",
|
"name": "@react-navigation/drawer",
|
||||||
"description": "Drawer navigator component with animated transitions and gesturess",
|
"description": "Drawer navigator component with animated transitions and gesturess",
|
||||||
"version": "6.0.0-next.4",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -34,40 +34,41 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/elements": "^1.0.0-next.4",
|
"@react-navigation/elements": "^1.0.0",
|
||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
"warn-once": "^0.0.1"
|
"warn-once": "^0.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-native-gesture-handler": "~1.10.2",
|
"react-native-gesture-handler": "~1.8.0",
|
||||||
"react-native-reanimated": "~2.1.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-native-safe-area-context": "~3.2.0",
|
"react-native-safe-area-context": "3.1.9",
|
||||||
"react-native-screens": "~3.0.0",
|
"react-native-screens": "~2.15.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-gesture-handler": ">= 1.0.0",
|
"react-native-gesture-handler": ">= 1.0.0",
|
||||||
"react-native-reanimated": ">= 1.0.0",
|
"react-native-reanimated": ">= 1.0.0",
|
||||||
"react-native-safe-area-context": ">= 3.0.0",
|
"react-native-safe-area-context": ">= 3.0.0",
|
||||||
"react-native-screens": ">= 3.0.0"
|
"react-native-screens": ">= 2.15.0"
|
||||||
},
|
},
|
||||||
"react-native-builder-bob": {
|
"react-native-builder-bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -11,16 +11,12 @@ export { default as DrawerItem } from './views/DrawerItem';
|
|||||||
export { default as DrawerItemList } from './views/DrawerItemList';
|
export { default as DrawerItemList } from './views/DrawerItemList';
|
||||||
export { default as DrawerContent } from './views/DrawerContent';
|
export { default as DrawerContent } from './views/DrawerContent';
|
||||||
export { default as DrawerContentScrollView } from './views/DrawerContentScrollView';
|
export { default as DrawerContentScrollView } from './views/DrawerContentScrollView';
|
||||||
export { default as DrawerToggleButton } from './views/DrawerToggleButton';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
export { default as DrawerGestureContext } from './utils/DrawerGestureContext';
|
export { default as DrawerGestureContext } from './utils/DrawerGestureContext';
|
||||||
|
|
||||||
export { default as DrawerProgressContext } from './utils/DrawerProgressContext';
|
|
||||||
export { default as useDrawerProgress } from './utils/useDrawerProgress';
|
|
||||||
|
|
||||||
export { default as getDrawerStatusFromState } from './utils/getDrawerStatusFromState';
|
export { default as getDrawerStatusFromState } from './utils/getDrawerStatusFromState';
|
||||||
export { default as useDrawerStatus } from './utils/useDrawerStatus';
|
export { default as useDrawerStatus } from './utils/useDrawerStatus';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import type { StyleProp, ViewStyle, TextStyle } from 'react-native';
|
import type { StyleProp, ViewStyle, TextStyle } from 'react-native';
|
||||||
import type {
|
import type Animated from 'react-native-reanimated';
|
||||||
PanGestureHandler,
|
import type { PanGestureHandlerProperties } from 'react-native-gesture-handler';
|
||||||
PanGestureHandlerProperties,
|
|
||||||
} from 'react-native-gesture-handler';
|
|
||||||
import type {
|
import type {
|
||||||
Route,
|
Route,
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
@@ -35,18 +33,6 @@ export type DrawerNavigationConfig = {
|
|||||||
* Defaults to `true`.
|
* Defaults to `true`.
|
||||||
*/
|
*/
|
||||||
detachInactiveScreens?: boolean;
|
detachInactiveScreens?: boolean;
|
||||||
/**
|
|
||||||
* Whether to use the legacy implementation based on Reanimated 1.
|
|
||||||
* The new implementation based on Reanimated 2 will perform better,
|
|
||||||
* but you need additional configuration and need to use Hermes with Flipper to debug.
|
|
||||||
*
|
|
||||||
* This defaults to `true` in following cases:
|
|
||||||
* - Reanimated 2 is not configured
|
|
||||||
* - App is connected to Chrome debugger (Reanimated 2 cannot be used with Chrome debugger)
|
|
||||||
*
|
|
||||||
* Otherwise, it defaults to `false`
|
|
||||||
*/
|
|
||||||
useLegacyImplementation?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DrawerNavigationOptions = HeaderOptions & {
|
export type DrawerNavigationOptions = HeaderOptions & {
|
||||||
@@ -221,6 +207,11 @@ export type DrawerContentComponentProps = {
|
|||||||
state: DrawerNavigationState<ParamListBase>;
|
state: DrawerNavigationState<ParamListBase>;
|
||||||
navigation: DrawerNavigationHelpers;
|
navigation: DrawerNavigationHelpers;
|
||||||
descriptors: DrawerDescriptorMap;
|
descriptors: DrawerDescriptorMap;
|
||||||
|
/**
|
||||||
|
* Animated node which represents the current progress of the drawer's open state.
|
||||||
|
* `0` is closed, `1` is open.
|
||||||
|
*/
|
||||||
|
progress: Animated.Node<number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DrawerHeaderProps = {
|
export type DrawerHeaderProps = {
|
||||||
@@ -277,24 +268,3 @@ export type DrawerDescriptor = Descriptor<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export type DrawerDescriptorMap = Record<string, DrawerDescriptor>;
|
export type DrawerDescriptorMap = Record<string, DrawerDescriptor>;
|
||||||
|
|
||||||
export type DrawerProps = {
|
|
||||||
dimensions: { width: number; height: number };
|
|
||||||
drawerPosition: 'left' | 'right';
|
|
||||||
drawerStyle?: StyleProp<ViewStyle>;
|
|
||||||
drawerType: 'front' | 'back' | 'slide' | 'permanent';
|
|
||||||
gestureHandlerProps?: React.ComponentProps<typeof PanGestureHandler>;
|
|
||||||
hideStatusBarOnOpen: boolean;
|
|
||||||
keyboardDismissMode: 'none' | 'on-drag';
|
|
||||||
onClose: () => void;
|
|
||||||
onOpen: () => void;
|
|
||||||
open: boolean;
|
|
||||||
overlayStyle?: StyleProp<ViewStyle>;
|
|
||||||
renderDrawerContent: () => React.ReactNode;
|
|
||||||
renderSceneContent: () => React.ReactNode;
|
|
||||||
statusBarAnimation: 'slide' | 'none' | 'fade';
|
|
||||||
swipeDistanceThreshold: number;
|
|
||||||
swipeEdgeWidth: number;
|
|
||||||
swipeEnabled: boolean;
|
|
||||||
swipeVelocityThreshold: number;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import type Animated from 'react-native-reanimated';
|
|
||||||
|
|
||||||
export default React.createContext<
|
|
||||||
Readonly<Animated.SharedValue<number>> | Animated.Node<number> | undefined
|
|
||||||
>(undefined);
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import type Animated from 'react-native-reanimated';
|
|
||||||
import DrawerProgressContext from './DrawerProgressContext';
|
|
||||||
|
|
||||||
export default function useDrawerProgress():
|
|
||||||
| Readonly<Animated.SharedValue<number>>
|
|
||||||
| Animated.Node<number> {
|
|
||||||
const progress = React.useContext(DrawerProgressContext);
|
|
||||||
|
|
||||||
if (progress === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
"Couldn't find a drawer. Is your component inside a drawer navigator?"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return progress;
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,24 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
ViewStyle,
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
I18nManager,
|
I18nManager,
|
||||||
Platform,
|
Platform,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
|
StyleProp,
|
||||||
View,
|
View,
|
||||||
InteractionManager,
|
InteractionManager,
|
||||||
|
Pressable,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
import { PanGestureHandler, GestureState } from '../GestureHandler';
|
import {
|
||||||
|
PanGestureHandler,
|
||||||
|
TapGestureHandler,
|
||||||
|
GestureState,
|
||||||
|
} from './GestureHandler';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import DrawerProgressContext from '../../utils/DrawerProgressContext';
|
|
||||||
import type { DrawerProps } from '../../types';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Clock,
|
Clock,
|
||||||
@@ -51,6 +56,7 @@ const UNSET = -1;
|
|||||||
const DIRECTION_LEFT = 1;
|
const DIRECTION_LEFT = 1;
|
||||||
const DIRECTION_RIGHT = -1;
|
const DIRECTION_RIGHT = -1;
|
||||||
|
|
||||||
|
const SWIPE_DISTANCE_THRESHOLD_DEFAULT = 60;
|
||||||
const SWIPE_DISTANCE_MINIMUM = 5;
|
const SWIPE_DISTANCE_MINIMUM = 5;
|
||||||
|
|
||||||
const DEFAULT_DRAWER_WIDTH = '80%';
|
const DEFAULT_DRAWER_WIDTH = '80%';
|
||||||
@@ -69,8 +75,54 @@ const ANIMATED_ONE = new Animated.Value(1);
|
|||||||
|
|
||||||
type Binary = 0 | 1;
|
type Binary = 0 | 1;
|
||||||
|
|
||||||
export default class DrawerView extends React.Component<DrawerProps> {
|
type Renderer = (props: { progress: Animated.Node<number> }) => React.ReactNode;
|
||||||
componentDidUpdate(prevProps: DrawerProps) {
|
|
||||||
|
type Props = {
|
||||||
|
open: boolean;
|
||||||
|
onOpen: () => void;
|
||||||
|
onClose: () => void;
|
||||||
|
gestureEnabled: boolean;
|
||||||
|
swipeEnabled: boolean;
|
||||||
|
drawerPosition: 'left' | 'right';
|
||||||
|
drawerType: 'front' | 'back' | 'slide' | 'permanent';
|
||||||
|
keyboardDismissMode: 'none' | 'on-drag';
|
||||||
|
swipeEdgeWidth: number;
|
||||||
|
swipeDistanceThreshold?: number;
|
||||||
|
swipeVelocityThreshold: number;
|
||||||
|
hideStatusBarOnOpen: boolean;
|
||||||
|
statusBarAnimation: 'slide' | 'none' | 'fade';
|
||||||
|
overlayStyle?: StyleProp<ViewStyle>;
|
||||||
|
drawerStyle?: StyleProp<ViewStyle>;
|
||||||
|
sceneContainerStyle?: StyleProp<ViewStyle>;
|
||||||
|
renderDrawerContent: Renderer;
|
||||||
|
renderSceneContent: Renderer;
|
||||||
|
gestureHandlerProps?: React.ComponentProps<typeof PanGestureHandler>;
|
||||||
|
dimensions: { width: number; height: number };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DrawerView extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
drawerPosition: I18nManager.isRTL ? 'left' : 'right',
|
||||||
|
drawerType: 'front',
|
||||||
|
gestureEnabled: true,
|
||||||
|
swipeEnabled:
|
||||||
|
Platform.OS !== 'web' &&
|
||||||
|
Platform.OS !== 'windows' &&
|
||||||
|
Platform.OS !== 'macos',
|
||||||
|
swipeEdgeWidth: 32,
|
||||||
|
swipeVelocityThreshold: 500,
|
||||||
|
keyboardDismissMode: 'on-drag',
|
||||||
|
hideStatusBarOnOpen: false,
|
||||||
|
statusBarAnimation: 'slide',
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
document?.body?.addEventListener?.('keyup', this.handleEscape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: Props) {
|
||||||
const {
|
const {
|
||||||
open,
|
open,
|
||||||
drawerPosition,
|
drawerPosition,
|
||||||
@@ -105,7 +157,11 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.swipeDistanceThreshold !== swipeDistanceThreshold) {
|
if (prevProps.swipeDistanceThreshold !== swipeDistanceThreshold) {
|
||||||
this.swipeDistanceThreshold.setValue(swipeDistanceThreshold);
|
this.swipeDistanceThreshold.setValue(
|
||||||
|
swipeDistanceThreshold !== undefined
|
||||||
|
? swipeDistanceThreshold
|
||||||
|
: SWIPE_DISTANCE_THRESHOLD_DEFAULT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.swipeVelocityThreshold !== swipeVelocityThreshold) {
|
if (prevProps.swipeVelocityThreshold !== swipeVelocityThreshold) {
|
||||||
@@ -116,8 +172,22 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.toggleStatusBar(false);
|
this.toggleStatusBar(false);
|
||||||
this.handleEndInteraction();
|
this.handleEndInteraction();
|
||||||
|
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
document?.body?.removeEventListener?.('keyup', this.handleEscape);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleEscape = (e: KeyboardEvent) => {
|
||||||
|
const { open, onClose } = this.props;
|
||||||
|
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
if (open) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private handleEndInteraction = () => {
|
private handleEndInteraction = () => {
|
||||||
if (this.interactionHandle !== undefined) {
|
if (this.interactionHandle !== undefined) {
|
||||||
InteractionManager.clearInteractionHandle(this.interactionHandle);
|
InteractionManager.clearInteractionHandle(this.interactionHandle);
|
||||||
@@ -234,7 +304,9 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
private swipeDistanceThreshold = new Value<number>(
|
private swipeDistanceThreshold = new Value<number>(
|
||||||
this.props.swipeDistanceThreshold
|
this.props.swipeDistanceThreshold !== undefined
|
||||||
|
? this.props.swipeDistanceThreshold
|
||||||
|
: SWIPE_DISTANCE_THRESHOLD_DEFAULT
|
||||||
);
|
);
|
||||||
private swipeVelocityThreshold = new Value<number>(
|
private swipeVelocityThreshold = new Value<number>(
|
||||||
this.props.swipeVelocityThreshold
|
this.props.swipeVelocityThreshold
|
||||||
@@ -444,6 +516,18 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
private handleTapStateChange = event([
|
||||||
|
{
|
||||||
|
nativeEvent: {
|
||||||
|
oldState: (s: Animated.Value<number>) =>
|
||||||
|
cond(
|
||||||
|
eq(s, GestureState.ACTIVE),
|
||||||
|
set(this.manuallyTriggerSpring, TRUE)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
private handleContainerLayout = (e: LayoutChangeEvent) =>
|
private handleContainerLayout = (e: LayoutChangeEvent) =>
|
||||||
this.containerWidth.setValue(e.nativeEvent.layout.width);
|
this.containerWidth.setValue(e.nativeEvent.layout.width);
|
||||||
|
|
||||||
@@ -484,10 +568,12 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
open,
|
open,
|
||||||
|
gestureEnabled,
|
||||||
swipeEnabled,
|
swipeEnabled,
|
||||||
drawerPosition,
|
drawerPosition,
|
||||||
drawerType,
|
drawerType,
|
||||||
swipeEdgeWidth,
|
swipeEdgeWidth,
|
||||||
|
sceneContainerStyle,
|
||||||
drawerStyle,
|
drawerStyle,
|
||||||
overlayStyle,
|
overlayStyle,
|
||||||
renderDrawerContent,
|
renderDrawerContent,
|
||||||
@@ -533,103 +619,109 @@ export default class DrawerView extends React.Component<DrawerProps> {
|
|||||||
const progress = drawerType === 'permanent' ? ANIMATED_ONE : this.progress;
|
const progress = drawerType === 'permanent' ? ANIMATED_ONE : this.progress;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerProgressContext.Provider value={progress}>
|
<PanGestureHandler
|
||||||
<PanGestureHandler
|
activeOffsetX={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
||||||
activeOffsetX={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
failOffsetY={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
||||||
failOffsetY={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
onGestureEvent={this.handleGestureEvent}
|
||||||
onGestureEvent={this.handleGestureEvent}
|
onHandlerStateChange={this.handleGestureStateChange}
|
||||||
onHandlerStateChange={this.handleGestureStateChange}
|
hitSlop={hitSlop}
|
||||||
hitSlop={hitSlop}
|
enabled={drawerType !== 'permanent' && gestureEnabled && swipeEnabled}
|
||||||
enabled={drawerType !== 'permanent' && swipeEnabled}
|
{...gestureHandlerProps}
|
||||||
{...gestureHandlerProps}
|
>
|
||||||
|
<Animated.View
|
||||||
|
onLayout={this.handleContainerLayout}
|
||||||
|
style={[
|
||||||
|
styles.main,
|
||||||
|
{
|
||||||
|
flexDirection:
|
||||||
|
drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row',
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
onLayout={this.handleContainerLayout}
|
|
||||||
style={[
|
style={[
|
||||||
styles.main,
|
styles.content,
|
||||||
{
|
{ transform: [{ translateX: contentTranslateX }] },
|
||||||
flexDirection:
|
sceneContainerStyle as any,
|
||||||
drawerType === 'permanent' && !isRight
|
|
||||||
? 'row-reverse'
|
|
||||||
: 'row',
|
|
||||||
},
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Animated.View
|
<View
|
||||||
style={[
|
accessibilityElementsHidden={isOpen && drawerType !== 'permanent'}
|
||||||
styles.content,
|
importantForAccessibility={
|
||||||
{ transform: [{ translateX: contentTranslateX }] },
|
isOpen && drawerType !== 'permanent'
|
||||||
]}
|
? 'no-hide-descendants'
|
||||||
>
|
: 'auto'
|
||||||
<View
|
|
||||||
accessibilityElementsHidden={
|
|
||||||
isOpen && drawerType !== 'permanent'
|
|
||||||
}
|
|
||||||
importantForAccessibility={
|
|
||||||
isOpen && drawerType !== 'permanent'
|
|
||||||
? 'no-hide-descendants'
|
|
||||||
: 'auto'
|
|
||||||
}
|
|
||||||
style={styles.content}
|
|
||||||
>
|
|
||||||
{renderSceneContent()}
|
|
||||||
</View>
|
|
||||||
{
|
|
||||||
// Disable overlay if sidebar is permanent
|
|
||||||
drawerType === 'permanent' ? null : (
|
|
||||||
<Overlay
|
|
||||||
progress={progress}
|
|
||||||
onPress={() => this.toggleDrawer(false)}
|
|
||||||
style={overlayStyle as any}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</Animated.View>
|
style={styles.content}
|
||||||
<Animated.Code
|
|
||||||
// This is needed to make sure that container width updates with `setValue`
|
|
||||||
// Without this, it won't update when not used in styles
|
|
||||||
exec={this.containerWidth}
|
|
||||||
/>
|
|
||||||
{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={isOpen && drawerType !== 'permanent'}
|
|
||||||
removeClippedSubviews={Platform.OS !== 'ios'}
|
|
||||||
onLayout={this.handleDrawerLayout}
|
|
||||||
style={[
|
|
||||||
styles.container,
|
|
||||||
{
|
|
||||||
transform: [{ translateX: drawerTranslateX }],
|
|
||||||
opacity: this.drawerOpacity,
|
|
||||||
},
|
|
||||||
drawerType === 'permanent'
|
|
||||||
? // Without this, the `left`/`right` values don't get reset
|
|
||||||
isRight
|
|
||||||
? { right: 0 }
|
|
||||||
: { left: 0 }
|
|
||||||
: [
|
|
||||||
styles.nonPermanent,
|
|
||||||
isRight ? { right: offset } : { left: offset },
|
|
||||||
{ zIndex: drawerType === 'back' ? -1 : 0 },
|
|
||||||
],
|
|
||||||
drawerStyle as any,
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
{renderDrawerContent()}
|
{renderSceneContent({ progress })}
|
||||||
</Animated.View>
|
</View>
|
||||||
|
{
|
||||||
|
// Disable overlay if sidebar is permanent
|
||||||
|
drawerType === 'permanent' ? null : Platform.OS === 'web' ||
|
||||||
|
Platform.OS === 'windows' ||
|
||||||
|
Platform.OS === 'macos' ? (
|
||||||
|
<Pressable
|
||||||
|
onPress={
|
||||||
|
gestureEnabled ? () => this.toggleDrawer(false) : undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Overlay progress={progress} style={overlayStyle as any} />
|
||||||
|
</Pressable>
|
||||||
|
) : (
|
||||||
|
<TapGestureHandler
|
||||||
|
enabled={gestureEnabled}
|
||||||
|
onHandlerStateChange={this.handleTapStateChange}
|
||||||
|
>
|
||||||
|
<Overlay progress={progress} style={overlayStyle as any} />
|
||||||
|
</TapGestureHandler>
|
||||||
|
)
|
||||||
|
}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</PanGestureHandler>
|
<Animated.Code
|
||||||
</DrawerProgressContext.Provider>
|
// This is needed to make sure that container width updates with `setValue`
|
||||||
|
// Without this, it won't update when not used in styles
|
||||||
|
exec={this.containerWidth}
|
||||||
|
/>
|
||||||
|
{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={isOpen && drawerType !== 'permanent'}
|
||||||
|
removeClippedSubviews={Platform.OS !== 'ios'}
|
||||||
|
onLayout={this.handleDrawerLayout}
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
{
|
||||||
|
transform: [{ translateX: drawerTranslateX }],
|
||||||
|
opacity: this.drawerOpacity,
|
||||||
|
},
|
||||||
|
drawerType === 'permanent'
|
||||||
|
? // Without this, the `left`/`right` values don't get reset
|
||||||
|
isRight
|
||||||
|
? { right: 0 }
|
||||||
|
: { left: 0 }
|
||||||
|
: [
|
||||||
|
styles.nonPermanent,
|
||||||
|
isRight ? { right: offset } : { left: offset },
|
||||||
|
{ zIndex: drawerType === 'back' ? -1 : 0 },
|
||||||
|
],
|
||||||
|
drawerStyle as any,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{renderDrawerContent({ progress })}
|
||||||
|
</Animated.View>
|
||||||
|
</Animated.View>
|
||||||
|
</PanGestureHandler>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,10 @@ import {
|
|||||||
I18nManager,
|
I18nManager,
|
||||||
Platform,
|
Platform,
|
||||||
BackHandler,
|
BackHandler,
|
||||||
|
NativeEventSubscription,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { ScreenContainer } from 'react-native-screens';
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import Animated from 'react-native-reanimated';
|
|
||||||
import {
|
import {
|
||||||
NavigationHelpersContext,
|
NavigationHelpersContext,
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
@@ -27,6 +27,7 @@ import { GestureHandlerRootView } from './GestureHandler';
|
|||||||
import ScreenFallback from './ScreenFallback';
|
import ScreenFallback from './ScreenFallback';
|
||||||
import DrawerToggleButton from './DrawerToggleButton';
|
import DrawerToggleButton from './DrawerToggleButton';
|
||||||
import DrawerContent from './DrawerContent';
|
import DrawerContent from './DrawerContent';
|
||||||
|
import Drawer from './Drawer';
|
||||||
import DrawerStatusContext from '../utils/DrawerStatusContext';
|
import DrawerStatusContext from '../utils/DrawerStatusContext';
|
||||||
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
||||||
import getDrawerStatusFromState from '../utils/getDrawerStatusFromState';
|
import getDrawerStatusFromState from '../utils/getDrawerStatusFromState';
|
||||||
@@ -37,7 +38,6 @@ import type {
|
|||||||
DrawerContentComponentProps,
|
DrawerContentComponentProps,
|
||||||
DrawerHeaderProps,
|
DrawerHeaderProps,
|
||||||
DrawerNavigationProp,
|
DrawerNavigationProp,
|
||||||
DrawerProps,
|
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
type Props = DrawerNavigationConfig & {
|
type Props = DrawerNavigationConfig & {
|
||||||
@@ -77,17 +77,7 @@ function DrawerViewBase({
|
|||||||
<DrawerContent {...props} />
|
<DrawerContent {...props} />
|
||||||
),
|
),
|
||||||
detachInactiveScreens = true,
|
detachInactiveScreens = true,
|
||||||
// Running in chrome debugger
|
|
||||||
// @ts-expect-error
|
|
||||||
useLegacyImplementation = !global.nativeCallSyncHook ||
|
|
||||||
// Reanimated 2 is not configured
|
|
||||||
// @ts-expect-error: the type definitions are incomplete
|
|
||||||
!Animated.isConfigured?.(),
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const Drawer: React.ComponentType<DrawerProps> = useLegacyImplementation
|
|
||||||
? require('./legacy/Drawer').default
|
|
||||||
: require('./modern/Drawer').default;
|
|
||||||
|
|
||||||
const focusedRouteKey = state.routes[state.index].key;
|
const focusedRouteKey = state.routes[state.index].key;
|
||||||
const {
|
const {
|
||||||
drawerHideStatusBarOnOpen = false,
|
drawerHideStatusBarOnOpen = false,
|
||||||
@@ -95,14 +85,14 @@ function DrawerViewBase({
|
|||||||
drawerStatusBarAnimation = 'slide',
|
drawerStatusBarAnimation = 'slide',
|
||||||
drawerStyle,
|
drawerStyle,
|
||||||
drawerType = Platform.select({ ios: 'slide', default: 'front' }),
|
drawerType = Platform.select({ ios: 'slide', default: 'front' }),
|
||||||
|
gestureEnabled,
|
||||||
gestureHandlerProps,
|
gestureHandlerProps,
|
||||||
keyboardDismissMode = 'on-drag',
|
keyboardDismissMode = 'on-drag',
|
||||||
overlayColor = 'rgba(0, 0, 0, 0.5)',
|
overlayColor = 'rgba(0, 0, 0, 0.5)',
|
||||||
swipeEdgeWidth = 32,
|
sceneContainerStyle,
|
||||||
swipeEnabled = Platform.OS !== 'web' &&
|
swipeEdgeWidth,
|
||||||
Platform.OS !== 'windows' &&
|
swipeEnabled,
|
||||||
Platform.OS !== 'macos',
|
swipeMinDistance,
|
||||||
swipeMinDistance = 60,
|
|
||||||
} = descriptors[focusedRouteKey].options;
|
} = descriptors[focusedRouteKey].options;
|
||||||
|
|
||||||
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
const [loaded, setLoaded] = React.useState([focusedRouteKey]);
|
||||||
@@ -132,53 +122,27 @@ function DrawerViewBase({
|
|||||||
}, [navigation, state.key]);
|
}, [navigation, state.key]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (drawerStatus !== 'open' || drawerType === 'permanent') {
|
let subscription: NativeEventSubscription | undefined;
|
||||||
return;
|
|
||||||
|
if (drawerStatus === 'open') {
|
||||||
|
// We only add the subscription when drawer opens
|
||||||
|
// This way we can make sure that the subscription is added as late as possible
|
||||||
|
// This will make sure that our handler will run first when back button is pressed
|
||||||
|
subscription = BackHandler.addEventListener('hardwareBackPress', () => {
|
||||||
|
handleDrawerClose();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
return () => subscription?.remove();
|
||||||
// We shouldn't handle the back button if the parent screen isn't focused
|
}, [handleDrawerClose, drawerStatus, navigation, state.key]);
|
||||||
// This will avoid the drawer overriding event listeners from a focused screen
|
|
||||||
if (!navigation.isFocused()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDrawerClose();
|
const renderDrawerContent = ({ progress }: any) => {
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEscape = (e: KeyboardEvent) => {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
handleClose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We only add the listeners when drawer opens
|
|
||||||
// This way we can make sure that the listener is added as late as possible
|
|
||||||
// This will make sure that our handler will run first when back button is pressed
|
|
||||||
const subscription = BackHandler.addEventListener(
|
|
||||||
'hardwareBackPress',
|
|
||||||
handleClose
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Platform.OS === 'web') {
|
|
||||||
document?.body?.addEventListener?.('keyup', handleEscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
subscription.remove();
|
|
||||||
|
|
||||||
if (Platform.OS === 'web') {
|
|
||||||
document?.body?.removeEventListener?.('keyup', handleEscape);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [drawerStatus, drawerType, handleDrawerClose, navigation]);
|
|
||||||
|
|
||||||
const renderDrawerContent = () => {
|
|
||||||
return (
|
return (
|
||||||
<DrawerPositionContext.Provider value={drawerPosition}>
|
<DrawerPositionContext.Provider value={drawerPosition}>
|
||||||
{drawerContent({
|
{drawerContent({
|
||||||
|
progress: progress,
|
||||||
state: state,
|
state: state,
|
||||||
navigation: navigation,
|
navigation: navigation,
|
||||||
descriptors: descriptors,
|
descriptors: descriptors,
|
||||||
@@ -217,7 +181,6 @@ function DrawerViewBase({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
sceneContainerStyle,
|
|
||||||
} = descriptor.options;
|
} = descriptor.options;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -228,7 +191,6 @@ function DrawerViewBase({
|
|||||||
enabled={detachInactiveScreens}
|
enabled={detachInactiveScreens}
|
||||||
>
|
>
|
||||||
<Screen
|
<Screen
|
||||||
focused={isFocused}
|
|
||||||
route={descriptor.route}
|
route={descriptor.route}
|
||||||
navigation={descriptor.navigation}
|
navigation={descriptor.navigation}
|
||||||
headerShown={descriptor.options.headerShown}
|
headerShown={descriptor.options.headerShown}
|
||||||
@@ -239,7 +201,6 @@ function DrawerViewBase({
|
|||||||
navigation: descriptor.navigation as DrawerNavigationProp<ParamListBase>,
|
navigation: descriptor.navigation as DrawerNavigationProp<ParamListBase>,
|
||||||
options: descriptor.options,
|
options: descriptor.options,
|
||||||
})}
|
})}
|
||||||
style={sceneContainerStyle}
|
|
||||||
>
|
>
|
||||||
{descriptor.render()}
|
{descriptor.render()}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -254,18 +215,17 @@ function DrawerViewBase({
|
|||||||
<DrawerStatusContext.Provider value={drawerStatus}>
|
<DrawerStatusContext.Provider value={drawerStatus}>
|
||||||
<Drawer
|
<Drawer
|
||||||
open={drawerStatus !== 'closed'}
|
open={drawerStatus !== 'closed'}
|
||||||
|
gestureEnabled={gestureEnabled}
|
||||||
|
swipeEnabled={swipeEnabled}
|
||||||
onOpen={handleDrawerOpen}
|
onOpen={handleDrawerOpen}
|
||||||
onClose={handleDrawerClose}
|
onClose={handleDrawerClose}
|
||||||
gestureHandlerProps={gestureHandlerProps}
|
gestureHandlerProps={gestureHandlerProps}
|
||||||
swipeEnabled={swipeEnabled}
|
|
||||||
swipeEdgeWidth={swipeEdgeWidth}
|
|
||||||
swipeVelocityThreshold={500}
|
|
||||||
swipeDistanceThreshold={swipeMinDistance}
|
|
||||||
hideStatusBarOnOpen={drawerHideStatusBarOnOpen}
|
|
||||||
statusBarAnimation={drawerStatusBarAnimation}
|
|
||||||
keyboardDismissMode={keyboardDismissMode}
|
|
||||||
drawerType={drawerType}
|
drawerType={drawerType}
|
||||||
drawerPosition={drawerPosition}
|
drawerPosition={drawerPosition}
|
||||||
|
sceneContainerStyle={[
|
||||||
|
{ backgroundColor: colors.background },
|
||||||
|
sceneContainerStyle,
|
||||||
|
]}
|
||||||
drawerStyle={[
|
drawerStyle={[
|
||||||
{
|
{
|
||||||
width: getDefaultDrawerWidth(dimensions),
|
width: getDefaultDrawerWidth(dimensions),
|
||||||
@@ -284,8 +244,13 @@ function DrawerViewBase({
|
|||||||
drawerStyle,
|
drawerStyle,
|
||||||
]}
|
]}
|
||||||
overlayStyle={{ backgroundColor: overlayColor }}
|
overlayStyle={{ backgroundColor: overlayColor }}
|
||||||
|
swipeEdgeWidth={swipeEdgeWidth}
|
||||||
|
swipeDistanceThreshold={swipeMinDistance}
|
||||||
|
hideStatusBarOnOpen={drawerHideStatusBarOnOpen}
|
||||||
|
statusBarAnimation={drawerStatusBarAnimation}
|
||||||
renderDrawerContent={renderDrawerContent}
|
renderDrawerContent={renderDrawerContent}
|
||||||
renderSceneContent={renderSceneContent}
|
renderSceneContent={renderSceneContent}
|
||||||
|
keyboardDismissMode={keyboardDismissMode}
|
||||||
dimensions={dimensions}
|
dimensions={dimensions}
|
||||||
/>
|
/>
|
||||||
</DrawerStatusContext.Provider>
|
</DrawerStatusContext.Provider>
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Pressable, Platform, StyleSheet } from 'react-native';
|
import { Platform, StyleSheet } from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
interpolate: interpolateDeprecated,
|
interpolate: interpolateDeprecated,
|
||||||
|
// @ts-expect-error: this property is only present in Reanimated 2
|
||||||
interpolateNode,
|
interpolateNode,
|
||||||
cond,
|
cond,
|
||||||
greaterThan,
|
greaterThan,
|
||||||
} = Animated;
|
} = Animated;
|
||||||
|
|
||||||
const interpolate: typeof interpolateNode =
|
const interpolate: typeof interpolateDeprecated =
|
||||||
interpolateNode ?? interpolateDeprecated;
|
interpolateNode ?? interpolateDeprecated;
|
||||||
|
|
||||||
const PROGRESS_EPSILON = 0.05;
|
const PROGRESS_EPSILON = 0.05;
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof Animated.View> & {
|
type Props = React.ComponentProps<typeof Animated.View> & {
|
||||||
progress: Animated.Node<number>;
|
progress: Animated.Node<number>;
|
||||||
onPress: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Overlay = React.forwardRef(function Overlay(
|
const Overlay = React.forwardRef(function Overlay(
|
||||||
{ progress, onPress, style, ...props }: Props,
|
{ progress, style, ...props }: Props,
|
||||||
ref: React.Ref<Animated.View>
|
ref: React.Ref<Animated.View>
|
||||||
) {
|
) {
|
||||||
const animatedStyle = {
|
const animatedStyle = {
|
||||||
@@ -46,9 +46,7 @@ const Overlay = React.forwardRef(function Overlay(
|
|||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
style={[styles.overlay, overlayStyle, animatedStyle, style]}
|
style={[styles.overlay, overlayStyle, animatedStyle, style]}
|
||||||
>
|
/>
|
||||||
<Pressable onPress={onPress} style={styles.pressable} />
|
|
||||||
</Animated.View>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -66,9 +64,6 @@ const styles = StyleSheet.create({
|
|||||||
...StyleSheet.absoluteFillObject,
|
...StyleSheet.absoluteFillObject,
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
},
|
},
|
||||||
pressable: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Overlay;
|
export default Overlay;
|
||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
shouldUseActivityState,
|
shouldUseActivityState,
|
||||||
} from 'react-native-screens';
|
} from 'react-native-screens';
|
||||||
import { ResourceSavingView } from '@react-navigation/elements';
|
import { ResourceSavingScene } from '@react-navigation/elements';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -34,8 +34,8 @@ export default function ScreenFallback({ visible, children, ...rest }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResourceSavingView visible={visible} {...rest}>
|
<ResourceSavingScene visible={visible} {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</ResourceSavingView>
|
</ResourceSavingScene>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,379 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import {
|
|
||||||
InteractionManager,
|
|
||||||
Keyboard,
|
|
||||||
Platform,
|
|
||||||
StatusBar,
|
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
} from 'react-native';
|
|
||||||
import {
|
|
||||||
PanGestureHandler,
|
|
||||||
PanGestureHandlerGestureEvent,
|
|
||||||
State as GestureState,
|
|
||||||
} from 'react-native-gesture-handler';
|
|
||||||
import Animated, {
|
|
||||||
interpolate,
|
|
||||||
runOnJS,
|
|
||||||
useAnimatedGestureHandler,
|
|
||||||
useAnimatedStyle,
|
|
||||||
useDerivedValue,
|
|
||||||
useSharedValue,
|
|
||||||
withSpring,
|
|
||||||
} from 'react-native-reanimated';
|
|
||||||
import type { DrawerProps } from '../../types';
|
|
||||||
import DrawerProgressContext from '../../utils/DrawerProgressContext';
|
|
||||||
import Overlay from './Overlay';
|
|
||||||
|
|
||||||
const SWIPE_DISTANCE_MINIMUM = 5;
|
|
||||||
const DEFAULT_DRAWER_WIDTH = '80%';
|
|
||||||
|
|
||||||
const minmax = (value: number, start: number, end: number) => {
|
|
||||||
'worklet';
|
|
||||||
|
|
||||||
return Math.min(Math.max(value, start), end);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Drawer({
|
|
||||||
dimensions,
|
|
||||||
drawerPosition,
|
|
||||||
drawerStyle,
|
|
||||||
drawerType,
|
|
||||||
gestureHandlerProps,
|
|
||||||
hideStatusBarOnOpen,
|
|
||||||
keyboardDismissMode,
|
|
||||||
onClose,
|
|
||||||
onOpen,
|
|
||||||
open,
|
|
||||||
overlayStyle,
|
|
||||||
renderDrawerContent,
|
|
||||||
renderSceneContent,
|
|
||||||
statusBarAnimation,
|
|
||||||
swipeDistanceThreshold,
|
|
||||||
swipeEdgeWidth,
|
|
||||||
swipeEnabled,
|
|
||||||
swipeVelocityThreshold,
|
|
||||||
}: DrawerProps) {
|
|
||||||
const getDrawerWidth = (): number => {
|
|
||||||
const { width = DEFAULT_DRAWER_WIDTH } =
|
|
||||||
StyleSheet.flatten(drawerStyle) || {};
|
|
||||||
|
|
||||||
if (typeof width === 'string' && width.endsWith('%')) {
|
|
||||||
// Try to calculate width if a percentage is given
|
|
||||||
const percentage = Number(width.replace(/%$/, ''));
|
|
||||||
|
|
||||||
if (Number.isFinite(percentage)) {
|
|
||||||
return dimensions.width * (percentage / 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeof width === 'number' ? width : 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawerWidth = getDrawerWidth();
|
|
||||||
|
|
||||||
const isOpen = drawerType === 'permanent' ? true : open;
|
|
||||||
const isRight = drawerPosition === 'right';
|
|
||||||
|
|
||||||
const getDrawerTranslationX = React.useCallback(
|
|
||||||
(open: boolean) => {
|
|
||||||
'worklet';
|
|
||||||
|
|
||||||
if (drawerPosition === 'left') {
|
|
||||||
return open ? 0 : -drawerWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return open ? 0 : drawerWidth;
|
|
||||||
},
|
|
||||||
[drawerPosition, drawerWidth]
|
|
||||||
);
|
|
||||||
|
|
||||||
const hideStatusBar = React.useCallback(
|
|
||||||
(hide: boolean) => {
|
|
||||||
if (hideStatusBarOnOpen) {
|
|
||||||
StatusBar.setHidden(hide, statusBarAnimation);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[hideStatusBarOnOpen, statusBarAnimation]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
hideStatusBar(isOpen);
|
|
||||||
|
|
||||||
return () => hideStatusBar(false);
|
|
||||||
}, [isOpen, hideStatusBarOnOpen, statusBarAnimation, hideStatusBar]);
|
|
||||||
|
|
||||||
const interactionHandleRef = React.useRef<number | null>(null);
|
|
||||||
|
|
||||||
const startInteraction = () => {
|
|
||||||
interactionHandleRef.current = InteractionManager.createInteractionHandle();
|
|
||||||
};
|
|
||||||
|
|
||||||
const endInteraction = () => {
|
|
||||||
if (interactionHandleRef.current != null) {
|
|
||||||
InteractionManager.clearInteractionHandle(interactionHandleRef.current);
|
|
||||||
interactionHandleRef.current = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideKeyboard = () => {
|
|
||||||
if (keyboardDismissMode === 'on-drag') {
|
|
||||||
Keyboard.dismiss();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onGestureStart = () => {
|
|
||||||
startInteraction();
|
|
||||||
hideKeyboard();
|
|
||||||
hideStatusBar(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onGestureEnd = () => {
|
|
||||||
endInteraction();
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: Currently hitSlop is broken when on Android when drawer is on right
|
|
||||||
// https://github.com/kmagiera/react-native-gesture-handler/issues/569
|
|
||||||
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: isOpen ? undefined : swipeEdgeWidth }
|
|
||||||
: { left: 0, width: isOpen ? undefined : swipeEdgeWidth };
|
|
||||||
|
|
||||||
const touchStartX = useSharedValue(0);
|
|
||||||
const touchX = useSharedValue(0);
|
|
||||||
const translationX = useSharedValue(getDrawerTranslationX(open));
|
|
||||||
const gestureState = useSharedValue<GestureState>(GestureState.UNDETERMINED);
|
|
||||||
|
|
||||||
const toggleDrawer = React.useCallback(
|
|
||||||
(open: boolean, velocity?: number) => {
|
|
||||||
'worklet';
|
|
||||||
|
|
||||||
const translateX = getDrawerTranslationX(open);
|
|
||||||
|
|
||||||
touchStartX.value = 0;
|
|
||||||
touchX.value = 0;
|
|
||||||
translationX.value = withSpring(
|
|
||||||
translateX,
|
|
||||||
{
|
|
||||||
velocity,
|
|
||||||
stiffness: 1000,
|
|
||||||
damping: 500,
|
|
||||||
mass: 3,
|
|
||||||
overshootClamping: true,
|
|
||||||
restDisplacementThreshold: 0.01,
|
|
||||||
restSpeedThreshold: 0.01,
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
if (translationX.value === getDrawerTranslationX(true)) {
|
|
||||||
runOnJS(onOpen)();
|
|
||||||
} else if (translationX.value === getDrawerTranslationX(false)) {
|
|
||||||
runOnJS(onClose)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[getDrawerTranslationX, onClose, onOpen, touchStartX, touchX, translationX]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => toggleDrawer(open), [open, toggleDrawer]);
|
|
||||||
|
|
||||||
const onGestureEvent = useAnimatedGestureHandler<
|
|
||||||
PanGestureHandlerGestureEvent,
|
|
||||||
{ startX: number }
|
|
||||||
>({
|
|
||||||
onStart: (event, ctx) => {
|
|
||||||
ctx.startX = translationX.value;
|
|
||||||
gestureState.value = event.state;
|
|
||||||
touchStartX.value = event.x;
|
|
||||||
|
|
||||||
runOnJS(onGestureStart)();
|
|
||||||
},
|
|
||||||
onActive: (event, ctx) => {
|
|
||||||
touchX.value = event.x;
|
|
||||||
translationX.value = ctx.startX + event.translationX;
|
|
||||||
gestureState.value = event.state;
|
|
||||||
},
|
|
||||||
onEnd: (event) => {
|
|
||||||
gestureState.value = event.state;
|
|
||||||
|
|
||||||
const nextOpen =
|
|
||||||
(Math.abs(event.translationX) > SWIPE_DISTANCE_MINIMUM &&
|
|
||||||
Math.abs(event.translationX) > swipeVelocityThreshold) ||
|
|
||||||
Math.abs(event.translationX) > swipeDistanceThreshold
|
|
||||||
? drawerPosition === 'left'
|
|
||||||
? // If swiped to right, open the drawer, otherwise close it
|
|
||||||
(event.velocityX === 0 ? event.translationX : event.velocityX) > 0
|
|
||||||
: // If swiped to left, open the drawer, otherwise close it
|
|
||||||
(event.velocityX === 0 ? event.translationX : event.velocityX) < 0
|
|
||||||
: open;
|
|
||||||
|
|
||||||
toggleDrawer(nextOpen, event.velocityX);
|
|
||||||
runOnJS(onGestureEnd)();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const translateX = useDerivedValue(() => {
|
|
||||||
// Comment stolen from react-native-gesture-handler/DrawerLayout
|
|
||||||
//
|
|
||||||
// While closing the drawer when user starts gesture outside of its area (in greyed
|
|
||||||
// out part of the window), we want the drawer to follow only once finger reaches the
|
|
||||||
// edge of the drawer.
|
|
||||||
// E.g. on the diagram below drawer is illustrate by X signs and the greyed out area by
|
|
||||||
// dots. The touch gesture starts at '*' and moves left, touch path is indicated by
|
|
||||||
// an arrow pointing left
|
|
||||||
// 1) +---------------+ 2) +---------------+ 3) +---------------+ 4) +---------------+
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|.<-*..| |XXXXXXXX|<--*..| |XXXXX|<-----*..|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
|
|
||||||
// +---------------+ +---------------+ +---------------+ +---------------+
|
|
||||||
//
|
|
||||||
// For the above to work properly we define animated value that will keep start position
|
|
||||||
// of the gesture. Then we use that value to calculate how much we need to subtract from
|
|
||||||
// the translationX. If the gesture started on the greyed out area we take the distance from the
|
|
||||||
// edge of the drawer to the start position. Otherwise we don't subtract at all and the
|
|
||||||
// drawer be pulled back as soon as you start the pan.
|
|
||||||
//
|
|
||||||
// This is used only when drawerType is "front"
|
|
||||||
const touchDistance =
|
|
||||||
drawerType === 'front' && gestureState.value === GestureState.ACTIVE
|
|
||||||
? minmax(
|
|
||||||
drawerPosition === 'left'
|
|
||||||
? touchStartX.value - drawerWidth
|
|
||||||
: dimensions.width - drawerWidth - touchStartX.value,
|
|
||||||
0,
|
|
||||||
dimensions.width
|
|
||||||
)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
const translateX =
|
|
||||||
drawerPosition === 'left'
|
|
||||||
? minmax(translationX.value + touchDistance, -drawerWidth, 0)
|
|
||||||
: minmax(translationX.value - touchDistance, 0, drawerWidth);
|
|
||||||
|
|
||||||
return translateX;
|
|
||||||
});
|
|
||||||
|
|
||||||
const drawerAnimatedStyle = useAnimatedStyle(() => {
|
|
||||||
return {
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
translateX:
|
|
||||||
drawerType === 'permanent' || drawerType === 'back'
|
|
||||||
? 0
|
|
||||||
: translateX.value,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const contentAnimatedStyle = useAnimatedStyle(() => {
|
|
||||||
return {
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
translateX:
|
|
||||||
drawerType === 'permanent' || drawerType === 'front'
|
|
||||||
? 0
|
|
||||||
: drawerPosition === 'left'
|
|
||||||
? drawerWidth + translateX.value
|
|
||||||
: translateX.value - drawerWidth,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const progress = useDerivedValue(() => {
|
|
||||||
return drawerType === 'permanent'
|
|
||||||
? 1
|
|
||||||
: interpolate(
|
|
||||||
translateX.value,
|
|
||||||
[getDrawerTranslationX(false), getDrawerTranslationX(true)],
|
|
||||||
[0, 1]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DrawerProgressContext.Provider value={progress}>
|
|
||||||
<PanGestureHandler
|
|
||||||
activeOffsetX={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
|
||||||
failOffsetY={[-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM]}
|
|
||||||
hitSlop={hitSlop}
|
|
||||||
enabled={drawerType !== 'permanent' && swipeEnabled}
|
|
||||||
onGestureEvent={onGestureEvent}
|
|
||||||
{...gestureHandlerProps}
|
|
||||||
>
|
|
||||||
{/* Immediate child of gesture handler needs to be an Animated.View */}
|
|
||||||
<Animated.View
|
|
||||||
style={[
|
|
||||||
styles.main,
|
|
||||||
{
|
|
||||||
flexDirection:
|
|
||||||
drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Animated.View style={[styles.content, contentAnimatedStyle]}>
|
|
||||||
<View
|
|
||||||
accessibilityElementsHidden={isOpen && drawerType !== 'permanent'}
|
|
||||||
importantForAccessibility={
|
|
||||||
isOpen && drawerType !== 'permanent'
|
|
||||||
? 'no-hide-descendants'
|
|
||||||
: 'auto'
|
|
||||||
}
|
|
||||||
style={styles.content}
|
|
||||||
>
|
|
||||||
{renderSceneContent()}
|
|
||||||
</View>
|
|
||||||
{drawerType !== 'permanent' ? (
|
|
||||||
<Overlay
|
|
||||||
progress={progress}
|
|
||||||
onPress={() => toggleDrawer(false)}
|
|
||||||
style={overlayStyle}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</Animated.View>
|
|
||||||
<Animated.View
|
|
||||||
accessibilityViewIsModal={isOpen && drawerType !== 'permanent'}
|
|
||||||
removeClippedSubviews={Platform.OS !== 'ios'}
|
|
||||||
style={[
|
|
||||||
styles.container,
|
|
||||||
{
|
|
||||||
position: drawerType === 'permanent' ? 'relative' : 'absolute',
|
|
||||||
zIndex: drawerType === 'back' ? -1 : 0,
|
|
||||||
},
|
|
||||||
drawerAnimatedStyle,
|
|
||||||
drawerStyle as any,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{renderDrawerContent()}
|
|
||||||
</Animated.View>
|
|
||||||
</Animated.View>
|
|
||||||
</PanGestureHandler>
|
|
||||||
</DrawerProgressContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
maxWidth: '100%',
|
|
||||||
width: DEFAULT_DRAWER_WIDTH,
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
main: {
|
|
||||||
flex: 1,
|
|
||||||
...Platform.select({
|
|
||||||
// FIXME: We need to hide `overflowX` on Web so the translated content doesn't show offscreen.
|
|
||||||
// But adding `overflowX: 'hidden'` prevents content from collapsing the URL bar.
|
|
||||||
web: null,
|
|
||||||
default: { overflow: 'hidden' },
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { Pressable, Platform, StyleSheet } from 'react-native';
|
|
||||||
import Animated, { useAnimatedStyle } from 'react-native-reanimated';
|
|
||||||
|
|
||||||
const PROGRESS_EPSILON = 0.05;
|
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof Animated.View> & {
|
|
||||||
progress: Animated.SharedValue<number>;
|
|
||||||
onPress: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Overlay = React.forwardRef(function Overlay(
|
|
||||||
{ progress, onPress, style, ...props }: Props,
|
|
||||||
ref: React.Ref<Animated.View>
|
|
||||||
) {
|
|
||||||
const animatedStyle = useAnimatedStyle(() => {
|
|
||||||
return {
|
|
||||||
opacity: progress.value,
|
|
||||||
// We don't want the user to be able to press through the overlay when drawer is open
|
|
||||||
// One approach is to adjust the pointerEvents based on the progress
|
|
||||||
// But we can also send the overlay behind the screen
|
|
||||||
zIndex: progress.value > PROGRESS_EPSILON ? 0 : -1,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Animated.View
|
|
||||||
{...props}
|
|
||||||
ref={ref}
|
|
||||||
style={[styles.overlay, overlayStyle, animatedStyle, style]}
|
|
||||||
>
|
|
||||||
<Pressable onPress={onPress} style={styles.pressable} />
|
|
||||||
</Animated.View>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const overlayStyle = Platform.select<Record<string, string>>({
|
|
||||||
web: {
|
|
||||||
// Disable touch highlight on mobile Safari.
|
|
||||||
// WebkitTapHighlightColor must be used outside of StyleSheet.create because react-native-web will omit the property.
|
|
||||||
WebkitTapHighlightColor: 'transparent',
|
|
||||||
},
|
|
||||||
default: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
overlay: {
|
|
||||||
...StyleSheet.absoluteFillObject,
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
||||||
},
|
|
||||||
pressable: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Overlay;
|
|
||||||
@@ -3,52 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [1.0.0-next.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/elements@1.0.0-next.3...@react-navigation/elements@1.0.0-next.4) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/elements
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.0.0-next.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/elements@1.0.0-next.2...@react-navigation/elements@1.0.0-next.3) (2021-03-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add a Background component ([cbaabc1](https://github.com/react-navigation/react-navigation/commit/cbaabc1288e780698e499a00b9ca06ab9746a0da))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/elements@1.0.0-next.1...@react-navigation/elements@1.0.0-next.2) (2021-03-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* use theme in PlatformPressable ([40439cc](https://github.com/react-navigation/react-navigation/commit/40439ccb420825a1aa480648526a816f2422ea6e))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* return nearest parent header height for useHeaderHeight ([24b3f73](https://github.com/react-navigation/react-navigation/commit/24b3f739da4b8af8dca77d92c72cfdaa762e564a))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/elements@1.0.0...@react-navigation/elements@1.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 1.0.0-next.0 (2021-03-09)
|
# 1.0.0-next.0 (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
UI Components for React Navigation.
|
UI Components for React Navigation.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/elements/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/elements/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/elements",
|
"name": "@react-navigation/elements",
|
||||||
"description": "UI Components for React Navigation",
|
"description": "UI Components for React Navigation",
|
||||||
"version": "1.0.0-next.4",
|
"version": "1.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation",
|
"react-navigation",
|
||||||
@@ -30,26 +30,27 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-masked-view/masked-view": "^0.2.3",
|
"@react-native-masked-view/masked-view": "^0.2.2",
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-safe-area-context": ">= 3.0.0"
|
"react-native-safe-area-context": ">= 3.0.0"
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { View, ViewProps } from 'react-native';
|
|
||||||
import { useTheme } from '@react-navigation/native';
|
|
||||||
|
|
||||||
type Props = ViewProps & {
|
|
||||||
children: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Background({ style, ...rest }: Props) {
|
|
||||||
const { colors } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
{...rest}
|
|
||||||
style={[{ flex: 1, backgroundColor: colors.background }, style]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -22,8 +22,7 @@ export default function HeaderBackButton({
|
|||||||
labelVisible = Platform.OS === 'ios',
|
labelVisible = Platform.OS === 'ios',
|
||||||
onLabelLayout,
|
onLabelLayout,
|
||||||
onPress,
|
onPress,
|
||||||
pressColor,
|
pressColorAndroid: customPressColorAndroid,
|
||||||
pressOpacity,
|
|
||||||
screenLayout,
|
screenLayout,
|
||||||
tintColor: customTintColor,
|
tintColor: customTintColor,
|
||||||
titleLayout,
|
titleLayout,
|
||||||
@@ -32,7 +31,7 @@ export default function HeaderBackButton({
|
|||||||
testID,
|
testID,
|
||||||
style,
|
style,
|
||||||
}: HeaderBackButtonProps) {
|
}: HeaderBackButtonProps) {
|
||||||
const { colors } = useTheme();
|
const { dark, colors } = useTheme();
|
||||||
|
|
||||||
const [initialLabelWidth, setInitialLabelWidth] = React.useState<
|
const [initialLabelWidth, setInitialLabelWidth] = React.useState<
|
||||||
undefined | number
|
undefined | number
|
||||||
@@ -46,6 +45,13 @@ export default function HeaderBackButton({
|
|||||||
default: colors.text,
|
default: colors.text,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pressColorAndroid =
|
||||||
|
customPressColorAndroid !== undefined
|
||||||
|
? customPressColorAndroid
|
||||||
|
: dark
|
||||||
|
? 'rgba(255, 255, 255, .32)'
|
||||||
|
: 'rgba(0, 0, 0, .32)';
|
||||||
|
|
||||||
const handleLabelLayout = (e: LayoutChangeEvent) => {
|
const handleLabelLayout = (e: LayoutChangeEvent) => {
|
||||||
onLabelLayout?.(e);
|
onLabelLayout?.(e);
|
||||||
|
|
||||||
@@ -150,8 +156,7 @@ export default function HeaderBackButton({
|
|||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
onPress={disabled ? undefined : handlePress}
|
onPress={disabled ? undefined : handlePress}
|
||||||
pressColor={pressColor}
|
pressColor={pressColorAndroid}
|
||||||
pressOpacity={pressOpacity}
|
|
||||||
android_ripple={{ borderless: true }}
|
android_ripple={{ borderless: true }}
|
||||||
style={[styles.container, disabled && styles.disabled, style]}
|
style={[styles.container, disabled && styles.disabled, style]}
|
||||||
hitSlop={Platform.select({
|
hitSlop={Platform.select({
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Platform, Pressable, PressableProps } from 'react-native';
|
import { Platform, Pressable, PressableProps } from 'react-native';
|
||||||
import { useTheme } from '@react-navigation/native';
|
|
||||||
|
|
||||||
export type Props = PressableProps & {
|
export type Props = PressableProps & {
|
||||||
pressColor?: string;
|
pressColor?: string;
|
||||||
@@ -13,30 +12,24 @@ const ANDROID_SUPPORTS_RIPPLE =
|
|||||||
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP;
|
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PlatformPressable provides an abstraction on top of Pressable to handle platform differences.
|
* PlatformPressable provides an abstraction on top of TouchableNativeFeedback and
|
||||||
|
* TouchableOpacity to handle platform differences.
|
||||||
|
*
|
||||||
|
* On Android, you can pass the props of TouchableNativeFeedback.
|
||||||
|
* On other platforms, you can pass the props of TouchableOpacity.
|
||||||
*/
|
*/
|
||||||
export default function PlatformPressable({
|
export default function PlatformPressable({
|
||||||
android_ripple,
|
android_ripple,
|
||||||
pressColor,
|
pressColor = 'rgba(0, 0, 0, .32)',
|
||||||
pressOpacity,
|
pressOpacity,
|
||||||
style,
|
style,
|
||||||
...rest
|
...rest
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { dark } = useTheme();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
android_ripple={
|
android_ripple={
|
||||||
ANDROID_SUPPORTS_RIPPLE
|
ANDROID_SUPPORTS_RIPPLE
|
||||||
? {
|
? { color: pressColor, ...android_ripple }
|
||||||
color:
|
|
||||||
pressColor !== undefined
|
|
||||||
? pressColor
|
|
||||||
: dark
|
|
||||||
? 'rgba(255, 255, 255, .32)'
|
|
||||||
: 'rgba(0, 0, 0, .32)',
|
|
||||||
...android_ripple,
|
|
||||||
}
|
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
style={({ pressed }) => [
|
style={({ pressed }) => [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
import { View, StyleSheet } from 'react-native';
|
||||||
import {
|
import {
|
||||||
useSafeAreaFrame,
|
useSafeAreaFrame,
|
||||||
useSafeAreaInsets,
|
useSafeAreaInsets,
|
||||||
@@ -12,19 +12,16 @@ import {
|
|||||||
ParamListBase,
|
ParamListBase,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
import Background from './Background';
|
|
||||||
import HeaderShownContext from './Header/HeaderShownContext';
|
import HeaderShownContext from './Header/HeaderShownContext';
|
||||||
import HeaderHeightContext from './Header/HeaderHeightContext';
|
import HeaderHeightContext from './Header/HeaderHeightContext';
|
||||||
import getDefaultHeaderHeight from './Header/getDefaultHeaderHeight';
|
import getDefaultHeaderHeight from './Header/getDefaultHeaderHeight';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
focused: boolean;
|
|
||||||
navigation: NavigationProp<ParamListBase>;
|
navigation: NavigationProp<ParamListBase>;
|
||||||
route: RouteProp<ParamListBase, string>;
|
route: RouteProp<ParamListBase, string>;
|
||||||
header: React.ReactNode;
|
header: React.ReactNode;
|
||||||
headerShown?: boolean;
|
headerShown?: boolean;
|
||||||
headerStatusBarHeight?: number;
|
headerStatusBarHeight?: number;
|
||||||
style?: StyleProp<ViewStyle>;
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,17 +30,14 @@ export default function Screen(props: Props) {
|
|||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
||||||
const parentHeaderHeight = React.useContext(HeaderHeightContext);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
focused,
|
|
||||||
header,
|
header,
|
||||||
headerShown = true,
|
headerShown = true,
|
||||||
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
||||||
|
children,
|
||||||
navigation,
|
navigation,
|
||||||
route,
|
route,
|
||||||
children,
|
|
||||||
style,
|
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [headerHeight, setHeaderHeight] = React.useState(() =>
|
const [headerHeight, setHeaderHeight] = React.useState(() =>
|
||||||
@@ -51,18 +45,12 @@ export default function Screen(props: Props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Background
|
<View style={styles.container}>
|
||||||
accessibilityElementsHidden={!focused}
|
|
||||||
importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
|
|
||||||
style={[styles.container, style]}
|
|
||||||
>
|
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<HeaderShownContext.Provider
|
<HeaderShownContext.Provider
|
||||||
value={isParentHeaderShown || headerShown !== false}
|
value={isParentHeaderShown || headerShown !== false}
|
||||||
>
|
>
|
||||||
<HeaderHeightContext.Provider
|
<HeaderHeightContext.Provider value={headerShown ? headerHeight : 0}>
|
||||||
value={headerShown ? headerHeight : parentHeaderHeight}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</HeaderHeightContext.Provider>
|
</HeaderHeightContext.Provider>
|
||||||
</HeaderShownContext.Provider>
|
</HeaderShownContext.Provider>
|
||||||
@@ -82,7 +70,7 @@ export default function Screen(props: Props) {
|
|||||||
</NavigationRouteContext.Provider>
|
</NavigationRouteContext.Provider>
|
||||||
</NavigationContext.Provider>
|
</NavigationContext.Provider>
|
||||||
) : null}
|
) : null}
|
||||||
</Background>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ export { default as getHeaderTitle } from './Header/getHeaderTitle';
|
|||||||
|
|
||||||
export { default as MissingIcon } from './MissingIcon';
|
export { default as MissingIcon } from './MissingIcon';
|
||||||
export { default as PlatformPressable } from './PlatformPressable';
|
export { default as PlatformPressable } from './PlatformPressable';
|
||||||
export { default as ResourceSavingView } from './ResourceSavingView';
|
export { default as ResourceSavingScene } from './ResourceSavingScene';
|
||||||
export { default as SafeAreaProviderCompat } from './SafeAreaProviderCompat';
|
export { default as SafeAreaProviderCompat } from './SafeAreaProviderCompat';
|
||||||
export { default as Screen } from './Screen';
|
export { default as Screen } from './Screen';
|
||||||
export { default as Background } from './Background';
|
|
||||||
|
|
||||||
export const Assets = [
|
export const Assets = [
|
||||||
// eslint-disable-next-line import/no-commonjs
|
// eslint-disable-next-line import/no-commonjs
|
||||||
|
|||||||
@@ -127,16 +127,13 @@ export type HeaderBackButtonProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
/**
|
/**
|
||||||
* Callback to call when the button is pressed.
|
* Callback to call when the button is pressed.
|
||||||
|
* By default, this triggers `goBack`.
|
||||||
*/
|
*/
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
/**
|
/**
|
||||||
* Color for material ripple (Android >= 5.0 only).
|
* Color for material ripple (Android >= 5.0 only).
|
||||||
*/
|
*/
|
||||||
pressColor?: string;
|
pressColorAndroid?: string;
|
||||||
/**
|
|
||||||
* Opacity when the button is pressed, used when ripple is not supported.
|
|
||||||
*/
|
|
||||||
pressOpacity?: number;
|
|
||||||
/**
|
/**
|
||||||
* Function which returns a React Element to display custom image in header's back button.
|
* Function which returns a React Element to display custom image in header's back button.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,25 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@6.0.0-next.1...@react-navigation/material-bottom-tabs@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@6.0.0...@react-navigation/material-bottom-tabs@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.9...@react-navigation/material-bottom-tabs@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-bottom-tabs@5.3.9...@react-navigation/material-bottom-tabs@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
React Navigation integration for [bottom navigation](https://material.io/components/bottom-navigation) component from [`react-native-paper`](https://callstack.github.io/react-native-paper/bottom-navigation.html).
|
React Navigation integration for [bottom navigation](https://material.io/components/bottom-navigation) component from [`react-native-paper`](https://callstack.github.io/react-native-paper/bottom-navigation.html).
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/material-bottom-tab-navigator/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/material-bottom-tab-navigator/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/material-bottom-tabs",
|
"name": "@react-navigation/material-bottom-tabs",
|
||||||
"description": "Integration for bottom navigation component from react-native-paper",
|
"description": "Integration for bottom navigation component from react-native-paper",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -34,28 +34,29 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"@types/react-native-vector-icons": "^6.4.6",
|
"@types/react-native-vector-icons": "^6.4.6",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-native-paper": "^4.7.2",
|
"react-native-paper": "^4.7.2",
|
||||||
"react-native-vector-icons": "^8.1.0",
|
"react-native-vector-icons": "^8.1.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-paper": ">= 3.0.0",
|
"react-native-paper": ">= 3.0.0",
|
||||||
|
|||||||
@@ -3,25 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@6.0.0-next.1...@react-navigation/material-top-tabs@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@6.0.0...@react-navigation/material-top-tabs@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.9...@react-navigation/material-top-tabs@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/material-top-tabs@5.3.9...@react-navigation/material-top-tabs@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# `@react-navigation/material-top-tabs`
|
# `@react-navigation/material-top-tabs`
|
||||||
|
|
||||||
React Navigation integration for animated tab view component from [`react-native-tab-view`](https://github.com/satya164/react-native-tab-view).
|
React Navigation integration for animated tab view component from [`react-native-tab-view`](https://github.com/react-native-community/react-native-tab-view).
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/material-top-tab-navigator/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/material-top-tab-navigator/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/material-top-tabs",
|
"name": "@react-navigation/material-top-tabs",
|
||||||
"description": "Integration for the animated tab view component from react-native-tab-view",
|
"description": "Integration for the animated tab view component from react-native-tab-view",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
@@ -45,23 +46,23 @@
|
|||||||
"warn-once": "^0.0.1"
|
"warn-once": "^0.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-native-pager-view": "^5.0.12",
|
"react-native-pager-view": "^4.2.4",
|
||||||
"react-native-tab-view": "^3.0.1",
|
"react-native-tab-view": "^3.0.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-pager-view": ">= 4.0.0",
|
"react-native-pager-view": ">= 1.0.0",
|
||||||
"react-native-tab-view": ">= 3.0.0"
|
"react-native-tab-view": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"react-native-builder-bob": {
|
"react-native-builder-bob": {
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ function MaterialTopTabNavigator({
|
|||||||
backBehavior,
|
backBehavior,
|
||||||
children,
|
children,
|
||||||
screenOptions,
|
screenOptions,
|
||||||
|
// @ts-expect-error: lazy is deprecated
|
||||||
lazy,
|
lazy,
|
||||||
|
// @ts-expect-error: tabBarOptions is deprecated
|
||||||
tabBarOptions,
|
tabBarOptions,
|
||||||
...rest
|
...rest
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
|||||||
@@ -3,22 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@6.0.0-next.1...@react-navigation/native@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/native
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@6.0.0...@react-navigation/native@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/native
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.9...@react-navigation/native@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/native@5.8.9...@react-navigation/native@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
React Native integration for React Navigation.
|
React Native integration for React Navigation.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/getting-started/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/getting-started/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/native",
|
"name": "@react-navigation/native",
|
||||||
"description": "React Native integration for React Navigation",
|
"description": "React Native integration for React Navigation",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation",
|
"react-navigation",
|
||||||
@@ -30,16 +30,17 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^6.0.0-next.2",
|
"@react-navigation/core": "^6.0.0-next.0",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"nanoid": "^3.1.22"
|
"nanoid": "^3.1.20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,22 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/routers@6.0.0-next.1...@react-navigation/routers@6.0.0-next.2) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/routers
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/routers@6.0.0...@react-navigation/routers@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/routers
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/routers@5.6.2...@react-navigation/routers@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/routers@5.6.2...@react-navigation/routers@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ yarn add @react-navigation/routers
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/custom-routers/).
|
Documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/custom-routers/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/routers",
|
"name": "@react-navigation/routers",
|
||||||
"description": "Routers to help build custom navigators",
|
"description": "Routers to help build custom navigators",
|
||||||
"version": "6.0.0-next.2",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -29,14 +29,15 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.1.22"
|
"nanoid": "^3.1.20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
|
|||||||
@@ -3,117 +3,6 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
# [6.0.0-next.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.8...@react-navigation/stack@6.0.0-next.9) (2021-04-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/stack
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.8](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.7...@react-navigation/stack@6.0.0-next.8) (2021-03-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add a Background component ([cbaabc1](https://github.com/react-navigation/react-navigation/commit/cbaabc1288e780698e499a00b9ca06ab9746a0da))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.7](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.6...@react-navigation/stack@6.0.0-next.7) (2021-03-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Code Refactoring
|
|
||||||
|
|
||||||
* make gestureResponseDistance a number ([48851c9](https://github.com/react-navigation/react-navigation/commit/48851c9ebdcf1b835bbcb673adeb88e56b989443))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* now we need to pass a number instead of an object
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.6](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.5...@react-navigation/stack@6.0.0-next.6) (2021-03-14)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/stack
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.5](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.4...@react-navigation/stack@6.0.0-next.5) (2021-03-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* consider header colors when managing statusbar ([3ad2bcb](https://github.com/react-navigation/react-navigation/commit/3ad2bcbaf85996ce0d5e1e961081978a32448899))
|
|
||||||
* consider header colors when managing statusbar ([faee245](https://github.com/react-navigation/react-navigation/commit/faee245d2ec8c59f9e9033d96ae21c5e60d95ba6))
|
|
||||||
|
|
||||||
|
|
||||||
### Code Refactoring
|
|
||||||
|
|
||||||
* move headerMode to options ([aacc1b5](https://github.com/react-navigation/react-navigation/commit/aacc1b525d86f0e0b1bad8016fd85e82024f16e9))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* headerMode is now moved to options instead of props
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.4](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.3...@react-navigation/stack@6.0.0-next.4) (2021-03-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* add special statusbar handling to modal presentation ([a204edd](https://github.com/react-navigation/react-navigation/commit/a204edd012060f0816eddee7a093183aa379d049))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.3](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.2...@react-navigation/stack@6.0.0-next.3) (2021-03-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* export drawer button ([2c8401d](https://github.com/react-navigation/react-navigation/commit/2c8401d5cb347d37c96e5b30f8ad05c17fd22ea4))
|
|
||||||
* return nearest parent header height for useHeaderHeight ([24b3f73](https://github.com/react-navigation/react-navigation/commit/24b3f739da4b8af8dca77d92c72cfdaa762e564a))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.2](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0-next.1...@react-navigation/stack@6.0.0-next.2) (2021-03-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* respect headerStatusBarHeight option in Stack ([#9405](https://github.com/react-navigation/react-navigation/issues/9405)) ([8a6511c](https://github.com/react-navigation/react-navigation/commit/8a6511c491b2affbe378d720e613a3e3041ca9c2))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.1](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@6.0.0...@react-navigation/stack@6.0.0-next.1) (2021-03-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* fix peer dep versions ([72f90b5](https://github.com/react-navigation/react-navigation/commit/72f90b50d27eda1315bb750beca8a36f26dafe17))
|
|
||||||
* remove use of deprecated currentlyFocusedField ([038eb87](https://github.com/react-navigation/react-navigation/commit/038eb87c42564f9d733e6870826726d3fb0adaee))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.6...@react-navigation/stack@6.0.0-next.0) (2021-03-09)
|
# [6.0.0-next.0](https://github.com/react-navigation/react-navigation/compare/@react-navigation/stack@5.12.6...@react-navigation/stack@6.0.0-next.0) (2021-03-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Stack navigator for React Navigation.
|
Stack navigator for React Navigation.
|
||||||
|
|
||||||
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/6.x/stack-navigator/).
|
Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/stack-navigator/).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/stack",
|
"name": "@react-navigation/stack",
|
||||||
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
|
||||||
"version": "6.0.0-next.9",
|
"version": "6.0.0-next.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -33,40 +33,41 @@
|
|||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"tag": "alpha"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/elements": "^1.0.0-next.4",
|
"@react-navigation/elements": "^1.0.0",
|
||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
"react-native-iphone-x-helper": "^1.3.0",
|
"react-native-iphone-x-helper": "^1.3.0",
|
||||||
"warn-once": "^0.0.1"
|
"warn-once": "^0.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0-next.2",
|
"@react-navigation/native": "^6.0.0-next.0",
|
||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.53",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "~0.63.51",
|
"@types/react-native": "~0.63.51",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.4",
|
"react-native": "~0.63.2",
|
||||||
"react-native-builder-bob": "^0.18.1",
|
"react-native-builder-bob": "^0.18.1",
|
||||||
"react-native-gesture-handler": "~1.10.2",
|
"react-native-gesture-handler": "~1.8.0",
|
||||||
"react-native-safe-area-context": "~3.2.0",
|
"react-native-safe-area-context": "3.1.9",
|
||||||
"react-native-screens": "~3.0.0",
|
"react-native-screens": "~2.15.0",
|
||||||
"typescript": "^4.2.3"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^6.0.0",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-gesture-handler": ">= 1.0.0",
|
"react-native-gesture-handler": ">= 1.0.0",
|
||||||
"react-native-safe-area-context": ">= 3.0.0",
|
"react-native-safe-area-context": ">= 3.0.0",
|
||||||
"react-native-screens": ">= 3.0.0"
|
"react-native-screens": ">= 2.15.0"
|
||||||
},
|
},
|
||||||
"react-native-builder-bob": {
|
"react-native-builder-bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -160,10 +160,6 @@ export function forModalPresentationIOS({
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
borderTopLeftRadius: borderRadius,
|
borderTopLeftRadius: borderRadius,
|
||||||
borderTopRightRadius: borderRadius,
|
borderTopRightRadius: borderRadius,
|
||||||
// We don't need these for the animation
|
|
||||||
// But different border radius for corners improves animation perf
|
|
||||||
borderBottomLeftRadius: isIphoneX() ? borderRadius : 0,
|
|
||||||
borderBottomRightRadius: isIphoneX() ? borderRadius : 0,
|
|
||||||
marginTop: index === 0 ? 0 : statusBarHeight,
|
marginTop: index === 0 ? 0 : statusBarHeight,
|
||||||
marginBottom: index === 0 ? 0 : topOffset,
|
marginBottom: index === 0 ? 0 : topOffset,
|
||||||
transform: [{ translateY }, { scale }],
|
transform: [{ translateY }, { scale }],
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import type {
|
|||||||
StackNavigationConfig,
|
StackNavigationConfig,
|
||||||
StackNavigationOptions,
|
StackNavigationOptions,
|
||||||
StackNavigationEventMap,
|
StackNavigationEventMap,
|
||||||
StackHeaderMode,
|
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
type Props = DefaultNavigatorOptions<StackNavigationOptions> &
|
type Props = DefaultNavigatorOptions<StackNavigationOptions> &
|
||||||
@@ -32,18 +31,13 @@ function StackNavigator({
|
|||||||
...rest
|
...rest
|
||||||
}: Props) {
|
}: Props) {
|
||||||
// @ts-expect-error: headerMode='none' is deprecated
|
// @ts-expect-error: headerMode='none' is deprecated
|
||||||
const headerMode = rest.headerMode as StackHeaderMode | 'none' | undefined;
|
const isHeaderModeNone = rest.headerMode === 'none';
|
||||||
|
|
||||||
warnOnce(
|
warnOnce(
|
||||||
headerMode === 'none',
|
isHeaderModeNone,
|
||||||
`Stack Navigator: 'headerMode="none"' is deprecated. Use 'headerShown: false' in 'screenOptions' instead.`
|
`Stack Navigator: 'headerMode="none"' is deprecated. Use 'headerShown: false' in 'screenOptions' instead.`
|
||||||
);
|
);
|
||||||
|
|
||||||
warnOnce(
|
|
||||||
headerMode && headerMode !== 'none',
|
|
||||||
`Stack Navigator: 'headerMode' is moved to 'options'. Moved it to 'screenOptions' to keep current behavior.`
|
|
||||||
);
|
|
||||||
|
|
||||||
const { state, descriptors, navigation } = useNavigationBuilder<
|
const { state, descriptors, navigation } = useNavigationBuilder<
|
||||||
StackNavigationState<ParamListBase>,
|
StackNavigationState<ParamListBase>,
|
||||||
StackRouterOptions,
|
StackRouterOptions,
|
||||||
@@ -54,22 +48,14 @@ function StackNavigator({
|
|||||||
initialRouteName,
|
initialRouteName,
|
||||||
children,
|
children,
|
||||||
screenOptions,
|
screenOptions,
|
||||||
defaultScreenOptions: ({ options }) => ({
|
defaultScreenOptions: {
|
||||||
headerShown: headerMode ? headerMode !== 'none' : true,
|
headerShown: !isHeaderModeNone,
|
||||||
headerMode:
|
|
||||||
headerMode && headerMode !== 'none'
|
|
||||||
? headerMode
|
|
||||||
: rest.mode !== 'modal' &&
|
|
||||||
Platform.OS === 'ios' &&
|
|
||||||
options.header === undefined
|
|
||||||
? 'float'
|
|
||||||
: 'screen',
|
|
||||||
gestureEnabled: Platform.OS === 'ios',
|
gestureEnabled: Platform.OS === 'ios',
|
||||||
animationEnabled:
|
animationEnabled:
|
||||||
Platform.OS !== 'web' &&
|
Platform.OS !== 'web' &&
|
||||||
Platform.OS !== 'windows' &&
|
Platform.OS !== 'windows' &&
|
||||||
Platform.OS !== 'macos',
|
Platform.OS !== 'macos',
|
||||||
}),
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type * as React from 'react';
|
import type * as React from 'react';
|
||||||
import type { Animated, StyleProp, TextStyle, ViewStyle } from 'react-native';
|
import type { Animated, StyleProp, TextStyle, ViewStyle } from 'react-native';
|
||||||
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
import type {
|
import type {
|
||||||
NavigationProp,
|
NavigationProp,
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
@@ -148,6 +149,10 @@ export type StackHeaderProps = {
|
|||||||
* Layout of the screen.
|
* Layout of the screen.
|
||||||
*/
|
*/
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
|
/**
|
||||||
|
* Safe area insets to use in the header, e.g. to apply extra spacing for statusbar and notch.
|
||||||
|
*/
|
||||||
|
insets: EdgeInsets;
|
||||||
/**
|
/**
|
||||||
* Options for the back button.
|
* Options for the back button.
|
||||||
*/
|
*/
|
||||||
@@ -198,12 +203,7 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
*/
|
*/
|
||||||
header?: (props: StackHeaderProps) => React.ReactNode;
|
header?: (props: StackHeaderProps) => React.ReactNode;
|
||||||
/**
|
/**
|
||||||
* Whether the header floats above the screen or part of the screen.
|
* Whether to show the header. The header is shown by default unless `headerMode` was set to `none`.
|
||||||
* Defaults to `float` on iOS for non-modals, and `screen` for the rest.
|
|
||||||
*/
|
|
||||||
headerMode?: StackHeaderMode;
|
|
||||||
/**
|
|
||||||
* Whether to show the header. The header is shown by default.
|
|
||||||
* Setting this to `false` hides the header.
|
* Setting this to `false` hides the header.
|
||||||
*/
|
*/
|
||||||
headerShown?: boolean;
|
headerShown?: boolean;
|
||||||
@@ -249,15 +249,35 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
*/
|
*/
|
||||||
gestureEnabled?: boolean;
|
gestureEnabled?: boolean;
|
||||||
/**
|
/**
|
||||||
* Distance of touch start from the edge of the screen to recognize gestures.
|
* Object to override the distance of touch start from the edge of the screen to recognize gestures.
|
||||||
* Not supported on Web.
|
* Not supported on Web.
|
||||||
*/
|
*/
|
||||||
gestureResponseDistance?: number;
|
gestureResponseDistance?: {
|
||||||
|
/**
|
||||||
|
* Distance for vertical direction. Defaults to 135.
|
||||||
|
*/
|
||||||
|
vertical?: number;
|
||||||
|
/**
|
||||||
|
* Distance for horizontal direction. Defaults to 25.
|
||||||
|
*/
|
||||||
|
horizontal?: number;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Number which determines the relevance of velocity for the gesture. Defaults to 0.3.
|
* Number which determines the relevance of velocity for the gesture. Defaults to 0.3.
|
||||||
* Not supported on Web.
|
* Not supported on Web.
|
||||||
*/
|
*/
|
||||||
gestureVelocityImpact?: number;
|
gestureVelocityImpact?: number;
|
||||||
|
/**
|
||||||
|
* Safe area insets for the screen. This is used to avoid elements like notch and status bar.
|
||||||
|
* By default, the device's safe area insets are automatically detected. You can override the behavior with this option.
|
||||||
|
* For example, to remove the extra spacing for status bar, pass `safeAreaInsets: { top: 0 }`.
|
||||||
|
*/
|
||||||
|
safeAreaInsets?: {
|
||||||
|
top?: number;
|
||||||
|
right?: number;
|
||||||
|
bottom?: number;
|
||||||
|
left?: number;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Whether to detach the previous screen from the view hierarchy to save memory.
|
* Whether to detach the previous screen from the view hierarchy to save memory.
|
||||||
* Set it to `false` if you need the previous screen to be seen through the active screen.
|
* Set it to `false` if you need the previous screen to be seen through the active screen.
|
||||||
@@ -269,6 +289,7 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
|
|
||||||
export type StackNavigationConfig = {
|
export type StackNavigationConfig = {
|
||||||
mode?: StackCardMode;
|
mode?: StackCardMode;
|
||||||
|
headerMode?: StackHeaderMode;
|
||||||
/**
|
/**
|
||||||
* If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen.
|
* If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen.
|
||||||
* Defaults to `true`.
|
* Defaults to `true`.
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
||||||
import { StackActions, useNavigationState } from '@react-navigation/native';
|
import { StackActions, useNavigationState } from '@react-navigation/native';
|
||||||
import { getHeaderTitle, HeaderShownContext } from '@react-navigation/elements';
|
import { getHeaderTitle, HeaderShownContext } from '@react-navigation/elements';
|
||||||
|
|
||||||
@@ -11,14 +10,13 @@ import type { StackHeaderProps } from '../../types';
|
|||||||
export default React.memo(function Header({
|
export default React.memo(function Header({
|
||||||
back,
|
back,
|
||||||
layout,
|
layout,
|
||||||
|
insets,
|
||||||
progress,
|
progress,
|
||||||
options,
|
options,
|
||||||
route,
|
route,
|
||||||
navigation,
|
navigation,
|
||||||
styleInterpolator,
|
styleInterpolator,
|
||||||
}: StackHeaderProps) {
|
}: StackHeaderProps) {
|
||||||
const insets = useSafeAreaInsets();
|
|
||||||
|
|
||||||
let previousTitle;
|
let previousTitle;
|
||||||
|
|
||||||
// The label for the left back button shows the title of the previous screen
|
// The label for the left back button shows the title of the previous screen
|
||||||
@@ -49,11 +47,7 @@ export default React.memo(function Header({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const statusBarHeight =
|
const statusBarHeight =
|
||||||
options.headerStatusBarHeight !== undefined
|
(isModal && !isFirstRouteInParent) || isParentHeaderShown ? 0 : insets.top;
|
||||||
? options.headerStatusBarHeight
|
|
||||||
: (isModal && !isFirstRouteInParent) || isParentHeaderShown
|
|
||||||
? 0
|
|
||||||
: insets.top;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderSegment
|
<HeaderSegment
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
ParamListBase,
|
ParamListBase,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import { HeaderBackContext, getHeaderTitle } from '@react-navigation/elements';
|
import { HeaderBackContext, getHeaderTitle } from '@react-navigation/elements';
|
||||||
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import {
|
import {
|
||||||
@@ -21,11 +22,13 @@ import type {
|
|||||||
StackHeaderStyleInterpolator,
|
StackHeaderStyleInterpolator,
|
||||||
StackNavigationProp,
|
StackNavigationProp,
|
||||||
StackHeaderProps,
|
StackHeaderProps,
|
||||||
|
GestureDirection,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
mode: 'float' | 'screen';
|
mode: 'float' | 'screen';
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
|
insets: EdgeInsets;
|
||||||
scenes: (Scene | undefined)[];
|
scenes: (Scene | undefined)[];
|
||||||
getPreviousScene: (props: { route: Route<string> }) => Scene | undefined;
|
getPreviousScene: (props: { route: Route<string> }) => Scene | undefined;
|
||||||
getFocusedRoute: () => Route<string>;
|
getFocusedRoute: () => Route<string>;
|
||||||
@@ -34,6 +37,7 @@ export type Props = {
|
|||||||
height: number;
|
height: number;
|
||||||
}) => void;
|
}) => void;
|
||||||
styleInterpolator: StackHeaderStyleInterpolator;
|
styleInterpolator: StackHeaderStyleInterpolator;
|
||||||
|
gestureDirection: GestureDirection;
|
||||||
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
|
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,9 +45,11 @@ export default function HeaderContainer({
|
|||||||
mode,
|
mode,
|
||||||
scenes,
|
scenes,
|
||||||
layout,
|
layout,
|
||||||
|
insets,
|
||||||
getPreviousScene,
|
getPreviousScene,
|
||||||
getFocusedRoute,
|
getFocusedRoute,
|
||||||
onContentHeightChange,
|
onContentHeightChange,
|
||||||
|
gestureDirection,
|
||||||
styleInterpolator,
|
styleInterpolator,
|
||||||
style,
|
style,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
@@ -57,10 +63,10 @@ export default function HeaderContainer({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { header, headerMode, headerShown = true, headerTransparent } =
|
const { header, headerShown = true, headerTransparent } =
|
||||||
scene.descriptor.options || {};
|
scene.descriptor.options || {};
|
||||||
|
|
||||||
if (headerMode !== mode || !headerShown) {
|
if (!headerShown) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,27 +90,22 @@ export default function HeaderContainer({
|
|||||||
const previousDescriptor = self[i - 1]?.descriptor;
|
const previousDescriptor = self[i - 1]?.descriptor;
|
||||||
const nextDescriptor = self[i + 1]?.descriptor;
|
const nextDescriptor = self[i + 1]?.descriptor;
|
||||||
|
|
||||||
const {
|
const { headerShown: previousHeaderShown = true } =
|
||||||
headerShown: previousHeaderShown = true,
|
previousDescriptor?.options || {};
|
||||||
headerMode: previousHeaderMode,
|
|
||||||
} = previousDescriptor?.options || {};
|
|
||||||
|
|
||||||
const {
|
const { headerShown: nextHeaderShown = true } =
|
||||||
headerShown: nextHeaderShown = true,
|
nextDescriptor?.options || {};
|
||||||
headerMode: nextHeaderMode,
|
|
||||||
gestureDirection: nextGestureDirection,
|
|
||||||
} = nextDescriptor?.options || {};
|
|
||||||
|
|
||||||
const isHeaderStatic =
|
const isHeaderStatic =
|
||||||
((previousHeaderShown === false || previousHeaderMode === 'screen') &&
|
(previousHeaderShown === false &&
|
||||||
// We still need to animate when coming back from next scene
|
// We still need to animate when coming back from next scene
|
||||||
// A hacky way to check this is if the next scene exists
|
// A hacky way to check this is if the next scene exists
|
||||||
!nextDescriptor) ||
|
!nextDescriptor) ||
|
||||||
nextHeaderShown === false ||
|
nextHeaderShown === false;
|
||||||
nextHeaderMode === 'screen';
|
|
||||||
|
|
||||||
const props: StackHeaderProps = {
|
const props: StackHeaderProps = {
|
||||||
layout,
|
layout,
|
||||||
|
insets,
|
||||||
back: headerBack,
|
back: headerBack,
|
||||||
progress: scene.progress,
|
progress: scene.progress,
|
||||||
options: scene.descriptor.options,
|
options: scene.descriptor.options,
|
||||||
@@ -114,10 +115,10 @@ export default function HeaderContainer({
|
|||||||
styleInterpolator:
|
styleInterpolator:
|
||||||
mode === 'float'
|
mode === 'float'
|
||||||
? isHeaderStatic
|
? isHeaderStatic
|
||||||
? nextGestureDirection === 'vertical' ||
|
? gestureDirection === 'vertical' ||
|
||||||
nextGestureDirection === 'vertical-inverted'
|
gestureDirection === 'vertical-inverted'
|
||||||
? forSlideUp
|
? forSlideUp
|
||||||
: nextGestureDirection === 'horizontal-inverted'
|
: gestureDirection === 'horizontal-inverted'
|
||||||
? forSlideRight
|
? forSlideRight
|
||||||
: forSlideLeft
|
: forSlideLeft
|
||||||
: styleInterpolator
|
: styleInterpolator
|
||||||
|
|||||||
@@ -111,10 +111,6 @@ export default function HeaderSegment(props: Props) {
|
|||||||
headerBackTestID,
|
headerBackTestID,
|
||||||
headerBackAllowFontScaling,
|
headerBackAllowFontScaling,
|
||||||
headerBackTitleStyle,
|
headerBackTitleStyle,
|
||||||
headerTitleContainerStyle,
|
|
||||||
headerLeftContainerStyle,
|
|
||||||
headerRightContainerStyle,
|
|
||||||
headerBackgroundContainerStyle,
|
|
||||||
headerStyle: customHeaderStyle,
|
headerStyle: customHeaderStyle,
|
||||||
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
||||||
styleInterpolator,
|
styleInterpolator,
|
||||||
@@ -176,13 +172,10 @@ export default function HeaderSegment(props: Props) {
|
|||||||
layout={layout}
|
layout={layout}
|
||||||
headerTitle={headerTitle}
|
headerTitle={headerTitle}
|
||||||
headerLeft={headerLeft}
|
headerLeft={headerLeft}
|
||||||
headerTitleContainerStyle={[titleStyle, headerTitleContainerStyle]}
|
headerTitleContainerStyle={titleStyle}
|
||||||
headerLeftContainerStyle={[leftButtonStyle, headerLeftContainerStyle]}
|
headerLeftContainerStyle={leftButtonStyle}
|
||||||
headerRightContainerStyle={[rightButtonStyle, headerRightContainerStyle]}
|
headerRightContainerStyle={rightButtonStyle}
|
||||||
headerBackgroundContainerStyle={[
|
headerBackgroundContainerStyle={backgroundStyle}
|
||||||
backgroundStyle,
|
|
||||||
headerBackgroundContainerStyle,
|
|
||||||
]}
|
|
||||||
headerStyle={customHeaderStyle}
|
headerStyle={customHeaderStyle}
|
||||||
headerStatusBarHeight={headerStatusBarHeight}
|
headerStatusBarHeight={headerStatusBarHeight}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
|
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
|
|
||||||
const input: InputRef = TextInput.State.currentlyFocusedInput();
|
// @ts-expect-error: blurTextInput accepts both number and ref, but types say only ref
|
||||||
|
const input: InputRef = TextInput.State.currentlyFocusedField();
|
||||||
|
|
||||||
// When a page change begins, blur the currently focused input
|
// When a page change begins, blur the currently focused input
|
||||||
input?.blur();
|
input?.blur();
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { StatusBar, StyleSheet } from 'react-native';
|
|
||||||
import { useTheme } from '@react-navigation/native';
|
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
|
||||||
import type { Layout } from '../types';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
dark: boolean | undefined;
|
|
||||||
layout: Layout;
|
|
||||||
insets: EdgeInsets;
|
|
||||||
style: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ModalStatusBarManager({
|
|
||||||
dark,
|
|
||||||
layout,
|
|
||||||
insets,
|
|
||||||
style,
|
|
||||||
}: Props) {
|
|
||||||
const { dark: darkTheme } = useTheme();
|
|
||||||
const [overlapping, setOverlapping] = React.useState(true);
|
|
||||||
|
|
||||||
const enabled = layout.width && layout.height > layout.width;
|
|
||||||
const scale = 1 - 20 / layout.width;
|
|
||||||
const offset = (insets.top - 34) * scale;
|
|
||||||
|
|
||||||
const flattenedStyle = StyleSheet.flatten(style);
|
|
||||||
const translateY = flattenedStyle?.transform?.find(
|
|
||||||
(s: any) => s.translateY !== undefined
|
|
||||||
)?.translateY;
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const listener = ({ value }: { value: number }) => {
|
|
||||||
setOverlapping(value < offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sub = translateY?.addListener(listener);
|
|
||||||
|
|
||||||
return () => translateY?.removeListener(sub);
|
|
||||||
}, [enabled, offset, translateY]);
|
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const darkContent = dark ?? !darkTheme;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StatusBar
|
|
||||||
animated
|
|
||||||
barStyle={overlapping && darkContent ? 'dark-content' : 'light-content'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -18,8 +18,6 @@ import {
|
|||||||
GestureState,
|
GestureState,
|
||||||
PanGestureHandlerGestureEvent,
|
PanGestureHandlerGestureEvent,
|
||||||
} from '../GestureHandler';
|
} from '../GestureHandler';
|
||||||
import ModalStatusBarManager from '../ModalStatusBarManager';
|
|
||||||
import { forModalPresentationIOS } from '../../TransitionConfigs/CardStyleInterpolators';
|
|
||||||
import CardAnimationContext from '../../utils/CardAnimationContext';
|
import CardAnimationContext from '../../utils/CardAnimationContext';
|
||||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||||
import getInvertedMultiplier from '../../utils/getInvertedMultiplier';
|
import getInvertedMultiplier from '../../utils/getInvertedMultiplier';
|
||||||
@@ -39,7 +37,6 @@ type Props = ViewProps & {
|
|||||||
gesture: Animated.Value;
|
gesture: Animated.Value;
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
insets: EdgeInsets;
|
insets: EdgeInsets;
|
||||||
headerDarkContent: boolean | undefined;
|
|
||||||
pageOverflowEnabled: boolean;
|
pageOverflowEnabled: boolean;
|
||||||
gestureDirection: GestureDirection;
|
gestureDirection: GestureDirection;
|
||||||
onOpen: () => void;
|
onOpen: () => void;
|
||||||
@@ -55,7 +52,10 @@ type Props = ViewProps & {
|
|||||||
overlayEnabled: boolean;
|
overlayEnabled: boolean;
|
||||||
shadowEnabled: boolean;
|
shadowEnabled: boolean;
|
||||||
gestureEnabled: boolean;
|
gestureEnabled: boolean;
|
||||||
gestureResponseDistance?: number;
|
gestureResponseDistance?: {
|
||||||
|
vertical?: number;
|
||||||
|
horizontal?: number;
|
||||||
|
};
|
||||||
gestureVelocityImpact: number;
|
gestureVelocityImpact: number;
|
||||||
transitionSpec: {
|
transitionSpec: {
|
||||||
open: TransitionSpec;
|
open: TransitionSpec;
|
||||||
@@ -406,11 +406,13 @@ export default class Card extends React.Component<Props> {
|
|||||||
const { layout, gestureDirection, gestureResponseDistance } = this.props;
|
const { layout, gestureDirection, gestureResponseDistance } = this.props;
|
||||||
|
|
||||||
const distance =
|
const distance =
|
||||||
gestureResponseDistance !== undefined
|
gestureDirection === 'vertical' ||
|
||||||
? gestureResponseDistance
|
gestureDirection === 'vertical-inverted'
|
||||||
: gestureDirection === 'vertical' ||
|
? gestureResponseDistance?.vertical !== undefined
|
||||||
gestureDirection === 'vertical-inverted'
|
? gestureResponseDistance.vertical
|
||||||
? GESTURE_RESPONSE_DISTANCE_VERTICAL
|
: GESTURE_RESPONSE_DISTANCE_VERTICAL
|
||||||
|
: gestureResponseDistance?.horizontal !== undefined
|
||||||
|
? gestureResponseDistance.horizontal
|
||||||
: GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
|
: GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
|
||||||
|
|
||||||
if (gestureDirection === 'vertical') {
|
if (gestureDirection === 'vertical') {
|
||||||
@@ -462,7 +464,6 @@ export default class Card extends React.Component<Props> {
|
|||||||
gestureEnabled,
|
gestureEnabled,
|
||||||
gestureDirection,
|
gestureDirection,
|
||||||
pageOverflowEnabled,
|
pageOverflowEnabled,
|
||||||
headerDarkContent,
|
|
||||||
children,
|
children,
|
||||||
containerStyle: customContainerStyle,
|
containerStyle: customContainerStyle,
|
||||||
contentStyle,
|
contentStyle,
|
||||||
@@ -522,22 +523,6 @@ export default class Card extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CardAnimationContext.Provider value={animationContext}>
|
<CardAnimationContext.Provider value={animationContext}>
|
||||||
{
|
|
||||||
// StatusBar messes with translucent status bar on Android
|
|
||||||
// So we should only enable it on iOS
|
|
||||||
Platform.OS === 'ios' &&
|
|
||||||
overlayEnabled &&
|
|
||||||
index === 0 &&
|
|
||||||
next &&
|
|
||||||
styleInterpolator === forModalPresentationIOS ? (
|
|
||||||
<ModalStatusBarManager
|
|
||||||
dark={headerDarkContent}
|
|
||||||
layout={layout}
|
|
||||||
insets={insets}
|
|
||||||
style={cardStyle}
|
|
||||||
/>
|
|
||||||
) : null
|
|
||||||
}
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
// This is a dummy style that doesn't actually change anything visually.
|
// This is a dummy style that doesn't actually change anything visually.
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ type Props = TransitionPreset & {
|
|||||||
layout: Layout;
|
layout: Layout;
|
||||||
gesture: Animated.Value;
|
gesture: Animated.Value;
|
||||||
scene: Scene;
|
scene: Scene;
|
||||||
headerDarkContent: boolean | undefined;
|
|
||||||
safeAreaInsetTop: number;
|
safeAreaInsetTop: number;
|
||||||
safeAreaInsetRight: number;
|
safeAreaInsetRight: number;
|
||||||
safeAreaInsetBottom: number;
|
safeAreaInsetBottom: number;
|
||||||
@@ -56,12 +55,15 @@ type Props = TransitionPreset & {
|
|||||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||||
onGestureCancel?: (props: { route: Route<string> }) => void;
|
onGestureCancel?: (props: { route: Route<string> }) => void;
|
||||||
gestureEnabled?: boolean;
|
gestureEnabled?: boolean;
|
||||||
gestureResponseDistance?: number;
|
gestureResponseDistance?: {
|
||||||
|
vertical?: number;
|
||||||
|
horizontal?: number;
|
||||||
|
};
|
||||||
gestureVelocityImpact?: number;
|
gestureVelocityImpact?: number;
|
||||||
mode: StackCardMode;
|
mode: StackCardMode;
|
||||||
headerMode: StackHeaderMode;
|
headerMode: StackHeaderMode;
|
||||||
headerShown: boolean;
|
headerShown: boolean;
|
||||||
hasAbsoluteFloatHeader: boolean;
|
hasAbsoluteHeader: boolean;
|
||||||
headerHeight: number;
|
headerHeight: number;
|
||||||
onHeaderHeightChange: (props: {
|
onHeaderHeightChange: (props: {
|
||||||
route: Route<string>;
|
route: Route<string>;
|
||||||
@@ -89,11 +91,10 @@ function CardContainer({
|
|||||||
getPreviousScene,
|
getPreviousScene,
|
||||||
getFocusedRoute,
|
getFocusedRoute,
|
||||||
mode,
|
mode,
|
||||||
headerDarkContent,
|
|
||||||
headerMode,
|
headerMode,
|
||||||
headerShown,
|
headerShown,
|
||||||
headerStyleInterpolator,
|
headerStyleInterpolator,
|
||||||
hasAbsoluteFloatHeader,
|
hasAbsoluteHeader,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
onHeaderHeightChange,
|
onHeaderHeightChange,
|
||||||
isParentHeaderShown,
|
isParentHeaderShown,
|
||||||
@@ -118,8 +119,6 @@ function CardContainer({
|
|||||||
scene,
|
scene,
|
||||||
transitionSpec,
|
transitionSpec,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const parentHeaderHeight = React.useContext(HeaderHeightContext);
|
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
const { route } = scene.descriptor;
|
const { route } = scene.descriptor;
|
||||||
|
|
||||||
@@ -247,12 +246,7 @@ function CardContainer({
|
|||||||
importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
|
importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
|
||||||
pointerEvents={active ? 'box-none' : pointerEvents}
|
pointerEvents={active ? 'box-none' : pointerEvents}
|
||||||
pageOverflowEnabled={headerMode !== 'float' && mode === 'card'}
|
pageOverflowEnabled={headerMode !== 'float' && mode === 'card'}
|
||||||
headerDarkContent={headerDarkContent}
|
containerStyle={hasAbsoluteHeader ? { marginTop: headerHeight } : null}
|
||||||
containerStyle={
|
|
||||||
hasAbsoluteFloatHeader && headerMode !== 'screen'
|
|
||||||
? { marginTop: headerHeight }
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
@@ -269,9 +263,7 @@ function CardContainer({
|
|||||||
<HeaderShownContext.Provider
|
<HeaderShownContext.Provider
|
||||||
value={isParentHeaderShown || headerShown !== false}
|
value={isParentHeaderShown || headerShown !== false}
|
||||||
>
|
>
|
||||||
<HeaderHeightContext.Provider
|
<HeaderHeightContext.Provider value={headerHeight}>
|
||||||
value={headerShown ? headerHeight : parentHeaderHeight}
|
|
||||||
>
|
|
||||||
{renderScene({ route: scene.descriptor.route })}
|
{renderScene({ route: scene.descriptor.route })}
|
||||||
</HeaderHeightContext.Provider>
|
</HeaderHeightContext.Provider>
|
||||||
</HeaderShownContext.Provider>
|
</HeaderShownContext.Provider>
|
||||||
@@ -282,9 +274,11 @@ function CardContainer({
|
|||||||
{renderHeader({
|
{renderHeader({
|
||||||
mode: 'screen',
|
mode: 'screen',
|
||||||
layout,
|
layout,
|
||||||
|
insets,
|
||||||
scenes: [previousScene, scene],
|
scenes: [previousScene, scene],
|
||||||
getPreviousScene,
|
getPreviousScene,
|
||||||
getFocusedRoute,
|
getFocusedRoute,
|
||||||
|
gestureDirection,
|
||||||
styleInterpolator: headerStyleInterpolator,
|
styleInterpolator: headerStyleInterpolator,
|
||||||
onContentHeightChange: onHeaderHeightChange,
|
onContentHeightChange: onHeaderHeightChange,
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
import Color from 'color';
|
|
||||||
import type {
|
import type {
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
Route,
|
Route,
|
||||||
@@ -15,7 +14,6 @@ import type {
|
|||||||
import {
|
import {
|
||||||
getDefaultHeaderHeight,
|
getDefaultHeaderHeight,
|
||||||
SafeAreaProviderCompat,
|
SafeAreaProviderCompat,
|
||||||
Background,
|
|
||||||
} from '@react-navigation/elements';
|
} from '@react-navigation/elements';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -29,10 +27,12 @@ import {
|
|||||||
DefaultTransition,
|
DefaultTransition,
|
||||||
ModalTransition,
|
ModalTransition,
|
||||||
} from '../../TransitionConfigs/TransitionPresets';
|
} from '../../TransitionConfigs/TransitionPresets';
|
||||||
|
import { forNoAnimation as forNoAnimationHeader } from '../../TransitionConfigs/HeaderStyleInterpolators';
|
||||||
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
|
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
|
||||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||||
import type {
|
import type {
|
||||||
Layout,
|
Layout,
|
||||||
|
StackHeaderMode,
|
||||||
StackCardMode,
|
StackCardMode,
|
||||||
StackDescriptorMap,
|
StackDescriptorMap,
|
||||||
StackNavigationOptions,
|
StackNavigationOptions,
|
||||||
@@ -60,6 +60,7 @@ type Props = {
|
|||||||
getGesturesEnabled: (props: { route: Route<string> }) => boolean;
|
getGesturesEnabled: (props: { route: Route<string> }) => boolean;
|
||||||
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
||||||
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
||||||
|
headerMode: StackHeaderMode;
|
||||||
isParentHeaderShown: boolean;
|
isParentHeaderShown: boolean;
|
||||||
onTransitionStart: (
|
onTransitionStart: (
|
||||||
props: { route: Route<string> },
|
props: { route: Route<string> },
|
||||||
@@ -107,8 +108,13 @@ const getHeaderHeights = (
|
|||||||
const height =
|
const height =
|
||||||
typeof style.height === 'number' ? style.height : previous[curr.key];
|
typeof style.height === 'number' ? style.height : previous[curr.key];
|
||||||
|
|
||||||
|
const safeAreaInsets = {
|
||||||
|
...insets,
|
||||||
|
...options.safeAreaInsets,
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
headerStatusBarHeight = isParentHeaderShown ? 0 : safeAreaInsets.top,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
acc[curr.key] =
|
acc[curr.key] =
|
||||||
@@ -380,6 +386,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
getGesturesEnabled,
|
getGesturesEnabled,
|
||||||
renderHeader,
|
renderHeader,
|
||||||
renderScene,
|
renderScene,
|
||||||
|
headerMode,
|
||||||
isParentHeaderShown,
|
isParentHeaderShown,
|
||||||
onTransitionStart,
|
onTransitionStart,
|
||||||
onTransitionEnd,
|
onTransitionEnd,
|
||||||
@@ -406,6 +413,20 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
let defaultTransitionPreset =
|
let defaultTransitionPreset =
|
||||||
mode === 'modal' ? ModalTransition : DefaultTransition;
|
mode === 'modal' ? ModalTransition : DefaultTransition;
|
||||||
|
|
||||||
|
if (headerMode !== 'float') {
|
||||||
|
defaultTransitionPreset = {
|
||||||
|
...defaultTransitionPreset,
|
||||||
|
headerStyleInterpolator: forNoAnimationHeader,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
top = insets.top,
|
||||||
|
right = insets.right,
|
||||||
|
bottom = insets.bottom,
|
||||||
|
left = insets.left,
|
||||||
|
} = focusedOptions.safeAreaInsets || {};
|
||||||
|
|
||||||
let activeScreensLimit = 1;
|
let activeScreensLimit = 1;
|
||||||
|
|
||||||
for (let i = scenes.length - 1; i >= 0; i--) {
|
for (let i = scenes.length - 1; i >= 0; i--) {
|
||||||
@@ -423,52 +444,54 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFloatHeaderAbsolute = this.state.scenes.slice(-2).some((scene) => {
|
const isFloatHeaderAbsolute =
|
||||||
const options = scene.descriptor.options ?? {};
|
headerMode === 'float'
|
||||||
const {
|
? this.state.scenes.slice(-2).some((scene) => {
|
||||||
headerMode = 'screen',
|
const { descriptor } = scene;
|
||||||
headerTransparent,
|
const options = descriptor ? descriptor.options : {};
|
||||||
headerShown = true,
|
const { headerTransparent, headerShown = true } = options;
|
||||||
} = options;
|
|
||||||
|
|
||||||
if (
|
if (headerTransparent || headerShown === false) {
|
||||||
headerTransparent ||
|
return true;
|
||||||
headerShown === false ||
|
}
|
||||||
headerMode === 'screen'
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
})
|
||||||
|
: false;
|
||||||
|
|
||||||
const floatingHeader = (
|
const floatingHeader =
|
||||||
<React.Fragment key="header">
|
headerMode === 'float' ? (
|
||||||
{renderHeader({
|
<React.Fragment key="header">
|
||||||
mode: 'float',
|
{renderHeader({
|
||||||
layout,
|
mode: 'float',
|
||||||
scenes,
|
layout,
|
||||||
getPreviousScene: this.getPreviousScene,
|
insets: { top, right, bottom, left },
|
||||||
getFocusedRoute: this.getFocusedRoute,
|
scenes,
|
||||||
onContentHeightChange: this.handleHeaderLayout,
|
getPreviousScene: this.getPreviousScene,
|
||||||
styleInterpolator:
|
getFocusedRoute: this.getFocusedRoute,
|
||||||
focusedOptions.headerStyleInterpolator !== undefined
|
onContentHeightChange: this.handleHeaderLayout,
|
||||||
? focusedOptions.headerStyleInterpolator
|
gestureDirection:
|
||||||
: defaultTransitionPreset.headerStyleInterpolator,
|
focusedOptions.gestureDirection !== undefined
|
||||||
style: [
|
? focusedOptions.gestureDirection
|
||||||
styles.floating,
|
: defaultTransitionPreset.gestureDirection,
|
||||||
isFloatHeaderAbsolute && [
|
styleInterpolator:
|
||||||
// Without this, the header buttons won't be touchable on Android when headerTransparent: true
|
focusedOptions.headerStyleInterpolator !== undefined
|
||||||
{ height: focusedHeaderHeight },
|
? focusedOptions.headerStyleInterpolator
|
||||||
styles.absolute,
|
: defaultTransitionPreset.headerStyleInterpolator,
|
||||||
|
style: [
|
||||||
|
styles.floating,
|
||||||
|
isFloatHeaderAbsolute && [
|
||||||
|
// Without this, the header buttons won't be touchable on Android when headerTransparent: true
|
||||||
|
{ height: focusedHeaderHeight },
|
||||||
|
styles.absolute,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
})}
|
||||||
})}
|
</React.Fragment>
|
||||||
</React.Fragment>
|
) : null;
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Background>
|
<React.Fragment>
|
||||||
{isFloatHeaderAbsolute ? null : floatingHeader}
|
{isFloatHeaderAbsolute ? null : floatingHeader}
|
||||||
<MaybeScreenContainer
|
<MaybeScreenContainer
|
||||||
enabled={detachInactiveScreens}
|
enabled={detachInactiveScreens}
|
||||||
@@ -517,11 +540,9 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
safeAreaInsets,
|
||||||
headerShown = true,
|
headerShown = true,
|
||||||
headerMode = 'screen',
|
|
||||||
headerTransparent,
|
headerTransparent,
|
||||||
headerStyle,
|
|
||||||
headerTintColor,
|
|
||||||
cardShadowEnabled,
|
cardShadowEnabled,
|
||||||
cardOverlayEnabled = Platform.OS !== 'ios' || mode === 'modal',
|
cardOverlayEnabled = Platform.OS !== 'ios' || mode === 'modal',
|
||||||
cardOverlay,
|
cardOverlay,
|
||||||
@@ -577,27 +598,16 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeAreaInsetTop = insets.top;
|
const {
|
||||||
const safeAreaInsetRight = insets.right;
|
top: safeAreaInsetTop = insets.top,
|
||||||
const safeAreaInsetBottom = insets.bottom;
|
right: safeAreaInsetRight = insets.right,
|
||||||
const safeAreaInsetLeft = insets.left;
|
bottom: safeAreaInsetBottom = insets.bottom,
|
||||||
|
left: safeAreaInsetLeft = insets.left,
|
||||||
|
} = safeAreaInsets || {};
|
||||||
|
|
||||||
const headerHeight =
|
const headerHeight =
|
||||||
headerShown !== false ? headerHeights[route.key] : 0;
|
headerShown !== false ? headerHeights[route.key] : 0;
|
||||||
|
|
||||||
const { backgroundColor: headerBackgroundColor } =
|
|
||||||
StyleSheet.flatten(headerStyle) || {};
|
|
||||||
|
|
||||||
let headerDarkContent: boolean | undefined;
|
|
||||||
|
|
||||||
if (headerShown) {
|
|
||||||
if (headerTintColor) {
|
|
||||||
headerDarkContent = Color(headerTintColor).isDark();
|
|
||||||
} else if (typeof headerBackgroundColor === 'string') {
|
|
||||||
headerDarkContent = !Color(headerBackgroundColor).isDark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MaybeScreen
|
<MaybeScreen
|
||||||
key={route.key}
|
key={route.key}
|
||||||
@@ -637,8 +647,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
mode={mode}
|
mode={mode}
|
||||||
headerMode={headerMode}
|
headerMode={headerMode}
|
||||||
headerShown={headerShown}
|
headerShown={headerShown}
|
||||||
headerDarkContent={headerDarkContent}
|
hasAbsoluteHeader={
|
||||||
hasAbsoluteFloatHeader={
|
|
||||||
isFloatHeaderAbsolute && !headerTransparent
|
isFloatHeaderAbsolute && !headerTransparent
|
||||||
}
|
}
|
||||||
renderHeader={renderHeader}
|
renderHeader={renderHeader}
|
||||||
@@ -656,7 +665,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
})}
|
})}
|
||||||
</MaybeScreenContainer>
|
</MaybeScreenContainer>
|
||||||
{isFloatHeaderAbsolute ? floatingHeader : null}
|
{isFloatHeaderAbsolute ? floatingHeader : null}
|
||||||
</Background>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, StyleSheet } from 'react-native';
|
import { View, Platform, StyleSheet } from 'react-native';
|
||||||
import {
|
import {
|
||||||
SafeAreaInsetsContext,
|
SafeAreaInsetsContext,
|
||||||
EdgeInsets,
|
EdgeInsets,
|
||||||
@@ -439,6 +439,9 @@ export default class StackView extends React.Component<Props, State> {
|
|||||||
navigation,
|
navigation,
|
||||||
keyboardHandlingEnabled,
|
keyboardHandlingEnabled,
|
||||||
mode = 'card',
|
mode = 'card',
|
||||||
|
headerMode = mode === 'card' && Platform.OS === 'ios'
|
||||||
|
? 'float'
|
||||||
|
: 'screen',
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
descriptors: _,
|
descriptors: _,
|
||||||
...rest
|
...rest
|
||||||
@@ -476,6 +479,7 @@ export default class StackView extends React.Component<Props, State> {
|
|||||||
onTransitionEnd={this.handleTransitionEnd}
|
onTransitionEnd={this.handleTransitionEnd}
|
||||||
renderHeader={this.renderHeader}
|
renderHeader={this.renderHeader}
|
||||||
renderScene={this.renderScene}
|
renderScene={this.renderScene}
|
||||||
|
headerMode={headerMode}
|
||||||
state={state}
|
state={state}
|
||||||
descriptors={descriptors}
|
descriptors={descriptors}
|
||||||
onGestureStart={this.handleGestureStart}
|
onGestureStart={this.handleGestureStart}
|
||||||
|
|||||||
Reference in New Issue
Block a user