@react-navigation/routers 8.0.0-alpha.2 → 8.0.0-alpha.21

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.
Files changed (42) hide show
  1. package/lib/module/BaseRouter.js +64 -61
  2. package/lib/module/BaseRouter.js.map +1 -1
  3. package/lib/module/CommonActions.js +9 -21
  4. package/lib/module/CommonActions.js.map +1 -1
  5. package/lib/module/DrawerRouter.js +15 -14
  6. package/lib/module/DrawerRouter.js.map +1 -1
  7. package/lib/module/StackRouter.js +287 -166
  8. package/lib/module/StackRouter.js.map +1 -1
  9. package/lib/module/SwitchRouter.js +426 -0
  10. package/lib/module/SwitchRouter.js.map +1 -0
  11. package/lib/module/TabRouter.js +14 -290
  12. package/lib/module/TabRouter.js.map +1 -1
  13. package/lib/typescript/src/BaseRouter.d.ts +10 -8
  14. package/lib/typescript/src/BaseRouter.d.ts.map +1 -1
  15. package/lib/typescript/src/CommonActions.d.ts +42 -39
  16. package/lib/typescript/src/CommonActions.d.ts.map +1 -1
  17. package/lib/typescript/src/DrawerRouter.d.ts +6 -5
  18. package/lib/typescript/src/DrawerRouter.d.ts.map +1 -1
  19. package/lib/typescript/src/StackRouter.d.ts +70 -24
  20. package/lib/typescript/src/StackRouter.d.ts.map +1 -1
  21. package/lib/typescript/src/SwitchRouter.d.ts +69 -0
  22. package/lib/typescript/src/SwitchRouter.d.ts.map +1 -0
  23. package/lib/typescript/src/TabRouter.d.ts +4 -24
  24. package/lib/typescript/src/TabRouter.d.ts.map +1 -1
  25. package/lib/typescript/src/createParamsFromAction.d.ts +2 -2
  26. package/lib/typescript/src/createParamsFromAction.d.ts.map +1 -1
  27. package/lib/typescript/src/createRouteFromAction.d.ts +2 -2
  28. package/lib/typescript/src/createRouteFromAction.d.ts.map +1 -1
  29. package/lib/typescript/src/index.d.ts +9 -9
  30. package/lib/typescript/src/index.d.ts.map +1 -1
  31. package/lib/typescript/src/types.d.ts +20 -30
  32. package/lib/typescript/src/types.d.ts.map +1 -1
  33. package/package.json +8 -8
  34. package/src/BaseRouter.tsx +93 -80
  35. package/src/CommonActions.tsx +44 -66
  36. package/src/DrawerRouter.tsx +28 -22
  37. package/src/StackRouter.tsx +551 -238
  38. package/src/SwitchRouter.tsx +724 -0
  39. package/src/TabRouter.tsx +24 -463
  40. package/src/createParamsFromAction.tsx +1 -1
  41. package/src/createRouteFromAction.tsx +1 -1
  42. package/src/types.tsx +39 -41
@@ -0,0 +1,724 @@
1
+ import { nanoid } from 'nanoid/non-secure';
2
+
3
+ import { BaseRouter } from './BaseRouter';
4
+ import { createParamsFromAction } from './createParamsFromAction';
5
+ import type {
6
+ CommonNavigationAction,
7
+ DefaultRouterOptions,
8
+ NavigationState,
9
+ PartialState,
10
+ Route,
11
+ RouterConfigOptions,
12
+ } from './types';
13
+
14
+ export type SwitchActionType = {
15
+ type: 'JUMP_TO';
16
+ payload: { name: string; params?: object | undefined };
17
+ source?: string | undefined;
18
+ target?: string | undefined;
19
+ };
20
+
21
+ export type SwitchRouterOptions = DefaultRouterOptions & {
22
+ /**
23
+ * Control how going back should behave
24
+ * - `firstRoute` - return to the first defined route
25
+ * - `initialRoute` - return to the route from `initialRouteName`
26
+ * - `order` - return to the route defined before the focused route
27
+ * - `history` - return to last visited route; if the same route is visited multiple times, the older entries are dropped from the history
28
+ * - `fullHistory` - return to last visited route; doesn't drop duplicate entries unlike `history` - matches behavior of web pages
29
+ * - `none` - do not handle going back
30
+ */
31
+ backBehavior?: BackBehavior | undefined;
32
+ };
33
+
34
+ type BackBehavior =
35
+ | 'firstRoute'
36
+ | 'initialRoute'
37
+ | 'order'
38
+ | 'history'
39
+ | 'fullHistory'
40
+ | 'none';
41
+
42
+ type RouteHistory = {
43
+ type: 'route';
44
+ key: string;
45
+ params?: object | undefined;
46
+ };
47
+
48
+ type DrawerHistory = {
49
+ type: 'drawer';
50
+ status: 'open' | 'closed';
51
+ };
52
+
53
+ type SwitchRouterState<History> = Omit<NavigationState, 'history' | 'type'> & {
54
+ history: History[];
55
+ preloadedRouteKeys: string[];
56
+ };
57
+
58
+ type SwitchRouterStateMap = {
59
+ tab: SwitchRouterState<RouteHistory> & { type: 'tab' };
60
+ drawer: SwitchRouterState<RouteHistory | DrawerHistory> & {
61
+ type: 'drawer';
62
+ default: DrawerHistory['status'];
63
+ };
64
+ };
65
+
66
+ type SwitchRouterType = 'tab' | 'drawer';
67
+
68
+ const TYPE_ROUTE = 'route' as const;
69
+
70
+ const getRouteHistory = (
71
+ routes: Route<string>[],
72
+ index: number,
73
+ backBehavior: BackBehavior,
74
+ initialRouteName: string | undefined
75
+ ) => {
76
+ const route = routes[index];
77
+
78
+ if (route == null) {
79
+ throw new Error(`Couldn't find a route at index ${index}.`);
80
+ }
81
+
82
+ const history: RouteHistory[] = [
83
+ {
84
+ type: TYPE_ROUTE,
85
+ key: route.key,
86
+ params: backBehavior === 'fullHistory' ? route.params : undefined,
87
+ },
88
+ ];
89
+
90
+ let initialRouteIndex;
91
+
92
+ switch (backBehavior) {
93
+ case 'order':
94
+ for (let i = index; i > 0; i--) {
95
+ const route = routes[i - 1];
96
+
97
+ if (route == null) {
98
+ throw new Error(`Couldn't find a route at index ${i - 1}.`);
99
+ }
100
+
101
+ history.unshift({
102
+ type: TYPE_ROUTE,
103
+ key: route.key,
104
+ });
105
+ }
106
+
107
+ break;
108
+
109
+ case 'firstRoute':
110
+ if (index !== 0) {
111
+ const route = routes[0];
112
+
113
+ if (route == null) {
114
+ throw new Error("Couldn't find a route at index 0.");
115
+ }
116
+
117
+ history.unshift({
118
+ type: TYPE_ROUTE,
119
+ key: route.key,
120
+ });
121
+ }
122
+
123
+ break;
124
+
125
+ case 'initialRoute':
126
+ initialRouteIndex = routes.findIndex(
127
+ (route) => route.name === initialRouteName
128
+ );
129
+
130
+ initialRouteIndex = initialRouteIndex === -1 ? 0 : initialRouteIndex;
131
+
132
+ if (index !== initialRouteIndex) {
133
+ const route = routes[initialRouteIndex];
134
+
135
+ if (route == null) {
136
+ throw new Error(
137
+ `Couldn't find a route at index ${initialRouteIndex}.`
138
+ );
139
+ }
140
+
141
+ history.unshift({
142
+ type: TYPE_ROUTE,
143
+ key: route.key,
144
+ });
145
+ }
146
+
147
+ break;
148
+
149
+ case 'history':
150
+ case 'fullHistory':
151
+ // The history will fill up on navigation
152
+ break;
153
+ }
154
+
155
+ return history;
156
+ };
157
+
158
+ const changeIndex = <Type extends SwitchRouterType>(
159
+ state: Pick<SwitchRouterStateMap[Type], 'routes' | 'history'>,
160
+ index: number,
161
+ backBehavior: BackBehavior,
162
+ initialRouteName: string | undefined
163
+ ): Pick<SwitchRouterStateMap[Type], 'index' | 'history'> => {
164
+ let history = state.history;
165
+
166
+ if (backBehavior === 'history' || backBehavior === 'fullHistory') {
167
+ const currentRoute = state.routes[index];
168
+
169
+ if (currentRoute == null) {
170
+ throw new Error(`Couldn't find a route at index ${index}.`);
171
+ }
172
+
173
+ if (backBehavior === 'history') {
174
+ // Remove the existing key from the history to de-duplicate it
175
+ history = history.filter((it) =>
176
+ it.type === 'route' ? it.key !== currentRoute.key : true
177
+ );
178
+ } else if (backBehavior === 'fullHistory') {
179
+ const lastHistoryRouteItemIndex = history.findLastIndex(
180
+ (item) => item.type === 'route'
181
+ );
182
+
183
+ const lastHistoryRouteItem = history[lastHistoryRouteItemIndex];
184
+
185
+ if (
186
+ lastHistoryRouteItem?.type === 'route' &&
187
+ currentRoute.key !== lastHistoryRouteItem.key
188
+ ) {
189
+ const previousRoute = state.routes.find(
190
+ (route) => route.key === lastHistoryRouteItem.key
191
+ );
192
+
193
+ if (
194
+ previousRoute != null &&
195
+ previousRoute.params !== lastHistoryRouteItem.params
196
+ ) {
197
+ history = [...history];
198
+ history[lastHistoryRouteItemIndex] = {
199
+ ...lastHistoryRouteItem,
200
+ params: previousRoute.params,
201
+ };
202
+ }
203
+ }
204
+
205
+ if (
206
+ lastHistoryRouteItem?.type === 'route' &&
207
+ currentRoute.key === lastHistoryRouteItem.key
208
+ ) {
209
+ // For full-history, only remove if it matches the last route
210
+ // Useful for drawer, if current route was in history, then drawer state changed
211
+ // Then we only need to move the route to the front
212
+ history = [
213
+ ...history.slice(0, lastHistoryRouteItemIndex),
214
+ ...history.slice(lastHistoryRouteItemIndex + 1),
215
+ ];
216
+ }
217
+ }
218
+
219
+ history = history.concat({
220
+ type: TYPE_ROUTE,
221
+ key: currentRoute.key,
222
+ params: backBehavior === 'fullHistory' ? currentRoute.params : undefined,
223
+ });
224
+ } else {
225
+ // Preserve non-route entries (e.g. drawer status) when rebuilding the history
226
+ history = [
227
+ ...state.history.filter((it) => it.type !== 'route'),
228
+ ...getRouteHistory(state.routes, index, backBehavior, initialRouteName),
229
+ ];
230
+ }
231
+
232
+ return {
233
+ index,
234
+ history,
235
+ };
236
+ };
237
+
238
+ export function SwitchRouter<Type extends SwitchRouterType>({
239
+ initialRouteName,
240
+ backBehavior = 'firstRoute',
241
+ }: SwitchRouterOptions) {
242
+ type State = SwitchRouterStateMap[Type];
243
+
244
+ const router = {
245
+ ...BaseRouter,
246
+
247
+ getInitialState({
248
+ routeNames,
249
+ routeParamList,
250
+ }: RouterConfigOptions): SwitchRouterState<RouteHistory> {
251
+ const index =
252
+ initialRouteName !== undefined && routeNames.includes(initialRouteName)
253
+ ? routeNames.indexOf(initialRouteName)
254
+ : 0;
255
+
256
+ const routes = routeNames.map((name) => ({
257
+ name,
258
+ key: `${name}-${nanoid()}`,
259
+ params: routeParamList[name],
260
+ }));
261
+
262
+ return {
263
+ stale: false,
264
+ key: nanoid(),
265
+ index,
266
+ routeNames,
267
+ history: getRouteHistory(routes, index, backBehavior, initialRouteName),
268
+ routes,
269
+ preloadedRouteKeys: [],
270
+ };
271
+ },
272
+
273
+ getRehydratedState(
274
+ state: PartialState<State>,
275
+ { routeNames, routeParamList }: RouterConfigOptions
276
+ ): SwitchRouterState<RouteHistory> {
277
+ const routes = routeNames.map((name) => {
278
+ const route = state.routes.find((r) => r.name === name);
279
+
280
+ return {
281
+ ...route,
282
+ name,
283
+ key:
284
+ route && route.name === name && route.key
285
+ ? route.key
286
+ : `${name}-${nanoid()}`,
287
+ params:
288
+ routeParamList[name] !== undefined
289
+ ? {
290
+ ...routeParamList[name],
291
+ ...(route ? route.params : undefined),
292
+ }
293
+ : route
294
+ ? route.params
295
+ : undefined,
296
+ } satisfies Route<string>;
297
+ });
298
+
299
+ const currentRoute = state.routes[state.index ?? 0];
300
+ const index = Math.min(
301
+ Math.max(currentRoute ? routeNames.indexOf(currentRoute.name) : 0, 0),
302
+ routes.length - 1
303
+ );
304
+
305
+ const routeKeys = routes.map((route) => route.key);
306
+ const history: RouteHistory[] = [];
307
+
308
+ for (const item of state.history ?? []) {
309
+ if (item.type === 'route' && routeKeys.includes(item.key)) {
310
+ history.push(item);
311
+ }
312
+ }
313
+
314
+ const stateData: SwitchRouterState<RouteHistory> = {
315
+ stale: false,
316
+ key: nanoid(),
317
+ index,
318
+ routeNames,
319
+ history,
320
+ routes,
321
+ preloadedRouteKeys:
322
+ state.preloadedRouteKeys?.filter((key) => routeKeys.includes(key)) ??
323
+ [],
324
+ };
325
+
326
+ return {
327
+ ...stateData,
328
+ ...changeIndex<'tab'>(stateData, index, backBehavior, initialRouteName),
329
+ };
330
+ },
331
+
332
+ getStateForRouteNamesChange(
333
+ state: State,
334
+ {
335
+ routeNames,
336
+ routeParamList,
337
+ routeKeyChanges,
338
+ }: RouterConfigOptions & { routeKeyChanges: string[] }
339
+ ): State {
340
+ const routes = routeNames.map(
341
+ (name) =>
342
+ state.routes.find(
343
+ (r) => r.name === name && !routeKeyChanges.includes(r.name)
344
+ ) ?? {
345
+ name,
346
+ key: `${name}-${nanoid()}`,
347
+ params: routeParamList[name],
348
+ }
349
+ );
350
+
351
+ const routeKeys = new Set(routes.map((route) => route.key));
352
+
353
+ const currentRoute = state.routes[state.index];
354
+
355
+ if (currentRoute == null) {
356
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
357
+ }
358
+
359
+ const history = state.history.filter(
360
+ // Type will always be 'route' for tabs, but could be different in a router extending this (e.g. drawer)
361
+ (item) => item.type !== 'route' || routeKeys.has(item.key)
362
+ );
363
+
364
+ let index = routeNames.indexOf(currentRoute.name);
365
+
366
+ if (index === -1) {
367
+ // The focused route was removed, so focus the most recently visited surviving route
368
+ const previousRouteItem = history.findLast(
369
+ (item): item is RouteHistory => item.type === 'route'
370
+ );
371
+
372
+ index = Math.max(
373
+ 0,
374
+ routes.findIndex((route) => route.key === previousRouteItem?.key)
375
+ );
376
+ }
377
+
378
+ return {
379
+ ...state,
380
+ routeNames,
381
+ routes,
382
+ ...changeIndex<Type>(
383
+ { routes, history },
384
+ index,
385
+ backBehavior,
386
+ initialRouteName
387
+ ),
388
+ preloadedRouteKeys: state.preloadedRouteKeys.filter((key) =>
389
+ routeKeys.has(key)
390
+ ),
391
+ };
392
+ },
393
+
394
+ getStateForRouteFocus(state: State, key: string): State {
395
+ const index = state.routes.findIndex((r) => r.key === key);
396
+
397
+ if (index === -1 || index === state.index) {
398
+ return state;
399
+ }
400
+
401
+ return {
402
+ ...state,
403
+ ...changeIndex<Type>(state, index, backBehavior, initialRouteName),
404
+ };
405
+ },
406
+
407
+ getStateForAction(
408
+ state: State,
409
+ action: SwitchActionType | CommonNavigationAction,
410
+ { routeParamList, routeGetIdList }: RouterConfigOptions
411
+ ): State | PartialState<State> | null {
412
+ switch (action.type) {
413
+ case 'JUMP_TO':
414
+ case 'NAVIGATE': {
415
+ const index = state.routes.findIndex(
416
+ (route) => route.name === action.payload.name
417
+ );
418
+
419
+ if (index === -1) {
420
+ return null;
421
+ }
422
+
423
+ if (action.source !== undefined) {
424
+ const sourceIndex = state.routes.findIndex(
425
+ (route) => route.key === action.source
426
+ );
427
+
428
+ if (sourceIndex === -1) {
429
+ return null;
430
+ }
431
+
432
+ if (backBehavior === 'history' || backBehavior === 'fullHistory') {
433
+ const sourceHistoryIndex = state.history.findLastIndex(
434
+ (item) => item.type === 'route' && item.key === action.source
435
+ );
436
+
437
+ if (sourceHistoryIndex !== -1) {
438
+ const history = state.history.filter(
439
+ (item, index) =>
440
+ item.type !== 'route' || index <= sourceHistoryIndex
441
+ );
442
+
443
+ state = {
444
+ ...state,
445
+ ...changeIndex<Type>(
446
+ { routes: state.routes, history },
447
+ sourceIndex,
448
+ backBehavior,
449
+ initialRouteName
450
+ ),
451
+ };
452
+ }
453
+ }
454
+ }
455
+
456
+ const route = state.routes[index];
457
+
458
+ if (route == null) {
459
+ throw new Error(`Couldn't find a route at index ${index}.`);
460
+ }
461
+
462
+ const getId = routeGetIdList[route.name];
463
+
464
+ const currentId = getId?.({ params: route.params });
465
+ const nextId = getId?.({ params: action.payload.params });
466
+
467
+ const key =
468
+ currentId === nextId ? route.key : `${route.name}-${nanoid()}`;
469
+
470
+ let params;
471
+
472
+ if (
473
+ action.type === 'NAVIGATE' &&
474
+ action.payload.merge &&
475
+ currentId === nextId
476
+ ) {
477
+ params =
478
+ action.payload.params !== undefined ||
479
+ routeParamList[route.name] !== undefined
480
+ ? {
481
+ ...routeParamList[route.name],
482
+ ...route.params,
483
+ ...action.payload.params,
484
+ }
485
+ : route.params;
486
+ } else {
487
+ params = createParamsFromAction({ action, routeParamList });
488
+ }
489
+
490
+ const path =
491
+ action.type === 'NAVIGATE' && action.payload.path != null
492
+ ? action.payload.path
493
+ : key === route.key
494
+ ? route.path
495
+ : undefined;
496
+
497
+ const nextRoute =
498
+ key !== route.key
499
+ ? { key, name: route.name, path, params }
500
+ : params !== route.params || path !== route.path
501
+ ? { ...route, path, params }
502
+ : route;
503
+
504
+ const routes =
505
+ nextRoute === route
506
+ ? state.routes
507
+ : state.routes.map((item, routeIndex) =>
508
+ routeIndex === index ? nextRoute : item
509
+ );
510
+
511
+ const updatedState: State = {
512
+ ...state,
513
+ routes,
514
+ history:
515
+ key === route.key
516
+ ? state.history
517
+ : state.history.filter(
518
+ (it) => it.type !== 'route' || it.key !== route.key
519
+ ),
520
+ };
521
+
522
+ return {
523
+ ...updatedState,
524
+ ...changeIndex<Type>(
525
+ updatedState,
526
+ index,
527
+ backBehavior,
528
+ initialRouteName
529
+ ),
530
+ preloadedRouteKeys: updatedState.preloadedRouteKeys.filter(
531
+ (key) => key !== route.key && key !== nextRoute.key
532
+ ),
533
+ };
534
+ }
535
+
536
+ case 'GO_BACK': {
537
+ if (action.source !== undefined) {
538
+ const sourceHistoryIndex = state.history.findLastIndex(
539
+ (item) => item.type === 'route' && item.key === action.source
540
+ );
541
+
542
+ if (sourceHistoryIndex === -1) {
543
+ // The source screen was never visited,
544
+ // so there's nothing before it to go back to
545
+ return null;
546
+ }
547
+
548
+ const sourceIndex = state.routes.findIndex(
549
+ (route) => route.key === action.source
550
+ );
551
+
552
+ // Remove the routes visited after the source from the history
553
+ // Since we're going back from the source route
554
+ const history = state.history.filter(
555
+ (item, index) =>
556
+ item.type !== 'route' || index <= sourceHistoryIndex
557
+ );
558
+
559
+ state = {
560
+ ...state,
561
+ ...changeIndex<Type>(
562
+ { routes: state.routes, history },
563
+ sourceIndex,
564
+ backBehavior,
565
+ initialRouteName
566
+ ),
567
+ };
568
+ }
569
+
570
+ const focusedRoute = state.routes[state.index];
571
+
572
+ if (focusedRoute == null) {
573
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
574
+ }
575
+
576
+ if (state.history.length === 1 && !focusedRoute.history?.length) {
577
+ return null;
578
+ }
579
+
580
+ const lastHistoryItem = state.history[state.history.length - 1];
581
+
582
+ if (
583
+ lastHistoryItem?.type === 'route' &&
584
+ focusedRoute.history?.length
585
+ ) {
586
+ const routes = [...state.routes];
587
+ const history = [...focusedRoute.history];
588
+ const last = history.pop();
589
+
590
+ routes[state.index] = {
591
+ ...focusedRoute,
592
+ params:
593
+ last?.type === 'params' ? last.params : focusedRoute.params,
594
+ history,
595
+ };
596
+
597
+ return {
598
+ ...state,
599
+ routes,
600
+ preloadedRouteKeys: state.preloadedRouteKeys.filter(
601
+ (key) => key !== focusedRoute.key
602
+ ),
603
+ };
604
+ }
605
+
606
+ const previousHistoryItem = state.history[state.history.length - 2];
607
+
608
+ if (
609
+ previousHistoryItem == null ||
610
+ previousHistoryItem.type !== 'route'
611
+ ) {
612
+ return null;
613
+ }
614
+
615
+ const previousKey = previousHistoryItem.key;
616
+ const index = state.routes.findLastIndex(
617
+ (route) => route.key === previousKey
618
+ );
619
+
620
+ if (index === -1) {
621
+ return null;
622
+ }
623
+
624
+ let routes = state.routes;
625
+
626
+ const previousRoute = routes[index];
627
+
628
+ if (previousRoute == null) {
629
+ throw new Error(`Couldn't find a route at index ${index}.`);
630
+ }
631
+
632
+ if (
633
+ backBehavior === 'fullHistory' &&
634
+ previousRoute.params !== previousHistoryItem.params
635
+ ) {
636
+ routes = [...state.routes];
637
+ routes[index] = {
638
+ ...previousRoute,
639
+ params: previousHistoryItem.params,
640
+ };
641
+ }
642
+
643
+ return {
644
+ ...state,
645
+ routes,
646
+ preloadedRouteKeys: state.preloadedRouteKeys.filter(
647
+ (key) => key !== previousRoute.key
648
+ ),
649
+ history: state.history.slice(0, -1),
650
+ index,
651
+ };
652
+ }
653
+
654
+ case 'PRELOAD': {
655
+ const routeIndex = state.routes.findIndex(
656
+ (route) => route.name === action.payload.name
657
+ );
658
+
659
+ if (routeIndex === -1) {
660
+ return null;
661
+ }
662
+
663
+ const route = state.routes[routeIndex];
664
+
665
+ if (route == null) {
666
+ throw new Error(`Couldn't find a route at index ${routeIndex}.`);
667
+ }
668
+
669
+ const getId = routeGetIdList[route.name];
670
+
671
+ const currentId = getId?.({ params: route.params });
672
+ const nextId = getId?.({ params: action.payload.params });
673
+
674
+ const key =
675
+ currentId === nextId ? route.key : `${route.name}-${nanoid()}`;
676
+
677
+ const params = createParamsFromAction({ action, routeParamList });
678
+ const newRoute =
679
+ key !== route.key
680
+ ? { key, name: route.name, params }
681
+ : params !== route.params
682
+ ? { ...route, params }
683
+ : route;
684
+
685
+ let history = state.history;
686
+
687
+ if (key !== route.key) {
688
+ history = history.filter(
689
+ (record) => record.type !== 'route' || record.key !== route.key
690
+ );
691
+
692
+ if (routeIndex === state.index) {
693
+ history = history.concat({
694
+ type: TYPE_ROUTE,
695
+ key: newRoute.key,
696
+ params:
697
+ backBehavior === 'fullHistory' ? newRoute.params : undefined,
698
+ });
699
+ }
700
+ }
701
+
702
+ return {
703
+ ...state,
704
+ preloadedRouteKeys: state.preloadedRouteKeys
705
+ .filter((key) => key !== route.key)
706
+ .concat(newRoute.key),
707
+ routes:
708
+ newRoute === route
709
+ ? state.routes
710
+ : state.routes.map((route, index) =>
711
+ index === routeIndex ? newRoute : route
712
+ ),
713
+ history,
714
+ };
715
+ }
716
+
717
+ default:
718
+ return BaseRouter.getStateForAction(state, action);
719
+ }
720
+ },
721
+ };
722
+
723
+ return router;
724
+ }