mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-15 09:42:27 +08:00
Compare commits
50 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
babb5027f9 | ||
|
|
78d7a66b2b | ||
|
|
a248c453ba | ||
|
|
e097df880a | ||
|
|
856449b200 | ||
|
|
d94e43c3c8 | ||
|
|
3096de6286 | ||
|
|
1c001424b5 | ||
|
|
0f2368965c | ||
|
|
61f16d3f25 | ||
|
|
853740bfaf | ||
|
|
179b6312fe | ||
|
|
043924ca48 | ||
|
|
813a5903b5 | ||
|
|
3709e652f4 | ||
|
|
5b15c7164f | ||
|
|
e030932497 | ||
|
|
adbfedcd58 | ||
|
|
bc9b044fb3 | ||
|
|
f24d3a3461 | ||
|
|
3df65e2819 | ||
|
|
5c4afc5cb4 | ||
|
|
d5bb357053 | ||
|
|
b1fe73097f | ||
|
|
49f6fed6d3 | ||
|
|
b1a65fc73e | ||
|
|
3ea8eec432 | ||
|
|
00e0f05190 | ||
|
|
193c344ba5 | ||
|
|
358d9e9feb | ||
|
|
6a5d0a035a | ||
|
|
b75744abd5 | ||
|
|
6dbda1a0c2 | ||
|
|
70029d6c13 | ||
|
|
469d0542c7 | ||
|
|
0dcaea3242 | ||
|
|
646cbfb28e | ||
|
|
660cac3557 | ||
|
|
e637250a7e | ||
|
|
82af7bed71 | ||
|
|
cb46d0bca4 | ||
|
|
b3665a325d | ||
|
|
0cc7a12b9c | ||
|
|
90e417248d | ||
|
|
e071a978e6 | ||
|
|
296c836064 | ||
|
|
09f6808d7d | ||
|
|
5bb0f405ce | ||
|
|
2dfa4f3629 | ||
|
|
cf41288760 |
2
.github/workflows/expo-preview.yml
vendored
2
.github/workflows/expo-preview.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Get expo link
|
- name: Get expo link
|
||||||
id: expo
|
id: expo
|
||||||
run: echo "::set-output name=path::@react-navigation/react-react-navigationample?release-channel=pr-${{ github.event.number }}"
|
run: echo "::set-output name=path::@react-navigation/react-navigation-example?release-channel=pr-${{ github.event.number }}"
|
||||||
|
|
||||||
- name: Comment on PR
|
- name: Comment on PR
|
||||||
uses: unsplash/comment-on-pr@master
|
uses: unsplash/comment-on-pr@master
|
||||||
|
|||||||
20
.github/workflows/stale.yml
vendored
20
.github/workflows/stale.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: "Close stale issues and pull requests"
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v1
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
stale-issue-message: 'Hello 👋, this issue has been open for more than 3 months with no activity on it. If the issue is still present in the latest version, please leave a comment within 7 days to keep it open, otherwise it will be closed automatically. If you found a solution on workaround for the issue, please comment here for others to find. If this issue is critical for you, please consider sending a pull request to fix the issue.'
|
|
||||||
stale-pr-message: 'Hello 👋, this pull request has been open for more than 3 months with no activity on it. If you think this is still necessary with the latest version, please comment and ping a maintainer to get this reviewed, otherwise it will be closed automatically in 7 days.'
|
|
||||||
days-before-stale: 90
|
|
||||||
days-before-close: 7
|
|
||||||
stale-issue-label: 'stale'
|
|
||||||
stale-pr-label: 'stale'
|
|
||||||
exempt-issue-label: 'keep open'
|
|
||||||
exempt-pr-label: 'keep open'
|
|
||||||
11
.github/workflows/triage.yml
vendored
11
.github/workflows/triage.yml
vendored
@@ -36,3 +36,14 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
args: comment "Hey! Thanks for opening the issue. The issue tracker is intended for only tracking bug reports. This helps us prioritize fixing bugs in the library. Seems you have a usage question. Please ask the question on [StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation) instead using the `react-navigation` label. You can also chat with other community members on [Reactiflux Discord server](https://www.reactiflux.com/) in the `#react-navigation` channel."
|
args: comment "Hey! Thanks for opening the issue. The issue tracker is intended for only tracking bug reports. This helps us prioritize fixing bugs in the library. Seems you have a usage question. Please ask the question on [StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation) instead using the `react-navigation` label. You can also chat with other community members on [Reactiflux Discord server](https://www.reactiflux.com/) in the `#react-navigation` channel."
|
||||||
|
|
||||||
|
feature-request:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.label.name == 'feature-request'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
- uses: actions/github@v1.0.0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
args: comment "Hey! Thanks for opening the issue. The issue tracker is intended for only tracking bug reports. Seems you have a feature request. Please post the feature request on [Canny](https://react-navigation.canny.io/feature-requests). This lets other users upvote your feature request and helps us prioritize the most requested features."
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
|||||||
.gradle
|
.gradle
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
|
.history
|
||||||
|
|
||||||
local.properties
|
local.properties
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = function(api) {
|
module.exports = function (api) {
|
||||||
api.cache(true);
|
api.cache(true);
|
||||||
return {
|
return {
|
||||||
presets: ['babel-preset-expo'],
|
presets: ['babel-preset-expo'],
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* eslint-disable jest/no-jasmine-globals, import/no-commonjs */
|
/* eslint-disable import/no-commonjs */
|
||||||
|
|
||||||
const detox = require('detox');
|
const detox = require('detox');
|
||||||
const config = require('../../package.json').detox;
|
const config = require('../../package.json').detox;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ const modules = ['@expo/vector-icons']
|
|||||||
// List all packages under `packages/`
|
// List all packages under `packages/`
|
||||||
.readdirSync(packages)
|
.readdirSync(packages)
|
||||||
// Ignore hidden files such as .DS_Store
|
// Ignore hidden files such as .DS_Store
|
||||||
.filter(p => !p.startsWith('.'))
|
.filter((p) => !p.startsWith('.'))
|
||||||
.map(p => {
|
.map((p) => {
|
||||||
const pak = JSON.parse(
|
const pak = JSON.parse(
|
||||||
fs.readFileSync(path.join(packages, p, 'package.json'), 'utf8')
|
fs.readFileSync(path.join(packages, p, 'package.json'), 'utf8')
|
||||||
);
|
);
|
||||||
@@ -50,9 +50,9 @@ module.exports = {
|
|||||||
blacklistRE: blacklist(
|
blacklistRE: blacklist(
|
||||||
fs
|
fs
|
||||||
.readdirSync(packages)
|
.readdirSync(packages)
|
||||||
.map(p => path.join(packages, p))
|
.map((p) => path.join(packages, p))
|
||||||
.map(
|
.map(
|
||||||
it => new RegExp(`^${escape(path.join(it, 'node_modules'))}\\/.*$`)
|
(it) => new RegExp(`^${escape(path.join(it, 'node_modules'))}\\/.*$`)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
enhanceMiddleware: middleware => {
|
enhanceMiddleware: (middleware) => {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
// When an asset is imported outside the project root, it has wrong path on Android
|
// When an asset is imported outside the project root, it has wrong path on Android
|
||||||
// This happens for the back button in stack, so we fix the path to correct one
|
// This happens for the back button in stack, so we fix the path to correct one
|
||||||
|
|||||||
@@ -12,31 +12,31 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^10.0.0",
|
"@expo/vector-icons": "^10.0.0",
|
||||||
"@react-native-community/masked-view": "0.1.6",
|
"@react-native-community/masked-view": "0.1.7",
|
||||||
"@types/react-native-restart": "^0.0.0",
|
"@types/react-native-restart": "^0.0.0",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"expo": "^36.0.2",
|
"expo": "^36.0.2",
|
||||||
"expo-asset": "~8.0.0",
|
"expo-asset": "~8.1.1",
|
||||||
"expo-blur": "^8.0.0",
|
"expo-blur": "~8.1.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-dom": "~16.9.0",
|
"react-dom": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.5.6",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-paper": "^3.6.0",
|
"react-native-paper": "^3.6.0",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.7.0",
|
||||||
"react-native-restart": "^0.0.13",
|
"react-native-restart": "^0.0.14",
|
||||||
"react-native-safe-area-context": "^0.7.2",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.0.0-beta.2",
|
"react-native-screens": "^2.3.0",
|
||||||
"react-native-tab-view": "2.13.0",
|
"react-native-tab-view": "2.13.0",
|
||||||
"react-native-unimodules": "^0.7.0",
|
"react-native-unimodules": "^0.8.1",
|
||||||
"react-native-web": "^0.11.7"
|
"react-native-web": "^0.11.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@expo/webpack-config": "^0.10.12",
|
"@expo/webpack-config": "^0.11.9",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"babel-preset-expo": "^8.0.0",
|
"babel-preset-expo": "^8.1.0",
|
||||||
"expo-cli": "^3.11.9",
|
"expo-cli": "^3.15.5",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function BottomTabsScreen() {
|
|||||||
return (
|
return (
|
||||||
<BottomTabs.Navigator
|
<BottomTabs.Navigator
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
tabBarButton: props => <TouchableBounce {...props} />,
|
tabBarButton: (props) => <TouchableBounce {...props} />,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<BottomTabs.Screen
|
<BottomTabs.Screen
|
||||||
@@ -38,7 +38,7 @@ export default function BottomTabsScreen() {
|
|||||||
tabBarIcon: getTabBarIcon('file-document-box'),
|
tabBarIcon: getTabBarIcon('file-document-box'),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props => <SimpleStackScreen {...props} headerMode="none" />}
|
{(props) => <SimpleStackScreen {...props} headerMode="none" />}
|
||||||
</BottomTabs.Screen>
|
</BottomTabs.Screen>
|
||||||
<BottomTabs.Screen
|
<BottomTabs.Screen
|
||||||
name="Chat"
|
name="Chat"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function BottomTabsScreen() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BottomTabs.Navigator>
|
<BottomTabs.Navigator>
|
||||||
{tabs.map(i => (
|
{tabs.map((i) => (
|
||||||
<BottomTabs.Screen
|
<BottomTabs.Screen
|
||||||
key={i}
|
key={i}
|
||||||
name={`tab-${i}`}
|
name={`tab-${i}`}
|
||||||
@@ -29,12 +29,14 @@ export default function BottomTabsScreen() {
|
|||||||
{() => (
|
{() => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Title>Tab {i}</Title>
|
<Title>Tab {i}</Title>
|
||||||
<Button onPress={() => setTabs(tabs => [...tabs, tabs.length])}>
|
<Button onPress={() => setTabs((tabs) => [...tabs, tabs.length])}>
|
||||||
Add a tab
|
Add a tab
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
setTabs(tabs => (tabs.length > 1 ? tabs.slice(0, -1) : tabs))
|
setTabs((tabs) =>
|
||||||
|
tabs.length > 1 ? tabs.slice(0, -1) : tabs
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Remove a tab
|
Remove a tab
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function MaterialBottomTabsScreen() {
|
|||||||
tabBarColor: '#C9E7F8',
|
tabBarColor: '#C9E7F8',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props => <SimpleStackScreen {...props} headerMode="none" />}
|
{(props) => <SimpleStackScreen {...props} headerMode="none" />}
|
||||||
</MaterialBottomTabs.Screen>
|
</MaterialBottomTabs.Screen>
|
||||||
<MaterialBottomTabs.Screen
|
<MaterialBottomTabs.Screen
|
||||||
name="Chat"
|
name="Chat"
|
||||||
|
|||||||
@@ -68,10 +68,7 @@ export default function Chat(props: Partial<ScrollViewProps>) {
|
|||||||
styles.input,
|
styles.input,
|
||||||
{ backgroundColor: colors.card, color: colors.text },
|
{ backgroundColor: colors.card, color: colors.text },
|
||||||
]}
|
]}
|
||||||
placeholderTextColor={Color(colors.text)
|
placeholderTextColor={Color(colors.text).alpha(0.5).rgb().string()}
|
||||||
.alpha(0.5)
|
|
||||||
.rgb()
|
|
||||||
.string()}
|
|
||||||
placeholder="Write a message"
|
placeholder="Write a message"
|
||||||
underlineColorAndroid="transparent"
|
underlineColorAndroid="transparent"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -51,10 +51,7 @@ export default function NewsFeed(props: Props) {
|
|||||||
<Card style={styles.card}>
|
<Card style={styles.card}>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="What's on your mind?"
|
placeholder="What's on your mind?"
|
||||||
placeholderTextColor={Color(colors.text)
|
placeholderTextColor={Color(colors.text).alpha(0.5).rgb().string()}
|
||||||
.alpha(0.5)
|
|
||||||
.rgb()
|
|
||||||
.string()}
|
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
I18nManager,
|
I18nManager,
|
||||||
|
Dimensions,
|
||||||
|
ScaledSize,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import { enableScreens } from 'react-native-screens';
|
import { enableScreens } from 'react-native-screens';
|
||||||
@@ -196,10 +198,24 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
}, [theme.colors, theme.dark]);
|
}, [theme.colors, theme.dark]);
|
||||||
|
|
||||||
|
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const onDimensionsChange = ({ window }: { window: ScaledSize }) => {
|
||||||
|
setDimensions(window);
|
||||||
|
};
|
||||||
|
|
||||||
|
Dimensions.addEventListener('change', onDimensionsChange);
|
||||||
|
|
||||||
|
return () => Dimensions.removeEventListener('change', onDimensionsChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isLargeScreen = dimensions.width > 900;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaperProvider theme={paperTheme}>
|
<PaperProvider theme={paperTheme}>
|
||||||
{Platform.OS === 'ios' && (
|
{Platform.OS === 'ios' && (
|
||||||
@@ -208,7 +224,7 @@ export default function App() {
|
|||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
initialState={initialState}
|
initialState={initialState}
|
||||||
onStateChange={state =>
|
onStateChange={(state) =>
|
||||||
AsyncStorage.setItem(
|
AsyncStorage.setItem(
|
||||||
NAVIGATION_PERSISTENCE_KEY,
|
NAVIGATION_PERSISTENCE_KEY,
|
||||||
JSON.stringify(state)
|
JSON.stringify(state)
|
||||||
@@ -216,7 +232,7 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
>
|
>
|
||||||
<Drawer.Navigator>
|
<Drawer.Navigator drawerType={isLargeScreen ? 'permanent' : undefined}>
|
||||||
<Drawer.Screen
|
<Drawer.Screen
|
||||||
name="Root"
|
name="Root"
|
||||||
options={{
|
options={{
|
||||||
@@ -240,13 +256,15 @@ export default function App() {
|
|||||||
name="Home"
|
name="Home"
|
||||||
options={{
|
options={{
|
||||||
title: 'Examples',
|
title: 'Examples',
|
||||||
headerLeft: () => (
|
headerLeft: isLargeScreen
|
||||||
<Appbar.Action
|
? undefined
|
||||||
color={theme.colors.text}
|
: () => (
|
||||||
icon="menu"
|
<Appbar.Action
|
||||||
onPress={() => navigation.toggleDrawer()}
|
color={theme.colors.text}
|
||||||
/>
|
icon="menu"
|
||||||
),
|
onPress={() => navigation.toggleDrawer()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({
|
{({
|
||||||
@@ -280,12 +298,12 @@ export default function App() {
|
|||||||
theme.dark ? 'light' : 'dark'
|
theme.dark ? 'light' : 'dark'
|
||||||
);
|
);
|
||||||
|
|
||||||
setTheme(t => (t.dark ? DefaultTheme : DarkTheme));
|
setTheme((t) => (t.dark ? DefaultTheme : DarkTheme));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Divider />
|
<Divider />
|
||||||
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
||||||
name => (
|
(name) => (
|
||||||
<List.Item
|
<List.Item
|
||||||
key={name}
|
key={name}
|
||||||
title={SCREENS[name].title}
|
title={SCREENS[name].title}
|
||||||
@@ -297,7 +315,7 @@ export default function App() {
|
|||||||
)}
|
)}
|
||||||
</Stack.Screen>
|
</Stack.Screen>
|
||||||
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
||||||
name => (
|
(name) => (
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
key={name}
|
key={name}
|
||||||
name={name}
|
name={name}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
|||||||
const node_modules = path.resolve(__dirname, '..', 'node_modules');
|
const node_modules = path.resolve(__dirname, '..', 'node_modules');
|
||||||
const packages = path.resolve(__dirname, '..', 'packages');
|
const packages = path.resolve(__dirname, '..', 'packages');
|
||||||
|
|
||||||
module.exports = async function(env, argv) {
|
module.exports = async function (env, argv) {
|
||||||
const config = await createExpoWebpackConfigAsync(env, argv);
|
const config = await createExpoWebpackConfigAsync(env, argv);
|
||||||
|
|
||||||
config.context = path.resolve(__dirname, '..');
|
config.context = path.resolve(__dirname, '..');
|
||||||
@@ -20,7 +20,7 @@ module.exports = async function(env, argv) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
config.resolve.plugins = config.resolve.plugins.filter(
|
config.resolve.plugins = config.resolve.plugins.filter(
|
||||||
p => !(p instanceof ModuleScopePlugin)
|
(p) => !(p instanceof ModuleScopePlugin)
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(config.resolve.alias, {
|
Object.assign(config.resolve.alias, {
|
||||||
@@ -30,7 +30,7 @@ module.exports = async function(env, argv) {
|
|||||||
'@expo/vector-icons': path.resolve(node_modules, '@expo/vector-icons'),
|
'@expo/vector-icons': path.resolve(node_modules, '@expo/vector-icons'),
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.readdirSync(packages).forEach(name => {
|
fs.readdirSync(packages).forEach((name) => {
|
||||||
config.resolve.alias[`@react-navigation/${name}`] = path.resolve(
|
config.resolve.alias[`@react-navigation/${name}`] = path.resolve(
|
||||||
packages,
|
packages,
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const error = console.error;
|
const error = console.error;
|
||||||
|
|
||||||
console.error = (...args) =>
|
console.error = (...args) =>
|
||||||
// Supress error messages regarding error boundary in tests
|
// Suppress error messages regarding error boundary in tests
|
||||||
/(Consider adding an error boundary to your tree to customize error handling behavior|React will try to recreate this component tree from scratch using the error boundary you provided|Error boundaries should implement getDerivedStateFromError)/m.test(
|
/(Consider adding an error boundary to your tree to customize error handling behavior|React will try to recreate this component tree from scratch using the error boundary you provided|Error boundaries should implement getDerivedStateFromError)/m.test(
|
||||||
args[0]
|
args[0]
|
||||||
)
|
)
|
||||||
|
|||||||
23
package.json
23
package.json
@@ -20,29 +20,30 @@
|
|||||||
"lint": "eslint --ext '.js,.ts,.tsx' .",
|
"lint": "eslint --ext '.js,.ts,.tsx' .",
|
||||||
"typescript": "tsc --noEmit",
|
"typescript": "tsc --noEmit",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
|
"prerelease": "lerna run clean",
|
||||||
"release": "lerna publish",
|
"release": "lerna publish",
|
||||||
"example": "yarn --cwd example"
|
"example": "yarn --cwd example"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
|
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||||
"@babel/preset-env": "^7.8.4",
|
"@babel/preset-env": "^7.9.0",
|
||||||
"@babel/preset-flow": "^7.8.3",
|
"@babel/preset-flow": "^7.9.0",
|
||||||
"@babel/preset-react": "^7.8.3",
|
"@babel/preset-react": "^7.9.4",
|
||||||
"@babel/preset-typescript": "^7.8.3",
|
"@babel/preset-typescript": "^7.9.0",
|
||||||
"@babel/runtime": "^7.8.4",
|
"@babel/runtime": "^7.9.2",
|
||||||
"@commitlint/config-conventional": "^8.3.4",
|
"@commitlint/config-conventional": "^8.3.4",
|
||||||
"@types/jest": "^25.1.2",
|
"@types/jest": "^25.1.4",
|
||||||
|
"babel-jest": "^25.2.1",
|
||||||
"codecov": "^3.6.5",
|
"codecov": "^3.6.5",
|
||||||
"commitlint": "^8.3.5",
|
"commitlint": "^8.3.5",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.4",
|
||||||
"detox": "^15.1.4",
|
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-satya164": "^3.1.5",
|
"eslint-config-satya164": "^3.1.6",
|
||||||
"husky": "^4.2.1",
|
"husky": "^4.2.3",
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.1.0",
|
||||||
"lerna": "^3.20.2",
|
"lerna": "^3.20.2",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^2.0.2",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|||||||
@@ -3,6 +3,61 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.3...@react-navigation/bottom-tabs@5.2.4) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.2...@react-navigation/bottom-tabs@5.2.3) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.1...@react-navigation/bottom-tabs@5.2.2) (2020-03-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't use react-native-screens on web ([b1a65fc](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/b1a65fc73e8603ae2c06ef101a74df31e80bb9b2)), closes [#7485](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/7485)
|
||||||
|
* initialize height and width to zero if undefined ([3df65e2](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/3df65e28197db3bb8371059146546d57661c5ba3)), closes [#6789](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/6789)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.2.0...@react-navigation/bottom-tabs@5.2.1) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.1.1...@react-navigation/bottom-tabs@5.2.0) (2020-03-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add safeAreaInsets to bottom tabs ([82af7be](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/82af7bed7135e42e24693b48cf7f1c6f9f5a6981))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.1.0...@react-navigation/bottom-tabs@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.7...@react-navigation/bottom-tabs@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.7...@react-navigation/bottom-tabs@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.1.0",
|
"version": "5.2.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -34,22 +34,24 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-safe-area-context": "^0.7.2",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
|
"react-native-screens": "^2.3.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-navigation/native": "^5.0.5",
|
"@react-navigation/native": "^5.0.5",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-safe-area-context": ">= 0.6.0"
|
"react-native-safe-area-context": ">= 0.6.0",
|
||||||
|
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
|
||||||
},
|
},
|
||||||
"@react-native-community/bob": {
|
"@react-native-community/bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
ParamListBase,
|
ParamListBase,
|
||||||
Descriptor,
|
Descriptor,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
|
TabActionHelpers,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type BottomTabNavigationEventMap = {
|
export type BottomTabNavigationEventMap = {
|
||||||
@@ -40,19 +41,8 @@ export type BottomTabNavigationProp<
|
|||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
BottomTabNavigationOptions,
|
BottomTabNavigationOptions,
|
||||||
BottomTabNavigationEventMap
|
BottomTabNavigationEventMap
|
||||||
> & {
|
> &
|
||||||
/**
|
TabActionHelpers<ParamList>;
|
||||||
* Jump to an existing tab.
|
|
||||||
*
|
|
||||||
* @param name Name of the route for the tab.
|
|
||||||
* @param [params] Params object for the route.
|
|
||||||
*/
|
|
||||||
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
|
|
||||||
...args: ParamList[RouteName] extends undefined | any
|
|
||||||
? [RouteName] | [RouteName, ParamList[RouteName]]
|
|
||||||
: [RouteName, ParamList[RouteName]]
|
|
||||||
): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BottomTabNavigationOptions = {
|
export type BottomTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
@@ -184,6 +174,16 @@ export type BottomTabBarOptions = {
|
|||||||
* Whether the label position should adapt to the orientation.
|
* Whether the label position should adapt to the orientation.
|
||||||
*/
|
*/
|
||||||
adaptive?: boolean;
|
adaptive?: boolean;
|
||||||
|
/**
|
||||||
|
* Safe area insets for the tab bar. This is used to avoid elements like the navigation bar on Android and bottom safe area on iOS.
|
||||||
|
* By default, the device's safe area insets are automatically detected. You can override the behavior with this option.
|
||||||
|
*/
|
||||||
|
safeAreaInsets?: {
|
||||||
|
top?: number;
|
||||||
|
right?: number;
|
||||||
|
bottom?: number;
|
||||||
|
left?: number;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Style object for the tab bar container.
|
* Style object for the tab bar container.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
CommonActions,
|
CommonActions,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import { SafeAreaConsumer } from 'react-native-safe-area-context';
|
import { useSafeArea } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import BottomTabItem from './BottomTabItem';
|
import BottomTabItem from './BottomTabItem';
|
||||||
import { BottomTabBarProps } from '../types';
|
import { BottomTabBarProps } from '../types';
|
||||||
@@ -43,6 +43,7 @@ export default function BottomTabBar({
|
|||||||
keyboardHidesTabBar = false,
|
keyboardHidesTabBar = false,
|
||||||
labelPosition,
|
labelPosition,
|
||||||
labelStyle,
|
labelStyle,
|
||||||
|
safeAreaInsets,
|
||||||
showIcon,
|
showIcon,
|
||||||
showLabel,
|
showLabel,
|
||||||
style,
|
style,
|
||||||
@@ -50,7 +51,12 @@ export default function BottomTabBar({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
|
const [dimensions, setDimensions] = React.useState(() => {
|
||||||
|
const { height = 0, width = 0 } = Dimensions.get('window');
|
||||||
|
|
||||||
|
return { height, width };
|
||||||
|
});
|
||||||
|
|
||||||
const [layout, setLayout] = React.useState({
|
const [layout, setLayout] = React.useState({
|
||||||
height: 0,
|
height: 0,
|
||||||
width: dimensions.width,
|
width: dimensions.width,
|
||||||
@@ -115,7 +121,7 @@ export default function BottomTabBar({
|
|||||||
const handleLayout = (e: LayoutChangeEvent) => {
|
const handleLayout = (e: LayoutChangeEvent) => {
|
||||||
const { height, width } = e.nativeEvent.layout;
|
const { height, width } = e.nativeEvent.layout;
|
||||||
|
|
||||||
setLayout(layout => {
|
setLayout((layout) => {
|
||||||
if (height === layout.height && width === layout.width) {
|
if (height === layout.height && width === layout.width) {
|
||||||
return layout;
|
return layout;
|
||||||
} else {
|
} else {
|
||||||
@@ -158,116 +164,122 @@ export default function BottomTabBar({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const defaultInsets = useSafeArea();
|
||||||
|
|
||||||
|
const insets = {
|
||||||
|
top: safeAreaInsets?.top ?? defaultInsets.top,
|
||||||
|
right: safeAreaInsets?.right ?? defaultInsets.right,
|
||||||
|
bottom: safeAreaInsets?.bottom ?? defaultInsets.bottom,
|
||||||
|
left: safeAreaInsets?.left ?? defaultInsets.left,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaConsumer>
|
<Animated.View
|
||||||
{insets => (
|
style={[
|
||||||
<Animated.View
|
styles.tabBar,
|
||||||
style={[
|
{
|
||||||
styles.tabBar,
|
backgroundColor: colors.card,
|
||||||
{
|
borderTopColor: colors.border,
|
||||||
backgroundColor: colors.card,
|
},
|
||||||
borderTopColor: colors.border,
|
keyboardHidesTabBar
|
||||||
},
|
? {
|
||||||
keyboardHidesTabBar
|
// When the keyboard is shown, slide down the tab bar
|
||||||
? {
|
transform: [
|
||||||
// When the keyboard is shown, slide down the tab bar
|
{
|
||||||
transform: [
|
translateY: visible.interpolate({
|
||||||
{
|
inputRange: [0, 1],
|
||||||
translateY: visible.interpolate({
|
outputRange: [layout.height, 0],
|
||||||
inputRange: [0, 1],
|
}),
|
||||||
outputRange: [layout.height, 0],
|
},
|
||||||
}),
|
],
|
||||||
},
|
// Absolutely position the tab bar so that the content is below it
|
||||||
],
|
// This is needed to avoid gap at bottom when the tab bar is hidden
|
||||||
// Absolutely position the tab bar so that the content is below it
|
position: keyboardShown ? 'absolute' : null,
|
||||||
// This is needed to avoid gap at bottom when the tab bar is hidden
|
}
|
||||||
position: keyboardShown ? 'absolute' : null,
|
: null,
|
||||||
}
|
{
|
||||||
: null,
|
height: DEFAULT_TABBAR_HEIGHT + insets.bottom,
|
||||||
{
|
paddingBottom: insets.bottom,
|
||||||
height: DEFAULT_TABBAR_HEIGHT + (insets ? insets.bottom : 0),
|
paddingHorizontal: Math.max(insets.left, insets.right),
|
||||||
paddingBottom: insets ? insets.bottom : 0,
|
},
|
||||||
},
|
style,
|
||||||
style,
|
]}
|
||||||
]}
|
pointerEvents={keyboardHidesTabBar && keyboardShown ? 'none' : 'auto'}
|
||||||
pointerEvents={keyboardHidesTabBar && keyboardShown ? 'none' : 'auto'}
|
>
|
||||||
>
|
<View style={styles.content} onLayout={handleLayout}>
|
||||||
<View 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];
|
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
const event = navigation.emit({
|
const event = navigation.emit({
|
||||||
type: 'tabPress',
|
type: 'tabPress',
|
||||||
target: route.key,
|
target: route.key,
|
||||||
canPreventDefault: true,
|
canPreventDefault: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!focused && !event.defaultPrevented) {
|
if (!focused && !event.defaultPrevented) {
|
||||||
navigation.dispatch({
|
navigation.dispatch({
|
||||||
...CommonActions.navigate(route.name),
|
...CommonActions.navigate(route.name),
|
||||||
target: state.key,
|
target: state.key,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLongPress = () => {
|
const onLongPress = () => {
|
||||||
navigation.emit({
|
navigation.emit({
|
||||||
type: 'tabLongPress',
|
type: 'tabLongPress',
|
||||||
target: route.key,
|
target: route.key,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const label =
|
const label =
|
||||||
options.tabBarLabel !== undefined
|
options.tabBarLabel !== undefined
|
||||||
? options.tabBarLabel
|
? options.tabBarLabel
|
||||||
: options.title !== undefined
|
: options.title !== undefined
|
||||||
? options.title
|
? options.title
|
||||||
: route.name;
|
: route.name;
|
||||||
|
|
||||||
const accessibilityLabel =
|
const accessibilityLabel =
|
||||||
options.tabBarAccessibilityLabel !== undefined
|
options.tabBarAccessibilityLabel !== undefined
|
||||||
? options.tabBarAccessibilityLabel
|
? options.tabBarAccessibilityLabel
|
||||||
: typeof label === 'string'
|
: typeof label === 'string'
|
||||||
? `${label}, tab, ${index + 1} of ${routes.length}`
|
? `${label}, tab, ${index + 1} of ${routes.length}`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContext.Provider
|
<NavigationContext.Provider
|
||||||
key={route.key}
|
key={route.key}
|
||||||
value={descriptors[route.key].navigation}
|
value={descriptors[route.key].navigation}
|
||||||
>
|
>
|
||||||
<NavigationRouteContext.Provider value={route}>
|
<NavigationRouteContext.Provider value={route}>
|
||||||
<BottomTabItem
|
<BottomTabItem
|
||||||
route={route}
|
route={route}
|
||||||
focused={focused}
|
focused={focused}
|
||||||
horizontal={shouldUseHorizontalLabels()}
|
horizontal={shouldUseHorizontalLabels()}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
testID={options.tabBarTestID}
|
testID={options.tabBarTestID}
|
||||||
allowFontScaling={allowFontScaling}
|
allowFontScaling={allowFontScaling}
|
||||||
activeTintColor={activeTintColor}
|
activeTintColor={activeTintColor}
|
||||||
inactiveTintColor={inactiveTintColor}
|
inactiveTintColor={inactiveTintColor}
|
||||||
activeBackgroundColor={activeBackgroundColor}
|
activeBackgroundColor={activeBackgroundColor}
|
||||||
inactiveBackgroundColor={inactiveBackgroundColor}
|
inactiveBackgroundColor={inactiveBackgroundColor}
|
||||||
button={options.tabBarButton}
|
button={options.tabBarButton}
|
||||||
icon={options.tabBarIcon}
|
icon={options.tabBarIcon}
|
||||||
label={label}
|
label={label}
|
||||||
showIcon={showIcon}
|
showIcon={showIcon}
|
||||||
showLabel={showLabel}
|
showLabel={showLabel}
|
||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
style={tabStyle}
|
style={tabStyle}
|
||||||
/>
|
/>
|
||||||
</NavigationRouteContext.Provider>
|
</NavigationRouteContext.Provider>
|
||||||
</NavigationContext.Provider>
|
</NavigationContext.Provider>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
)}
|
|
||||||
</SafeAreaConsumer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,9 +133,7 @@ export default function BottomTabBarItem({
|
|||||||
|
|
||||||
const inactiveTintColor =
|
const inactiveTintColor =
|
||||||
customInactiveTintColor === undefined
|
customInactiveTintColor === undefined
|
||||||
? Color(colors.text)
|
? Color(colors.text).mix(Color(colors.card), 0.5).hex()
|
||||||
.mix(Color(colors.card), 0.5)
|
|
||||||
.hex()
|
|
||||||
: customInactiveTintColor;
|
: customInactiveTintColor;
|
||||||
|
|
||||||
const renderLabel = ({ focused }: { focused: boolean }) => {
|
const renderLabel = ({ focused }: { focused: boolean }) => {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Platform, StyleSheet, View } from 'react-native';
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import { Screen, screensEnabled } from 'react-native-screens';
|
import { Screen, screensEnabled } from 'react-native-screens';
|
||||||
|
|
||||||
@@ -10,12 +9,14 @@ type Props = {
|
|||||||
style?: any;
|
style?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
|
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
||||||
|
|
||||||
export default class ResourceSavingScene extends React.Component<Props> {
|
export default class ResourceSavingScene extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
if (screensEnabled?.()) {
|
// react-native-screens is buggy on web
|
||||||
|
if (screensEnabled?.() && Platform.OS !== 'web') {
|
||||||
const { isVisible, ...rest } = this.props;
|
const { isVisible, ...rest } = this.props;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,13 @@ export default class ResourceSavingScene extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[styles.container, style, { opacity: isVisible ? 1 : 0 }]}
|
style={[
|
||||||
|
styles.container,
|
||||||
|
Platform.OS === 'web'
|
||||||
|
? { display: isVisible ? 'flex' : 'none' }
|
||||||
|
: null,
|
||||||
|
style,
|
||||||
|
]}
|
||||||
collapsable={false}
|
collapsable={false}
|
||||||
removeClippedSubviews={
|
removeClippedSubviews={
|
||||||
// On iOS, set removeClippedSubviews to true only when not focused
|
// On iOS, set removeClippedSubviews to true only when not focused
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ type Props = {
|
|||||||
export default function SafeAreaProviderCompat({ children }: Props) {
|
export default function SafeAreaProviderCompat({ children }: Props) {
|
||||||
return (
|
return (
|
||||||
<SafeAreaConsumer>
|
<SafeAreaConsumer>
|
||||||
{insets => {
|
{(insets) => {
|
||||||
if (insets) {
|
if (insets) {
|
||||||
// If we already have insets, don't wrap the stack in another safe area provider
|
// If we already have insets, don't wrap the stack in another safe area provider
|
||||||
// This avoids an issue with updates at the cost of potentially incorrect values
|
// This avoids an issue with updates at the cost of potentially incorrect values
|
||||||
|
|||||||
@@ -3,6 +3,54 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.5...@react-navigation/compat@5.1.6) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.5](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.4...@react-navigation/compat@5.1.5) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.4](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.3...@react-navigation/compat@5.1.4) (2020-03-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.2...@react-navigation/compat@5.1.3) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.1...@react-navigation/compat@5.1.2) (2020-03-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.1.0...@react-navigation/compat@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.7...@react-navigation/compat@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.7...@react-navigation/compat@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/compat",
|
"name": "@react-navigation/compat",
|
||||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||||
"version": "5.1.0",
|
"version": "5.1.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
|
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default function createCompatNavigatorFactory<
|
|||||||
function Navigator({ screenProps }: { screenProps?: unknown }) {
|
function Navigator({ screenProps }: { screenProps?: unknown }) {
|
||||||
const screens = React.useMemo(
|
const screens = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
routeNames.map(name => {
|
routeNames.map((name) => {
|
||||||
let getScreenComponent: () => CompatScreenType<NavigationPropType>;
|
let getScreenComponent: () => CompatScreenType<NavigationPropType>;
|
||||||
|
|
||||||
let initialParams;
|
let initialParams;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export default function useCompatNavigation<
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const isFirstRouteInParent = useNavigationState(
|
const isFirstRouteInParent = useNavigationState(
|
||||||
state => state.routes[0].key === route.key
|
(state) => state.routes[0].key === route.key
|
||||||
);
|
);
|
||||||
|
|
||||||
const context = React.useRef<Record<string, any>>({});
|
const context = React.useRef<Record<string, any>>({});
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ export default function withNavigation<
|
|||||||
return <Comp ref={onRef} navigation={navigation} {...rest} />;
|
return <Comp ref={onRef} navigation={navigation} {...rest} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
WrappedComponent.displayName = `withNavigation(${Comp.displayName ||
|
WrappedComponent.displayName = `withNavigation(${
|
||||||
Comp.name})`;
|
Comp.displayName || Comp.name
|
||||||
|
})`;
|
||||||
|
|
||||||
return WrappedComponent;
|
return WrappedComponent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ export default function withNavigationFocus<
|
|||||||
return <Comp ref={onRef} isFocused={isFocused} {...rest} />;
|
return <Comp ref={onRef} isFocused={isFocused} {...rest} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
WrappedComponent.displayName = `withNavigationFocus(${Comp.displayName ||
|
WrappedComponent.displayName = `withNavigationFocus(${
|
||||||
Comp.name})`;
|
Comp.displayName || Comp.name
|
||||||
|
})`;
|
||||||
|
|
||||||
return WrappedComponent;
|
return WrappedComponent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,62 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.3.0...@react-navigation/core@5.3.1) (2020-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't emit events for screens that don't exist anymore ([1c00142](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/1c001424b595b40f9db9343096c833f75353b099))
|
||||||
|
* only call listeners for focused screen for global events ([3096de6](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/3096de62868a7ed9ed65e529c8ddfa001b9be486))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.3...@react-navigation/core@5.3.0) (2020-03-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* return correct value for isFocused after changing screens ([5b15c71](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/5b15c7164f5503f2f0d51006a3f23bd0c58fd9b7)), closes [#7843](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/7843)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* support function in listeners prop ([3709e65](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/3709e652f41a16c2c2b05d5dbbe1da2017ba2c3f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.2...@react-navigation/core@5.2.3) (2020-03-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.1...@react-navigation/core@5.2.2) (2020-03-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.2.0...@react-navigation/core@5.2.1) (2020-03-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix links for documentation ([5bb0f40](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/5bb0f405ceb5755d39a0b5b1f2e4ecee0da051bc))
|
||||||
|
* move updating state to useEffect ([2dfa4f3](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/2dfa4f36293a2acb718814f6b2fa79d7c7ddf09c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.6...@react-navigation/core@5.2.0) (2020-02-26)
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.6...@react-navigation/core@5.2.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.2.0",
|
"version": "5.3.1",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -29,23 +29,23 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.0.3",
|
"@react-navigation/routers": "^5.2.0",
|
||||||
"escape-string-regexp": "^2.0.0",
|
"escape-string-regexp": "^2.0.0",
|
||||||
"query-string": "^6.10.1",
|
"query-string": "^6.11.1",
|
||||||
"react-is": "^16.12.0",
|
"react-is": "^16.13.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"use-subscription": "^1.3.0"
|
"use-subscription": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-is": "^16.7.1",
|
"@types/react-is": "^16.7.1",
|
||||||
"@types/shortid": "^0.0.29",
|
"@types/shortid": "^0.0.29",
|
||||||
"@types/use-subscription": "^1.0.0",
|
"@types/use-subscription": "^1.0.0",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native-testing-library": "^1.12.0",
|
"react-native-testing-library": "^1.12.0",
|
||||||
"react-test-renderer": "~16.12.0",
|
"react-test-renderer": "~16.9.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ import useSyncState from './useSyncState';
|
|||||||
type State = NavigationState | PartialState<NavigationState> | undefined;
|
type State = NavigationState | PartialState<NavigationState> | undefined;
|
||||||
|
|
||||||
const MISSING_CONTEXT_ERROR =
|
const MISSING_CONTEXT_ERROR =
|
||||||
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started.html for setup instructions.";
|
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.";
|
||||||
|
|
||||||
const NOT_INITIALIZED_ERROR =
|
const NOT_INITIALIZED_ERROR =
|
||||||
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop.html#handling-initialization for more details.";
|
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization for more details.";
|
||||||
|
|
||||||
export const NavigationStateContext = React.createContext<{
|
export const NavigationStateContext = React.createContext<{
|
||||||
isDefault?: true;
|
isDefault?: true;
|
||||||
@@ -73,7 +73,7 @@ const getPartialState = (
|
|||||||
return {
|
return {
|
||||||
...partialState,
|
...partialState,
|
||||||
stale: true,
|
stale: true,
|
||||||
routes: state.routes.map(route => {
|
routes: state.routes.map((route) => {
|
||||||
if (route.state === undefined) {
|
if (route.state === undefined) {
|
||||||
return route as Route<string> & {
|
return route as Route<string> & {
|
||||||
state?: PartialState<NavigationState>;
|
state?: PartialState<NavigationState>;
|
||||||
@@ -136,6 +136,7 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { trackState, trackAction } = useDevTools({
|
const { trackState, trackAction } = useDevTools({
|
||||||
|
enabled: false,
|
||||||
name: '@react-navigation',
|
name: '@react-navigation',
|
||||||
reset,
|
reset,
|
||||||
state,
|
state,
|
||||||
@@ -155,7 +156,7 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
throw new Error(NOT_INITIALIZED_ERROR);
|
throw new Error(NOT_INITIALIZED_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners[0](navigation => navigation.dispatch(action));
|
listeners[0]((navigation) => navigation.dispatch(action));
|
||||||
};
|
};
|
||||||
|
|
||||||
const canGoBack = () => {
|
const canGoBack = () => {
|
||||||
@@ -163,7 +164,7 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result, handled } = listeners[0](navigation =>
|
const { result, handled } = listeners[0]((navigation) =>
|
||||||
navigation.canGoBack()
|
navigation.canGoBack()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ const BaseNavigationContainer = React.forwardRef(
|
|||||||
hasWarnedForSerialization = true;
|
hasWarnedForSerialization = true;
|
||||||
|
|
||||||
console.warn(
|
console.warn(
|
||||||
"Non-serializable values were found in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting.html#i-get-the-warning-we-found-non-serializable-values-in-the-navigation-state for more details."
|
"Non-serializable values were found in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type Props = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators.html for a guide on nesting.`;
|
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators for a guide on nesting.`;
|
||||||
|
|
||||||
export const SingleNavigatorContext = React.createContext<
|
export const SingleNavigatorContext = React.createContext<
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default function SceneView<
|
|||||||
|
|
||||||
const getCurrentState = React.useCallback(() => {
|
const getCurrentState = React.useCallback(() => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const currentRoute = state.routes.find(r => r.key === route.key);
|
const currentRoute = state.routes.find((r) => r.key === route.key);
|
||||||
|
|
||||||
return currentRoute ? currentRoute.state : undefined;
|
return currentRoute ? currentRoute.state : undefined;
|
||||||
}, [getState, route.key]);
|
}, [getState, route.key]);
|
||||||
@@ -62,7 +62,7 @@ export default function SceneView<
|
|||||||
|
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
routes: state.routes.map(r =>
|
routes: state.routes.map((r) =>
|
||||||
r.key === route.key ? { ...r, state: child } : r
|
r.key === route.key ? { ...r, state: child } : r
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ it('handle dispatching with ref', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -220,7 +220,7 @@ it('handle resetting state with ref', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -371,7 +371,7 @@ it('emits state events when the state changes', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
|
|||||||
key: String(MockRouterKey.current++),
|
key: String(MockRouterKey.current++),
|
||||||
index,
|
index,
|
||||||
routeNames,
|
routeNames,
|
||||||
routes: routeNames.map(name => ({
|
routes: routeNames.map((name) => ({
|
||||||
name,
|
name,
|
||||||
key: name,
|
key: name,
|
||||||
params: routeParamList[name],
|
params: routeParamList[name],
|
||||||
@@ -43,9 +43,9 @@ export default function MockRouter(options: DefaultRouterOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const routes = state.routes
|
const routes = state.routes
|
||||||
.filter(route => routeNames.includes(route.name))
|
.filter((route) => routeNames.includes(route.name))
|
||||||
.map(
|
.map(
|
||||||
route =>
|
(route) =>
|
||||||
({
|
({
|
||||||
...route,
|
...route,
|
||||||
key: route.key || `${route.name}-${MockRouterKey.current++}`,
|
key: route.key || `${route.name}-${MockRouterKey.current++}`,
|
||||||
@@ -73,7 +73,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStateForRouteNamesChange(state, { routeNames }) {
|
getStateForRouteNamesChange(state, { routeNames }) {
|
||||||
const routes = state.routes.filter(route =>
|
const routes = state.routes.filter((route) =>
|
||||||
routeNames.includes(route.name)
|
routeNames.includes(route.name)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStateForRouteFocus(state, key) {
|
getStateForRouteFocus(state, key) {
|
||||||
const index = state.routes.findIndex(r => r.key === key);
|
const index = state.routes.findIndex((r) => r.key === key);
|
||||||
|
|
||||||
if (index === -1 || index === state.index) {
|
if (index === -1 || index === state.index) {
|
||||||
return state;
|
return state;
|
||||||
@@ -105,7 +105,7 @@ export default function MockRouter(options: DefaultRouterOptions) {
|
|||||||
|
|
||||||
case 'NAVIGATE': {
|
case 'NAVIGATE': {
|
||||||
const index = state.routes.findIndex(
|
const index = state.routes.findIndex(
|
||||||
route => route.name === action.payload.name
|
(route) => route.name === action.payload.name
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ it('converts state to path string with config', () => {
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
id: (id: string) => Number(id.replace(/^x/, '')),
|
id: (id: string) => Number(id.replace(/^x/, '')),
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -128,7 +129,8 @@ it('handles state with config with nested screens', () => {
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -192,12 +194,14 @@ it('handles state with config with nested screens and unused configs', () => {
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toLowerCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
unknown: (_: unknown) => 'x',
|
unknown: (_: unknown) => 'x',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -255,11 +259,11 @@ it('handles nested object with stringify in it', () => {
|
|||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
},
|
},
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toUpperCase()),
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ it('converts path string to initial state with config', () => {
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -153,7 +154,8 @@ it('converts path string to initial state with config with nested screens', () =
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -217,7 +219,8 @@ it('converts path string to initial state with config with nested screens and un
|
|||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) => author.replace(/^\w/, c => c.toUpperCase()),
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
id: Boolean,
|
id: Boolean,
|
||||||
@@ -277,11 +280,11 @@ it('handles nested object with unused configs and with parse in it', () => {
|
|||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
},
|
},
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toUpperCase()),
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -528,11 +531,11 @@ it('handles two initialRouteNames', () => {
|
|||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
},
|
},
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toUpperCase()),
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
@@ -610,11 +613,11 @@ it('accepts initialRouteName without config for it', () => {
|
|||||||
path: 'bis/:author',
|
path: 'bis/:author',
|
||||||
stringify: {
|
stringify: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toLowerCase()),
|
author.replace(/^\w/, (c) => c.toLowerCase()),
|
||||||
},
|
},
|
||||||
parse: {
|
parse: {
|
||||||
author: (author: string) =>
|
author: (author: string) =>
|
||||||
author.replace(/^\w/, c => c.toUpperCase()),
|
author.replace(/^\w/, (c) => c.toUpperCase()),
|
||||||
count: Number,
|
count: Number,
|
||||||
valid: Boolean,
|
valid: Boolean,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ it('sets options with screenOptions prop as an object', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{state.routes.map(route => {
|
{state.routes.map((route) => {
|
||||||
const { render, options } = descriptors[route.key];
|
const { render, options } = descriptors[route.key];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -179,7 +179,7 @@ it('sets options with screenOptions prop as a fuction', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{state.routes.map(route => {
|
{state.routes.map((route) => {
|
||||||
const { render, options } = descriptors[route.key];
|
const { render, options } = descriptors[route.key];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -273,7 +273,7 @@ it('sets initial options with setOptions', () => {
|
|||||||
<BaseNavigationContainer>
|
<BaseNavigationContainer>
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="foo" options={{ color: 'blue' }}>
|
<Screen name="foo" options={{ color: 'blue' }}>
|
||||||
{props => <TestScreen {...props} />}
|
{(props) => <TestScreen {...props} />}
|
||||||
</Screen>
|
</Screen>
|
||||||
<Screen name="bar" component={jest.fn()} />
|
<Screen name="bar" component={jest.fn()} />
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
@@ -338,7 +338,7 @@ it('updates options with setOptions', () => {
|
|||||||
<BaseNavigationContainer>
|
<BaseNavigationContainer>
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="foo" options={{ color: 'blue' }}>
|
<Screen name="foo" options={{ color: 'blue' }}>
|
||||||
{props => <TestScreen {...props} />}
|
{(props) => <TestScreen {...props} />}
|
||||||
</Screen>
|
</Screen>
|
||||||
<Screen name="bar" component={jest.fn()} />
|
<Screen name="bar" component={jest.fn()} />
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ it('fires focus and blur events in root navigator', () => {
|
|||||||
|
|
||||||
React.useImperativeHandle(ref, () => navigation, [navigation]);
|
React.useImperativeHandle(ref, () => navigation, [navigation]);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
});
|
});
|
||||||
|
|
||||||
const firstFocusCallback = jest.fn();
|
const firstFocusCallback = jest.fn();
|
||||||
@@ -106,7 +106,7 @@ it('fires focus and blur events in nested navigator', () => {
|
|||||||
|
|
||||||
React.useImperativeHandle(ref, () => navigation, [navigation]);
|
React.useImperativeHandle(ref, () => navigation, [navigation]);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
});
|
});
|
||||||
|
|
||||||
const firstFocusCallback = jest.fn();
|
const firstFocusCallback = jest.fn();
|
||||||
@@ -376,7 +376,7 @@ it('fires custom events added with addListener', () => {
|
|||||||
state,
|
state,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
});
|
});
|
||||||
|
|
||||||
const firstCallback = jest.fn();
|
const firstCallback = jest.fn();
|
||||||
@@ -456,7 +456,7 @@ it("doesn't call same listener multiple times with addListener", () => {
|
|||||||
state,
|
state,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
});
|
});
|
||||||
|
|
||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
@@ -565,12 +565,10 @@ it('fires custom events added with listeners prop', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
|
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
|
||||||
expect(secondCallback.mock.calls[0][0].target).toBe(undefined);
|
|
||||||
expect(thirdCallback.mock.calls[1][0].target).toBe(undefined);
|
|
||||||
|
|
||||||
expect(firstCallback).toBeCalledTimes(1);
|
expect(firstCallback).toBeCalledTimes(1);
|
||||||
expect(secondCallback).toBeCalledTimes(1);
|
expect(secondCallback).toBeCalledTimes(0);
|
||||||
expect(thirdCallback).toBeCalledTimes(2);
|
expect(thirdCallback).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("doesn't call same listener multiple times with listeners", () => {
|
it("doesn't call same listener multiple times with listeners", () => {
|
||||||
@@ -624,6 +622,91 @@ it("doesn't call same listener multiple times with listeners", () => {
|
|||||||
expect(callback).toBeCalledTimes(1);
|
expect(callback).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fires listeners when callback is provided for listeners prop', () => {
|
||||||
|
const eventName = 'someSuperCoolEvent';
|
||||||
|
|
||||||
|
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
|
||||||
|
const { state, navigation } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
|
React.useImperativeHandle(ref, () => ({ navigation, state }), [
|
||||||
|
navigation,
|
||||||
|
state,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstCallback = jest.fn();
|
||||||
|
const secondCallback = jest.fn();
|
||||||
|
const thirdCallback = jest.fn();
|
||||||
|
|
||||||
|
const ref = React.createRef<any>();
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator ref={ref}>
|
||||||
|
<Screen
|
||||||
|
name="first"
|
||||||
|
listeners={({ route, navigation }) => ({
|
||||||
|
someSuperCoolEvent: (e) => firstCallback(e, route, navigation),
|
||||||
|
})}
|
||||||
|
component={jest.fn()}
|
||||||
|
/>
|
||||||
|
<Screen
|
||||||
|
name="second"
|
||||||
|
listeners={({ route, navigation }) => ({
|
||||||
|
someSuperCoolEvent: (e) => secondCallback(e, route, navigation),
|
||||||
|
})}
|
||||||
|
component={jest.fn()}
|
||||||
|
/>
|
||||||
|
<Screen
|
||||||
|
name="third"
|
||||||
|
listeners={({ route, navigation }) => ({
|
||||||
|
someSuperCoolEvent: (e) => thirdCallback(e, route, navigation),
|
||||||
|
})}
|
||||||
|
component={jest.fn()}
|
||||||
|
/>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
render(element);
|
||||||
|
|
||||||
|
expect(firstCallback).toBeCalledTimes(0);
|
||||||
|
expect(secondCallback).toBeCalledTimes(0);
|
||||||
|
expect(thirdCallback).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
const target =
|
||||||
|
ref.current.state.routes[ref.current.state.routes.length - 1].key;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
ref.current.navigation.emit({
|
||||||
|
type: eventName,
|
||||||
|
target,
|
||||||
|
data: 42,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(firstCallback).toBeCalledTimes(0);
|
||||||
|
expect(secondCallback).toBeCalledTimes(0);
|
||||||
|
expect(thirdCallback).toBeCalledTimes(1);
|
||||||
|
expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent');
|
||||||
|
expect(thirdCallback.mock.calls[0][0].data).toBe(42);
|
||||||
|
expect(thirdCallback.mock.calls[0][0].target).toBe(target);
|
||||||
|
expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined);
|
||||||
|
expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
ref.current.navigation.emit({ type: eventName });
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
|
||||||
|
|
||||||
|
expect(firstCallback).toBeCalledTimes(1);
|
||||||
|
expect(secondCallback).toBeCalledTimes(0);
|
||||||
|
expect(thirdCallback).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('has option to prevent default', () => {
|
it('has option to prevent default', () => {
|
||||||
expect.assertions(5);
|
expect.assertions(5);
|
||||||
|
|
||||||
@@ -640,7 +723,7 @@ it('has option to prevent default', () => {
|
|||||||
state,
|
state,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
});
|
});
|
||||||
|
|
||||||
const callback = (e: any) => {
|
const callback = (e: any) => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ it('runs focus effect on focus change', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const focusEffect = jest.fn();
|
const focusEffect = jest.fn();
|
||||||
@@ -107,7 +107,7 @@ it('runs focus effect when initial state is given', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const focusEffect = jest.fn();
|
const focusEffect = jest.fn();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ it('renders correct focus state', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ it('gets navigation prop from context', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
@@ -38,7 +38,7 @@ it("gets navigation's parent from context", () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
@@ -70,7 +70,7 @@ it("gets navigation's parent's parent from context", () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { render } from 'react-native-testing-library';
|
import { render, act } from 'react-native-testing-library';
|
||||||
import useEventEmitter from '../useEventEmitter';
|
import useEventEmitter from '../useEventEmitter';
|
||||||
import useNavigationCache from '../useNavigationCache';
|
import useNavigationCache from '../useNavigationCache';
|
||||||
|
import useNavigationBuilder from '../useNavigationBuilder';
|
||||||
|
import BaseNavigationContainer from '../BaseNavigationContainer';
|
||||||
|
import Screen from '../Screen';
|
||||||
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
|
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
|
||||||
|
|
||||||
beforeEach(() => (MockRouterKey.current = 0));
|
beforeEach(() => (MockRouterKey.current = 0));
|
||||||
@@ -40,7 +43,7 @@ it('preserves reference for navigation objects', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (previous.current) {
|
if (previous.current) {
|
||||||
Object.keys(navigations).forEach(key => {
|
Object.keys(navigations).forEach((key) => {
|
||||||
expect(navigations[key]).toBe(previous.current[key]);
|
expect(navigations[key]).toBe(previous.current[key]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -56,3 +59,136 @@ it('preserves reference for navigation objects', () => {
|
|||||||
|
|
||||||
root.update(<Test />);
|
root.update(<Test />);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns correct value for isFocused', () => {
|
||||||
|
const TestNavigator = (props: any): any => {
|
||||||
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
|
};
|
||||||
|
|
||||||
|
let navigation: any;
|
||||||
|
|
||||||
|
const Test = (props: any) => {
|
||||||
|
navigation = props.navigation;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="first">{() => null}</Screen>
|
||||||
|
<Screen name="second" component={Test} />
|
||||||
|
<Screen name="third">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(false);
|
||||||
|
|
||||||
|
act(() => navigation.navigate('second'));
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(true);
|
||||||
|
|
||||||
|
act(() => navigation.navigate('third'));
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(false);
|
||||||
|
|
||||||
|
act(() => navigation.navigate('second'));
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct value for isFocused after changing screens', () => {
|
||||||
|
const TestRouter = (
|
||||||
|
options: Parameters<typeof MockRouter>[0]
|
||||||
|
): ReturnType<typeof MockRouter> => {
|
||||||
|
const router = MockRouter(options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...router,
|
||||||
|
|
||||||
|
getStateForRouteNamesChange(state, { routeNames }) {
|
||||||
|
const routes = routeNames.map(
|
||||||
|
(name) =>
|
||||||
|
state.routes.find((r) => r.name === name) || {
|
||||||
|
name,
|
||||||
|
key: name,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
routeNames,
|
||||||
|
routes,
|
||||||
|
index: routes.length - 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const TestNavigator = (props: any): any => {
|
||||||
|
const { state, descriptors } = useNavigationBuilder(TestRouter, props);
|
||||||
|
|
||||||
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
|
};
|
||||||
|
|
||||||
|
let navigation: any;
|
||||||
|
|
||||||
|
const Test = (props: any) => {
|
||||||
|
navigation = props.navigation;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = render(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="first">{() => null}</Screen>
|
||||||
|
<Screen name="second" component={Test} />
|
||||||
|
<Screen name="third">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(false);
|
||||||
|
|
||||||
|
root.update(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="first">{() => null}</Screen>
|
||||||
|
<Screen name="third">{() => null}</Screen>
|
||||||
|
<Screen name="second" component={Test} />
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(true);
|
||||||
|
|
||||||
|
root.update(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="first">{() => null}</Screen>
|
||||||
|
<Screen name="third">{() => null}</Screen>
|
||||||
|
<Screen name="fourth">{() => null}</Screen>
|
||||||
|
<Screen name="second" component={Test} />
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(true);
|
||||||
|
|
||||||
|
root.update(
|
||||||
|
<BaseNavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="first">{() => null}</Screen>
|
||||||
|
<Screen name="third">{() => null}</Screen>
|
||||||
|
<Screen name="second" component={Test} />
|
||||||
|
<Screen name="fourth">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</BaseNavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(navigation.isFocused()).toBe(false);
|
||||||
|
});
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ it('gets the current navigation state', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
const state = useNavigationState(state => state);
|
const state = useNavigationState((state) => state);
|
||||||
|
|
||||||
callback(state);
|
callback(state);
|
||||||
|
|
||||||
@@ -62,13 +62,13 @@ it('gets the current navigation state with selector', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
const index = useNavigationState(state => state.index);
|
const index = useNavigationState((state) => state.index);
|
||||||
|
|
||||||
callback(index);
|
callback(index);
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ it('gets the correct value if selector changes', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
@@ -144,12 +144,12 @@ it('gets the correct value if selector changes', () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const root = render(<App selector={state => state.index} />);
|
const root = render(<App selector={(state) => state.index} />);
|
||||||
|
|
||||||
expect(callback).toBeCalledTimes(1);
|
expect(callback).toBeCalledTimes(1);
|
||||||
expect(callback.mock.calls[0][0]).toBe(0);
|
expect(callback.mock.calls[0][0]).toBe(0);
|
||||||
|
|
||||||
root.update(<App selector={state => state.routes[state.index].name} />);
|
root.update(<App selector={(state) => state.routes[state.index].name} />);
|
||||||
|
|
||||||
expect(callback).toBeCalledTimes(2);
|
expect(callback).toBeCalledTimes(2);
|
||||||
expect(callback.mock.calls[1][0]).toBe('first');
|
expect(callback.mock.calls[1][0]).toBe('first');
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ it("lets children handle the action if parent didn't", () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -270,7 +270,7 @@ it("action doesn't bubble if target is specified", () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -317,7 +317,7 @@ it('logs error if no navigator handled the action', () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{state.routes.map(route => descriptors[route.key].render())}
|
{state.routes.map((route) => descriptors[route.key].render())}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ it('gets route prop from context', () => {
|
|||||||
const TestNavigator = (props: any): any => {
|
const TestNavigator = (props: any): any => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
return state.routes.map(route => descriptors[route.key].render());
|
return state.routes.map((route) => descriptors[route.key].render());
|
||||||
};
|
};
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export default function createNavigatorFactory<
|
|||||||
EventMap extends EventMapBase,
|
EventMap extends EventMapBase,
|
||||||
NavigatorComponent extends React.ComponentType<any>
|
NavigatorComponent extends React.ComponentType<any>
|
||||||
>(Navigator: NavigatorComponent) {
|
>(Navigator: NavigatorComponent) {
|
||||||
return function<ParamList extends ParamListBase>(): TypedNavigator<
|
return function <ParamList extends ParamListBase>(): TypedNavigator<
|
||||||
ParamList,
|
ParamList,
|
||||||
State,
|
State,
|
||||||
ScreenOptions,
|
ScreenOptions,
|
||||||
@@ -25,7 +25,7 @@ export default function createNavigatorFactory<
|
|||||||
> {
|
> {
|
||||||
if (arguments[0] !== undefined) {
|
if (arguments[0] !== undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/upgrading-from-4.x.html for migration guide."
|
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/upgrading-from-4.x for migration guide."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export default function getPathFromState(
|
|||||||
if (currentOptions[route.name] !== undefined) {
|
if (currentOptions[route.name] !== undefined) {
|
||||||
path += pattern
|
path += pattern
|
||||||
.split('/')
|
.split('/')
|
||||||
.map(p => {
|
.map((p) => {
|
||||||
const name = p.replace(/^:/, '');
|
const name = p.replace(/^:/, '');
|
||||||
|
|
||||||
// If the path has a pattern for a param, put the param in the path
|
// If the path has a pattern for a param, put the param in the path
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export default function getStateFromPath(
|
|||||||
let initialRoutes: InitialRouteConfig[] = [];
|
let initialRoutes: InitialRouteConfig[] = [];
|
||||||
// Create a normalized configs array which will be easier to use
|
// Create a normalized configs array which will be easier to use
|
||||||
const configs = ([] as RouteConfig[]).concat(
|
const configs = ([] as RouteConfig[]).concat(
|
||||||
...Object.keys(options).map(key =>
|
...Object.keys(options).map((key) =>
|
||||||
createNormalizedConfigs(key, options, [], initialRoutes)
|
createNormalizedConfigs(key, options, [], initialRoutes)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -91,7 +91,7 @@ export default function getStateFromPath(
|
|||||||
|
|
||||||
const paramPatterns = config.pattern
|
const paramPatterns = config.pattern
|
||||||
.split('/')
|
.split('/')
|
||||||
.filter(p => p.startsWith(':'));
|
.filter((p) => p.startsWith(':'));
|
||||||
|
|
||||||
if (paramPatterns.length) {
|
if (paramPatterns.length) {
|
||||||
params = paramPatterns.reduce<Record<string, any>>((acc, p, i) => {
|
params = paramPatterns.reduce<Record<string, any>>((acc, p, i) => {
|
||||||
@@ -188,7 +188,7 @@ export default function getStateFromPath(
|
|||||||
const parseFunction = findParseConfigForRoute(route.name, configs);
|
const parseFunction = findParseConfigForRoute(route.name, configs);
|
||||||
|
|
||||||
if (parseFunction) {
|
if (parseFunction) {
|
||||||
Object.keys(params).forEach(name => {
|
Object.keys(params).forEach((name) => {
|
||||||
if (parseFunction[name] && typeof params[name] === 'string') {
|
if (parseFunction[name] && typeof params[name] === 'string') {
|
||||||
params[name] = parseFunction[name](params[name] as string);
|
params[name] = parseFunction[name](params[name] as string);
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ function createNormalizedConfigs(
|
|||||||
connectedRoutes: Object.keys(value.screens),
|
connectedRoutes: Object.keys(value.screens),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Object.keys(value.screens).forEach(nestedConfig => {
|
Object.keys(value.screens).forEach((nestedConfig) => {
|
||||||
const result = createNormalizedConfigs(
|
const result = createNormalizedConfigs(
|
||||||
nestedConfig,
|
nestedConfig,
|
||||||
value.screens as Options,
|
value.screens as Options,
|
||||||
|
|||||||
@@ -168,18 +168,6 @@ type NavigationHelpersCommon<
|
|||||||
| { name: RouteName; key?: string; params: ParamList[RouteName] }
|
| { name: RouteName; key?: string; params: ParamList[RouteName] }
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the current route with a new one.
|
|
||||||
*
|
|
||||||
* @param name Route name of the new route.
|
|
||||||
* @param [params] Params object for the new route.
|
|
||||||
*/
|
|
||||||
replace<RouteName extends keyof ParamList>(
|
|
||||||
...args: ParamList[RouteName] extends undefined
|
|
||||||
? [RouteName] | [RouteName, ParamList[RouteName]]
|
|
||||||
: [RouteName, ParamList[RouteName]]
|
|
||||||
): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the navigation state to the provided state.
|
* Reset the navigation state to the provided state.
|
||||||
*
|
*
|
||||||
@@ -358,6 +346,16 @@ export type Descriptor<
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ScreenListeners<
|
||||||
|
State extends NavigationState,
|
||||||
|
EventMap extends EventMapBase
|
||||||
|
> = Partial<
|
||||||
|
{
|
||||||
|
[EventName in keyof (EventMap &
|
||||||
|
EventMapCore<State>)]: EventListenerCallback<EventMap, EventName>;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
export type RouteConfig<
|
export type RouteConfig<
|
||||||
ParamList extends ParamListBase,
|
ParamList extends ParamListBase,
|
||||||
RouteName extends keyof ParamList,
|
RouteName extends keyof ParamList,
|
||||||
@@ -383,12 +381,12 @@ export type RouteConfig<
|
|||||||
/**
|
/**
|
||||||
* Event listeners for this screen.
|
* Event listeners for this screen.
|
||||||
*/
|
*/
|
||||||
listeners?: Partial<
|
listeners?:
|
||||||
{
|
| ScreenListeners<State, EventMap>
|
||||||
[EventName in keyof (EventMap &
|
| ((props: {
|
||||||
EventMapCore<State>)]: EventListenerCallback<EventMap, EventName>;
|
route: RouteProp<ParamList, RouteName>;
|
||||||
}
|
navigation: any;
|
||||||
>;
|
}) => ScreenListeners<State, EventMap>);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initial params object for the route.
|
* Initial params object for the route.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
type State = NavigationState | PartialState<NavigationState> | undefined;
|
type State = NavigationState | PartialState<NavigationState> | undefined;
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
|
enabled: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
reset: (state: NavigationState) => void;
|
reset: (state: NavigationState) => void;
|
||||||
state: State;
|
state: State;
|
||||||
@@ -35,10 +36,11 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useDevTools({ name, reset, state }: Options) {
|
export default function useDevTools({ name, reset, state, enabled }: Options) {
|
||||||
const devToolsRef = React.useRef<DevTools>();
|
const devToolsRef = React.useRef<DevTools>();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
enabled &&
|
||||||
process.env.NODE_ENV !== 'production' &&
|
process.env.NODE_ENV !== 'production' &&
|
||||||
global.__REDUX_DEVTOOLS_EXTENSION__ &&
|
global.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||||
devToolsRef.current === undefined
|
devToolsRef.current === undefined
|
||||||
@@ -56,7 +58,7 @@ export default function useDevTools({ name, reset, state }: Options) {
|
|||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
() =>
|
() =>
|
||||||
devTools?.subscribe(message => {
|
devTools?.subscribe((message) => {
|
||||||
if (message.type === 'DISPATCH' && message.state) {
|
if (message.type === 'DISPATCH' && message.state) {
|
||||||
reset(JSON.parse(message.state));
|
reset(JSON.parse(message.state));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default function useEventEmitter(
|
|||||||
target !== undefined
|
target !== undefined
|
||||||
? items[target] && items[target].slice()
|
? items[target] && items[target].slice()
|
||||||
: ([] as Listeners)
|
: ([] as Listeners)
|
||||||
.concat(...Object.keys(items).map(t => items[t]))
|
.concat(...Object.keys(items).map((t) => items[t]))
|
||||||
.filter((cb, i, self) => self.lastIndexOf(cb) === i);
|
.filter((cb, i, self) => self.lastIndexOf(cb) === i);
|
||||||
|
|
||||||
const event: EventArg<any, any, any> = {
|
const event: EventArg<any, any, any> = {
|
||||||
@@ -117,7 +117,7 @@ export default function useEventEmitter(
|
|||||||
|
|
||||||
listenRef.current?.(event);
|
listenRef.current?.(event);
|
||||||
|
|
||||||
callbacks?.forEach(cb => cb(event));
|
callbacks?.forEach((cb) => cb(event));
|
||||||
|
|
||||||
return event as any;
|
return event as any;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default function useFocusEffect(effect: EffectCallback) {
|
|||||||
' fetchData();\n' +
|
' fetchData();\n' +
|
||||||
' }, [someId])\n' +
|
' }, [someId])\n' +
|
||||||
'};\n\n' +
|
'};\n\n' +
|
||||||
'See usage guide: https://reactnavigation.org/docs/use-focus-effect.html';
|
'See usage guide: https://reactnavigation.org/docs/use-focus-effect';
|
||||||
} else {
|
} else {
|
||||||
message += ` You returned: '${JSON.stringify(destroy)}'`;
|
message += ` You returned: '${JSON.stringify(destroy)}'`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
RouterFactory,
|
RouterFactory,
|
||||||
PartialState,
|
PartialState,
|
||||||
NavigationAction,
|
NavigationAction,
|
||||||
|
Route,
|
||||||
} from '@react-navigation/routers';
|
} from '@react-navigation/routers';
|
||||||
import { NavigationStateContext } from './BaseNavigationContainer';
|
import { NavigationStateContext } from './BaseNavigationContainer';
|
||||||
import NavigationRouteContext from './NavigationRouteContext';
|
import NavigationRouteContext from './NavigationRouteContext';
|
||||||
@@ -103,7 +104,7 @@ const getRouteConfigsFromChildren = <
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
configs.forEach(config => {
|
configs.forEach((config) => {
|
||||||
const { name, children, component } = config as any;
|
const { name, children, component } = config as any;
|
||||||
|
|
||||||
if (typeof name !== 'string' || !name) {
|
if (typeof name !== 'string' || !name) {
|
||||||
@@ -212,7 +213,7 @@ export default function useNavigationBuilder<
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const routeNames = routeConfigs.map(config => config.name);
|
const routeNames = routeConfigs.map((config) => config.name);
|
||||||
const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
|
const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
|
||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
const { initialParams } = screens[curr];
|
const { initialParams } = screens[curr];
|
||||||
@@ -241,12 +242,12 @@ export default function useNavigationBuilder<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isStateValid = React.useCallback(
|
const isStateValid = React.useCallback(
|
||||||
state => state.type === undefined || state.type === router.type,
|
(state) => state.type === undefined || state.type === router.type,
|
||||||
[router.type]
|
[router.type]
|
||||||
);
|
);
|
||||||
|
|
||||||
const isStateInitialized = React.useCallback(
|
const isStateInitialized = React.useCallback(
|
||||||
state =>
|
(state) =>
|
||||||
state !== undefined && state.stale === false && isStateValid(state),
|
state !== undefined && state.stale === false && isStateValid(state),
|
||||||
[isStateValid]
|
[isStateValid]
|
||||||
);
|
);
|
||||||
@@ -333,12 +334,14 @@ export default function useNavigationBuilder<
|
|||||||
: state;
|
: state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state !== nextState) {
|
const shouldUpdate = state !== nextState;
|
||||||
// If the state needs to be updated, we'll schedule an update with React
|
|
||||||
// setState in render seems hacky, but that's how React docs implement getDerivedPropsFromState
|
React.useEffect(() => {
|
||||||
// https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops
|
if (shouldUpdate) {
|
||||||
setState(nextState);
|
// If the state needs to be updated, we'll schedule an update with React
|
||||||
}
|
setState(nextState);
|
||||||
|
}
|
||||||
|
}, [nextState, setState, shouldUpdate]);
|
||||||
|
|
||||||
// The up-to-date state will come in next render, but we don't need to wait for it
|
// The up-to-date state will come in next render, but we don't need to wait for it
|
||||||
// We can't use the outdated state since the screens have changed, which will cause error due to mismatched config
|
// We can't use the outdated state since the screens have changed, which will cause error due to mismatched config
|
||||||
@@ -365,34 +368,49 @@ export default function useNavigationBuilder<
|
|||||||
: (initializedStateRef.current as State);
|
: (initializedStateRef.current as State);
|
||||||
}, [getCurrentState, isStateInitialized]);
|
}, [getCurrentState, isStateInitialized]);
|
||||||
|
|
||||||
const emitter = useEventEmitter(e => {
|
const emitter = useEventEmitter((e) => {
|
||||||
let routeNames = [];
|
let routeNames = [];
|
||||||
|
|
||||||
if (e.target) {
|
let route: Route<string> | undefined;
|
||||||
const name = state.routes.find(route => route.key === e.target)?.name;
|
|
||||||
|
|
||||||
if (name) {
|
if (e.target) {
|
||||||
routeNames.push(name);
|
route = state.routes.find((route) => route.key === e.target);
|
||||||
|
|
||||||
|
if (route?.name) {
|
||||||
|
routeNames.push(route.name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
routeNames.push(...Object.keys(screens));
|
route = state.routes[state.index];
|
||||||
|
routeNames.push(
|
||||||
|
...Object.keys(screens).filter((name) => route?.name === name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (route == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigation = descriptors[route.key].navigation;
|
||||||
|
|
||||||
const listeners = ([] as (((e: any) => void) | undefined)[])
|
const listeners = ([] as (((e: any) => void) | undefined)[])
|
||||||
.concat(
|
.concat(
|
||||||
...routeNames.map(name => {
|
...routeNames.map((name) => {
|
||||||
const { listeners } = screens[name];
|
const { listeners } = screens[name];
|
||||||
|
const map =
|
||||||
|
typeof listeners === 'function'
|
||||||
|
? listeners({ route: route as any, navigation })
|
||||||
|
: listeners;
|
||||||
|
|
||||||
return listeners
|
return map
|
||||||
? Object.keys(listeners)
|
? Object.keys(map)
|
||||||
.filter(type => type === e.type)
|
.filter((type) => type === e.type)
|
||||||
.map(type => listeners[type])
|
.map((type) => map?.[type])
|
||||||
: undefined;
|
: undefined;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
||||||
|
|
||||||
listeners.forEach(listener => listener?.(e));
|
listeners.forEach((listener) => listener?.(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
useFocusEvents({ state, emitter });
|
useFocusEvents({ state, emitter });
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default function useNavigationCache<
|
|||||||
};
|
};
|
||||||
|
|
||||||
cache.current = state.routes.reduce<NavigationCache<State, ScreenOptions>>(
|
cache.current = state.routes.reduce<NavigationCache<State, ScreenOptions>>(
|
||||||
(acc, route, index) => {
|
(acc, route) => {
|
||||||
const previous = cache.current[route.key];
|
const previous = cache.current[route.key];
|
||||||
|
|
||||||
if (previous) {
|
if (previous) {
|
||||||
@@ -103,14 +103,14 @@ export default function useNavigationCache<
|
|||||||
dangerouslyGetState: getState,
|
dangerouslyGetState: getState,
|
||||||
dispatch,
|
dispatch,
|
||||||
setOptions: (options: object) =>
|
setOptions: (options: object) =>
|
||||||
setOptions(o => ({
|
setOptions((o) => ({
|
||||||
...o,
|
...o,
|
||||||
[route.key]: { ...o[route.key], ...options },
|
[route.key]: { ...o[route.key], ...options },
|
||||||
})),
|
})),
|
||||||
isFocused: () => {
|
isFocused: () => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
if (index !== state.index) {
|
if (state.routes[state.index].key !== route.key) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ export default function useNavigationHelpers<
|
|||||||
case 'REPLACE':
|
case 'REPLACE':
|
||||||
case 'JUMP_TO':
|
case 'JUMP_TO':
|
||||||
if (payload?.name) {
|
if (payload?.name) {
|
||||||
message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators.html#navigating-to-a-screen-in-a-nested-navigator.`;
|
message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.`;
|
||||||
} else {
|
} else {
|
||||||
message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions.html for usage.`;
|
message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions for usage.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function useNavigationState<T>(selector: Selector<T>): T {
|
|||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const unsubscribe = navigation.addListener('state', e => {
|
const unsubscribe = navigation.addListener('state', (e) => {
|
||||||
setResult(selectorRef.current(e.data.state));
|
setResult(selectorRef.current(e.data.state));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function useOnGetState({
|
|||||||
const state = getState();
|
const state = getState();
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
routes: state.routes.map(route => ({
|
routes: state.routes.map((route) => ({
|
||||||
...route,
|
...route,
|
||||||
state: getStateForRoute(route.key),
|
state: getStateForRoute(route.key),
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -3,6 +3,74 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.3.4](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.3...@react-navigation/drawer@5.3.4) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.3](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.2...@react-navigation/drawer@5.3.3) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.2](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.1...@react-navigation/drawer@5.3.2) (2020-03-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* close drawer on pressing Esc on web ([5c4afc5](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/5c4afc5cb40c1206a9d8c40efe3cf947030da48e)), closes [#6745](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/6745)
|
||||||
|
* don't use react-native-screens on web ([b1a65fc](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/b1a65fc73e8603ae2c06ef101a74df31e80bb9b2)), closes [#7485](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7485)
|
||||||
|
* fix permanent sidebar position ([#7830](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7830)) ([3ea8eec](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/3ea8eec4324ea82f0ed427f4662e68e1115e60ab))
|
||||||
|
* initialize height and width to zero if undefined ([3df65e2](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/3df65e28197db3bb8371059146546d57661c5ba3)), closes [#6789](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/6789)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.3.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.3.0...@react-navigation/drawer@5.3.1) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.3.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.2.0...@react-navigation/drawer@5.3.0) (2020-03-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add permanent drawer type ([#7818](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7818)) ([6a5d0a0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/6a5d0a035afae60d91aef78401ec8826295746fe))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.1.1...@react-navigation/drawer@5.2.0) (2020-03-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* make useIsDrawerOpen workable inside drawer content ([#7746](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/7746)) ([cb46d0b](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/cb46d0bca4e17e847fff46ac94276213ac9697bf))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.1.0...@react-navigation/drawer@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.7...@react-navigation/drawer@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.7...@react-navigation/drawer@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.1.0",
|
"version": "5.3.4",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -39,17 +39,17 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.5.6",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.7.0",
|
||||||
"react-native-safe-area-context": "^0.7.2",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.0.0-beta.2",
|
"react-native-screens": "^2.3.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"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": ">= 0.6.0",
|
"react-native-safe-area-context": ">= 0.6.0",
|
||||||
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0"
|
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
|
||||||
},
|
},
|
||||||
"@react-native-community/bob": {
|
"@react-native-community/bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Descriptor,
|
Descriptor,
|
||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
|
DrawerActionHelpers,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import { PanGestureHandler } from 'react-native-gesture-handler';
|
import { PanGestureHandler } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
@@ -26,8 +27,9 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
|
|||||||
* - `front`: Traditional drawer which covers the screen with a overlay behind it.
|
* - `front`: Traditional drawer which covers the screen with a overlay behind it.
|
||||||
* - `back`: The drawer is revealed behind the screen on swipe.
|
* - `back`: The drawer is revealed behind the screen on swipe.
|
||||||
* - `slide`: Both the screen and the drawer slide on swipe to reveal the drawer.
|
* - `slide`: Both the screen and the drawer slide on swipe to reveal the drawer.
|
||||||
|
* - `permanent`: A permanent drawer is shown as a sidebar.
|
||||||
*/
|
*/
|
||||||
drawerType?: 'front' | 'back' | 'slide';
|
drawerType?: 'front' | 'back' | 'slide' | 'permanent';
|
||||||
/**
|
/**
|
||||||
* How far from the edge of the screen the swipe gesture should activate.
|
* How far from the edge of the screen the swipe gesture should activate.
|
||||||
*/
|
*/
|
||||||
@@ -190,22 +192,8 @@ export type DrawerNavigationProp<
|
|||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
DrawerNavigationOptions,
|
DrawerNavigationOptions,
|
||||||
DrawerNavigationEventMap
|
DrawerNavigationEventMap
|
||||||
> & {
|
> &
|
||||||
/**
|
DrawerActionHelpers<ParamList>;
|
||||||
* Open the drawer sidebar.
|
|
||||||
*/
|
|
||||||
openDrawer(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the drawer sidebar.
|
|
||||||
*/
|
|
||||||
closeDrawer(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the drawer sidebar if closed, or close if opened.
|
|
||||||
*/
|
|
||||||
toggleDrawer(): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DrawerDescriptor = Descriptor<
|
export type DrawerDescriptor = Descriptor<
|
||||||
ParamListBase,
|
ParamListBase,
|
||||||
|
|||||||
5
packages/drawer/src/utils/DrawerOpenContext.tsx
Normal file
5
packages/drawer/src/utils/DrawerOpenContext.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
const DrawerOpenContext = React.createContext<boolean | null>(null);
|
||||||
|
|
||||||
|
export default DrawerOpenContext;
|
||||||
@@ -1,38 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useNavigation, ParamListBase } from '@react-navigation/native';
|
import DrawerOpenContext from './DrawerOpenContext';
|
||||||
import { DrawerNavigationProp } from '../types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to detect if the drawer is open in a parent navigator.
|
* Hook to detect if the drawer is open in a parent navigator.
|
||||||
*/
|
*/
|
||||||
export default function useIsDrawerOpen() {
|
export default function useIsDrawerOpen() {
|
||||||
const navigation = useNavigation();
|
const isDrawerOpen = React.useContext(DrawerOpenContext);
|
||||||
|
|
||||||
let drawer = navigation as DrawerNavigationProp<ParamListBase>;
|
if (typeof isDrawerOpen !== 'boolean') {
|
||||||
|
throw new Error(
|
||||||
// The screen might be inside another navigator such as stack nested in drawer
|
"Couldn't find a drawer. Is your component inside a drawer navigator?"
|
||||||
// We need to find the closest drawer navigator and add the listener there
|
);
|
||||||
while (drawer && drawer.dangerouslyGetState().type !== 'drawer') {
|
|
||||||
drawer = drawer.dangerouslyGetParent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = React.useState(() =>
|
|
||||||
drawer
|
|
||||||
? Boolean(
|
|
||||||
drawer.dangerouslyGetState().history.find(it => it.type === 'drawer')
|
|
||||||
)
|
|
||||||
: false
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const unsubscribe = drawer.addListener('state', e => {
|
|
||||||
setIsDrawerOpen(
|
|
||||||
Boolean(e.data.state.history.find(it => it.type === 'drawer'))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return unsubscribe;
|
|
||||||
}, [drawer, isDrawerOpen]);
|
|
||||||
|
|
||||||
return isDrawerOpen;
|
return isDrawerOpen;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ const SPRING_CONFIG = {
|
|||||||
restSpeedThreshold: 0.01,
|
restSpeedThreshold: 0.01,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ANIMATED_ONE = new Animated.Value(1);
|
||||||
|
|
||||||
type Binary = 0 | 1;
|
type Binary = 0 | 1;
|
||||||
|
|
||||||
type Renderer = (props: { progress: Animated.Node<number> }) => React.ReactNode;
|
type Renderer = (props: { progress: Animated.Node<number> }) => React.ReactNode;
|
||||||
@@ -79,7 +81,7 @@ type Props = {
|
|||||||
onGestureRef?: (ref: PanGestureHandler | null) => void;
|
onGestureRef?: (ref: PanGestureHandler | null) => void;
|
||||||
gestureEnabled: boolean;
|
gestureEnabled: boolean;
|
||||||
drawerPosition: 'left' | 'right';
|
drawerPosition: 'left' | 'right';
|
||||||
drawerType: 'front' | 'back' | 'slide';
|
drawerType: 'front' | 'back' | 'slide' | 'permanent';
|
||||||
keyboardDismissMode: 'none' | 'on-drag';
|
keyboardDismissMode: 'none' | 'on-drag';
|
||||||
swipeEdgeWidth: number;
|
swipeEdgeWidth: number;
|
||||||
swipeDistanceThreshold?: number;
|
swipeDistanceThreshold?: number;
|
||||||
@@ -125,6 +127,12 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
statusBarAnimation: 'slide',
|
statusBarAnimation: 'slide',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
document?.body?.addEventListener?.('keyup', this.handleEscape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
const {
|
const {
|
||||||
open,
|
open,
|
||||||
@@ -180,8 +188,22 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
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);
|
||||||
@@ -544,6 +566,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
gestureHandlerProps,
|
gestureHandlerProps,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const isOpen = drawerType === 'permanent' ? true : open;
|
||||||
const isRight = drawerPosition === 'right';
|
const isRight = drawerPosition === 'right';
|
||||||
|
|
||||||
const contentTranslateX = drawerType === 'front' ? 0 : this.translateX;
|
const contentTranslateX = drawerType === 'front' ? 0 : this.translateX;
|
||||||
@@ -569,8 +592,10 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
const hitSlop = isRight
|
const hitSlop = isRight
|
||||||
? // Extend hitSlop to the side of the screen when drawer is closed
|
? // 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
|
// This lets the user drag the drawer from the side of the screen
|
||||||
{ right: 0, width: open ? undefined : swipeEdgeWidth }
|
{ right: 0, width: isOpen ? undefined : swipeEdgeWidth }
|
||||||
: { left: 0, width: open ? undefined : swipeEdgeWidth };
|
: { left: 0, width: isOpen ? undefined : swipeEdgeWidth };
|
||||||
|
|
||||||
|
const progress = drawerType === 'permanent' ? ANIMATED_ONE : this.progress;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanGestureHandler
|
<PanGestureHandler
|
||||||
@@ -580,62 +605,83 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
onGestureEvent={this.handleGestureEvent}
|
onGestureEvent={this.handleGestureEvent}
|
||||||
onHandlerStateChange={this.handleGestureStateChange}
|
onHandlerStateChange={this.handleGestureStateChange}
|
||||||
hitSlop={hitSlop}
|
hitSlop={hitSlop}
|
||||||
enabled={gestureEnabled}
|
enabled={drawerType !== 'permanent' && gestureEnabled}
|
||||||
{...gestureHandlerProps}
|
{...gestureHandlerProps}
|
||||||
>
|
>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
onLayout={this.handleContainerLayout}
|
onLayout={this.handleContainerLayout}
|
||||||
style={styles.main}
|
style={[
|
||||||
|
styles.main,
|
||||||
|
{
|
||||||
|
flexDirection:
|
||||||
|
drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row',
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[
|
style={[
|
||||||
styles.content,
|
styles.content,
|
||||||
{
|
drawerType !== 'permanent' && {
|
||||||
transform: [{ translateX: contentTranslateX }],
|
transform: [{ translateX: contentTranslateX }],
|
||||||
},
|
},
|
||||||
sceneContainerStyle as any,
|
sceneContainerStyle as any,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
accessibilityElementsHidden={open}
|
accessibilityElementsHidden={isOpen}
|
||||||
importantForAccessibility={open ? 'no-hide-descendants' : 'auto'}
|
importantForAccessibility={
|
||||||
|
isOpen ? 'no-hide-descendants' : 'auto'
|
||||||
|
}
|
||||||
style={styles.content}
|
style={styles.content}
|
||||||
>
|
>
|
||||||
{renderSceneContent({ progress: this.progress })}
|
{renderSceneContent({ progress })}
|
||||||
</View>
|
</View>
|
||||||
<TapGestureHandler
|
{// Disable overlay if sidebar is permanent
|
||||||
enabled={gestureEnabled}
|
drawerType === 'permanent' ? null : (
|
||||||
onHandlerStateChange={this.handleTapStateChange}
|
<TapGestureHandler
|
||||||
>
|
enabled={gestureEnabled}
|
||||||
<Overlay progress={this.progress} style={overlayStyle} />
|
onHandlerStateChange={this.handleTapStateChange}
|
||||||
</TapGestureHandler>
|
>
|
||||||
|
<Overlay progress={progress} style={overlayStyle} />
|
||||||
|
</TapGestureHandler>
|
||||||
|
)}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Animated.Code
|
{drawerType === 'permanent' ? null : (
|
||||||
exec={block([
|
<Animated.Code
|
||||||
onChange(this.manuallyTriggerSpring, [
|
exec={block([
|
||||||
cond(eq(this.manuallyTriggerSpring, TRUE), [
|
onChange(this.manuallyTriggerSpring, [
|
||||||
set(this.nextIsOpen, FALSE),
|
cond(eq(this.manuallyTriggerSpring, TRUE), [
|
||||||
call([], () => (this.currentOpenValue = false)),
|
set(this.nextIsOpen, FALSE),
|
||||||
|
call([], () => (this.currentOpenValue = false)),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
])}
|
||||||
])}
|
/>
|
||||||
/>
|
)}
|
||||||
<Animated.View
|
<Animated.View
|
||||||
accessibilityViewIsModal={open}
|
accessibilityViewIsModal={isOpen}
|
||||||
removeClippedSubviews={Platform.OS !== 'ios'}
|
removeClippedSubviews={Platform.OS !== 'ios'}
|
||||||
onLayout={this.handleDrawerLayout}
|
onLayout={this.handleDrawerLayout}
|
||||||
style={[
|
style={[
|
||||||
styles.container,
|
styles.container,
|
||||||
isRight ? { right: offset } : { left: offset },
|
drawerType === 'permanent'
|
||||||
{
|
? // Without this, the `left`/`right` values don't get reset
|
||||||
transform: [{ translateX: drawerTranslateX }],
|
isRight
|
||||||
opacity: this.drawerOpacity,
|
? { right: 0 }
|
||||||
zIndex: drawerType === 'back' ? -1 : 0,
|
: { left: 0 }
|
||||||
},
|
: [
|
||||||
|
styles.nonPermanent,
|
||||||
|
{
|
||||||
|
transform: [{ translateX: drawerTranslateX }],
|
||||||
|
opacity: this.drawerOpacity,
|
||||||
|
},
|
||||||
|
isRight ? { right: offset } : { left: offset },
|
||||||
|
{ zIndex: drawerType === 'back' ? -1 : 0 },
|
||||||
|
],
|
||||||
drawerStyle as any,
|
drawerStyle as any,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{renderDrawerContent({ progress: this.progress })}
|
{renderDrawerContent({ progress })}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</PanGestureHandler>
|
</PanGestureHandler>
|
||||||
@@ -646,11 +692,13 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
|
maxWidth: '100%',
|
||||||
|
},
|
||||||
|
nonPermanent: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
width: '80%',
|
width: '80%',
|
||||||
maxWidth: '100%',
|
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
@@ -72,14 +72,8 @@ export default function DrawerItem(props: Props) {
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
focused = false,
|
focused = false,
|
||||||
activeTintColor = colors.primary,
|
activeTintColor = colors.primary,
|
||||||
inactiveTintColor = Color(colors.text)
|
inactiveTintColor = Color(colors.text).alpha(0.68).rgb().string(),
|
||||||
.alpha(0.68)
|
activeBackgroundColor = Color(activeTintColor).alpha(0.12).rgb().string(),
|
||||||
.rgb()
|
|
||||||
.string(),
|
|
||||||
activeBackgroundColor = Color(activeTintColor)
|
|
||||||
.alpha(0.12)
|
|
||||||
.rgb()
|
|
||||||
.string(),
|
|
||||||
inactiveBackgroundColor = 'transparent',
|
inactiveBackgroundColor = 'transparent',
|
||||||
style,
|
style,
|
||||||
onPress,
|
onPress,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
DrawerNavigationHelpers,
|
DrawerNavigationHelpers,
|
||||||
DrawerContentComponentProps,
|
DrawerContentComponentProps,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
import DrawerOpenContext from '../utils/DrawerOpenContext';
|
||||||
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
||||||
|
|
||||||
type Props = DrawerNavigationConfig & {
|
type Props = DrawerNavigationConfig & {
|
||||||
@@ -88,15 +89,17 @@ export default function DrawerView({
|
|||||||
sceneContainerStyle,
|
sceneContainerStyle,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [loaded, setLoaded] = React.useState([state.index]);
|
const [loaded, setLoaded] = React.useState([state.index]);
|
||||||
const [drawerWidth, setDrawerWidth] = React.useState(() =>
|
const [drawerWidth, setDrawerWidth] = React.useState(() => {
|
||||||
getDefaultDrawerWidth(Dimensions.get('window'))
|
const { height = 0, width = 0 } = Dimensions.get('window');
|
||||||
);
|
|
||||||
|
return getDefaultDrawerWidth({ height, width });
|
||||||
|
});
|
||||||
|
|
||||||
const drawerGestureRef = React.useRef<PanGestureHandler>(null);
|
const drawerGestureRef = React.useRef<PanGestureHandler>(null);
|
||||||
|
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const isDrawerOpen = Boolean(state.history.find(it => it.type === 'drawer'));
|
const isDrawerOpen = state.history.some((it) => it.type === 'drawer');
|
||||||
|
|
||||||
const handleDrawerOpen = React.useCallback(() => {
|
const handleDrawerOpen = React.useCallback(() => {
|
||||||
navigation.dispatch({
|
navigation.dispatch({
|
||||||
@@ -203,36 +206,48 @@ export default function DrawerView({
|
|||||||
<GestureHandlerWrapper style={styles.content}>
|
<GestureHandlerWrapper style={styles.content}>
|
||||||
<SafeAreaProviderCompat>
|
<SafeAreaProviderCompat>
|
||||||
<DrawerGestureContext.Provider value={drawerGestureRef}>
|
<DrawerGestureContext.Provider value={drawerGestureRef}>
|
||||||
<Drawer
|
<DrawerOpenContext.Provider value={isDrawerOpen}>
|
||||||
open={isDrawerOpen}
|
<Drawer
|
||||||
gestureEnabled={gestureEnabled}
|
open={isDrawerOpen}
|
||||||
onOpen={handleDrawerOpen}
|
gestureEnabled={gestureEnabled}
|
||||||
onClose={handleDrawerClose}
|
onOpen={handleDrawerOpen}
|
||||||
onGestureRef={ref => {
|
onClose={handleDrawerClose}
|
||||||
// @ts-ignore
|
onGestureRef={(ref) => {
|
||||||
drawerGestureRef.current = ref;
|
// @ts-ignore
|
||||||
}}
|
drawerGestureRef.current = ref;
|
||||||
gestureHandlerProps={gestureHandlerProps}
|
}}
|
||||||
drawerType={drawerType}
|
gestureHandlerProps={gestureHandlerProps}
|
||||||
drawerPosition={drawerPosition}
|
drawerType={drawerType}
|
||||||
sceneContainerStyle={[
|
drawerPosition={drawerPosition}
|
||||||
{ backgroundColor: colors.background },
|
sceneContainerStyle={[
|
||||||
sceneContainerStyle,
|
{ backgroundColor: colors.background },
|
||||||
]}
|
sceneContainerStyle,
|
||||||
drawerStyle={[
|
]}
|
||||||
{ width: drawerWidth, backgroundColor: colors.card },
|
drawerStyle={[
|
||||||
drawerStyle,
|
{ width: drawerWidth, backgroundColor: colors.card },
|
||||||
]}
|
drawerType === 'permanent' &&
|
||||||
overlayStyle={{ backgroundColor: overlayColor }}
|
(drawerPosition === 'left'
|
||||||
swipeEdgeWidth={edgeWidth}
|
? {
|
||||||
swipeDistanceThreshold={minSwipeDistance}
|
borderRightColor: colors.border,
|
||||||
hideStatusBar={hideStatusBar}
|
borderRightWidth: StyleSheet.hairlineWidth,
|
||||||
statusBarAnimation={statusBarAnimation}
|
}
|
||||||
renderDrawerContent={renderNavigationView}
|
: {
|
||||||
renderSceneContent={renderContent}
|
borderLeftColor: colors.border,
|
||||||
keyboardDismissMode={keyboardDismissMode}
|
borderLeftWidth: StyleSheet.hairlineWidth,
|
||||||
drawerPostion={drawerPosition}
|
}),
|
||||||
/>
|
drawerStyle,
|
||||||
|
]}
|
||||||
|
overlayStyle={{ backgroundColor: overlayColor }}
|
||||||
|
swipeEdgeWidth={edgeWidth}
|
||||||
|
swipeDistanceThreshold={minSwipeDistance}
|
||||||
|
hideStatusBar={hideStatusBar}
|
||||||
|
statusBarAnimation={statusBarAnimation}
|
||||||
|
renderDrawerContent={renderNavigationView}
|
||||||
|
renderSceneContent={renderContent}
|
||||||
|
keyboardDismissMode={keyboardDismissMode}
|
||||||
|
drawerPostion={drawerPosition}
|
||||||
|
/>
|
||||||
|
</DrawerOpenContext.Provider>
|
||||||
</DrawerGestureContext.Provider>
|
</DrawerGestureContext.Provider>
|
||||||
</SafeAreaProviderCompat>
|
</SafeAreaProviderCompat>
|
||||||
</GestureHandlerWrapper>
|
</GestureHandlerWrapper>
|
||||||
|
|||||||
@@ -9,21 +9,29 @@ type Props = {
|
|||||||
style?: any;
|
style?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
|
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
||||||
|
|
||||||
export default class ResourceSavingScene extends React.Component<Props> {
|
export default class ResourceSavingScene extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
if (screensEnabled?.()) {
|
// react-native-screens is buggy on web
|
||||||
|
if (screensEnabled?.() && Platform.OS !== 'web') {
|
||||||
const { isVisible, ...rest } = this.props;
|
const { isVisible, ...rest } = this.props;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isVisible, children, style, ...rest } = this.props;
|
const { isVisible, children, style, ...rest } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[styles.container, style]}
|
style={[
|
||||||
|
styles.container,
|
||||||
|
Platform.OS === 'web'
|
||||||
|
? { display: isVisible ? 'flex' : 'none' }
|
||||||
|
: null,
|
||||||
|
style,
|
||||||
|
]}
|
||||||
collapsable={false}
|
collapsable={false}
|
||||||
removeClippedSubviews={
|
removeClippedSubviews={
|
||||||
// On iOS, set removeClippedSubviews to true only when not focused
|
// On iOS, set removeClippedSubviews to true only when not focused
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ type Props = {
|
|||||||
export default function SafeAreaProviderCompat({ children }: Props) {
|
export default function SafeAreaProviderCompat({ children }: Props) {
|
||||||
return (
|
return (
|
||||||
<SafeAreaConsumer>
|
<SafeAreaConsumer>
|
||||||
{insets => {
|
{(insets) => {
|
||||||
if (insets) {
|
if (insets) {
|
||||||
// If we already have insets, don't wrap the stack in another safe area provider
|
// If we already have insets, don't wrap the stack in another safe area provider
|
||||||
// This avoids an issue with updates at the cost of potentially incorrect values
|
// This avoids an issue with updates at the cost of potentially incorrect values
|
||||||
|
|||||||
@@ -3,6 +3,54 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.5...@react-navigation/material-bottom-tabs@5.1.6) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.5](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.4...@react-navigation/material-bottom-tabs@5.1.5) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.4](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.3...@react-navigation/material-bottom-tabs@5.1.4) (2020-03-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.2...@react-navigation/material-bottom-tabs@5.1.3) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.1...@react-navigation/material-bottom-tabs@5.1.2) (2020-03-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.1.0...@react-navigation/material-bottom-tabs@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.7...@react-navigation/material-bottom-tabs@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.7...@react-navigation/material-bottom-tabs@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.1.0",
|
"version": "5.1.6",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -35,10 +35,10 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"@types/react-native-vector-icons": "^6.4.5",
|
"@types/react-native-vector-icons": "^6.4.5",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
NavigationProp,
|
NavigationProp,
|
||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
|
TabActionHelpers,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type MaterialBottomTabNavigationEventMap = {
|
export type MaterialBottomTabNavigationEventMap = {
|
||||||
@@ -28,19 +29,8 @@ export type MaterialBottomTabNavigationProp<
|
|||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
MaterialBottomTabNavigationOptions,
|
MaterialBottomTabNavigationOptions,
|
||||||
MaterialBottomTabNavigationEventMap
|
MaterialBottomTabNavigationEventMap
|
||||||
> & {
|
> &
|
||||||
/**
|
TabActionHelpers<ParamList>;
|
||||||
* Jump to an existing tab.
|
|
||||||
*
|
|
||||||
* @param name Name of the route for the tab.
|
|
||||||
* @param [params] Params object for the route.
|
|
||||||
*/
|
|
||||||
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
|
|
||||||
...args: ParamList[RouteName] extends undefined | any
|
|
||||||
? [RouteName] | [RouteName, ParamList[RouteName]]
|
|
||||||
: [RouteName, ParamList[RouteName]]
|
|
||||||
): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MaterialBottomTabNavigationOptions = {
|
export type MaterialBottomTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,54 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.5...@react-navigation/material-top-tabs@5.1.6) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.5](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.4...@react-navigation/material-top-tabs@5.1.5) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.4](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.3...@react-navigation/material-top-tabs@5.1.4) (2020-03-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.2...@react-navigation/material-top-tabs@5.1.3) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.1...@react-navigation/material-top-tabs@5.1.2) (2020-03-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.1.0...@react-navigation/material-top-tabs@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.7...@react-navigation/material-top-tabs@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.7...@react-navigation/material-top-tabs@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.1.0",
|
"version": "5.1.6",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -38,14 +38,14 @@
|
|||||||
"color": "^3.1.2"
|
"color": "^3.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.5.6",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-reanimated": "^1.7.0",
|
"react-native-reanimated": "^1.7.0",
|
||||||
"react-native-tab-view": "^2.13.0",
|
"react-native-tab-view": "^2.13.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Route,
|
Route,
|
||||||
NavigationProp,
|
NavigationProp,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
|
TabActionHelpers,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type MaterialTopTabNavigationEventMap = {
|
export type MaterialTopTabNavigationEventMap = {
|
||||||
@@ -42,19 +43,8 @@ export type MaterialTopTabNavigationProp<
|
|||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
MaterialTopTabNavigationOptions,
|
MaterialTopTabNavigationOptions,
|
||||||
MaterialTopTabNavigationEventMap
|
MaterialTopTabNavigationEventMap
|
||||||
> & {
|
> &
|
||||||
/**
|
TabActionHelpers<ParamList>;
|
||||||
* Jump to an existing tab.
|
|
||||||
*
|
|
||||||
* @param name Name of the route for the tab.
|
|
||||||
* @param [params] Params object for the route.
|
|
||||||
*/
|
|
||||||
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
|
|
||||||
...args: ParamList[RouteName] extends undefined | any
|
|
||||||
? [RouteName] | [RouteName, ParamList[RouteName]]
|
|
||||||
: [RouteName, ParamList[RouteName]]
|
|
||||||
): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MaterialTopTabNavigationOptions = {
|
export type MaterialTopTabNavigationOptions = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,17 +14,11 @@ export default function TabBarTop(props: MaterialTopTabBarProps) {
|
|||||||
navigation,
|
navigation,
|
||||||
descriptors,
|
descriptors,
|
||||||
activeTintColor = colors.text,
|
activeTintColor = colors.text,
|
||||||
inactiveTintColor = Color(activeTintColor)
|
inactiveTintColor = Color(activeTintColor).alpha(0.5).rgb().string(),
|
||||||
.alpha(0.5)
|
|
||||||
.rgb()
|
|
||||||
.string(),
|
|
||||||
allowFontScaling = true,
|
allowFontScaling = true,
|
||||||
showIcon = false,
|
showIcon = false,
|
||||||
showLabel = true,
|
showLabel = true,
|
||||||
pressColor = Color(activeTintColor)
|
pressColor = Color(activeTintColor).alpha(0.08).rgb().string(),
|
||||||
.alpha(0.08)
|
|
||||||
.rgb()
|
|
||||||
.string(),
|
|
||||||
iconStyle,
|
iconStyle,
|
||||||
labelStyle,
|
labelStyle,
|
||||||
indicatorStyle,
|
indicatorStyle,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default function MaterialTopTabView({
|
|||||||
return (
|
return (
|
||||||
<TabView
|
<TabView
|
||||||
{...rest}
|
{...rest}
|
||||||
onIndexChange={index =>
|
onIndexChange={(index) =>
|
||||||
navigation.dispatch({
|
navigation.dispatch({
|
||||||
...TabActions.jumpTo(state.routes[index].name),
|
...TabActions.jumpTo(state.routes[index].name),
|
||||||
target: state.key,
|
target: state.key,
|
||||||
|
|||||||
@@ -3,6 +3,60 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.1.3](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.2...@react-navigation/native@5.1.3) (2020-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add info about android launchMode in useLinking error ([d94e43c](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/d94e43c3c8625b209a5c883b8cb560496d07fda7))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.2](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.1...@react-navigation/native@5.1.2) (2020-03-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.1.0...@react-navigation/native@5.1.1) (2020-03-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.10...@react-navigation/native@5.1.0) (2020-03-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add permanent drawer type ([#7818](https://github.com/react-navigation/react-navigation/tree/master/packages/native/issues/7818)) ([6a5d0a0](https://github.com/react-navigation/react-navigation/tree/master/packages/native/commit/6a5d0a035afae60d91aef78401ec8826295746fe))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.0.10](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.9...@react-navigation/native@5.0.10) (2020-03-16)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.0.9](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.8...@react-navigation/native@5.0.9) (2020-03-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.0.8](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.7...@react-navigation/native@5.0.8) (2020-02-26)
|
## [5.0.8](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.7...@react-navigation/native@5.0.8) (2020-02-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/native
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|||||||
@@ -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": "5.0.8",
|
"version": "5.1.3",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation",
|
"react-navigation",
|
||||||
@@ -31,12 +31,12 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^5.2.0"
|
"@react-navigation/core": "^5.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default function() {
|
export default function () {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'NavigationNativeContainer' has been renamed to 'NavigationContainer"
|
"'NavigationNativeContainer' has been renamed to 'NavigationContainer"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const DefaultTheme: Theme = {
|
|||||||
background: 'rgb(242, 242, 242)',
|
background: 'rgb(242, 242, 242)',
|
||||||
card: 'rgb(255, 255, 255)',
|
card: 'rgb(255, 255, 255)',
|
||||||
text: 'rgb(28, 28, 30)',
|
text: 'rgb(28, 28, 30)',
|
||||||
border: 'rgb(199, 199, 204)',
|
border: 'rgb(224, 224, 224)',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Linking } from 'react-native';
|
import { Linking, Platform } from 'react-native';
|
||||||
import {
|
import {
|
||||||
getActionFromState,
|
getActionFromState,
|
||||||
getStateFromPath as getStateFromPathDefault,
|
getStateFromPath as getStateFromPathDefault,
|
||||||
@@ -20,7 +20,10 @@ export default function useLinking(
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isUsingLinking) {
|
if (isUsingLinking) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Looks like you are using 'useLinking' in multiple components. This is likely an error since deep links should only be handled in one place to avoid conflicts."
|
"Looks like you are using 'useLinking' in multiple components. This is likely an error since deep links should only be handled in one place to avoid conflicts." +
|
||||||
|
(Platform.OS === 'android'
|
||||||
|
? "\n\nIf you're not using it in multiple components, ensure that you have set 'android:launchMode=singleTask' in the '<activity />' section of the 'AndroidManifest.xml' file to avoid launching multiple activities which run multiple instances of the root component."
|
||||||
|
: '')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
isUsingLinking = true;
|
isUsingLinking = true;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export default function useLinking(
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isUsingLinking) {
|
if (isUsingLinking) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Looks like you are using 'useLinking' in multiple components. This is likely an error since URL integration should only be handled in one place to avoid conflicts."
|
"Looks like you are using 'useLinking' in multiple components. This is likely an error since URL integration should only be handled in one place to avoid conflicts. Also ensure that you set your android activity launchMode to single task in your AndroiManifest.xml file."
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
isUsingLinking = true;
|
isUsingLinking = true;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ type ScrollOptions = { y?: number; animated?: boolean };
|
|||||||
type ScrollableView =
|
type ScrollableView =
|
||||||
| { scrollToTop(): void }
|
| { scrollToTop(): void }
|
||||||
| { scrollTo(options: ScrollOptions): void }
|
| { scrollTo(options: ScrollOptions): void }
|
||||||
| { scrollToOffset(options: ScrollOptions): void }
|
| { scrollToOffset(options: { offset?: number; animated?: boolean }): void }
|
||||||
| { scrollResponderScrollTo(options: ScrollOptions): void };
|
| { scrollResponderScrollTo(options: ScrollOptions): void };
|
||||||
|
|
||||||
type ScrollableWrapper =
|
type ScrollableWrapper =
|
||||||
| { getScrollResponder(): ScrollableView }
|
| { getScrollResponder(): React.ReactNode }
|
||||||
| { getNode(): ScrollableView }
|
| { getNode(): ScrollableView }
|
||||||
| ScrollableView;
|
| ScrollableView;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export default function useScrollToTop(
|
|||||||
// Run the operation in the next frame so we're sure all listeners have been run
|
// Run the operation in the next frame so we're sure all listeners have been run
|
||||||
// This is necessary to know if preventDefault() has been called
|
// This is necessary to know if preventDefault() has been called
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const scrollable = getScrollableNode(ref);
|
const scrollable = getScrollableNode(ref) as ScrollableWrapper;
|
||||||
|
|
||||||
if (isFocused && isFirst && scrollable && !e.defaultPrevented) {
|
if (isFocused && isFirst && scrollable && !e.defaultPrevented) {
|
||||||
if ('scrollToTop' in scrollable) {
|
if ('scrollToTop' in scrollable) {
|
||||||
@@ -87,7 +87,7 @@ export default function useScrollToTop(
|
|||||||
} else if ('scrollTo' in scrollable) {
|
} else if ('scrollTo' in scrollable) {
|
||||||
scrollable.scrollTo({ y: 0, animated: true });
|
scrollable.scrollTo({ y: 0, animated: true });
|
||||||
} else if ('scrollToOffset' in scrollable) {
|
} else if ('scrollToOffset' in scrollable) {
|
||||||
scrollable.scrollToOffset({ y: 0, animated: true });
|
scrollable.scrollToOffset({ offset: 0, animated: true });
|
||||||
} else if ('scrollResponderScrollTo' in scrollable) {
|
} else if ('scrollResponderScrollTo' in scrollable) {
|
||||||
scrollable.scrollResponderScrollTo({ y: 0, animated: true });
|
scrollable.scrollResponderScrollTo({ y: 0, animated: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,44 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.1.1...@react-navigation/routers@5.2.0) (2020-03-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add keys to routes missing keys during reset ([813a590](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/813a5903b5f44506b9097538ed85229e565b855e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.1.0...@react-navigation/routers@5.1.1) (2020-03-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't handle action if no routes are present ([660cac3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/660cac3557bce8978812ce2750e961e7ada92d13))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.3...@react-navigation/routers@5.1.0) (2020-03-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix links for documentation ([5bb0f40](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/5bb0f405ceb5755d39a0b5b1f2e4ecee0da051bc))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* make reset bubble up ([09f6808](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/commit/09f6808d7d43c70b2c502151f9f20fad03972886))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [5.0.3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.2...@react-navigation/routers@5.0.3) (2020-02-26)
|
## [5.0.3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.2...@react-navigation/routers@5.0.3) (2020-02-26)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/routers
|
**Note:** Version bump only for package @react-navigation/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": "5.0.3",
|
"version": "5.2.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
"react-native",
|
"react-native",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"shortid": "^2.2.15"
|
"shortid": "^2.2.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import shortid from 'shortid';
|
||||||
import { CommonNavigationAction, NavigationState, PartialState } from './types';
|
import { CommonNavigationAction, NavigationState, PartialState } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,7 +13,7 @@ const BaseRouter = {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_PARAMS': {
|
case 'SET_PARAMS': {
|
||||||
const index = action.source
|
const index = action.source
|
||||||
? state.routes.findIndex(r => r.key === action.source)
|
? state.routes.findIndex((r) => r.key === action.source)
|
||||||
: state.index;
|
: state.index;
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
@@ -29,8 +30,40 @@ const BaseRouter = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'RESET':
|
case 'RESET': {
|
||||||
return action.payload as PartialState<State>;
|
const nextState = action.payload as State | PartialState<State>;
|
||||||
|
|
||||||
|
if (
|
||||||
|
nextState.routes.length === 0 ||
|
||||||
|
nextState.routes.some(
|
||||||
|
(route: { name: string }) => !state.routeNames.includes(route.name)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextState.stale === false) {
|
||||||
|
if (
|
||||||
|
state.routeNames.length !== nextState.routeNames.length ||
|
||||||
|
nextState.routeNames.some(
|
||||||
|
(name) => !state.routeNames.includes(name)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...nextState,
|
||||||
|
routes: nextState.routes.map((route) =>
|
||||||
|
route.key
|
||||||
|
? route
|
||||||
|
: { ...route, key: `${route.name}-${shortid()}` }
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextState;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function navigate(...args: any): Action {
|
|||||||
|
|
||||||
if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) {
|
if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'You need to specify name or key when calling navigate with an object as the argument. See https://reactnavigation.org/docs/navigation-actions.html#navigate for usage.'
|
'You need to specify name or key when calling navigate with an object as the argument. See https://reactnavigation.org/docs/navigation-actions#navigate for usage.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import { PartialState, CommonNavigationAction, Router } from './types';
|
import {
|
||||||
|
PartialState,
|
||||||
|
CommonNavigationAction,
|
||||||
|
Router,
|
||||||
|
ParamListBase,
|
||||||
|
} from './types';
|
||||||
import TabRouter, {
|
import TabRouter, {
|
||||||
TabActions,
|
TabActions,
|
||||||
TabActionType,
|
TabActionType,
|
||||||
TabRouterOptions,
|
TabRouterOptions,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
|
TabActionHelpers,
|
||||||
} from './TabRouter';
|
} from './TabRouter';
|
||||||
|
|
||||||
export type DrawerActionType =
|
export type DrawerActionType =
|
||||||
@@ -31,6 +37,25 @@ export type DrawerNavigationState = Omit<
|
|||||||
history: ({ type: 'route'; key: string } | { type: 'drawer' })[];
|
history: ({ type: 'route'; key: string } | { type: 'drawer' })[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DrawerActionHelpers<
|
||||||
|
ParamList extends ParamListBase
|
||||||
|
> = TabActionHelpers<ParamList> & {
|
||||||
|
/**
|
||||||
|
* Open the drawer sidebar.
|
||||||
|
*/
|
||||||
|
openDrawer(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the drawer sidebar.
|
||||||
|
*/
|
||||||
|
closeDrawer(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the drawer sidebar if closed, or close if opened.
|
||||||
|
*/
|
||||||
|
toggleDrawer(): void;
|
||||||
|
};
|
||||||
|
|
||||||
export const DrawerActions = {
|
export const DrawerActions = {
|
||||||
...TabActions,
|
...TabActions,
|
||||||
openDrawer(): DrawerActionType {
|
openDrawer(): DrawerActionType {
|
||||||
@@ -46,7 +71,7 @@ export const DrawerActions = {
|
|||||||
|
|
||||||
const isDrawerOpen = (
|
const isDrawerOpen = (
|
||||||
state: DrawerNavigationState | PartialState<DrawerNavigationState>
|
state: DrawerNavigationState | PartialState<DrawerNavigationState>
|
||||||
) => Boolean(state.history?.find(it => it.type === 'drawer'));
|
) => Boolean(state.history?.find((it) => it.type === 'drawer'));
|
||||||
|
|
||||||
const openDrawer = (state: DrawerNavigationState): DrawerNavigationState => {
|
const openDrawer = (state: DrawerNavigationState): DrawerNavigationState => {
|
||||||
if (isDrawerOpen(state)) {
|
if (isDrawerOpen(state)) {
|
||||||
@@ -66,7 +91,7 @@ const closeDrawer = (state: DrawerNavigationState): DrawerNavigationState => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
history: state.history.filter(it => it.type !== 'drawer'),
|
history: state.history.filter((it) => it.type !== 'drawer'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
DefaultRouterOptions,
|
DefaultRouterOptions,
|
||||||
Route,
|
Route,
|
||||||
|
ParamListBase,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export type StackActionType =
|
export type StackActionType =
|
||||||
@@ -42,6 +43,42 @@ export type StackNavigationState = NavigationState & {
|
|||||||
type: 'stack';
|
type: 'stack';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type StackActionHelpers<ParamList extends ParamListBase> = {
|
||||||
|
/**
|
||||||
|
* Replace the current route with a new one.
|
||||||
|
*
|
||||||
|
* @param name Route name of the new route.
|
||||||
|
* @param [params] Params object for the new route.
|
||||||
|
*/
|
||||||
|
replace<RouteName extends keyof ParamList>(
|
||||||
|
...args: ParamList[RouteName] extends undefined
|
||||||
|
? [RouteName] | [RouteName, ParamList[RouteName]]
|
||||||
|
: [RouteName, ParamList[RouteName]]
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a new screen onto the stack.
|
||||||
|
*
|
||||||
|
* @param name Name of the route for the tab.
|
||||||
|
* @param [params] Params object for the route.
|
||||||
|
*/
|
||||||
|
push<RouteName extends keyof ParamList>(
|
||||||
|
...args: ParamList[RouteName] extends undefined | any
|
||||||
|
? [RouteName] | [RouteName, ParamList[RouteName]]
|
||||||
|
: [RouteName, ParamList[RouteName]]
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop a screen from the stack.
|
||||||
|
*/
|
||||||
|
pop(count?: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop to the first route in the stack, dismissing all other screens.
|
||||||
|
*/
|
||||||
|
popToTop(): void;
|
||||||
|
};
|
||||||
|
|
||||||
export const StackActions = {
|
export const StackActions = {
|
||||||
replace(name: string, params?: object): StackActionType {
|
replace(name: string, params?: object): StackActionType {
|
||||||
return { type: 'REPLACE', payload: { name, params } };
|
return { type: 'REPLACE', payload: { name, params } };
|
||||||
@@ -97,9 +134,9 @@ export default function StackRouter(options: StackRouterOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const routes = state.routes
|
const routes = state.routes
|
||||||
.filter(route => routeNames.includes(route.name))
|
.filter((route) => routeNames.includes(route.name))
|
||||||
.map(
|
.map(
|
||||||
route =>
|
(route) =>
|
||||||
({
|
({
|
||||||
...route,
|
...route,
|
||||||
key: route.key || `${route.name}-${shortid()}`,
|
key: route.key || `${route.name}-${shortid()}`,
|
||||||
@@ -137,7 +174,7 @@ export default function StackRouter(options: StackRouterOptions) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStateForRouteNamesChange(state, { routeNames, routeParamList }) {
|
getStateForRouteNamesChange(state, { routeNames, routeParamList }) {
|
||||||
const routes = state.routes.filter(route =>
|
const routes = state.routes.filter((route) =>
|
||||||
routeNames.includes(route.name)
|
routeNames.includes(route.name)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -164,7 +201,7 @@ export default function StackRouter(options: StackRouterOptions) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStateForRouteFocus(state, key) {
|
getStateForRouteFocus(state, key) {
|
||||||
const index = state.routes.findIndex(r => r.key === key);
|
const index = state.routes.findIndex((r) => r.key === key);
|
||||||
|
|
||||||
if (index === -1 || index === state.index) {
|
if (index === -1 || index === state.index) {
|
||||||
return state;
|
return state;
|
||||||
@@ -183,7 +220,7 @@ export default function StackRouter(options: StackRouterOptions) {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'REPLACE': {
|
case 'REPLACE': {
|
||||||
const index = action.source
|
const index = action.source
|
||||||
? state.routes.findIndex(r => r.key === action.source)
|
? state.routes.findIndex((r) => r.key === action.source)
|
||||||
: state.index;
|
: state.index;
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
@@ -246,7 +283,7 @@ export default function StackRouter(options: StackRouterOptions) {
|
|||||||
case 'POP': {
|
case 'POP': {
|
||||||
const index =
|
const index =
|
||||||
action.target === state.key && action.source
|
action.target === state.key && action.source
|
||||||
? state.routes.findIndex(r => r.key === action.source)
|
? state.routes.findIndex((r) => r.key === action.source)
|
||||||
: state.index;
|
: state.index;
|
||||||
|
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
DefaultRouterOptions,
|
DefaultRouterOptions,
|
||||||
Route,
|
Route,
|
||||||
|
ParamListBase,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export type TabActionType = {
|
export type TabActionType = {
|
||||||
@@ -33,6 +34,20 @@ export type TabNavigationState = Omit<NavigationState, 'history'> & {
|
|||||||
history: { type: 'route'; key: string }[];
|
history: { type: 'route'; key: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TabActionHelpers<ParamList extends ParamListBase> = {
|
||||||
|
/**
|
||||||
|
* Jump to an existing tab.
|
||||||
|
*
|
||||||
|
* @param name Name of the route for the tab.
|
||||||
|
* @param [params] Params object for the route.
|
||||||
|
*/
|
||||||
|
jumpTo<RouteName extends Extract<keyof ParamList, string>>(
|
||||||
|
...args: ParamList[RouteName] extends undefined | any
|
||||||
|
? [RouteName] | [RouteName, ParamList[RouteName]]
|
||||||
|
: [RouteName, ParamList[RouteName]]
|
||||||
|
): void;
|
||||||
|
};
|
||||||
|
|
||||||
const TYPE_ROUTE = 'route' as const;
|
const TYPE_ROUTE = 'route' as const;
|
||||||
|
|
||||||
export const TabActions = {
|
export const TabActions = {
|
||||||
@@ -78,7 +93,7 @@ const changeIndex = (
|
|||||||
const currentKey = state.routes[index].key;
|
const currentKey = state.routes[index].key;
|
||||||
|
|
||||||
history = state.history
|
history = state.history
|
||||||
.filter(it => (it.type === 'route' ? it.key !== currentKey : false))
|
.filter((it) => (it.type === 'route' ? it.key !== currentKey : false))
|
||||||
.concat({ type: TYPE_ROUTE, key: currentKey });
|
.concat({ type: TYPE_ROUTE, key: currentKey });
|
||||||
} else {
|
} else {
|
||||||
history = getRouteHistory(state.routes, index, backBehavior);
|
history = getRouteHistory(state.routes, index, backBehavior);
|
||||||
@@ -109,7 +124,7 @@ export default function TabRouter({
|
|||||||
? routeNames.indexOf(initialRouteName)
|
? routeNames.indexOf(initialRouteName)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const routes = routeNames.map(name => ({
|
const routes = routeNames.map((name) => ({
|
||||||
name,
|
name,
|
||||||
key: `${name}-${shortid()}`,
|
key: `${name}-${shortid()}`,
|
||||||
params: routeParamList[name],
|
params: routeParamList[name],
|
||||||
@@ -135,9 +150,9 @@ export default function TabRouter({
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
const routes = routeNames.map(name => {
|
const routes = routeNames.map((name) => {
|
||||||
const route = (state as PartialState<TabNavigationState>).routes.find(
|
const route = (state as PartialState<TabNavigationState>).routes.find(
|
||||||
r => r.name === name
|
(r) => r.name === name
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -169,8 +184,8 @@ export default function TabRouter({
|
|||||||
routes.length - 1
|
routes.length - 1
|
||||||
);
|
);
|
||||||
|
|
||||||
let history = state.history?.filter(it =>
|
let history = state.history?.filter((it) =>
|
||||||
routes.find(r => r.key === it.key)
|
routes.find((r) => r.key === it.key)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!history?.length) {
|
if (!history?.length) {
|
||||||
@@ -190,8 +205,8 @@ export default function TabRouter({
|
|||||||
|
|
||||||
getStateForRouteNamesChange(state, { routeNames, routeParamList }) {
|
getStateForRouteNamesChange(state, { routeNames, routeParamList }) {
|
||||||
const routes = routeNames.map(
|
const routes = routeNames.map(
|
||||||
name =>
|
(name) =>
|
||||||
state.routes.find(r => r.name === name) || {
|
state.routes.find((r) => r.name === name) || {
|
||||||
name,
|
name,
|
||||||
key: `${name}-${shortid()}`,
|
key: `${name}-${shortid()}`,
|
||||||
params: routeParamList[name],
|
params: routeParamList[name],
|
||||||
@@ -203,8 +218,8 @@ export default function TabRouter({
|
|||||||
routeNames.indexOf(state.routes[state.index].name)
|
routeNames.indexOf(state.routes[state.index].name)
|
||||||
);
|
);
|
||||||
|
|
||||||
let history = state.history.filter(it =>
|
let history = state.history.filter((it) =>
|
||||||
routes.find(r => r.key === it.key)
|
routes.find((r) => r.key === it.key)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!history.length) {
|
if (!history.length) {
|
||||||
@@ -221,7 +236,7 @@ export default function TabRouter({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getStateForRouteFocus(state, key) {
|
getStateForRouteFocus(state, key) {
|
||||||
const index = state.routes.findIndex(r => r.key === key);
|
const index = state.routes.findIndex((r) => r.key === key);
|
||||||
|
|
||||||
if (index === -1 || index === state.index) {
|
if (index === -1 || index === state.index) {
|
||||||
return state;
|
return state;
|
||||||
@@ -238,11 +253,11 @@ export default function TabRouter({
|
|||||||
|
|
||||||
if (action.type === 'NAVIGATE' && action.payload.key) {
|
if (action.type === 'NAVIGATE' && action.payload.key) {
|
||||||
index = state.routes.findIndex(
|
index = state.routes.findIndex(
|
||||||
route => route.key === action.payload.key
|
(route) => route.key === action.payload.key
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
index = state.routes.findIndex(
|
index = state.routes.findIndex(
|
||||||
route => route.name === action.payload.name
|
(route) => route.name === action.payload.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +295,7 @@ export default function TabRouter({
|
|||||||
|
|
||||||
const previousKey = state.history[state.history.length - 2].key;
|
const previousKey = state.history[state.history.length - 2].key;
|
||||||
const index = state.routes.findIndex(
|
const index = state.routes.findIndex(
|
||||||
route => route.key === previousKey
|
(route) => route.key === previousKey
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
|
|||||||
@@ -83,3 +83,62 @@ it('resets state to new state with RESET', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({ index: 0, routes });
|
expect(result).toEqual({ index: 0, routes });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('adds keys to routes missing keys during RESET', () => {
|
||||||
|
const result = BaseRouter.getStateForAction(
|
||||||
|
STATE,
|
||||||
|
// @ts-ignore
|
||||||
|
CommonActions.reset({
|
||||||
|
...STATE,
|
||||||
|
routes: [...STATE.routes, { name: 'qux' }],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
...STATE,
|
||||||
|
routes: [...STATE.routes, { key: 'qux-test', name: 'qux' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't handle RESET if routes don't match routeNames", () => {
|
||||||
|
const routes = [
|
||||||
|
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
|
||||||
|
{ key: 'baz', name: 'baz' },
|
||||||
|
{ key: 'qux', name: 'quz' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = BaseRouter.getStateForAction(
|
||||||
|
STATE,
|
||||||
|
CommonActions.reset({
|
||||||
|
index: 0,
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't handle RESET if routeNames don't match", () => {
|
||||||
|
const result = BaseRouter.getStateForAction(
|
||||||
|
STATE,
|
||||||
|
CommonActions.reset({
|
||||||
|
...STATE,
|
||||||
|
// @ts-ignore
|
||||||
|
routeNames: ['ten'],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't handle RESET if there are no routes", () => {
|
||||||
|
const result = BaseRouter.getStateForAction(
|
||||||
|
STATE,
|
||||||
|
CommonActions.reset({
|
||||||
|
index: 0,
|
||||||
|
routes: [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual(null);
|
||||||
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export { default as BaseRouter } from './BaseRouter';
|
|||||||
export {
|
export {
|
||||||
default as StackRouter,
|
default as StackRouter,
|
||||||
StackActions,
|
StackActions,
|
||||||
|
StackActionHelpers,
|
||||||
StackActionType,
|
StackActionType,
|
||||||
StackRouterOptions,
|
StackRouterOptions,
|
||||||
StackNavigationState,
|
StackNavigationState,
|
||||||
@@ -15,6 +16,7 @@ export {
|
|||||||
export {
|
export {
|
||||||
default as TabRouter,
|
default as TabRouter,
|
||||||
TabActions,
|
TabActions,
|
||||||
|
TabActionHelpers,
|
||||||
TabActionType,
|
TabActionType,
|
||||||
TabRouterOptions,
|
TabRouterOptions,
|
||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
@@ -23,6 +25,7 @@ export {
|
|||||||
export {
|
export {
|
||||||
default as DrawerRouter,
|
default as DrawerRouter,
|
||||||
DrawerActions,
|
DrawerActions,
|
||||||
|
DrawerActionHelpers,
|
||||||
DrawerActionType,
|
DrawerActionType,
|
||||||
DrawerRouterOptions,
|
DrawerRouterOptions,
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
|
|||||||
@@ -3,6 +3,109 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
## [5.2.7](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.6...@react-navigation/stack@5.2.7) (2020-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add pointerEvents=box-none to overlay View ([#7871](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7871)) ([e097df8](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/e097df880adab984aae29f847003d2548cfbdce5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.6](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.5...@react-navigation/stack@5.2.6) (2020-03-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.5](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.4...@react-navigation/stack@5.2.5) (2020-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix swipe gestures requiring a lot of velocity to dismiss ([61f16d3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/61f16d3f25cbbcc00d699dd09c5f4abde9b17d5a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.4](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.3...@react-navigation/stack@5.2.4) (2020-03-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix swipe not dismissing card in RTL ([043924c](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/043924ca4843b6f02626532cbf4aafc7cad9fab1)), closes [#7841](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7841)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.2...@react-navigation/stack@5.2.3) (2020-03-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use the correct velocity value in closing animation ([#7836](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7836)) ([adbfedc](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/adbfedcd58d4e3d358c6c9691710bb8e4e0d8afb))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.2](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.1...@react-navigation/stack@5.2.2) (2020-03-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't use react-native-screens on web ([b1a65fc](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/b1a65fc73e8603ae2c06ef101a74df31e80bb9b2)), closes [#7485](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7485)
|
||||||
|
* fix blank page if stack was inside display: none before ([49f6fed](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/49f6fed6d3da878e02a9fe9115c05bcf84e332bf))
|
||||||
|
* fix closing stack using inverted gesture. ([#7824](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7824)) ([f24d3a3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/f24d3a3461ee8a566c25ce7d13f31035b4be2691))
|
||||||
|
* initialize height and width to zero if undefined ([3df65e2](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/3df65e28197db3bb8371059146546d57661c5ba3)), closes [#6789](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6789)
|
||||||
|
* only dismiss previously focused input on page change. closes [#6918](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6918) ([b1fe730](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/b1fe73097f3ad58d3ba4a8a9b875276d1d8d220c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.2.1](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.2.0...@react-navigation/stack@5.2.1) (2020-03-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.1.1...@react-navigation/stack@5.2.0) (2020-03-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix android header title font weight ([#7720](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7720)) ([0dcaea3](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/0dcaea32428484cdc9b4d56f7bf38f9f1bdf1dee))
|
||||||
|
* fix back gesture cancellation ([#7700](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7700)) ([469d054](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/469d0542c7341dc524a597d70216ba743602a51e)), closes [#6782](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6782)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add an option to change use a custom card overlay ([#7809](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7809)) ([70029d6](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/70029d6c130f0f47de94b6a6c4cbee6afa12b405))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.1](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.1.0...@react-navigation/stack@5.1.1) (2020-03-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ignore back button press if screen isn't focused. closes [#7673](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/7673) ([296c836](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/296c836064447e055a88e43cfbbf5f9de93838f0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.9...@react-navigation/stack@5.1.0) (2020-02-26)
|
# [5.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.9...@react-navigation/stack@5.1.0) (2020-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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": "5.1.0",
|
"version": "5.2.8",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react-native-component",
|
"react-native-component",
|
||||||
"react-component",
|
"react-component",
|
||||||
@@ -38,18 +38,18 @@
|
|||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.9.3",
|
"@react-native-community/bob": "^0.10.0",
|
||||||
"@react-native-community/masked-view": "^0.1.6",
|
"@react-native-community/masked-view": "^0.1.7",
|
||||||
"@react-navigation/native": "^5.0.8",
|
"@react-navigation/native": "^5.1.3",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.23",
|
||||||
"@types/react-native": "^0.60.30",
|
"@types/react-native": "^0.61.22",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.5.6",
|
"react-native-gesture-handler": "^1.6.0",
|
||||||
"react-native-safe-area-context": "^0.7.2",
|
"react-native-safe-area-context": "^0.7.3",
|
||||||
"react-native-screens": "^2.0.0-beta.2",
|
"react-native-screens": "^2.3.0",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
"react-native-gesture-handler": ">= 1.0.0",
|
"react-native-gesture-handler": ">= 1.0.0",
|
||||||
"react-native-safe-area-context": ">= 0.6.0",
|
"react-native-safe-area-context": ">= 0.6.0",
|
||||||
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0"
|
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
|
||||||
},
|
},
|
||||||
"@react-native-community/bob": {
|
"@react-native-community/bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function StackNavigator({
|
|||||||
React.useEffect(
|
React.useEffect(
|
||||||
() =>
|
() =>
|
||||||
navigation.addListener &&
|
navigation.addListener &&
|
||||||
navigation.addListener('tabPress', e => {
|
navigation.addListener('tabPress', (e) => {
|
||||||
const isFocused = navigation.isFocused();
|
const isFocused = navigation.isFocused();
|
||||||
|
|
||||||
// Run the operation in the next frame so we're sure all listeners have been run
|
// Run the operation in the next frame so we're sure all listeners have been run
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
Animated,
|
Animated,
|
||||||
StyleProp,
|
StyleProp,
|
||||||
@@ -13,6 +14,7 @@ import {
|
|||||||
Route,
|
Route,
|
||||||
NavigationHelpers,
|
NavigationHelpers,
|
||||||
StackNavigationState,
|
StackNavigationState,
|
||||||
|
StackActionHelpers,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
|
|
||||||
export type StackNavigationEventMap = {
|
export type StackNavigationEventMap = {
|
||||||
@@ -40,29 +42,8 @@ export type StackNavigationProp<
|
|||||||
StackNavigationState,
|
StackNavigationState,
|
||||||
StackNavigationOptions,
|
StackNavigationOptions,
|
||||||
StackNavigationEventMap
|
StackNavigationEventMap
|
||||||
> & {
|
> &
|
||||||
/**
|
StackActionHelpers<ParamList>;
|
||||||
* Push a new screen onto the stack.
|
|
||||||
*
|
|
||||||
* @param name Name of the route for the tab.
|
|
||||||
* @param [params] Params object for the route.
|
|
||||||
*/
|
|
||||||
push<RouteName extends keyof ParamList>(
|
|
||||||
...args: ParamList[RouteName] extends undefined | any
|
|
||||||
? [RouteName] | [RouteName, ParamList[RouteName]]
|
|
||||||
: [RouteName, ParamList[RouteName]]
|
|
||||||
): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pop a screen from the stack.
|
|
||||||
*/
|
|
||||||
pop(count?: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pop to the first route in the stack, dismissing all other screens.
|
|
||||||
*/
|
|
||||||
popToTop(): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Layout = { width: number; height: number };
|
export type Layout = { width: number; height: number };
|
||||||
|
|
||||||
@@ -122,7 +103,7 @@ export type StackHeaderOptions = {
|
|||||||
/**
|
/**
|
||||||
* Style object for the title component.
|
* Style object for the title component.
|
||||||
*/
|
*/
|
||||||
headerTitleStyle?: StyleProp<TextStyle>;
|
headerTitleStyle?: React.ComponentProps<typeof Animated.Text>['style'];
|
||||||
/**
|
/**
|
||||||
* Style object for the container of the `headerTitle` component, for example to add padding.
|
* Style object for the container of the `headerTitle` component, for example to add padding.
|
||||||
* By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`.
|
* By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`.
|
||||||
@@ -279,6 +260,10 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
* Defaults to `true` on Android and `false` on iOS.
|
* Defaults to `true` on Android and `false` on iOS.
|
||||||
*/
|
*/
|
||||||
cardOverlayEnabled?: boolean;
|
cardOverlayEnabled?: boolean;
|
||||||
|
/**
|
||||||
|
* Function that returns a React Element to display as a overlay for the card.
|
||||||
|
*/
|
||||||
|
cardOverlay?: (props: { style: StyleProp<ViewStyle> }) => React.ReactNode;
|
||||||
/**
|
/**
|
||||||
* Style object for the card in stack.
|
* Style object for the card in stack.
|
||||||
* You can provide a custom background color to use instead of the default background here.
|
* You can provide a custom background color to use instead of the default background here.
|
||||||
@@ -430,7 +415,7 @@ export type StackHeaderTitleProps = {
|
|||||||
/**
|
/**
|
||||||
* Style object for the title element.
|
* Style object for the title element.
|
||||||
*/
|
*/
|
||||||
style?: StyleProp<TextStyle>;
|
style?: React.ComponentProps<typeof Animated.Text>['style'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TransitionSpec =
|
export type TransitionSpec =
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export default function debounce<T extends (...args: any[]) => void>(
|
|||||||
): T {
|
): T {
|
||||||
let timeout: NodeJS.Timeout | number | undefined;
|
let timeout: NodeJS.Timeout | number | undefined;
|
||||||
|
|
||||||
return function(this: any, ...args) {
|
return function (this: any, ...args) {
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
// eslint-disable-next-line babel/no-invalid-this
|
// eslint-disable-next-line babel/no-invalid-this
|
||||||
func.apply(this, args);
|
func.apply(this, args);
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ export default class BorderlessButton extends React.Component<Props> {
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onActiveStateChange && this.props.onActiveStateChange(active);
|
this.props.onActiveStateChange?.(active);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, style, enabled, ...rest } = this.props;
|
const { children, style, enabled, ...rest } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// @ts-ignore
|
||||||
<AnimatedBaseButton
|
<AnimatedBaseButton
|
||||||
{...rest}
|
{...rest}
|
||||||
onActiveStateChange={this.handleActiveStateChange}
|
onActiveStateChange={this.handleActiveStateChange}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user