@react-navigation/core 7.17.2 → 7.17.4
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/StaticNavigation.js +0 -19
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/checkSerializable.js +11 -4
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/getActionFromState.js +15 -2
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +98 -74
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +55 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useEventEmitter.js +28 -29
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +48 -47
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useRouteCache.js +2 -1
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +2 -63
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/checkSerializable.d.ts +5 -3
- package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +102 -2
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/StaticNavigation.tsx +1 -91
- package/src/checkSerializable.tsx +22 -12
- package/src/getActionFromState.tsx +20 -4
- package/src/getStateFromPath.tsx +147 -100
- package/src/index.tsx +0 -1
- package/src/types.tsx +138 -4
- package/src/useEventEmitter.tsx +33 -38
- package/src/useNavigationBuilder.tsx +77 -76
- package/src/useRouteCache.tsx +2 -1
|
@@ -63,6 +63,14 @@ type NavigatorRoute = {
|
|
|
63
63
|
params?: NavigatorScreenParams<ParamListBase>;
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
const isNavigationState = (
|
|
67
|
+
state: unknown
|
|
68
|
+
): state is NavigationState | PartialState<NavigationState> =>
|
|
69
|
+
state != null &&
|
|
70
|
+
typeof state === 'object' &&
|
|
71
|
+
'routes' in state &&
|
|
72
|
+
Array.isArray(state.routes);
|
|
73
|
+
|
|
66
74
|
const isScreen = (
|
|
67
75
|
child: React.ReactElement<unknown>
|
|
68
76
|
): child is React.ReactElement<{
|
|
@@ -279,8 +287,10 @@ const getRouteConfigsFromChildren = <
|
|
|
279
287
|
};
|
|
280
288
|
|
|
281
289
|
const getStateFromParams = (params: NavigatorRoute['params']) => {
|
|
282
|
-
|
|
283
|
-
|
|
290
|
+
const state = params?.state;
|
|
291
|
+
|
|
292
|
+
if (isNavigationState(state)) {
|
|
293
|
+
return state;
|
|
284
294
|
} else if (typeof params?.screen === 'string' && params?.initial !== false) {
|
|
285
295
|
return {
|
|
286
296
|
routes: [
|
|
@@ -376,44 +386,7 @@ export function useNavigationBuilder<
|
|
|
376
386
|
return original;
|
|
377
387
|
});
|
|
378
388
|
|
|
379
|
-
const screens = routeConfigs.reduce<
|
|
380
|
-
Record<string, ScreenConfigWithParent<State, ScreenOptions, EventMap>>
|
|
381
|
-
>((acc, config) => {
|
|
382
|
-
if (config.props.name in acc) {
|
|
383
|
-
throw new Error(
|
|
384
|
-
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${config.props.name}')`
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
acc[config.props.name] = config;
|
|
389
|
-
return acc;
|
|
390
|
-
}, {});
|
|
391
|
-
|
|
392
389
|
const routeNames = routeConfigs.map((config) => config.props.name);
|
|
393
|
-
const routeKeyList = routeNames.reduce<Record<string, React.Key | undefined>>(
|
|
394
|
-
(acc, curr) => {
|
|
395
|
-
acc[curr] = screens[curr].keys.map((key) => key ?? '').join(':');
|
|
396
|
-
return acc;
|
|
397
|
-
},
|
|
398
|
-
{}
|
|
399
|
-
);
|
|
400
|
-
const routeParamList = routeNames.reduce<Record<string, object | undefined>>(
|
|
401
|
-
(acc, curr) => {
|
|
402
|
-
const { initialParams } = screens[curr].props;
|
|
403
|
-
acc[curr] = initialParams;
|
|
404
|
-
return acc;
|
|
405
|
-
},
|
|
406
|
-
{}
|
|
407
|
-
);
|
|
408
|
-
const routeGetIdList = routeNames.reduce<
|
|
409
|
-
RouterConfigOptions['routeGetIdList']
|
|
410
|
-
>(
|
|
411
|
-
(acc, curr) =>
|
|
412
|
-
Object.assign(acc, {
|
|
413
|
-
[curr]: screens[curr].props.getId,
|
|
414
|
-
}),
|
|
415
|
-
{}
|
|
416
|
-
);
|
|
417
390
|
|
|
418
391
|
if (!routeNames.length) {
|
|
419
392
|
throw new Error(
|
|
@@ -421,6 +394,31 @@ export function useNavigationBuilder<
|
|
|
421
394
|
);
|
|
422
395
|
}
|
|
423
396
|
|
|
397
|
+
const screens: Record<
|
|
398
|
+
string,
|
|
399
|
+
ScreenConfigWithParent<State, ScreenOptions, EventMap>
|
|
400
|
+
> = {};
|
|
401
|
+
|
|
402
|
+
const routeKeyList: Record<string, React.Key | undefined> = {};
|
|
403
|
+
const routeParamList: Record<string, object | undefined> = {};
|
|
404
|
+
const routeGetIdList: RouterConfigOptions['routeGetIdList'] = {};
|
|
405
|
+
|
|
406
|
+
for (const config of routeConfigs) {
|
|
407
|
+
const name = config.props.name;
|
|
408
|
+
|
|
409
|
+
if (name in screens) {
|
|
410
|
+
throw new Error(
|
|
411
|
+
`A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named '${name}')`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
screens[name] = config;
|
|
416
|
+
routeKeyList[name] = config.keys.map((key) => key ?? '').join(':');
|
|
417
|
+
routeParamList[name] = config.props.initialParams;
|
|
418
|
+
|
|
419
|
+
Object.assign(routeGetIdList, { [name]: config.props.getId });
|
|
420
|
+
}
|
|
421
|
+
|
|
424
422
|
const isStateValid = React.useCallback(
|
|
425
423
|
(state: NavigationState | PartialState<NavigationState>) =>
|
|
426
424
|
state.type === undefined || state.type === router.type,
|
|
@@ -659,24 +657,21 @@ export function useNavigationBuilder<
|
|
|
659
657
|
|
|
660
658
|
if (route?.params && !didConsumeNestedParams) {
|
|
661
659
|
let action: CommonActions.Action | undefined;
|
|
660
|
+
const stateFromParams = route.params.state;
|
|
662
661
|
|
|
663
|
-
if (
|
|
664
|
-
typeof route.params.state === 'object' &&
|
|
665
|
-
route.params.state != null &&
|
|
666
|
-
!isNestedParamsConsumed
|
|
667
|
-
) {
|
|
662
|
+
if (isNavigationState(stateFromParams) && !isNestedParamsConsumed) {
|
|
668
663
|
didConsumeNestedParams = true;
|
|
669
664
|
|
|
670
665
|
if (
|
|
671
666
|
options.UNSTABLE_routeNamesChangeBehavior === 'lastUnhandled' &&
|
|
672
|
-
doesStateHaveOnlyInvalidRoutes(
|
|
667
|
+
doesStateHaveOnlyInvalidRoutes(stateFromParams)
|
|
673
668
|
) {
|
|
674
|
-
if (
|
|
675
|
-
setUnhandledState(
|
|
669
|
+
if (stateFromParams !== unhandledState) {
|
|
670
|
+
setUnhandledState(stateFromParams);
|
|
676
671
|
}
|
|
677
672
|
} else {
|
|
678
673
|
// If the route was updated with new state, we should reset to it
|
|
679
|
-
action = CommonActions.reset(
|
|
674
|
+
action = CommonActions.reset(stateFromParams);
|
|
680
675
|
}
|
|
681
676
|
} else if (
|
|
682
677
|
typeof route.params.screen === 'string' &&
|
|
@@ -835,35 +830,41 @@ export function useNavigationBuilder<
|
|
|
835
830
|
return;
|
|
836
831
|
}
|
|
837
832
|
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
833
|
+
const hasPerScreenListeners = routeNames.some(
|
|
834
|
+
(name) => screens[name].props.listeners != null
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
if (screenListeners != null || hasPerScreenListeners) {
|
|
838
|
+
const navigation = descriptors[route.key].navigation;
|
|
839
|
+
|
|
840
|
+
const listeners = ([] as (((e: any) => void) | undefined)[])
|
|
841
|
+
.concat(
|
|
842
|
+
// Get an array of listeners for all screens + common listeners on navigator
|
|
843
|
+
...[
|
|
844
|
+
screenListeners,
|
|
845
|
+
...routeNames.map((name) => {
|
|
846
|
+
const { listeners } = screens[name].props;
|
|
847
|
+
return listeners;
|
|
848
|
+
}),
|
|
849
|
+
].map((listeners) => {
|
|
850
|
+
const map =
|
|
851
|
+
typeof listeners === 'function'
|
|
852
|
+
? listeners({ route: route as any, navigation })
|
|
853
|
+
: listeners;
|
|
854
|
+
|
|
855
|
+
return map
|
|
856
|
+
? Object.keys(map)
|
|
857
|
+
.filter((type) => type === e.type)
|
|
858
|
+
.map((type) => map?.[type])
|
|
859
|
+
: undefined;
|
|
860
|
+
})
|
|
861
|
+
)
|
|
862
|
+
// We don't want same listener to be called multiple times for same event
|
|
863
|
+
// So we remove any duplicate functions from the array
|
|
864
|
+
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
|
|
865
865
|
|
|
866
|
-
|
|
866
|
+
listeners.forEach((listener) => listener?.(e));
|
|
867
|
+
}
|
|
867
868
|
});
|
|
868
869
|
|
|
869
870
|
useFocusEvents({ state, emitter });
|
package/src/useRouteCache.tsx
CHANGED
|
@@ -36,9 +36,10 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
36
36
|
proxy = routeWithoutState;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
39
|
+
if (process.env.NODE_ENV !== 'production' && proxy !== previous) {
|
|
40
40
|
// FIXME: since the state is updated with mutation, the route object cannot be frozen
|
|
41
41
|
// As a workaround, loop through the object and make the properties readonly
|
|
42
|
+
// Only needed once per proxy - skip if we're reusing a previously-frozen one
|
|
42
43
|
for (const key in proxy) {
|
|
43
44
|
// @ts-expect-error: this is fine since we are looping through the object
|
|
44
45
|
const value = proxy[key];
|