@react-navigation/routers 8.0.0-alpha.0 → 8.0.0-alpha.10
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/BaseRouter.js +3 -2
- package/lib/module/BaseRouter.js.map +1 -1
- package/lib/module/CommonActions.js.map +1 -1
- package/lib/module/StackRouter.js +256 -136
- package/lib/module/StackRouter.js.map +1 -1
- package/lib/typescript/src/BaseRouter.d.ts +6 -6
- package/lib/typescript/src/BaseRouter.d.ts.map +1 -1
- package/lib/typescript/src/CommonActions.d.ts +34 -34
- package/lib/typescript/src/CommonActions.d.ts.map +1 -1
- package/lib/typescript/src/DrawerRouter.d.ts +3 -3
- package/lib/typescript/src/DrawerRouter.d.ts.map +1 -1
- package/lib/typescript/src/StackRouter.d.ts +40 -17
- package/lib/typescript/src/StackRouter.d.ts.map +1 -1
- package/lib/typescript/src/TabRouter.d.ts +4 -4
- package/lib/typescript/src/TabRouter.d.ts.map +1 -1
- package/lib/typescript/src/createParamsFromAction.d.ts +1 -1
- package/lib/typescript/src/createParamsFromAction.d.ts.map +1 -1
- package/lib/typescript/src/createRouteFromAction.d.ts +1 -1
- package/lib/typescript/src/createRouteFromAction.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +14 -14
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/BaseRouter.tsx +4 -4
- package/src/CommonActions.tsx +36 -34
- package/src/DrawerRouter.tsx +3 -3
- package/src/StackRouter.tsx +433 -182
- package/src/TabRouter.tsx +4 -4
- package/src/createParamsFromAction.tsx +1 -1
- package/src/createRouteFromAction.tsx +1 -1
- package/src/types.tsx +18 -14
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,
|
|
@@ -16,36 +15,42 @@ import type {
|
|
|
16
15
|
export type StackActionType =
|
|
17
16
|
| {
|
|
18
17
|
type: 'REPLACE';
|
|
19
|
-
payload: { name: string; params?: object };
|
|
20
|
-
source?: string;
|
|
21
|
-
target?: string;
|
|
18
|
+
payload: { name: string; params?: object | undefined };
|
|
19
|
+
source?: string | undefined;
|
|
20
|
+
target?: string | undefined;
|
|
22
21
|
}
|
|
23
22
|
| {
|
|
24
23
|
type: 'PUSH';
|
|
25
|
-
payload: { name: string; params?: object };
|
|
26
|
-
source?: string;
|
|
27
|
-
target?: string;
|
|
24
|
+
payload: { name: string; params?: object | undefined };
|
|
25
|
+
source?: string | undefined;
|
|
26
|
+
target?: string | undefined;
|
|
28
27
|
}
|
|
29
28
|
| {
|
|
30
29
|
type: 'POP';
|
|
31
30
|
payload: { count: number };
|
|
32
|
-
source?: string;
|
|
33
|
-
target?: string;
|
|
31
|
+
source?: string | undefined;
|
|
32
|
+
target?: string | undefined;
|
|
34
33
|
}
|
|
35
34
|
| {
|
|
36
35
|
type: 'POP_TO_TOP';
|
|
37
|
-
source?: string;
|
|
38
|
-
target?: string;
|
|
36
|
+
source?: string | undefined;
|
|
37
|
+
target?: string | undefined;
|
|
39
38
|
}
|
|
40
39
|
| {
|
|
41
40
|
type: 'POP_TO';
|
|
42
41
|
payload: {
|
|
43
42
|
name: string;
|
|
44
|
-
params?: object;
|
|
45
|
-
merge?: boolean;
|
|
43
|
+
params?: object | undefined;
|
|
44
|
+
merge?: boolean | undefined;
|
|
46
45
|
};
|
|
47
|
-
source?: string;
|
|
48
|
-
target?: string;
|
|
46
|
+
source?: string | undefined;
|
|
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 })
|
|
@@ -332,17 +466,22 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
332
466
|
|
|
333
467
|
if (!route) {
|
|
334
468
|
route = createRouteFromAction({ action, routeParamList });
|
|
469
|
+
} else {
|
|
470
|
+
const params = createParamsFromAction({ action, routeParamList });
|
|
471
|
+
|
|
472
|
+
if (route.params !== params) {
|
|
473
|
+
route = { ...route, params };
|
|
474
|
+
}
|
|
335
475
|
}
|
|
336
476
|
|
|
337
|
-
return
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
};
|
|
477
|
+
return retainRoutes(
|
|
478
|
+
state,
|
|
479
|
+
getStateWithRoutes(
|
|
480
|
+
state,
|
|
481
|
+
routes.map((r, i) => (i === currentIndex ? route : r)),
|
|
482
|
+
preloadedRoutes.filter((r) => r.key !== route.key)
|
|
483
|
+
)
|
|
484
|
+
);
|
|
346
485
|
}
|
|
347
486
|
|
|
348
487
|
case 'PUSH':
|
|
@@ -356,27 +495,63 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
356
495
|
|
|
357
496
|
let route: Route<string> | undefined;
|
|
358
497
|
|
|
359
|
-
if (
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
498
|
+
if (action.type === 'NAVIGATE') {
|
|
499
|
+
const currentRoute = routes[state.index];
|
|
500
|
+
|
|
501
|
+
if (id !== undefined) {
|
|
502
|
+
if (
|
|
503
|
+
currentRoute.name === action.payload.name &&
|
|
504
|
+
id === getId?.({ params: currentRoute.params })
|
|
505
|
+
) {
|
|
506
|
+
route = currentRoute;
|
|
507
|
+
} else if (action.payload.pop) {
|
|
508
|
+
for (let i = routes.length - 1; i >= 0; i--) {
|
|
509
|
+
const r = routes[i];
|
|
510
|
+
|
|
511
|
+
if (r.name !== action.payload.name) {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (id === getId?.({ params: r.params })) {
|
|
516
|
+
route = r;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (r.history?.length) {
|
|
521
|
+
for (let j = r.history.length - 1; j >= 0; j--) {
|
|
522
|
+
if (
|
|
523
|
+
r.history[j].type === 'params' &&
|
|
524
|
+
id === getId?.({ params: r.history[j].params })
|
|
525
|
+
) {
|
|
526
|
+
route = {
|
|
527
|
+
...r,
|
|
528
|
+
params: r.history[j].params,
|
|
529
|
+
history: r.history.slice(0, j),
|
|
530
|
+
};
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (route) {
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
// If the route matches the current one, then navigate to it
|
|
543
|
+
if (action.payload.name === currentRoute.name) {
|
|
544
|
+
route = currentRoute;
|
|
545
|
+
} else if (action.payload.pop) {
|
|
546
|
+
route = routes.findLast(
|
|
547
|
+
(route) => route.name === action.payload.name
|
|
548
|
+
);
|
|
549
|
+
}
|
|
375
550
|
}
|
|
376
551
|
}
|
|
377
552
|
|
|
378
553
|
if (!route) {
|
|
379
|
-
route =
|
|
554
|
+
route = inactiveRoutes.find(
|
|
380
555
|
(route) =>
|
|
381
556
|
route.name === action.payload.name &&
|
|
382
557
|
id === getId?.({ params: route.params })
|
|
@@ -399,16 +574,16 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
399
574
|
params = createParamsFromAction({ action, routeParamList });
|
|
400
575
|
}
|
|
401
576
|
|
|
402
|
-
let
|
|
577
|
+
let nextRoutes: Route<string>[];
|
|
403
578
|
|
|
404
579
|
if (route) {
|
|
405
580
|
if (action.type === 'NAVIGATE' && action.payload.pop) {
|
|
406
|
-
|
|
581
|
+
nextRoutes = [];
|
|
407
582
|
|
|
408
583
|
// Get all routes until the matching one
|
|
409
|
-
for (const r of
|
|
584
|
+
for (const r of routes) {
|
|
410
585
|
if (r.key === route.key) {
|
|
411
|
-
|
|
586
|
+
nextRoutes.push({
|
|
412
587
|
...route,
|
|
413
588
|
path:
|
|
414
589
|
action.payload.path !== undefined
|
|
@@ -419,11 +594,22 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
419
594
|
break;
|
|
420
595
|
}
|
|
421
596
|
|
|
422
|
-
|
|
597
|
+
nextRoutes.push(r);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (!nextRoutes.some((r) => r.key === route.key)) {
|
|
601
|
+
nextRoutes.push({
|
|
602
|
+
...route,
|
|
603
|
+
path:
|
|
604
|
+
action.payload.path !== undefined
|
|
605
|
+
? action.payload.path
|
|
606
|
+
: route.path,
|
|
607
|
+
params,
|
|
608
|
+
});
|
|
423
609
|
}
|
|
424
610
|
} else {
|
|
425
|
-
|
|
426
|
-
|
|
611
|
+
nextRoutes = routes.filter((r) => r.key !== route.key);
|
|
612
|
+
nextRoutes.push({
|
|
427
613
|
...route,
|
|
428
614
|
path:
|
|
429
615
|
action.type === 'NAVIGATE' &&
|
|
@@ -434,8 +620,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
434
620
|
});
|
|
435
621
|
}
|
|
436
622
|
} else {
|
|
437
|
-
|
|
438
|
-
...
|
|
623
|
+
nextRoutes = [
|
|
624
|
+
...routes,
|
|
439
625
|
{
|
|
440
626
|
key: `${action.payload.name}-${nanoid()}`,
|
|
441
627
|
name: action.payload.name,
|
|
@@ -446,23 +632,29 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
446
632
|
];
|
|
447
633
|
}
|
|
448
634
|
|
|
449
|
-
return
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
635
|
+
return retainRoutes(
|
|
636
|
+
state,
|
|
637
|
+
getStateWithRoutes(
|
|
638
|
+
state,
|
|
639
|
+
nextRoutes,
|
|
640
|
+
preloadedRoutes.filter(
|
|
641
|
+
(route) => nextRoutes[nextRoutes.length - 1].key !== route.key
|
|
642
|
+
)
|
|
643
|
+
)
|
|
644
|
+
);
|
|
457
645
|
}
|
|
458
646
|
|
|
459
647
|
case 'POP': {
|
|
460
648
|
let currentIndex =
|
|
461
649
|
action.target === state.key && action.source
|
|
462
|
-
?
|
|
650
|
+
? routes.findIndex((r) => r.key === action.source)
|
|
463
651
|
: state.index;
|
|
464
652
|
|
|
465
|
-
|
|
653
|
+
if (currentIndex === -1) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
let route = routes[currentIndex];
|
|
466
658
|
|
|
467
659
|
/**
|
|
468
660
|
* When popping entries,
|
|
@@ -475,11 +667,11 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
475
667
|
*/
|
|
476
668
|
if (route.history?.length || currentIndex > 0) {
|
|
477
669
|
let count = action.payload.count;
|
|
478
|
-
let
|
|
670
|
+
let nextRoutes = routes;
|
|
479
671
|
|
|
480
672
|
while (count > 0 && (route.history?.length || currentIndex > 0)) {
|
|
481
673
|
if (route.history?.length) {
|
|
482
|
-
|
|
674
|
+
nextRoutes = [...nextRoutes];
|
|
483
675
|
|
|
484
676
|
const end = Math.min(count, route.history.length);
|
|
485
677
|
const last = route.history.at(-end);
|
|
@@ -488,7 +680,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
488
680
|
|
|
489
681
|
count = count - removed;
|
|
490
682
|
|
|
491
|
-
|
|
683
|
+
nextRoutes[currentIndex] = {
|
|
492
684
|
...route,
|
|
493
685
|
params: last?.type === 'params' ? last.params : route.params,
|
|
494
686
|
history,
|
|
@@ -496,33 +688,29 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
496
688
|
}
|
|
497
689
|
|
|
498
690
|
if (currentIndex > 0 && count > 0) {
|
|
499
|
-
const length =
|
|
691
|
+
const length = nextRoutes.length;
|
|
500
692
|
const end = Math.max(currentIndex - count + 1, 1);
|
|
501
693
|
|
|
502
|
-
|
|
694
|
+
nextRoutes = nextRoutes
|
|
503
695
|
.slice(0, end)
|
|
504
|
-
.concat(
|
|
696
|
+
.concat(nextRoutes.slice(currentIndex + 1));
|
|
505
697
|
|
|
506
|
-
const removed = length -
|
|
698
|
+
const removed = length - nextRoutes.length;
|
|
507
699
|
|
|
508
700
|
count = count - removed;
|
|
509
|
-
currentIndex =
|
|
510
|
-
route =
|
|
701
|
+
currentIndex = nextRoutes.length - 1;
|
|
702
|
+
route = nextRoutes[currentIndex];
|
|
511
703
|
}
|
|
512
704
|
}
|
|
513
705
|
|
|
514
|
-
return
|
|
515
|
-
...state,
|
|
516
|
-
index: routes.length - 1,
|
|
517
|
-
routes,
|
|
518
|
-
};
|
|
706
|
+
return retainRoutes(state, getStateWithRoutes(state, nextRoutes));
|
|
519
707
|
}
|
|
520
708
|
|
|
521
709
|
return null;
|
|
522
710
|
}
|
|
523
711
|
|
|
524
712
|
case 'POP_TO_TOP': {
|
|
525
|
-
let route =
|
|
713
|
+
let route = routes[0];
|
|
526
714
|
|
|
527
715
|
if (state.index > 0 || route.history?.length) {
|
|
528
716
|
if (route.history?.length) {
|
|
@@ -532,11 +720,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
532
720
|
};
|
|
533
721
|
}
|
|
534
722
|
|
|
535
|
-
return
|
|
536
|
-
...state,
|
|
537
|
-
index: 0,
|
|
538
|
-
routes: [route],
|
|
539
|
-
};
|
|
723
|
+
return retainRoutes(state, getStateWithRoutes(state, [route]));
|
|
540
724
|
}
|
|
541
725
|
|
|
542
726
|
return null;
|
|
@@ -545,7 +729,7 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
545
729
|
case 'POP_TO': {
|
|
546
730
|
const currentIndex =
|
|
547
731
|
action.target === state.key && action.source
|
|
548
|
-
?
|
|
732
|
+
? routes.findLastIndex((r) => r.key === action.source)
|
|
549
733
|
: state.index;
|
|
550
734
|
|
|
551
735
|
if (currentIndex === -1) {
|
|
@@ -558,21 +742,46 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
558
742
|
|
|
559
743
|
// If the route already exists, navigate to it
|
|
560
744
|
let index = -1;
|
|
745
|
+
let historyIndex: number | undefined;
|
|
561
746
|
|
|
562
747
|
const getId = options.routeGetIdList[action.payload.name];
|
|
563
748
|
const id = getId?.({ params: action.payload.params });
|
|
564
749
|
|
|
565
750
|
if (id !== undefined) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
751
|
+
for (let i = currentIndex; i >= 0; i--) {
|
|
752
|
+
const r = routes[i];
|
|
753
|
+
|
|
754
|
+
if (r.name !== action.payload.name) {
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (id === getId?.({ params: r.params })) {
|
|
759
|
+
index = i;
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (r.history?.length) {
|
|
764
|
+
for (let j = r.history.length - 1; j >= 0; j--) {
|
|
765
|
+
if (
|
|
766
|
+
r.history[j].type === 'params' &&
|
|
767
|
+
id === getId?.({ params: r.history[j].params })
|
|
768
|
+
) {
|
|
769
|
+
index = i;
|
|
770
|
+
historyIndex = j;
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (index !== -1) {
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
} else if (routes[currentIndex].name === action.payload.name) {
|
|
572
781
|
index = currentIndex;
|
|
573
782
|
} else {
|
|
574
783
|
for (let i = currentIndex; i >= 0; i--) {
|
|
575
|
-
if (
|
|
784
|
+
if (routes[i].name === action.payload.name) {
|
|
576
785
|
index = i;
|
|
577
786
|
break;
|
|
578
787
|
}
|
|
@@ -581,8 +790,8 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
581
790
|
|
|
582
791
|
// If the route doesn't exist, remove the current route and add the new one
|
|
583
792
|
if (index === -1) {
|
|
584
|
-
// Re-use
|
|
585
|
-
let route =
|
|
793
|
+
// Re-use inactive route if available
|
|
794
|
+
let route = inactiveRoutes.find(
|
|
586
795
|
(route) =>
|
|
587
796
|
route.name === action.payload.name &&
|
|
588
797
|
id === getId?.({ params: route.params })
|
|
@@ -590,21 +799,35 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
590
799
|
|
|
591
800
|
if (!route) {
|
|
592
801
|
route = createRouteFromAction({ action, routeParamList });
|
|
802
|
+
} else {
|
|
803
|
+
const params = createParamsFromAction({ action, routeParamList });
|
|
804
|
+
|
|
805
|
+
if (route.params !== params) {
|
|
806
|
+
route = { ...route, params };
|
|
807
|
+
}
|
|
593
808
|
}
|
|
594
809
|
|
|
595
|
-
const
|
|
810
|
+
const nextRoutes = routes.slice(0, currentIndex).concat(route);
|
|
596
811
|
|
|
597
|
-
return
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
(r) => r.key !== route.key
|
|
603
|
-
)
|
|
604
|
-
|
|
812
|
+
return retainRoutes(
|
|
813
|
+
state,
|
|
814
|
+
getStateWithRoutes(
|
|
815
|
+
state,
|
|
816
|
+
nextRoutes,
|
|
817
|
+
preloadedRoutes.filter((r) => r.key !== route.key)
|
|
818
|
+
)
|
|
819
|
+
);
|
|
605
820
|
}
|
|
606
821
|
|
|
607
|
-
const route =
|
|
822
|
+
const route = routes[index];
|
|
823
|
+
|
|
824
|
+
let baseParams = route.params;
|
|
825
|
+
let history = route.history;
|
|
826
|
+
|
|
827
|
+
if (historyIndex !== undefined && route.history) {
|
|
828
|
+
baseParams = route.history[historyIndex].params;
|
|
829
|
+
history = route.history.slice(0, historyIndex);
|
|
830
|
+
}
|
|
608
831
|
|
|
609
832
|
let params;
|
|
610
833
|
|
|
@@ -614,28 +837,27 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
614
837
|
routeParamList[route.name] !== undefined
|
|
615
838
|
? {
|
|
616
839
|
...routeParamList[route.name],
|
|
617
|
-
...
|
|
840
|
+
...baseParams,
|
|
618
841
|
...action.payload.params,
|
|
619
842
|
}
|
|
620
|
-
:
|
|
843
|
+
: baseParams;
|
|
621
844
|
} else {
|
|
622
845
|
params = createParamsFromAction({ action, routeParamList });
|
|
623
846
|
}
|
|
624
847
|
|
|
625
|
-
return
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
};
|
|
848
|
+
return retainRoutes(
|
|
849
|
+
state,
|
|
850
|
+
getStateWithRoutes(state, [
|
|
851
|
+
...routes.slice(0, index),
|
|
852
|
+
params !== baseParams || historyIndex !== undefined
|
|
853
|
+
? { ...route, params, history }
|
|
854
|
+
: routes[index],
|
|
855
|
+
])
|
|
856
|
+
);
|
|
635
857
|
}
|
|
636
858
|
|
|
637
859
|
case 'GO_BACK':
|
|
638
|
-
if (state.index > 0 ||
|
|
860
|
+
if (state.index > 0 || routes[state.index].history?.length) {
|
|
639
861
|
return router.getStateForAction(
|
|
640
862
|
state,
|
|
641
863
|
{
|
|
@@ -650,45 +872,74 @@ export function StackRouter(options: StackRouterOptions) {
|
|
|
650
872
|
|
|
651
873
|
return null;
|
|
652
874
|
|
|
653
|
-
case '
|
|
654
|
-
const
|
|
655
|
-
const id = getId?.({ params: action.payload.params });
|
|
875
|
+
case 'RETAIN': {
|
|
876
|
+
const routeKey = action.source ?? routes[state.index].key;
|
|
656
877
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (id !== undefined) {
|
|
660
|
-
route = state.routes.find(
|
|
661
|
-
(route) =>
|
|
662
|
-
route.name === action.payload.name &&
|
|
663
|
-
id === getId?.({ params: route.params })
|
|
664
|
-
);
|
|
878
|
+
if (!state.routes.some((route) => route.key === routeKey)) {
|
|
879
|
+
return null;
|
|
665
880
|
}
|
|
666
881
|
|
|
667
|
-
if (
|
|
882
|
+
if (action.payload.enable) {
|
|
883
|
+
if (state.retainedRouteKeys.includes(routeKey)) {
|
|
884
|
+
return state;
|
|
885
|
+
}
|
|
886
|
+
|
|
668
887
|
return {
|
|
669
888
|
...state,
|
|
670
|
-
|
|
671
|
-
if (r.key !== route?.key) {
|
|
672
|
-
return r;
|
|
673
|
-
}
|
|
674
|
-
return {
|
|
675
|
-
...r,
|
|
676
|
-
params: createParamsFromAction({ action, routeParamList }),
|
|
677
|
-
};
|
|
678
|
-
}),
|
|
889
|
+
retainedRouteKeys: [...state.retainedRouteKeys, routeKey],
|
|
679
890
|
};
|
|
680
|
-
}
|
|
681
|
-
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (!state.retainedRouteKeys.includes(routeKey)) {
|
|
894
|
+
return state;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
return getStateWithRoutes(
|
|
898
|
+
{
|
|
682
899
|
...state,
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
900
|
+
retainedRouteKeys: state.retainedRouteKeys.filter(
|
|
901
|
+
(key) => key !== routeKey
|
|
902
|
+
),
|
|
903
|
+
},
|
|
904
|
+
routes,
|
|
905
|
+
preloadedRoutes.filter((route) => route.key !== routeKey)
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
case 'PRELOAD': {
|
|
910
|
+
if (!state.routeNames.includes(action.payload.name)) {
|
|
911
|
+
return null;
|
|
691
912
|
}
|
|
913
|
+
|
|
914
|
+
const getId = options.routeGetIdList[action.payload.name];
|
|
915
|
+
const id = getId?.({ params: action.payload.params });
|
|
916
|
+
const params = createParamsFromAction({ action, routeParamList });
|
|
917
|
+
|
|
918
|
+
const route = preloadedRoutes.findLast(
|
|
919
|
+
(route) =>
|
|
920
|
+
route.name === action.payload.name &&
|
|
921
|
+
(id === undefined || id === getId?.({ params: route.params }))
|
|
922
|
+
);
|
|
923
|
+
|
|
924
|
+
if (route) {
|
|
925
|
+
return getStateWithRoutes(
|
|
926
|
+
state,
|
|
927
|
+
routes,
|
|
928
|
+
preloadedRoutes.map((r) =>
|
|
929
|
+
r.key === route.key && r.params !== params
|
|
930
|
+
? { ...r, params }
|
|
931
|
+
: r
|
|
932
|
+
)
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return getStateWithRoutes(
|
|
937
|
+
state,
|
|
938
|
+
routes,
|
|
939
|
+
preloadedRoutes.concat(
|
|
940
|
+
createRouteFromAction({ action, routeParamList })
|
|
941
|
+
)
|
|
942
|
+
);
|
|
692
943
|
}
|
|
693
944
|
|
|
694
945
|
default:
|