@react-navigation/routers 8.0.0-alpha.13 → 8.0.0-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,105 +6,116 @@ import type {
6
6
  PartialState,
7
7
  } from './types';
8
8
 
9
- /**
10
- * Base router object that can be used when writing custom routers.
11
- * This provides few helper methods to handle common actions such as `RESET`.
12
- */
13
- export const BaseRouter = {
14
- getStateForAction<State extends NavigationState>(
15
- state: State,
16
- action: CommonNavigationAction
17
- ): State | PartialState<State> | null {
18
- switch (action.type) {
19
- case 'SET_PARAMS':
20
- case 'REPLACE_PARAMS': {
21
- const index = action.source
22
- ? state.routes.findIndex((r) => r.key === action.source)
23
- : state.index;
24
-
25
- if (index === -1) {
26
- return null;
27
- }
9
+ function getStateForAction<State extends NavigationState>(
10
+ state: State,
11
+ action: CommonNavigationAction
12
+ ): State | PartialState<State> | null;
13
+ function getStateForAction(
14
+ state: NavigationState,
15
+ action: CommonNavigationAction
16
+ ) {
17
+ switch (action.type) {
18
+ case 'SET_PARAMS':
19
+ case 'REPLACE_PARAMS': {
20
+ const index = action.source
21
+ ? state.routes.findIndex((r) => r.key === action.source)
22
+ : state.index;
28
23
 
29
- return {
30
- ...state,
31
- routes: state.routes.map((r, i) =>
32
- i === index
33
- ? {
34
- ...r,
35
- params:
36
- action.type === 'REPLACE_PARAMS'
37
- ? action.payload.params
38
- : { ...r.params, ...action.payload.params },
39
- }
40
- : r
41
- ),
42
- };
24
+ if (index === -1) {
25
+ return null;
43
26
  }
44
27
 
45
- case 'PUSH_PARAMS': {
46
- const index = action.source
47
- ? state.routes.findIndex((r) => r.key === action.source)
48
- : state.index;
28
+ return {
29
+ ...state,
30
+ routes: state.routes.map((r, i) =>
31
+ i === index
32
+ ? {
33
+ ...r,
34
+ params:
35
+ action.type === 'REPLACE_PARAMS'
36
+ ? action.payload.params
37
+ : { ...r.params, ...action.payload.params },
38
+ }
39
+ : r
40
+ ),
41
+ };
42
+ }
49
43
 
50
- if (index === -1) {
51
- return null;
52
- }
44
+ case 'PUSH_PARAMS': {
45
+ const index = action.source
46
+ ? state.routes.findIndex((r) => r.key === action.source)
47
+ : state.index;
53
48
 
54
- return {
55
- ...state,
56
- routes: state.routes.map((r, i) =>
57
- i === index
58
- ? {
59
- ...r,
60
- params: action.payload.params,
61
- history: [
62
- ...(r.history ?? []),
63
- { type: 'params', params: r.params },
64
- ],
65
- }
66
- : r
67
- ),
68
- };
49
+ if (index === -1) {
50
+ return null;
69
51
  }
70
52
 
71
- case 'RESET': {
72
- const nextState = action.payload as State | PartialState<State>;
53
+ return {
54
+ ...state,
55
+ routes: state.routes.map((r, i) =>
56
+ i === index
57
+ ? {
58
+ ...r,
59
+ params: action.payload.params,
60
+ history: [
61
+ ...(r.history ?? []),
62
+ { type: 'params', params: r.params },
63
+ ],
64
+ }
65
+ : r
66
+ ),
67
+ };
68
+ }
73
69
 
74
- const routeNamesSet = new Set(state.routeNames);
70
+ case 'RESET': {
71
+ const nextState = action.payload;
75
72
 
73
+ const routeNamesSet = new Set(state.routeNames);
74
+
75
+ if (
76
+ nextState.routes.length === 0 ||
77
+ nextState.routes.some(
78
+ (route: { name: string }) => !routeNamesSet.has(route.name)
79
+ )
80
+ ) {
81
+ return null;
82
+ }
83
+
84
+ if (nextState.stale === false) {
76
85
  if (
77
- nextState.routes.length === 0 ||
78
- nextState.routes.some(
79
- (route: { name: string }) => !routeNamesSet.has(route.name)
80
- )
86
+ state.routeNames.length !== nextState.routeNames.length ||
87
+ nextState.routeNames.some((name) => !routeNamesSet.has(name)) ||
88
+ !Number.isInteger(nextState.index) ||
89
+ nextState.index < 0 ||
90
+ nextState.index >= nextState.routes.length
81
91
  ) {
82
92
  return null;
83
93
  }
84
94
 
85
- if (nextState.stale === false) {
86
- if (
87
- state.routeNames.length !== nextState.routeNames.length ||
88
- nextState.routeNames.some((name) => !routeNamesSet.has(name))
89
- ) {
90
- return null;
91
- }
92
-
93
- return {
94
- ...nextState,
95
- routes: nextState.routes.map((route) =>
96
- route.key ? route : { ...route, key: `${route.name}-${nanoid()}` }
97
- ),
98
- };
99
- }
100
-
101
- return nextState;
95
+ return {
96
+ ...nextState,
97
+ routes: nextState.routes.map((route) =>
98
+ 'key' in route && route.key
99
+ ? route
100
+ : { ...route, key: `${route.name}-${nanoid()}` }
101
+ ),
102
+ };
102
103
  }
103
104
 
104
- default:
105
- return null;
105
+ return nextState;
106
106
  }
107
- },
107
+
108
+ default:
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Base router object that can be used when writing custom routers.
115
+ * This provides few helper methods to handle common actions such as `RESET`.
116
+ */
117
+ export const BaseRouter = {
118
+ getStateForAction,
108
119
 
109
120
  shouldActionChangeFocus(action: CommonNavigationAction) {
110
121
  return action.type === 'NAVIGATE';
@@ -1,11 +1,11 @@
1
1
  import { nanoid } from 'nanoid/non-secure';
2
2
 
3
+ import { SwitchRouter } from './SwitchRouter';
3
4
  import {
4
5
  type TabActionHelpers,
5
6
  TabActions,
6
7
  type TabActionType,
7
8
  type TabNavigationState,
8
- TabRouter,
9
9
  type TabRouterOptions,
10
10
  } from './TabRouter';
11
11
  import type {
@@ -14,6 +14,7 @@ import type {
14
14
  PartialState,
15
15
  Router,
16
16
  } from './types';
17
+
17
18
  export type DrawerStatus = 'open' | 'closed';
18
19
 
19
20
  export type DrawerActionType =
@@ -44,7 +45,11 @@ export type DrawerNavigationState<ParamList extends ParamListBase> = Omit<
44
45
  * List of previously visited route keys and drawer open status.
45
46
  */
46
47
  history: (
47
- | { type: 'route'; key: string }
48
+ | {
49
+ type: 'route';
50
+ key: string;
51
+ params?: object | undefined;
52
+ }
48
53
  | { type: 'drawer'; status: DrawerStatus }
49
54
  )[];
50
55
  };
@@ -87,10 +92,7 @@ export function DrawerRouter({
87
92
  DrawerNavigationState<ParamListBase>,
88
93
  DrawerActionType | CommonNavigationAction
89
94
  > {
90
- const router = TabRouter(rest) as unknown as Router<
91
- DrawerNavigationState<ParamListBase>,
92
- TabActionType | CommonNavigationAction
93
- >;
95
+ const router = SwitchRouter<'drawer'>(rest);
94
96
 
95
97
  const isDrawerInHistory = (
96
98
  state:
@@ -179,11 +181,16 @@ export function DrawerRouter({
179
181
  return partialState;
180
182
  }
181
183
 
182
- let state = router.getRehydratedState(partialState, {
183
- routeNames,
184
- routeParamList,
185
- routeGetIdList,
186
- });
184
+ let state: DrawerNavigationState<ParamListBase> = {
185
+ ...router.getRehydratedState(partialState, {
186
+ routeNames,
187
+ routeParamList,
188
+ routeGetIdList,
189
+ }),
190
+ default: defaultStatus,
191
+ type: 'drawer',
192
+ key: `drawer-${nanoid()}`,
193
+ };
187
194
 
188
195
  if (isDrawerInHistory(partialState)) {
189
196
  // Re-sync the drawer entry in history to correct it if it was wrong
@@ -191,12 +198,7 @@ export function DrawerRouter({
191
198
  state = addDrawerToHistory(state);
192
199
  }
193
200
 
194
- return {
195
- ...state,
196
- default: defaultStatus,
197
- type: 'drawer',
198
- key: `drawer-${nanoid()}`,
199
- };
201
+ return state;
200
202
  },
201
203
 
202
204
  getStateForRouteFocus(state, key) {
@@ -224,8 +226,12 @@ export function DrawerRouter({
224
226
  case 'NAVIGATE': {
225
227
  const result = router.getStateForAction(state, action, options);
226
228
 
227
- if (result != null && result.index !== state.index) {
228
- return closeDrawer(result as DrawerNavigationState<ParamListBase>);
229
+ if (
230
+ result != null &&
231
+ result.stale === false &&
232
+ result.index !== state.index
233
+ ) {
234
+ return closeDrawer(result);
229
235
  }
230
236
 
231
237
  return result;
@@ -703,20 +703,23 @@ export function StackRouter(options: StackRouterOptions) {
703
703
  /**
704
704
  * When popping entries,
705
705
  * - Pop entries from route.history
706
- * - Pop routes from state.routes
706
+ * - Pop the route itself and continue from the route below it
707
707
  *
708
708
  * Repeat until:
709
709
  * - We have popped the amount of items in count
710
710
  * - There are no more items to pop
711
+ *
712
+ * Routes above the current route (e.g. above the source) are kept intact
711
713
  */
712
714
  if (route.history?.length || currentIndex > 0) {
713
715
  let count = action.payload.count;
714
- let nextRoutes = routes;
716
+
717
+ let removedFromIndex: number | undefined;
718
+
719
+ const sourceIndex = currentIndex;
715
720
 
716
721
  while (count > 0 && (route.history?.length || currentIndex > 0)) {
717
722
  if (route.history?.length) {
718
- nextRoutes = [...nextRoutes];
719
-
720
723
  const end = Math.min(count, route.history.length);
721
724
  const last = route.history.at(-end);
722
725
  const history = route.history.slice(0, -end);
@@ -724,7 +727,7 @@ export function StackRouter(options: StackRouterOptions) {
724
727
 
725
728
  count = count - removed;
726
729
 
727
- nextRoutes[currentIndex] = {
730
+ route = {
728
731
  ...route,
729
732
  params: last?.type === 'params' ? last.params : route.params,
730
733
  history,
@@ -732,19 +735,11 @@ export function StackRouter(options: StackRouterOptions) {
732
735
  }
733
736
 
734
737
  if (currentIndex > 0 && count > 0) {
735
- const length = nextRoutes.length;
736
- const end = Math.max(currentIndex - count + 1, 1);
738
+ count = count - 1;
739
+ removedFromIndex = currentIndex;
740
+ currentIndex = currentIndex - 1;
737
741
 
738
- nextRoutes = nextRoutes
739
- .slice(0, end)
740
- .concat(nextRoutes.slice(currentIndex + 1));
741
-
742
- const removed = length - nextRoutes.length;
743
-
744
- count = count - removed;
745
- currentIndex = nextRoutes.length - 1;
746
-
747
- const currentRoute = nextRoutes[currentIndex];
742
+ const currentRoute = routes[currentIndex];
748
743
 
749
744
  if (currentRoute == null) {
750
745
  throw new Error(
@@ -756,6 +751,21 @@ export function StackRouter(options: StackRouterOptions) {
756
751
  }
757
752
  }
758
753
 
754
+ let nextRoutes =
755
+ removedFromIndex === undefined
756
+ ? routes
757
+ : routes
758
+ .slice(0, removedFromIndex)
759
+ .concat(routes.slice(sourceIndex + 1));
760
+
761
+ if (route !== routes[currentIndex]) {
762
+ if (nextRoutes === routes) {
763
+ nextRoutes = [...routes];
764
+ }
765
+
766
+ nextRoutes[currentIndex] = route;
767
+ }
768
+
759
769
  return retainRoutes(state, getStateWithRoutes(state, nextRoutes));
760
770
  }
761
771