mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-05-16 00:29:54 +08:00
refactor: track history for tabs and drawer in a history key
This commit is contained in:
@@ -16,6 +16,10 @@ export type NavigationState = {
|
||||
* List of valid route names as defined in the screen components.
|
||||
*/
|
||||
routeNames: string[];
|
||||
/**
|
||||
* Alternative entries for history.
|
||||
*/
|
||||
history?: unknown[];
|
||||
/**
|
||||
* List of rendered routes.
|
||||
*/
|
||||
|
||||
@@ -168,7 +168,7 @@ export default function DrawerView({
|
||||
<SafeAreaProviderCompat>
|
||||
<DrawerGestureContext.Provider value={drawerGestureRef}>
|
||||
<Drawer
|
||||
open={state.isDrawerOpen}
|
||||
open={Boolean(state.history.find(it => it.type === 'drawer'))}
|
||||
gestureEnabled={gestureEnabled !== false}
|
||||
onOpen={handleDrawerOpen}
|
||||
onClose={handleDrawerClose}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CommonActions } from '@react-navigation/core';
|
||||
import { DrawerRouter, DrawerActions } from '../src';
|
||||
import { DrawerRouter, DrawerActions, DrawerNavigationState } from '../src';
|
||||
|
||||
jest.mock('shortid', () => () => 'test');
|
||||
|
||||
@@ -17,14 +17,13 @@ it('gets initial state from route names and params with initialRouteName', () =>
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-test' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -44,14 +43,13 @@ it('gets initial state from route names and params without initialRouteName', ()
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -81,14 +79,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-1', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-0' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -103,14 +100,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-0' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -130,14 +126,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 2,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-1', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-2', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-2' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -153,14 +148,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 2,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-test' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -169,8 +163,12 @@ it('gets rehydrated state from partial state', () => {
|
||||
router.getRehydratedState(
|
||||
{
|
||||
index: 1,
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: ['bar-test', 'qux-test', 'foo-test'],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
{ type: 'route', key: 'foo-test' },
|
||||
{ type: 'drawer' },
|
||||
],
|
||||
routes: [],
|
||||
},
|
||||
options
|
||||
@@ -178,14 +176,17 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: ['bar-test', 'qux-test'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
{ type: 'drawer' },
|
||||
],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -194,17 +195,16 @@ it('gets rehydrated state from partial state', () => {
|
||||
it("doesn't rehydrate state if it's not stale", () => {
|
||||
const router = DrawerRouter({});
|
||||
|
||||
const state = {
|
||||
const state: DrawerNavigationState = {
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }, { type: 'drawer' }],
|
||||
stale: false as const,
|
||||
type: 'drawer' as const,
|
||||
};
|
||||
@@ -232,12 +232,11 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: false,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
},
|
||||
CommonActions.navigate('baz', { answer: 42 }),
|
||||
options
|
||||
@@ -248,12 +247,14 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: ['bar'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar' },
|
||||
{ type: 'route', key: 'baz' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -272,12 +273,11 @@ it('handles navigate action with open drawer', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: true,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
},
|
||||
CommonActions.navigate('baz', { answer: 42 }),
|
||||
options
|
||||
@@ -288,12 +288,14 @@ it('handles navigate action with open drawer', () => {
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: ['bar'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar' },
|
||||
{ type: 'route', key: 'baz' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -312,12 +314,11 @@ it('handles open drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: false,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
},
|
||||
DrawerActions.openDrawer(),
|
||||
options
|
||||
@@ -328,26 +329,24 @@ it('handles open drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
});
|
||||
|
||||
const state = {
|
||||
const state: DrawerNavigationState = {
|
||||
stale: false as const,
|
||||
type: 'drawer' as const,
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
};
|
||||
|
||||
expect(
|
||||
@@ -370,12 +369,11 @@ it('handles close drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: true,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
},
|
||||
DrawerActions.closeDrawer(),
|
||||
options
|
||||
@@ -386,26 +384,27 @@ it('handles close drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
});
|
||||
|
||||
const state = {
|
||||
const state: DrawerNavigationState = {
|
||||
stale: false as const,
|
||||
type: 'drawer' as const,
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar' },
|
||||
{ type: 'route', key: 'baz' },
|
||||
],
|
||||
};
|
||||
|
||||
expect(
|
||||
@@ -428,12 +427,11 @@ it('handles toggle drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: true,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
},
|
||||
DrawerActions.toggleDrawer(),
|
||||
options
|
||||
@@ -444,12 +442,11 @@ it('handles toggle drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
});
|
||||
|
||||
expect(
|
||||
@@ -460,12 +457,11 @@ it('handles toggle drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
isDrawerOpen: false,
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
},
|
||||
DrawerActions.toggleDrawer(),
|
||||
options
|
||||
@@ -476,39 +472,38 @@ it('handles toggle drawer action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }, { type: 'drawer' }],
|
||||
});
|
||||
});
|
||||
|
||||
it('updates route key history on focus change', () => {
|
||||
it('updates history on focus change', () => {
|
||||
const router = DrawerRouter({ backBehavior: 'history' });
|
||||
|
||||
const state = {
|
||||
const state: DrawerNavigationState = {
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routeNames: ['baz', 'bar'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-0', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-0' }],
|
||||
stale: false as const,
|
||||
type: 'drawer' as const,
|
||||
};
|
||||
|
||||
expect(router.getStateForRouteFocus(state, 'bar-0').routeKeyHistory).toEqual(
|
||||
[]
|
||||
);
|
||||
expect(router.getStateForRouteFocus(state, 'bar-0').history).toEqual([
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
]);
|
||||
|
||||
expect(router.getStateForRouteFocus(state, 'baz-0').routeKeyHistory).toEqual([
|
||||
'bar-0',
|
||||
expect(router.getStateForRouteFocus(state, 'baz-0').history).toEqual([
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -520,14 +515,13 @@ it('closes drawer on focus change', () => {
|
||||
{
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: false,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz' },
|
||||
{ key: 'qux-0', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-0' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
},
|
||||
@@ -535,15 +529,17 @@ it('closes drawer on focus change', () => {
|
||||
)
|
||||
).toEqual({
|
||||
index: 1,
|
||||
isDrawerOpen: false,
|
||||
key: 'drawer-test',
|
||||
routeKeyHistory: ['bar-0'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz' },
|
||||
{ key: 'qux-0', name: 'qux' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
@@ -553,14 +549,13 @@ it('closes drawer on focus change', () => {
|
||||
{
|
||||
index: 0,
|
||||
key: 'drawer-test',
|
||||
isDrawerOpen: true,
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz' },
|
||||
{ key: 'qux-0', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-0' }, { type: 'drawer' }],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
},
|
||||
@@ -568,15 +563,17 @@ it('closes drawer on focus change', () => {
|
||||
)
|
||||
).toEqual({
|
||||
index: 1,
|
||||
isDrawerOpen: false,
|
||||
key: 'drawer-test',
|
||||
routeKeyHistory: ['bar-0'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz' },
|
||||
{ key: 'qux-0', name: 'qux' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
],
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
});
|
||||
|
||||
@@ -17,13 +17,13 @@ it('gets initial state from route names and params with initialRouteName', () =>
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -43,13 +43,13 @@ it('gets initial state from route names and params without initialRouteName', ()
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -79,13 +79,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-1', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-0' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -100,13 +100,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-0' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -126,13 +126,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 2,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-1', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-2', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-2' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -148,13 +148,13 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 2,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -163,7 +163,11 @@ it('gets rehydrated state from partial state', () => {
|
||||
router.getRehydratedState(
|
||||
{
|
||||
index: 1,
|
||||
routeKeyHistory: ['bar-test', 'qux-test', 'foo-test'],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
{ type: 'route', key: 'foo-test' },
|
||||
],
|
||||
routes: [],
|
||||
},
|
||||
options
|
||||
@@ -171,13 +175,16 @@ it('gets rehydrated state from partial state', () => {
|
||||
).toEqual({
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: ['bar-test', 'qux-test'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -186,18 +193,18 @@ it('gets rehydrated state from partial state', () => {
|
||||
it("doesn't rehydrate state if it's not stale", () => {
|
||||
const router = TabRouter({});
|
||||
|
||||
const state = {
|
||||
const state: TabNavigationState = {
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
stale: false as const,
|
||||
type: 'tab' as const,
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
};
|
||||
|
||||
expect(
|
||||
@@ -216,13 +223,13 @@ it('gets state on route names change', () => {
|
||||
{
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
},
|
||||
@@ -237,7 +244,6 @@ it('gets state on route names change', () => {
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['qux', 'baz', 'foo', 'fiz'],
|
||||
routes: [
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
@@ -245,6 +251,7 @@ it('gets state on route names change', () => {
|
||||
{ key: 'foo-test', name: 'foo' },
|
||||
{ key: 'fiz-test', name: 'fiz', params: { fruit: 'apple' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -258,13 +265,13 @@ it('preserves focused route on route names change', () => {
|
||||
{
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
},
|
||||
@@ -279,7 +286,6 @@ it('preserves focused route on route names change', () => {
|
||||
).toEqual({
|
||||
index: 3,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['qux', 'foo', 'fiz', 'baz'],
|
||||
routes: [
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
@@ -287,6 +293,7 @@ it('preserves focused route on route names change', () => {
|
||||
{ key: 'fiz-test', name: 'fiz', params: { fruit: 'apple' } },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -300,13 +307,13 @@ it('falls back to first route if route is removed on route names change', () =>
|
||||
{
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
},
|
||||
@@ -321,13 +328,13 @@ it('falls back to first route if route is removed on route names change', () =>
|
||||
).toEqual({
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['qux', 'foo', 'fiz'],
|
||||
routes: [
|
||||
{ key: 'qux-test', name: 'qux', params: { name: 'Jane' } },
|
||||
{ key: 'foo-test', name: 'foo' },
|
||||
{ key: 'fiz-test', name: 'fiz', params: { fruit: 'apple' } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'qux-test' }],
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
});
|
||||
@@ -348,11 +355,11 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz-1', name: 'baz' },
|
||||
{ key: 'bar-1', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-1' }],
|
||||
},
|
||||
CommonActions.navigate({ key: 'bar-1', params: { answer: 42 } }),
|
||||
options
|
||||
@@ -363,11 +370,11 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: ['bar-1'],
|
||||
routes: [
|
||||
{ key: 'baz-1', name: 'baz' },
|
||||
{ key: 'bar-1', name: 'bar', params: { answer: 42 } },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-1' }],
|
||||
});
|
||||
|
||||
expect(
|
||||
@@ -378,11 +385,11 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
},
|
||||
CommonActions.navigate('baz', { answer: 42 }),
|
||||
options
|
||||
@@ -393,11 +400,14 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: ['bar'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar' },
|
||||
{ type: 'route', key: 'baz' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
@@ -408,11 +418,11 @@ it('handles navigate action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar' }],
|
||||
},
|
||||
CommonActions.navigate('non-existent'),
|
||||
options
|
||||
@@ -435,11 +445,11 @@ it('handles jump to action', () => {
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'baz' }],
|
||||
},
|
||||
TabActions.jumpTo('bar'),
|
||||
options
|
||||
@@ -450,213 +460,259 @@ it('handles jump to action', () => {
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: ['baz'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'baz' },
|
||||
{ type: 'route', key: 'bar' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles back action with backBehavior: history', () => {
|
||||
const router = TabRouter({ backBehavior: 'history' });
|
||||
const options = {
|
||||
routeNames: ['bar', 'baz'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routeParamList: {},
|
||||
};
|
||||
|
||||
let state = router.getInitialState(options);
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: ['bar'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('qux'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
key: 'tab-test',
|
||||
index: 0,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('baz'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'tab-test',
|
||||
index: 2,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('bar'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
).toBe(null);
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'tab-test',
|
||||
index: 1,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'qux-test' },
|
||||
{ type: 'route', key: 'baz-test' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles back action with backBehavior: order', () => {
|
||||
const router = TabRouter({ backBehavior: 'order' });
|
||||
const options = {
|
||||
routeNames: ['bar', 'baz'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routeParamList: {},
|
||||
};
|
||||
|
||||
let state = router.getInitialState(options);
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('qux'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
key: 'tab-test',
|
||||
index: 1,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [
|
||||
{ type: 'route', key: 'bar-test' },
|
||||
{ type: 'route', key: 'baz-test' },
|
||||
],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('baz'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
).toBe(null);
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'tab-test',
|
||||
index: 0,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('bar'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
it('handles back action with backBehavior: initialRoute', () => {
|
||||
const router = TabRouter({
|
||||
backBehavior: 'initialRoute',
|
||||
initialRouteName: 'bar',
|
||||
});
|
||||
|
||||
const router = TabRouter({ backBehavior: 'initialRoute' });
|
||||
const options = {
|
||||
routeNames: ['bar', 'baz'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routeParamList: {},
|
||||
};
|
||||
|
||||
let state = router.getInitialState(options);
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('qux'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
key: 'tab-test',
|
||||
index: 0,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('baz'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 1,
|
||||
routeNames: ['baz', 'bar'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
).toBe(null);
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual({
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'tab-test',
|
||||
index: 0,
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-test', name: 'bar' },
|
||||
{ key: 'baz-test', name: 'baz' },
|
||||
{ key: 'qux-test', name: 'qux' },
|
||||
],
|
||||
history: [{ type: 'route', key: 'bar-test' }],
|
||||
});
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('bar'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
it('handles back action with backBehavior: none', () => {
|
||||
const router = TabRouter({ backBehavior: 'none' });
|
||||
const options = {
|
||||
routeNames: ['bar', 'baz'],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routeParamList: {},
|
||||
};
|
||||
|
||||
let state = router.getInitialState(options);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('baz'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(
|
||||
router.getStateForAction(
|
||||
{
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: 'root',
|
||||
index: 0,
|
||||
routeNames: ['bar', 'baz'],
|
||||
routeKeyHistory: [],
|
||||
routes: [
|
||||
{ key: 'baz', name: 'baz' },
|
||||
{ key: 'bar', name: 'bar' },
|
||||
],
|
||||
},
|
||||
CommonActions.goBack(),
|
||||
options
|
||||
)
|
||||
router.getStateForAction(state, CommonActions.goBack(), options)
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
@@ -670,8 +726,8 @@ it('updates route key history on navigate and jump to', () => {
|
||||
let state: TabNavigationState = {
|
||||
index: 1,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
history: [{ type: 'route', key: 'baz-0' }],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
|
||||
@@ -681,15 +737,16 @@ it('updates route key history on navigate and jump to', () => {
|
||||
type: 'tab',
|
||||
};
|
||||
|
||||
expect(state.routeKeyHistory).toEqual([]);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
TabActions.jumpTo('qux'),
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(state.routeKeyHistory).toEqual(['baz-0']);
|
||||
expect(state.history).toEqual([
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
{ type: 'route', key: 'qux-0' },
|
||||
]);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
@@ -697,7 +754,11 @@ it('updates route key history on navigate and jump to', () => {
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(state.routeKeyHistory).toEqual(['baz-0', 'qux-0']);
|
||||
expect(state.history).toEqual([
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
{ type: 'route', key: 'qux-0' },
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
]);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
@@ -705,7 +766,11 @@ it('updates route key history on navigate and jump to', () => {
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(state.routeKeyHistory).toEqual(['qux-0', 'bar-0']);
|
||||
expect(state.history).toEqual([
|
||||
{ type: 'route', key: 'qux-0' },
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
]);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
@@ -713,7 +778,10 @@ it('updates route key history on navigate and jump to', () => {
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(state.routeKeyHistory).toEqual(['qux-0']);
|
||||
expect(state.history).toEqual([
|
||||
{ type: 'route', key: 'qux-0' },
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
]);
|
||||
|
||||
state = router.getStateForAction(
|
||||
state,
|
||||
@@ -721,7 +789,7 @@ it('updates route key history on navigate and jump to', () => {
|
||||
options
|
||||
) as TabNavigationState;
|
||||
|
||||
expect(state.routeKeyHistory).toEqual([]);
|
||||
expect(state.history).toEqual([{ type: 'route', key: 'qux-0' }]);
|
||||
});
|
||||
|
||||
it('updates route key history on focus change', () => {
|
||||
@@ -730,22 +798,23 @@ it('updates route key history on focus change', () => {
|
||||
const state = {
|
||||
index: 0,
|
||||
key: 'tab-test',
|
||||
routeKeyHistory: [],
|
||||
routeNames: ['bar', 'baz', 'qux'],
|
||||
routes: [
|
||||
{ key: 'bar-0', name: 'bar' },
|
||||
{ key: 'baz-0', name: 'baz', params: { answer: 42 } },
|
||||
{ key: 'qux-0', name: 'qux', params: { name: 'Jane' } },
|
||||
],
|
||||
history: [{ type: 'route' as const, key: 'bar-0' }],
|
||||
stale: false as const,
|
||||
type: 'tab' as const,
|
||||
};
|
||||
|
||||
expect(router.getStateForRouteFocus(state, 'bar-0').routeKeyHistory).toEqual(
|
||||
[]
|
||||
);
|
||||
expect(router.getStateForRouteFocus(state, 'bar-0').history).toEqual([
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
]);
|
||||
|
||||
expect(router.getStateForRouteFocus(state, 'baz-0').routeKeyHistory).toEqual([
|
||||
'bar-0',
|
||||
expect(router.getStateForRouteFocus(state, 'baz-0').history).toEqual([
|
||||
{ type: 'route', key: 'bar-0' },
|
||||
{ type: 'route', key: 'baz-0' },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import shortid from 'shortid';
|
||||
import { CommonAction, Router } from '@react-navigation/core';
|
||||
import { CommonAction, Router, PartialState } from '@react-navigation/core';
|
||||
import TabRouter, {
|
||||
TabActions,
|
||||
TabActionType,
|
||||
@@ -17,15 +17,18 @@ export type DrawerActionType =
|
||||
|
||||
export type DrawerRouterOptions = TabRouterOptions;
|
||||
|
||||
export type DrawerNavigationState = Omit<TabNavigationState, 'type'> & {
|
||||
export type DrawerNavigationState = Omit<
|
||||
TabNavigationState,
|
||||
'type' | 'history'
|
||||
> & {
|
||||
/**
|
||||
* Type of the router, in this case, it's drawer.
|
||||
*/
|
||||
type: 'drawer';
|
||||
/**
|
||||
* Whether the drawer is open or closed.
|
||||
* List of previously visited route keys and drawer open status.
|
||||
*/
|
||||
isDrawerOpen: boolean;
|
||||
history: ({ type: 'route'; key: string } | { type: 'drawer' })[];
|
||||
};
|
||||
|
||||
export const DrawerActions = {
|
||||
@@ -41,6 +44,32 @@ export const DrawerActions = {
|
||||
},
|
||||
};
|
||||
|
||||
const isDrawerOpen = (
|
||||
state: DrawerNavigationState | PartialState<DrawerNavigationState>
|
||||
) => Boolean(state.history?.find(it => it.type === 'drawer'));
|
||||
|
||||
const openDrawer = (state: DrawerNavigationState): DrawerNavigationState => {
|
||||
if (isDrawerOpen(state)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
history: [...state.history, { type: 'drawer' }],
|
||||
};
|
||||
};
|
||||
|
||||
const closeDrawer = (state: DrawerNavigationState): DrawerNavigationState => {
|
||||
if (!isDrawerOpen(state)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
history: state.history.filter(it => it.type !== 'drawer'),
|
||||
};
|
||||
};
|
||||
|
||||
export default function DrawerRouter(
|
||||
options: DrawerRouterOptions
|
||||
): Router<DrawerNavigationState, DrawerActionType | CommonAction> {
|
||||
@@ -55,24 +84,13 @@ export default function DrawerRouter(
|
||||
type: 'drawer',
|
||||
|
||||
getInitialState({ routeNames, routeParamList }) {
|
||||
const index =
|
||||
options.initialRouteName === undefined
|
||||
? 0
|
||||
: routeNames.indexOf(options.initialRouteName);
|
||||
const state = router.getInitialState({ routeNames, routeParamList });
|
||||
|
||||
return {
|
||||
...state,
|
||||
stale: false,
|
||||
type: 'drawer',
|
||||
key: `drawer-${shortid()}`,
|
||||
index,
|
||||
routeNames,
|
||||
routeKeyHistory: [],
|
||||
routes: routeNames.map(name => ({
|
||||
name,
|
||||
key: `${name}-${shortid()}`,
|
||||
params: routeParamList[name],
|
||||
})),
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -81,84 +99,46 @@ export default function DrawerRouter(
|
||||
return partialState;
|
||||
}
|
||||
|
||||
const state = router.getRehydratedState(partialState, {
|
||||
let state = router.getRehydratedState(partialState, {
|
||||
routeNames,
|
||||
routeParamList,
|
||||
});
|
||||
|
||||
if (isDrawerOpen(partialState)) {
|
||||
state = openDrawer(state);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
type: 'drawer',
|
||||
key: `drawer-${shortid()}`,
|
||||
isDrawerOpen:
|
||||
typeof partialState.isDrawerOpen === 'boolean'
|
||||
? partialState.isDrawerOpen
|
||||
: false,
|
||||
};
|
||||
},
|
||||
|
||||
getStateForRouteFocus(state, key) {
|
||||
const index = state.routes.findIndex(r => r.key === key);
|
||||
const result = router.getStateForRouteFocus(state, key);
|
||||
|
||||
const result =
|
||||
index === -1 || index === state.index
|
||||
? state
|
||||
: router.getStateForRouteFocus(state, key);
|
||||
|
||||
if (result.isDrawerOpen) {
|
||||
return {
|
||||
...result,
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
return closeDrawer(result);
|
||||
},
|
||||
|
||||
getStateForAction(state, action, options) {
|
||||
switch (action.type) {
|
||||
case 'OPEN_DRAWER':
|
||||
if (state.isDrawerOpen) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: true,
|
||||
};
|
||||
return openDrawer(state);
|
||||
|
||||
case 'CLOSE_DRAWER':
|
||||
if (!state.isDrawerOpen) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
return closeDrawer(state);
|
||||
|
||||
case 'TOGGLE_DRAWER':
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: !state.isDrawerOpen,
|
||||
};
|
||||
if (isDrawerOpen(state)) {
|
||||
return closeDrawer(state);
|
||||
}
|
||||
|
||||
case 'NAVIGATE':
|
||||
return router.getStateForAction(
|
||||
{
|
||||
...state,
|
||||
isDrawerOpen: false,
|
||||
},
|
||||
action,
|
||||
options
|
||||
);
|
||||
return openDrawer(state);
|
||||
|
||||
case 'GO_BACK':
|
||||
if (state.isDrawerOpen) {
|
||||
return {
|
||||
...state,
|
||||
isDrawerOpen: false,
|
||||
};
|
||||
if (isDrawerOpen(state)) {
|
||||
return closeDrawer(state);
|
||||
}
|
||||
|
||||
return router.getStateForAction(state, action, options);
|
||||
|
||||
@@ -16,11 +16,13 @@ export type TabActionType = {
|
||||
target?: string;
|
||||
};
|
||||
|
||||
export type BackBehavior = 'initialRoute' | 'order' | 'history' | 'none';
|
||||
|
||||
export type TabRouterOptions = DefaultRouterOptions & {
|
||||
backBehavior?: 'initialRoute' | 'order' | 'history' | 'none';
|
||||
backBehavior?: BackBehavior;
|
||||
};
|
||||
|
||||
export type TabNavigationState = NavigationState & {
|
||||
export type TabNavigationState = Omit<NavigationState, 'history'> & {
|
||||
/**
|
||||
* Type of the router, in this case, it's tab.
|
||||
*/
|
||||
@@ -28,26 +30,64 @@ export type TabNavigationState = NavigationState & {
|
||||
/**
|
||||
* List of previously visited route keys.
|
||||
*/
|
||||
routeKeyHistory: string[];
|
||||
history: { type: 'route'; key: string }[];
|
||||
};
|
||||
|
||||
const TYPE_ROUTE = 'route' as const;
|
||||
|
||||
export const TabActions = {
|
||||
jumpTo(name: string, params?: object): TabActionType {
|
||||
return { type: 'JUMP_TO', payload: { name, params } };
|
||||
},
|
||||
};
|
||||
|
||||
const changeIndex = (state: TabNavigationState, index: number) => {
|
||||
const previousKey = state.routes[state.index].key;
|
||||
const currentKey = state.routes[index].key;
|
||||
const routeKeyHistory = state.routeKeyHistory
|
||||
.filter(key => key !== currentKey && key !== previousKey)
|
||||
.concat(previousKey);
|
||||
const getRouteHistory = (
|
||||
routes: Route<string>[],
|
||||
index: number,
|
||||
backBehavior: BackBehavior
|
||||
) => {
|
||||
const history = [{ type: TYPE_ROUTE, key: routes[index].key }];
|
||||
|
||||
switch (backBehavior) {
|
||||
case 'initialRoute':
|
||||
if (index !== 0) {
|
||||
history.unshift({ type: TYPE_ROUTE, key: routes[0].key });
|
||||
}
|
||||
break;
|
||||
case 'order':
|
||||
for (let i = index; i > 0; i--) {
|
||||
history.unshift({ type: TYPE_ROUTE, key: routes[i - 1].key });
|
||||
}
|
||||
break;
|
||||
case 'history':
|
||||
// The history will fill up on navigation
|
||||
break;
|
||||
}
|
||||
|
||||
return history;
|
||||
};
|
||||
|
||||
const changeIndex = (
|
||||
state: TabNavigationState,
|
||||
index: number,
|
||||
backBehavior: BackBehavior
|
||||
) => {
|
||||
let history;
|
||||
|
||||
if (backBehavior === 'history') {
|
||||
const currentKey = state.routes[index].key;
|
||||
|
||||
history = state.history
|
||||
.filter(it => (it.type === 'route' ? it.key !== currentKey : false))
|
||||
.concat({ type: TYPE_ROUTE, key: currentKey });
|
||||
} else {
|
||||
history = getRouteHistory(state.routes, index, backBehavior);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
index,
|
||||
routeKeyHistory,
|
||||
history,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -66,18 +106,22 @@ export default function TabRouter({
|
||||
? routeNames.indexOf(initialRouteName)
|
||||
: 0;
|
||||
|
||||
const routes = routeNames.map(name => ({
|
||||
name,
|
||||
key: `${name}-${shortid()}`,
|
||||
params: routeParamList[name],
|
||||
}));
|
||||
|
||||
const history = getRouteHistory(routes, index, backBehavior);
|
||||
|
||||
return {
|
||||
stale: false,
|
||||
type: 'tab',
|
||||
key: `tab-${shortid()}`,
|
||||
index,
|
||||
routeNames,
|
||||
routeKeyHistory: [],
|
||||
routes: routeNames.map(name => ({
|
||||
name,
|
||||
key: `${name}-${shortid()}`,
|
||||
params: routeParamList[name],
|
||||
})),
|
||||
history,
|
||||
routes,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -122,9 +166,13 @@ export default function TabRouter({
|
||||
routes.length - 1
|
||||
);
|
||||
|
||||
const routeKeyHistory = state.routeKeyHistory
|
||||
? state.routeKeyHistory.filter(key => routes.find(r => r.key === key))
|
||||
: [];
|
||||
let history = state.history?.filter(it =>
|
||||
routes.find(r => r.key === it.key)
|
||||
);
|
||||
|
||||
if (!history?.length) {
|
||||
history = getRouteHistory(routes, index, backBehavior);
|
||||
}
|
||||
|
||||
return {
|
||||
stale: false,
|
||||
@@ -132,7 +180,7 @@ export default function TabRouter({
|
||||
key: `tab-${shortid()}`,
|
||||
index,
|
||||
routeNames,
|
||||
routeKeyHistory,
|
||||
history,
|
||||
routes,
|
||||
};
|
||||
},
|
||||
@@ -152,8 +200,17 @@ export default function TabRouter({
|
||||
routeNames.indexOf(state.routes[state.index].name)
|
||||
);
|
||||
|
||||
let history = state.history.filter(it =>
|
||||
routes.find(r => r.key === it.key)
|
||||
);
|
||||
|
||||
if (!history.length) {
|
||||
history = getRouteHistory(routes, index, backBehavior);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
history,
|
||||
routeNames,
|
||||
routes,
|
||||
index,
|
||||
@@ -167,7 +224,7 @@ export default function TabRouter({
|
||||
return state;
|
||||
}
|
||||
|
||||
return changeIndex(state, index);
|
||||
return changeIndex(state, index, backBehavior);
|
||||
},
|
||||
|
||||
getStateForAction(state, action) {
|
||||
@@ -208,56 +265,32 @@ export default function TabRouter({
|
||||
)
|
||||
: state.routes,
|
||||
},
|
||||
index
|
||||
index,
|
||||
backBehavior
|
||||
);
|
||||
}
|
||||
|
||||
case 'GO_BACK':
|
||||
switch (backBehavior) {
|
||||
case 'initialRoute': {
|
||||
const index = initialRouteName
|
||||
? state.routeNames.indexOf(initialRouteName)
|
||||
: 0;
|
||||
|
||||
if (index === -1 || index === state.index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { ...state, index };
|
||||
}
|
||||
|
||||
case 'order':
|
||||
if (state.index === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
index: state.index - 1,
|
||||
};
|
||||
|
||||
case 'history': {
|
||||
const previousKey =
|
||||
state.routeKeyHistory[state.routeKeyHistory.length - 1];
|
||||
const index = state.routes.findIndex(
|
||||
route => route.key === previousKey
|
||||
);
|
||||
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
routeKeyHistory: state.routeKeyHistory.slice(0, -1),
|
||||
index,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
case 'GO_BACK': {
|
||||
if (state.history.length === 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const previousKey = state.history[state.history.length - 2].key;
|
||||
const index = state.routes.findIndex(
|
||||
route => route.key === previousKey
|
||||
);
|
||||
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
history: state.history.slice(0, -1),
|
||||
index,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return BaseRouter.getStateForAction(state, action);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user