@react-navigation/routers 8.0.0-alpha.5 → 8.0.0-alpha.7
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.
- package/lib/module/StackRouter.js +155 -123
- package/lib/module/StackRouter.js.map +1 -1
- package/lib/typescript/src/StackRouter.d.ts +26 -3
- package/lib/typescript/src/StackRouter.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +0 -10
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/StackRouter.tsx +308 -138
- package/src/types.tsx +0 -11
package/src/StackRouter.tsx
CHANGED
|
@@ -6,7 +6,6 @@ import { createRouteFromAction } from './createRouteFromAction';
|
|
|
6
6
|
import type {
|
|
7
7
|
CommonNavigationAction,
|
|
8
8
|
DefaultRouterOptions,
|
|
9
|
-
NavigationRoute,
|
|
10
9
|
NavigationState,
|
|
11
10
|
ParamListBase,
|
|
12
11
|
Route,
|
|
@@ -46,6 +45,12 @@ export type StackActionType =
|
|
|
46
45
|
};
|
|
47
46
|
source?: string | undefined;
|
|
48
47
|
target?: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
| {
|
|
50
|
+
type: 'RETAIN';
|
|
51
|
+
payload: { enable: boolean };
|
|
52
|
+
source?: string | undefined;
|
|
53
|
+
target?: string | undefined;
|
|
49
54
|
};
|
|
50
55
|
|
|
51
56
|
export type StackRouterOptions = DefaultRouterOptions;
|
|
@@ -57,9 +62,11 @@ export type StackNavigationState<ParamList extends ParamListBase> =
|
|
|
57
62
|
*/
|
|
58
63
|
type: 'stack';
|
|
59
64
|
/**
|
|
60
|
-
* List of
|
|
65
|
+
* List of route keys to retain in the stack.
|
|
66
|
+
* When a retained route gets removed from the stack,
|
|
67
|
+
* it'll be kept in routes and can be navigated to again.
|
|
61
68
|
*/
|
|
62
|
-
|
|
69
|
+
retainedRouteKeys: string[];
|
|
63
70
|
};
|
|
64
71
|
|
|
65
72
|
export type StackActionHelpers<ParamList extends ParamListBase> = {
|
|
@@ -124,6 +131,15 @@ export type StackActionHelpers<ParamList extends ParamListBase> = {
|
|
|
124
131
|
]
|
|
125
132
|
: never
|
|
126
133
|
): void;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Enable or disable retaining the current route in the stack.
|
|
137
|
+
* When a retained route gets removed from the stack,
|
|
138
|
+
* it'll be kept in routes and can be navigated to again.
|
|
139
|
+
*
|
|
140
|
+
* @param enable Whether to retain the current route in the stack or not.
|
|
141
|
+
*/
|
|
142
|
+
retain(enable: boolean): void;
|
|
127
143
|
};
|
|
128
144
|
|
|
129
145
|
export const StackActions = {
|
|
@@ -158,6 +174,103 @@ export const StackActions = {
|
|
|
158
174
|
},
|
|
159
175
|
} as const satisfies StackActionType;
|
|
160
176
|
},
|
|
177
|
+
retain(enable: boolean) {
|
|
178
|
+
return {
|
|
179
|
+
type: 'RETAIN',
|
|
180
|
+
payload: { enable },
|
|
181
|
+
} as const satisfies StackActionType;
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
function retainRoutes<ParamList extends ParamListBase>(
|
|
186
|
+
previousState: StackNavigationState<ParamList>,
|
|
187
|
+
nextState: StackNavigationState<ParamList>
|
|
188
|
+
) {
|
|
189
|
+
if (!nextState.retainedRouteKeys.length) {
|
|
190
|
+
return nextState;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const retainedRouteKeySet = new Set(nextState.retainedRouteKeys);
|
|
194
|
+
const nextRouteKeySet = new Set(nextState.routes.map((route) => route.key));
|
|
195
|
+
const retainedRoutes = getActiveRoutes(previousState).filter(
|
|
196
|
+
(route) =>
|
|
197
|
+
retainedRouteKeySet.has(route.key) && !nextRouteKeySet.has(route.key)
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (!retainedRoutes.length) {
|
|
201
|
+
return nextState;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const removedRetainedRouteKeys = new Set(
|
|
205
|
+
retainedRoutes.map((route) => route.key)
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
return getStateWithRoutes(
|
|
209
|
+
nextState,
|
|
210
|
+
getActiveRoutes(nextState),
|
|
211
|
+
getPreloadedRoutes(nextState),
|
|
212
|
+
retainedRoutes.concat(
|
|
213
|
+
getRetainedRoutes(nextState).filter(
|
|
214
|
+
(route) => !removedRetainedRouteKeys.has(route.key)
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const getActiveRoutes = <ParamList extends ParamListBase>(
|
|
221
|
+
state: StackNavigationState<ParamList>
|
|
222
|
+
) => state.routes.slice(0, state.index + 1);
|
|
223
|
+
|
|
224
|
+
const getInactiveRoutes = <ParamList extends ParamListBase>(
|
|
225
|
+
state: StackNavigationState<ParamList>
|
|
226
|
+
) => state.routes.slice(state.index + 1);
|
|
227
|
+
|
|
228
|
+
const getPreloadedRoutes = <ParamList extends ParamListBase>(
|
|
229
|
+
state: StackNavigationState<ParamList>
|
|
230
|
+
) => {
|
|
231
|
+
const retainedRouteKeySet = new Set(state.retainedRouteKeys);
|
|
232
|
+
|
|
233
|
+
return getInactiveRoutes(state).filter(
|
|
234
|
+
(route) => !retainedRouteKeySet.has(route.key)
|
|
235
|
+
);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const getRetainedRoutes = <ParamList extends ParamListBase>(
|
|
239
|
+
state: StackNavigationState<ParamList>
|
|
240
|
+
) => {
|
|
241
|
+
const retainedRouteKeySet = new Set(state.retainedRouteKeys);
|
|
242
|
+
|
|
243
|
+
return getInactiveRoutes(state).filter((route) =>
|
|
244
|
+
retainedRouteKeySet.has(route.key)
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const getStateWithRoutes = <ParamList extends ParamListBase>(
|
|
249
|
+
state: StackNavigationState<ParamList>,
|
|
250
|
+
activeRoutes: Route<string>[],
|
|
251
|
+
preloadedRoutes = getPreloadedRoutes(state),
|
|
252
|
+
retainedRoutes = getRetainedRoutes(state)
|
|
253
|
+
) => {
|
|
254
|
+
const routeKeySet = new Set(activeRoutes.map((route) => route.key));
|
|
255
|
+
const retainedRouteKeySet = new Set(state.retainedRouteKeys);
|
|
256
|
+
|
|
257
|
+
const filteredRetainedRoutes = retainedRoutes.filter(
|
|
258
|
+
(route) => !routeKeySet.has(route.key)
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const filteredPreloadedRoutes = preloadedRoutes.filter(
|
|
262
|
+
(route) =>
|
|
263
|
+
!retainedRouteKeySet.has(route.key) && !routeKeySet.has(route.key)
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
...state,
|
|
268
|
+
index: activeRoutes.length - 1,
|
|
269
|
+
routes: activeRoutes.concat(
|
|
270
|
+
filteredRetainedRoutes,
|
|
271
|
+
filteredPreloadedRoutes
|
|
272
|
+
),
|
|
273
|
+
};
|
|
161
274
|
};
|
|
162
275
|
|
|
163
276
|
export function StackRouter(options: StackRouterOptions) {
|
|
@@ -182,7 +295,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
182
295
|
key: `stack-${nanoid()}`,
|
|
183
296
|
index: 0,
|
|
184
297
|
routeNames,
|
|
185
|
-
|
|
298
|
+
retainedRouteKeys: [],
|
|
186
299
|
routes: [
|
|
187
300
|
{
|
|
188
301
|
key: `${initialRouteName}-${nanoid()}`,
|
|
@@ -214,24 +327,6 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
214
327
|
: route.params,
|
|
215
328
|
}));
|
|
216
329
|
|
|
217
|
-
const preloadedRoutes =
|
|
218
|
-
state.preloadedRoutes
|
|
219
|
-
?.filter((route) => routeNames.includes(route.name))
|
|
220
|
-
.map(
|
|
221
|
-
(route) =>
|
|
222
|
-
({
|
|
223
|
-
...route,
|
|
224
|
-
key: route.key || `${route.name}-${nanoid()}`,
|
|
225
|
-
params:
|
|
226
|
-
routeParamList[route.name] !== undefined
|
|
227
|
-
? {
|
|
228
|
-
...routeParamList[route.name],
|
|
229
|
-
...route.params,
|
|
230
|
-
}
|
|
231
|
-
: route.params,
|
|
232
|
-
}) as Route<string>
|
|
233
|
-
) ?? [];
|
|
234
|
-
|
|
235
330
|
if (routes.length === 0) {
|
|
236
331
|
const initialRouteName =
|
|
237
332
|
options.initialRouteName !== undefined
|
|
@@ -245,14 +340,23 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
245
340
|
});
|
|
246
341
|
}
|
|
247
342
|
|
|
343
|
+
const index = Math.min(
|
|
344
|
+
Math.max(state.index ?? routes.length - 1, 0),
|
|
345
|
+
routes.length - 1
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const routeKeys = new Set(routes.map((route) => route.key));
|
|
349
|
+
const retainedRouteKeys =
|
|
350
|
+
state.retainedRouteKeys?.filter((key) => routeKeys.has(key)) ?? [];
|
|
351
|
+
|
|
248
352
|
return {
|
|
249
353
|
stale: false,
|
|
250
354
|
type: 'stack',
|
|
251
355
|
key: `stack-${nanoid()}`,
|
|
252
|
-
index
|
|
356
|
+
index,
|
|
253
357
|
routeNames,
|
|
254
358
|
routes,
|
|
255
|
-
|
|
359
|
+
retainedRouteKeys,
|
|
256
360
|
};
|
|
257
361
|
},
|
|
258
362
|
|
|
@@ -260,7 +364,19 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
260
364
|
state,
|
|
261
365
|
{ routeNames, routeParamList, routeKeyChanges }
|
|
262
366
|
) {
|
|
263
|
-
const routes = state.
|
|
367
|
+
const routes = getActiveRoutes(state).filter(
|
|
368
|
+
(route) =>
|
|
369
|
+
routeNames.includes(route.name) &&
|
|
370
|
+
!routeKeyChanges.includes(route.name)
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
const preloadedRoutes = getPreloadedRoutes(state).filter(
|
|
374
|
+
(route) =>
|
|
375
|
+
routeNames.includes(route.name) &&
|
|
376
|
+
!routeKeyChanges.includes(route.name)
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const retainedRoutes = getRetainedRoutes(state).filter(
|
|
264
380
|
(route) =>
|
|
265
381
|
routeNames.includes(route.name) &&
|
|
266
382
|
!routeKeyChanges.includes(route.name)
|
|
@@ -280,36 +396,54 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
280
396
|
});
|
|
281
397
|
}
|
|
282
398
|
|
|
283
|
-
|
|
284
|
-
...
|
|
285
|
-
|
|
399
|
+
const routeKeys = new Set(
|
|
400
|
+
[...routes, ...preloadedRoutes, ...retainedRoutes].map(
|
|
401
|
+
(route) => route.key
|
|
402
|
+
)
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
const retainedRouteKeys = state.retainedRouteKeys.filter((key) =>
|
|
406
|
+
routeKeys.has(key)
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
return getStateWithRoutes(
|
|
410
|
+
{
|
|
411
|
+
...state,
|
|
412
|
+
routeNames,
|
|
413
|
+
retainedRouteKeys,
|
|
414
|
+
},
|
|
286
415
|
routes,
|
|
287
|
-
|
|
288
|
-
|
|
416
|
+
preloadedRoutes,
|
|
417
|
+
retainedRoutes
|
|
418
|
+
);
|
|
289
419
|
},
|
|
290
420
|
|
|
291
421
|
getStateForRouteFocus(state, key) {
|
|
292
|
-
const
|
|
422
|
+
const routes = getActiveRoutes(state);
|
|
423
|
+
const index = routes.findIndex((r) => r.key === key);
|
|
293
424
|
|
|
294
425
|
if (index === -1 || index === state.index) {
|
|
295
426
|
return state;
|
|
296
427
|
}
|
|
297
428
|
|
|
298
|
-
return
|
|
299
|
-
|
|
300
|
-
index
|
|
301
|
-
|
|
302
|
-
};
|
|
429
|
+
return retainRoutes(
|
|
430
|
+
state,
|
|
431
|
+
getStateWithRoutes(state, routes.slice(0, index + 1))
|
|
432
|
+
);
|
|
303
433
|
},
|
|
304
434
|
|
|
305
435
|
getStateForAction(state, action, options) {
|
|
306
436
|
const { routeParamList } = options;
|
|
307
437
|
|
|
438
|
+
const routes = getActiveRoutes(state);
|
|
439
|
+
const preloadedRoutes = getPreloadedRoutes(state);
|
|
440
|
+
const inactiveRoutes = getInactiveRoutes(state);
|
|
441
|
+
|
|
308
442
|
switch (action.type) {
|
|
309
443
|
case 'REPLACE': {
|
|
310
444
|
const currentIndex =
|
|
311
445
|
action.target === state.key && action.source
|
|
312
|
-
?
|
|
446
|
+
? routes.findIndex((r) => r.key === action.source)
|
|
313
447
|
: state.index;
|
|
314
448
|
|
|
315
449
|
if (currentIndex === -1) {
|
|
@@ -323,8 +457,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
323
457
|
const getId = options.routeGetIdList[action.payload.name];
|
|
324
458
|
const id = getId?.({ params: action.payload.params });
|
|
325
459
|
|
|
326
|
-
// Re-use
|
|
327
|
-
let route =
|
|
460
|
+
// Re-use inactive route if available
|
|
461
|
+
let route = inactiveRoutes.find(
|
|
328
462
|
(route) =>
|
|
329
463
|
route.name === action.payload.name &&
|
|
330
464
|
id === getId?.({ params: route.params })
|
|
@@ -334,15 +468,14 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
334
468
|
route = createRouteFromAction({ action, routeParamList });
|
|
335
469
|
}
|
|
336
470
|
|
|
337
|
-
return
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
};
|
|
471
|
+
return retainRoutes(
|
|
472
|
+
state,
|
|
473
|
+
getStateWithRoutes(
|
|
474
|
+
state,
|
|
475
|
+
routes.map((r, i) => (i === currentIndex ? route : r)),
|
|
476
|
+
preloadedRoutes.filter((r) => r.key !== route.key)
|
|
477
|
+
)
|
|
478
|
+
);
|
|
346
479
|
}
|
|
347
480
|
|
|
348
481
|
case 'PUSH':
|
|
@@ -357,7 +490,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
357
490
|
let route: Route<string> | undefined;
|
|
358
491
|
|
|
359
492
|
if (action.type === 'NAVIGATE') {
|
|
360
|
-
const currentRoute =
|
|
493
|
+
const currentRoute = routes[state.index];
|
|
361
494
|
|
|
362
495
|
if (id !== undefined) {
|
|
363
496
|
if (
|
|
@@ -366,8 +499,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
366
499
|
) {
|
|
367
500
|
route = currentRoute;
|
|
368
501
|
} else if (action.payload.pop) {
|
|
369
|
-
for (let i =
|
|
370
|
-
const r =
|
|
502
|
+
for (let i = routes.length - 1; i >= 0; i--) {
|
|
503
|
+
const r = routes[i];
|
|
371
504
|
|
|
372
505
|
if (r.name !== action.payload.name) {
|
|
373
506
|
continue;
|
|
@@ -404,7 +537,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
404
537
|
if (action.payload.name === currentRoute.name) {
|
|
405
538
|
route = currentRoute;
|
|
406
539
|
} else if (action.payload.pop) {
|
|
407
|
-
route =
|
|
540
|
+
route = routes.findLast(
|
|
408
541
|
(route) => route.name === action.payload.name
|
|
409
542
|
);
|
|
410
543
|
}
|
|
@@ -412,7 +545,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
412
545
|
}
|
|
413
546
|
|
|
414
547
|
if (!route) {
|
|
415
|
-
route =
|
|
548
|
+
route = inactiveRoutes.find(
|
|
416
549
|
(route) =>
|
|
417
550
|
route.name === action.payload.name &&
|
|
418
551
|
id === getId?.({ params: route.params })
|
|
@@ -435,16 +568,16 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
435
568
|
params = createParamsFromAction({ action, routeParamList });
|
|
436
569
|
}
|
|
437
570
|
|
|
438
|
-
let
|
|
571
|
+
let nextRoutes: Route<string>[];
|
|
439
572
|
|
|
440
573
|
if (route) {
|
|
441
574
|
if (action.type === 'NAVIGATE' && action.payload.pop) {
|
|
442
|
-
|
|
575
|
+
nextRoutes = [];
|
|
443
576
|
|
|
444
577
|
// Get all routes until the matching one
|
|
445
|
-
for (const r of
|
|
578
|
+
for (const r of routes) {
|
|
446
579
|
if (r.key === route.key) {
|
|
447
|
-
|
|
580
|
+
nextRoutes.push({
|
|
448
581
|
...route,
|
|
449
582
|
path:
|
|
450
583
|
action.payload.path !== undefined
|
|
@@ -455,11 +588,22 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
455
588
|
break;
|
|
456
589
|
}
|
|
457
590
|
|
|
458
|
-
|
|
591
|
+
nextRoutes.push(r);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (!nextRoutes.some((r) => r.key === route.key)) {
|
|
595
|
+
nextRoutes.push({
|
|
596
|
+
...route,
|
|
597
|
+
path:
|
|
598
|
+
action.payload.path !== undefined
|
|
599
|
+
? action.payload.path
|
|
600
|
+
: route.path,
|
|
601
|
+
params,
|
|
602
|
+
});
|
|
459
603
|
}
|
|
460
604
|
} else {
|
|
461
|
-
|
|
462
|
-
|
|
605
|
+
nextRoutes = routes.filter((r) => r.key !== route.key);
|
|
606
|
+
nextRoutes.push({
|
|
463
607
|
...route,
|
|
464
608
|
path:
|
|
465
609
|
action.type === 'NAVIGATE' &&
|
|
@@ -470,8 +614,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
470
614
|
});
|
|
471
615
|
}
|
|
472
616
|
} else {
|
|
473
|
-
|
|
474
|
-
...
|
|
617
|
+
nextRoutes = [
|
|
618
|
+
...routes,
|
|
475
619
|
{
|
|
476
620
|
key: `${action.payload.name}-${nanoid()}`,
|
|
477
621
|
name: action.payload.name,
|
|
@@ -482,23 +626,25 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
482
626
|
];
|
|
483
627
|
}
|
|
484
628
|
|
|
485
|
-
return
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
629
|
+
return retainRoutes(
|
|
630
|
+
state,
|
|
631
|
+
getStateWithRoutes(
|
|
632
|
+
state,
|
|
633
|
+
nextRoutes,
|
|
634
|
+
preloadedRoutes.filter(
|
|
635
|
+
(route) => nextRoutes[nextRoutes.length - 1].key !== route.key
|
|
636
|
+
)
|
|
637
|
+
)
|
|
638
|
+
);
|
|
493
639
|
}
|
|
494
640
|
|
|
495
641
|
case 'POP': {
|
|
496
642
|
let currentIndex =
|
|
497
643
|
action.target === state.key && action.source
|
|
498
|
-
?
|
|
644
|
+
? routes.findIndex((r) => r.key === action.source)
|
|
499
645
|
: state.index;
|
|
500
646
|
|
|
501
|
-
let route =
|
|
647
|
+
let route = routes[currentIndex];
|
|
502
648
|
|
|
503
649
|
/**
|
|
504
650
|
* When popping entries,
|
|
@@ -511,11 +657,11 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
511
657
|
*/
|
|
512
658
|
if (route.history?.length || currentIndex > 0) {
|
|
513
659
|
let count = action.payload.count;
|
|
514
|
-
let
|
|
660
|
+
let nextRoutes = routes;
|
|
515
661
|
|
|
516
662
|
while (count > 0 && (route.history?.length || currentIndex > 0)) {
|
|
517
663
|
if (route.history?.length) {
|
|
518
|
-
|
|
664
|
+
nextRoutes = [...nextRoutes];
|
|
519
665
|
|
|
520
666
|
const end = Math.min(count, route.history.length);
|
|
521
667
|
const last = route.history.at(-end);
|
|
@@ -524,7 +670,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
524
670
|
|
|
525
671
|
count = count - removed;
|
|
526
672
|
|
|
527
|
-
|
|
673
|
+
nextRoutes[currentIndex] = {
|
|
528
674
|
...route,
|
|
529
675
|
params: last?.type === 'params' ? last.params : route.params,
|
|
530
676
|
history,
|
|
@@ -532,33 +678,29 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
532
678
|
}
|
|
533
679
|
|
|
534
680
|
if (currentIndex > 0 && count > 0) {
|
|
535
|
-
const length =
|
|
681
|
+
const length = nextRoutes.length;
|
|
536
682
|
const end = Math.max(currentIndex - count + 1, 1);
|
|
537
683
|
|
|
538
|
-
|
|
684
|
+
nextRoutes = nextRoutes
|
|
539
685
|
.slice(0, end)
|
|
540
|
-
.concat(
|
|
686
|
+
.concat(nextRoutes.slice(currentIndex + 1));
|
|
541
687
|
|
|
542
|
-
const removed = length -
|
|
688
|
+
const removed = length - nextRoutes.length;
|
|
543
689
|
|
|
544
690
|
count = count - removed;
|
|
545
|
-
currentIndex =
|
|
546
|
-
route =
|
|
691
|
+
currentIndex = nextRoutes.length - 1;
|
|
692
|
+
route = nextRoutes[currentIndex];
|
|
547
693
|
}
|
|
548
694
|
}
|
|
549
695
|
|
|
550
|
-
return
|
|
551
|
-
...state,
|
|
552
|
-
index: routes.length - 1,
|
|
553
|
-
routes,
|
|
554
|
-
};
|
|
696
|
+
return retainRoutes(state, getStateWithRoutes(state, nextRoutes));
|
|
555
697
|
}
|
|
556
698
|
|
|
557
699
|
return null;
|
|
558
700
|
}
|
|
559
701
|
|
|
560
702
|
case 'POP_TO_TOP': {
|
|
561
|
-
let route =
|
|
703
|
+
let route = routes[0];
|
|
562
704
|
|
|
563
705
|
if (state.index > 0 || route.history?.length) {
|
|
564
706
|
if (route.history?.length) {
|
|
@@ -568,11 +710,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
568
710
|
};
|
|
569
711
|
}
|
|
570
712
|
|
|
571
|
-
return
|
|
572
|
-
...state,
|
|
573
|
-
index: 0,
|
|
574
|
-
routes: [route],
|
|
575
|
-
};
|
|
713
|
+
return retainRoutes(state, getStateWithRoutes(state, [route]));
|
|
576
714
|
}
|
|
577
715
|
|
|
578
716
|
return null;
|
|
@@ -581,7 +719,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
581
719
|
case 'POP_TO': {
|
|
582
720
|
const currentIndex =
|
|
583
721
|
action.target === state.key && action.source
|
|
584
|
-
?
|
|
722
|
+
? routes.findLastIndex((r) => r.key === action.source)
|
|
585
723
|
: state.index;
|
|
586
724
|
|
|
587
725
|
if (currentIndex === -1) {
|
|
@@ -601,7 +739,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
601
739
|
|
|
602
740
|
if (id !== undefined) {
|
|
603
741
|
for (let i = currentIndex; i >= 0; i--) {
|
|
604
|
-
const r =
|
|
742
|
+
const r = routes[i];
|
|
605
743
|
|
|
606
744
|
if (r.name !== action.payload.name) {
|
|
607
745
|
continue;
|
|
@@ -629,11 +767,11 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
629
767
|
}
|
|
630
768
|
}
|
|
631
769
|
}
|
|
632
|
-
} else if (
|
|
770
|
+
} else if (routes[currentIndex].name === action.payload.name) {
|
|
633
771
|
index = currentIndex;
|
|
634
772
|
} else {
|
|
635
773
|
for (let i = currentIndex; i >= 0; i--) {
|
|
636
|
-
if (
|
|
774
|
+
if (routes[i].name === action.payload.name) {
|
|
637
775
|
index = i;
|
|
638
776
|
break;
|
|
639
777
|
}
|
|
@@ -642,8 +780,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
642
780
|
|
|
643
781
|
// If the route doesn't exist, remove the current route and add the new one
|
|
644
782
|
if (index === -1) {
|
|
645
|
-
// Re-use
|
|
646
|
-
let route =
|
|
783
|
+
// Re-use inactive route if available
|
|
784
|
+
let route = inactiveRoutes.find(
|
|
647
785
|
(route) =>
|
|
648
786
|
route.name === action.payload.name &&
|
|
649
787
|
id === getId?.({ params: route.params })
|
|
@@ -653,19 +791,19 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
653
791
|
route = createRouteFromAction({ action, routeParamList });
|
|
654
792
|
}
|
|
655
793
|
|
|
656
|
-
const
|
|
794
|
+
const nextRoutes = routes.slice(0, currentIndex).concat(route);
|
|
657
795
|
|
|
658
|
-
return
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
(r) => r.key !== route.key
|
|
664
|
-
)
|
|
665
|
-
|
|
796
|
+
return retainRoutes(
|
|
797
|
+
state,
|
|
798
|
+
getStateWithRoutes(
|
|
799
|
+
state,
|
|
800
|
+
nextRoutes,
|
|
801
|
+
preloadedRoutes.filter((r) => r.key !== route.key)
|
|
802
|
+
)
|
|
803
|
+
);
|
|
666
804
|
}
|
|
667
805
|
|
|
668
|
-
const route =
|
|
806
|
+
const route = routes[index];
|
|
669
807
|
|
|
670
808
|
let baseParams = route.params;
|
|
671
809
|
let history = route.history;
|
|
@@ -691,20 +829,19 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
691
829
|
params = createParamsFromAction({ action, routeParamList });
|
|
692
830
|
}
|
|
693
831
|
|
|
694
|
-
return
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
...state.routes.slice(0, index),
|
|
832
|
+
return retainRoutes(
|
|
833
|
+
state,
|
|
834
|
+
getStateWithRoutes(state, [
|
|
835
|
+
...routes.slice(0, index),
|
|
699
836
|
params !== baseParams || historyIndex !== undefined
|
|
700
837
|
? { ...route, params, history }
|
|
701
|
-
:
|
|
702
|
-
]
|
|
703
|
-
|
|
838
|
+
: routes[index],
|
|
839
|
+
])
|
|
840
|
+
);
|
|
704
841
|
}
|
|
705
842
|
|
|
706
843
|
case 'GO_BACK':
|
|
707
|
-
if (state.index > 0 ||
|
|
844
|
+
if (state.index > 0 || routes[state.index].history?.length) {
|
|
708
845
|
return router.getStateForAction(
|
|
709
846
|
state,
|
|
710
847
|
{
|
|
@@ -719,6 +856,40 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
719
856
|
|
|
720
857
|
return null;
|
|
721
858
|
|
|
859
|
+
case 'RETAIN': {
|
|
860
|
+
const routeKey = action.source ?? routes[state.index].key;
|
|
861
|
+
|
|
862
|
+
if (!state.routes.some((route) => route.key === routeKey)) {
|
|
863
|
+
return null;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (action.payload.enable) {
|
|
867
|
+
if (state.retainedRouteKeys.includes(routeKey)) {
|
|
868
|
+
return state;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return {
|
|
872
|
+
...state,
|
|
873
|
+
retainedRouteKeys: [...state.retainedRouteKeys, routeKey],
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (!state.retainedRouteKeys.includes(routeKey)) {
|
|
878
|
+
return state;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
return getStateWithRoutes(
|
|
882
|
+
{
|
|
883
|
+
...state,
|
|
884
|
+
retainedRouteKeys: state.retainedRouteKeys.filter(
|
|
885
|
+
(key) => key !== routeKey
|
|
886
|
+
),
|
|
887
|
+
},
|
|
888
|
+
routes,
|
|
889
|
+
preloadedRoutes.filter((route) => route.key !== routeKey)
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
|
|
722
893
|
case 'PRELOAD': {
|
|
723
894
|
const getId = options.routeGetIdList[action.payload.name];
|
|
724
895
|
const id = getId?.({ params: action.payload.params });
|
|
@@ -727,56 +898,59 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
727
898
|
let route: Route<string> | undefined;
|
|
728
899
|
|
|
729
900
|
if (action.payload.reuse) {
|
|
730
|
-
route =
|
|
901
|
+
route = preloadedRoutes.findLast(
|
|
731
902
|
(route) =>
|
|
732
903
|
route.name === action.payload.name &&
|
|
733
904
|
(id === undefined || id === getId?.({ params: route.params }))
|
|
734
905
|
);
|
|
735
906
|
|
|
736
907
|
if (route) {
|
|
737
|
-
return
|
|
738
|
-
|
|
739
|
-
|
|
908
|
+
return getStateWithRoutes(
|
|
909
|
+
state,
|
|
910
|
+
routes,
|
|
911
|
+
preloadedRoutes.map((r) =>
|
|
740
912
|
r.key === route?.key && r.params !== params
|
|
741
913
|
? { ...r, params }
|
|
742
914
|
: r
|
|
743
|
-
)
|
|
744
|
-
|
|
915
|
+
)
|
|
916
|
+
);
|
|
745
917
|
}
|
|
746
918
|
}
|
|
747
919
|
|
|
748
920
|
if (id !== undefined) {
|
|
749
|
-
route =
|
|
921
|
+
route = routes.findLast(
|
|
750
922
|
(route) =>
|
|
751
923
|
route.name === action.payload.name &&
|
|
752
924
|
id === getId?.({ params: route.params })
|
|
753
925
|
);
|
|
754
926
|
} else if (action.payload.reuse) {
|
|
755
|
-
route =
|
|
927
|
+
route = routes.findLast(
|
|
756
928
|
(route) => route.name === action.payload.name
|
|
757
929
|
);
|
|
758
930
|
}
|
|
759
931
|
|
|
760
932
|
if (route) {
|
|
761
|
-
return
|
|
762
|
-
|
|
763
|
-
routes
|
|
933
|
+
return getStateWithRoutes(
|
|
934
|
+
state,
|
|
935
|
+
routes.map((r) =>
|
|
764
936
|
r.key === route.key && r.params !== params
|
|
765
937
|
? { ...r, params }
|
|
766
938
|
: r
|
|
767
939
|
),
|
|
768
|
-
|
|
940
|
+
preloadedRoutes
|
|
941
|
+
);
|
|
769
942
|
} else {
|
|
770
|
-
return
|
|
771
|
-
|
|
772
|
-
|
|
943
|
+
return getStateWithRoutes(
|
|
944
|
+
state,
|
|
945
|
+
routes,
|
|
946
|
+
preloadedRoutes
|
|
773
947
|
.filter(
|
|
774
948
|
(r) =>
|
|
775
949
|
r.name !== action.payload.name ||
|
|
776
950
|
id !== getId?.({ params: r.params })
|
|
777
951
|
)
|
|
778
|
-
.concat(createRouteFromAction({ action, routeParamList }))
|
|
779
|
-
|
|
952
|
+
.concat(createRouteFromAction({ action, routeParamList }))
|
|
953
|
+
);
|
|
780
954
|
}
|
|
781
955
|
}
|
|
782
956
|
|
|
@@ -785,10 +959,6 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
785
959
|
}
|
|
786
960
|
},
|
|
787
961
|
|
|
788
|
-
getRoutesFromState(state) {
|
|
789
|
-
return [...state.routes, ...state.preloadedRoutes];
|
|
790
|
-
},
|
|
791
|
-
|
|
792
962
|
actionCreators: StackActions,
|
|
793
963
|
};
|
|
794
964
|
|