@react-navigation/core 7.0.0-alpha.12 → 7.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.
Files changed (67) hide show
  1. package/lib/commonjs/Group.js.map +1 -1
  2. package/lib/commonjs/Screen.js.map +1 -1
  3. package/lib/commonjs/StaticNavigation.js.map +1 -1
  4. package/lib/commonjs/createNavigatorFactory.js.map +1 -1
  5. package/lib/commonjs/deepFreeze.js +37 -0
  6. package/lib/commonjs/deepFreeze.js.map +1 -0
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/commonjs/types.js.map +1 -1
  9. package/lib/commonjs/useDescriptors.js.map +1 -1
  10. package/lib/commonjs/useFocusEffect.js +2 -2
  11. package/lib/commonjs/useNavigationBuilder.js +3 -2
  12. package/lib/commonjs/useNavigationBuilder.js.map +1 -1
  13. package/lib/commonjs/useRouteCache.js +15 -1
  14. package/lib/commonjs/useRouteCache.js.map +1 -1
  15. package/lib/commonjs/useSyncState.js +12 -3
  16. package/lib/commonjs/useSyncState.js.map +1 -1
  17. package/lib/module/Group.js.map +1 -1
  18. package/lib/module/Screen.js.map +1 -1
  19. package/lib/module/StaticNavigation.js.map +1 -1
  20. package/lib/module/createNavigatorFactory.js +1 -0
  21. package/lib/module/createNavigatorFactory.js.map +1 -1
  22. package/lib/module/deepFreeze.js +29 -0
  23. package/lib/module/deepFreeze.js.map +1 -0
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/types.js.map +1 -1
  26. package/lib/module/useDescriptors.js.map +1 -1
  27. package/lib/module/useFocusEffect.js +2 -2
  28. package/lib/module/useNavigationBuilder.js +3 -2
  29. package/lib/module/useNavigationBuilder.js.map +1 -1
  30. package/lib/module/useRouteCache.js +15 -1
  31. package/lib/module/useRouteCache.js.map +1 -1
  32. package/lib/module/useSyncState.js +12 -3
  33. package/lib/module/useSyncState.js.map +1 -1
  34. package/lib/typescript/src/Group.d.ts +1 -1
  35. package/lib/typescript/src/Group.d.ts.map +1 -1
  36. package/lib/typescript/src/Screen.d.ts +1 -1
  37. package/lib/typescript/src/Screen.d.ts.map +1 -1
  38. package/lib/typescript/src/StaticNavigation.d.ts +17 -15
  39. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  40. package/lib/typescript/src/createNavigatorFactory.d.ts +1 -9
  41. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  42. package/lib/typescript/src/deepFreeze.d.ts +3 -0
  43. package/lib/typescript/src/deepFreeze.d.ts.map +1 -0
  44. package/lib/typescript/src/index.d.ts +1 -1
  45. package/lib/typescript/src/index.d.ts.map +1 -1
  46. package/lib/typescript/src/types.d.ts +59 -22
  47. package/lib/typescript/src/types.d.ts.map +1 -1
  48. package/lib/typescript/src/useDescriptors.d.ts +1 -1
  49. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  50. package/lib/typescript/src/useNavigationBuilder.d.ts +1 -22
  51. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  52. package/lib/typescript/src/useRouteCache.d.ts +1 -1
  53. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  54. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  55. package/package.json +2 -2
  56. package/src/Group.tsx +2 -1
  57. package/src/Screen.tsx +11 -1
  58. package/src/StaticNavigation.tsx +107 -26
  59. package/src/createNavigatorFactory.tsx +1 -36
  60. package/src/deepFreeze.tsx +34 -0
  61. package/src/index.tsx +1 -0
  62. package/src/types.tsx +128 -21
  63. package/src/useDescriptors.tsx +8 -1
  64. package/src/useFocusEffect.tsx +2 -2
  65. package/src/useNavigationBuilder.tsx +12 -6
  66. package/src/useRouteCache.tsx +17 -1
  67. package/src/useSyncState.tsx +16 -3
package/src/types.tsx CHANGED
@@ -24,15 +24,12 @@ type Keyof<T extends {}> = Extract<keyof T, string>;
24
24
 
25
25
  export type DefaultNavigatorOptions<
26
26
  ParamList extends ParamListBase,
27
+ NavigatorID extends string | undefined,
27
28
  State extends NavigationState,
28
29
  ScreenOptions extends {},
29
30
  EventMap extends EventMapBase,
31
+ Navigation,
30
32
  > = DefaultRouterOptions<Keyof<ParamList>> & {
31
- /**
32
- * Optional ID for the navigator. Can be used with `navigation.getParent(id)` to refer to a parent.
33
- */
34
- id?: string;
35
-
36
33
  /**
37
34
  * Children React Elements to extract the route configuration from.
38
35
  * Only `Screen`, `Group` and `React.Fragment` are supported as children.
@@ -71,7 +68,7 @@ export type DefaultNavigatorOptions<
71
68
  | ScreenListeners<State, EventMap>
72
69
  | ((props: {
73
70
  route: RouteProp<ParamList>;
74
- navigation: any;
71
+ navigation: Navigation;
75
72
  }) => ScreenListeners<State, EventMap>);
76
73
 
77
74
  /**
@@ -81,7 +78,7 @@ export type DefaultNavigatorOptions<
81
78
  | ScreenOptions
82
79
  | ((props: {
83
80
  route: RouteProp<ParamList>;
84
- navigation: any;
81
+ navigation: Navigation;
85
82
  theme: ReactNavigation.Theme;
86
83
  }) => ScreenOptions);
87
84
 
@@ -90,7 +87,7 @@ export type DefaultNavigatorOptions<
90
87
  */
91
88
  screenLayout?: (props: {
92
89
  route: RouteProp<ParamList, keyof ParamList>;
93
- navigation: any;
90
+ navigation: Navigation;
94
91
  theme: ReactNavigation.Theme;
95
92
  children: React.ReactElement;
96
93
  }) => React.ReactElement;
@@ -101,7 +98,16 @@ export type DefaultNavigatorOptions<
101
98
  getStateForRouteNamesChange?: (
102
99
  state: NavigationState
103
100
  ) => PartialState<NavigationState> | undefined;
104
- };
101
+ } & (NavigatorID extends string
102
+ ? {
103
+ /**
104
+ * Optional ID for the navigator. Can be used with `navigation.getParent(id)` to refer to a parent.
105
+ */
106
+ id: NavigatorID;
107
+ }
108
+ : {
109
+ id?: undefined;
110
+ });
105
111
 
106
112
  export type EventMapBase = Record<
107
113
  string,
@@ -602,12 +608,13 @@ export type RouteConfigComponent<
602
608
  getComponent?: never;
603
609
  };
604
610
 
605
- export type RouteConfig<
611
+ export type RouteConfigProps<
606
612
  ParamList extends ParamListBase,
607
613
  RouteName extends keyof ParamList,
608
614
  State extends NavigationState,
609
615
  ScreenOptions extends {},
610
616
  EventMap extends EventMapBase,
617
+ Navigation,
611
618
  > = {
612
619
  /**
613
620
  * Optional key for this screen. This doesn't need to be unique.
@@ -628,7 +635,7 @@ export type RouteConfig<
628
635
  | ScreenOptions
629
636
  | ((props: {
630
637
  route: RouteProp<ParamList, RouteName>;
631
- navigation: any;
638
+ navigation: Navigation;
632
639
  theme: ReactNavigation.Theme;
633
640
  }) => ScreenOptions);
634
641
 
@@ -639,7 +646,7 @@ export type RouteConfig<
639
646
  | ScreenListeners<State, EventMap>
640
647
  | ((props: {
641
648
  route: RouteProp<ParamList, RouteName>;
642
- navigation: any;
649
+ navigation: Navigation;
643
650
  }) => ScreenListeners<State, EventMap>);
644
651
 
645
652
  /**
@@ -648,8 +655,8 @@ export type RouteConfig<
648
655
  * e.g. for styling, error boundaries, suspense, etc.
649
656
  */
650
657
  layout?: (props: {
651
- route: RouteProp<ParamList, keyof ParamList>;
652
- navigation: any;
658
+ route: RouteProp<ParamList, RouteName>;
659
+ navigation: Navigation;
653
660
  theme: ReactNavigation.Theme;
654
661
  children: React.ReactElement;
655
662
  }) => React.ReactElement;
@@ -670,11 +677,29 @@ export type RouteConfig<
670
677
  * Initial params object for the route.
671
678
  */
672
679
  initialParams?: Partial<ParamList[RouteName]>;
673
- } & RouteConfigComponent<ParamList, RouteName>;
680
+ };
681
+
682
+ export type RouteConfig<
683
+ ParamList extends ParamListBase,
684
+ RouteName extends keyof ParamList,
685
+ State extends NavigationState,
686
+ ScreenOptions extends {},
687
+ EventMap extends EventMapBase,
688
+ Navigation,
689
+ > = RouteConfigProps<
690
+ ParamList,
691
+ RouteName,
692
+ State,
693
+ ScreenOptions,
694
+ EventMap,
695
+ Navigation
696
+ > &
697
+ RouteConfigComponent<ParamList, RouteName>;
674
698
 
675
699
  export type RouteGroupConfig<
676
700
  ParamList extends ParamListBase,
677
701
  ScreenOptions extends {},
702
+ Navigation,
678
703
  > = {
679
704
  /**
680
705
  * Optional key for the screens in this group.
@@ -689,7 +714,7 @@ export type RouteGroupConfig<
689
714
  | ScreenOptions
690
715
  | ((props: {
691
716
  route: RouteProp<ParamList, keyof ParamList>;
692
- navigation: any;
717
+ navigation: Navigation;
693
718
  theme: ReactNavigation.Theme;
694
719
  }) => ScreenOptions);
695
720
 
@@ -699,7 +724,7 @@ export type RouteGroupConfig<
699
724
  */
700
725
  screenLayout?: (props: {
701
726
  route: RouteProp<ParamList, keyof ParamList>;
702
- navigation: any;
727
+ navigation: Navigation;
703
728
  theme: ReactNavigation.Theme;
704
729
  children: React.ReactElement;
705
730
  }) => React.ReactElement;
@@ -790,11 +815,77 @@ export type NavigationContainerRefWithCurrent<ParamList extends {}> =
790
815
  current: NavigationContainerRef<ParamList> | null;
791
816
  };
792
817
 
818
+ export type NavigationListBase<ParamList extends ParamListBase> = {
819
+ [RouteName in keyof ParamList]: unknown;
820
+ };
821
+
822
+ export type TypeBag<
823
+ ParamList extends ParamListBase,
824
+ NavigatorID extends string | undefined,
825
+ State extends NavigationState,
826
+ ScreenOptions extends {},
827
+ EventMap extends EventMapBase,
828
+ NavigationList extends NavigationListBase<ParamList>,
829
+ Navigator extends React.ComponentType<any>,
830
+ > = {
831
+ ParamList: ParamList;
832
+ NavigatorID: NavigatorID;
833
+ State: State;
834
+ ScreenOptions: ScreenOptions;
835
+ EventMap: EventMap;
836
+ NavigationList: NavigationList;
837
+ Navigator: Navigator;
838
+ };
839
+
840
+ export type NavigatorTypeBagBase = {
841
+ ParamList: ParamListBase;
842
+ NavigatorID: string | undefined;
843
+ State: NavigationState;
844
+ ScreenOptions: {};
845
+ EventMap: EventMapBase;
846
+ NavigationList: NavigationListBase<ParamListBase>;
847
+ Navigator: React.ComponentType<any>;
848
+ };
849
+
850
+ export type NavigatorTypeBag<
851
+ ParamList extends ParamListBase,
852
+ NavigatorID extends string | undefined,
853
+ State extends NavigationState,
854
+ ScreenOptions extends {},
855
+ EventMap extends EventMapBase,
856
+ NavigationList extends NavigationListBase<ParamList>,
857
+ Navigator extends React.ComponentType<any>,
858
+ > = {
859
+ ParamList: ParamList;
860
+ NavigatorID: NavigatorID;
861
+ State: State;
862
+ ScreenOptions: ScreenOptions;
863
+ EventMap: EventMap;
864
+ NavigationList: NavigationList;
865
+ Navigator: Navigator;
866
+ };
867
+
793
868
  export type TypedNavigator<
869
+ Bag extends NavigatorTypeBagBase,
870
+ Config = unknown,
871
+ > = TypedNavigatorInternal<
872
+ Bag['ParamList'],
873
+ Bag['NavigatorID'],
874
+ Bag['State'],
875
+ Bag['ScreenOptions'],
876
+ Bag['EventMap'],
877
+ Bag['NavigationList'],
878
+ Bag['Navigator']
879
+ > &
880
+ (undefined extends Config ? {} : { config: Config });
881
+
882
+ type TypedNavigatorInternal<
794
883
  ParamList extends ParamListBase,
884
+ NavigatorID extends string | undefined,
795
885
  State extends NavigationState,
796
886
  ScreenOptions extends {},
797
887
  EventMap extends EventMapBase,
888
+ NavigationList extends NavigationListBase<ParamList>,
798
889
  Navigator extends React.ComponentType<any>,
799
890
  > = {
800
891
  /**
@@ -803,19 +894,35 @@ export type TypedNavigator<
803
894
  Navigator: React.ComponentType<
804
895
  Omit<
805
896
  React.ComponentProps<Navigator>,
806
- keyof DefaultNavigatorOptions<any, any, any, any>
897
+ keyof DefaultNavigatorOptions<any, any, any, any, any, any>
807
898
  > &
808
- DefaultNavigatorOptions<ParamList, State, ScreenOptions, EventMap>
899
+ DefaultNavigatorOptions<
900
+ ParamList,
901
+ NavigatorID,
902
+ State,
903
+ ScreenOptions,
904
+ EventMap,
905
+ NavigationList[keyof ParamList]
906
+ >
809
907
  >;
810
908
  /**
811
909
  * Component used for grouping multiple route configuration.
812
910
  */
813
- Group: React.ComponentType<RouteGroupConfig<ParamList, ScreenOptions>>;
911
+ Group: React.ComponentType<
912
+ RouteGroupConfig<ParamList, ScreenOptions, NavigationList[keyof ParamList]>
913
+ >;
814
914
  /**
815
915
  * Component used for specifying route configuration.
816
916
  */
817
917
  Screen: <RouteName extends keyof ParamList>(
818
- _: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>
918
+ _: RouteConfig<
919
+ ParamList,
920
+ RouteName,
921
+ State,
922
+ ScreenOptions,
923
+ EventMap,
924
+ NavigationList[RouteName]
925
+ >
819
926
  ) => null;
820
927
  };
821
928
 
@@ -36,7 +36,14 @@ export type ScreenConfigWithParent<
36
36
  keys: (string | undefined)[];
37
37
  options: (ScreenOptionsOrCallback<ScreenOptions> | undefined)[] | undefined;
38
38
  layout: ScreenLayout | undefined;
39
- props: RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>;
39
+ props: RouteConfig<
40
+ ParamListBase,
41
+ string,
42
+ State,
43
+ ScreenOptions,
44
+ EventMap,
45
+ unknown
46
+ >;
40
47
  };
41
48
 
42
49
  type ScreenLayout = (props: {
@@ -71,7 +71,7 @@ export function useFocusEffect(effect: EffectCallback) {
71
71
  }
72
72
  };
73
73
 
74
- // We need to run the effect on intial render/dep changes if the screen is focused
74
+ // We need to run the effect on initial render/dep changes if the screen is focused
75
75
  if (navigation.isFocused()) {
76
76
  cleanup = callback();
77
77
  isFocused = true;
@@ -79,7 +79,7 @@ export function useFocusEffect(effect: EffectCallback) {
79
79
 
80
80
  const unsubscribeFocus = navigation.addListener('focus', () => {
81
81
  // If callback was already called for focus, avoid calling it again
82
- // The focus event may also fire on intial render, so we guard against runing the effect twice
82
+ // The focus event may also fire on initial render, so we guard against running the effect twice
83
83
  if (isFocused) {
84
84
  return;
85
85
  }
@@ -14,6 +14,7 @@ import * as React from 'react';
14
14
  import { isValidElementType } from 'react-is';
15
15
  import useLatestCallback from 'use-latest-callback';
16
16
 
17
+ import { deepFreeze } from './deepFreeze';
17
18
  import { Group } from './Group';
18
19
  import { isArrayEqual } from './isArrayEqual';
19
20
  import { isRecordEqual } from './isRecordEqual';
@@ -102,7 +103,8 @@ const getRouteConfigsFromChildren = <
102
103
  string,
103
104
  State,
104
105
  ScreenOptions,
105
- EventMap
106
+ EventMap,
107
+ unknown
106
108
  >,
107
109
  });
108
110
 
@@ -251,9 +253,11 @@ export function useNavigationBuilder<
251
253
  createRouter: RouterFactory<State, any, RouterOptions>,
252
254
  options: DefaultNavigatorOptions<
253
255
  ParamListBase,
256
+ string | undefined,
254
257
  State,
255
258
  ScreenOptions,
256
- EventMap
259
+ EventMap,
260
+ any
257
261
  > &
258
262
  RouterOptions
259
263
  ) {
@@ -457,7 +461,7 @@ export function useNavigationBuilder<
457
461
 
458
462
  let state =
459
463
  // If the state isn't initialized, or stale, use the state we initialized instead
460
- // The state won't update until there's a change needed in the state we have initalized locally
464
+ // The state won't update until there's a change needed in the state we have initialized locally
461
465
  // So it'll be `undefined` or stale until the first navigation event happens
462
466
  isStateInitialized(currentState)
463
467
  ? (currentState as State)
@@ -582,9 +586,11 @@ export function useNavigationBuilder<
582
586
  const getState = useLatestCallback((): State => {
583
587
  const currentState = shouldUpdate ? nextState : getCurrentState();
584
588
 
585
- return (
586
- isStateInitialized(currentState) ? currentState : initializedState
587
- ) as State;
589
+ return deepFreeze(
590
+ (isStateInitialized(currentState)
591
+ ? currentState
592
+ : initializedState) as State
593
+ );
588
594
  });
589
595
 
590
596
  const emitter = useEventEmitter<EventMapCore<State>>((e) => {
@@ -7,7 +7,7 @@ import type { RouteProp } from './types';
7
7
  type RouteCache = Map<string, RouteProp<ParamListBase>>;
8
8
 
9
9
  /**
10
- * Utilites such as `getFocusedRouteNameFromRoute` need to access state.
10
+ * Utilities such as `getFocusedRouteNameFromRoute` need to access state.
11
11
  * So we need a way to suppress the warning for those use cases.
12
12
  * This is fine since they are internal utilities and this is not public API.
13
13
  */
@@ -41,6 +41,22 @@ export function useRouteCache<State extends NavigationState>(
41
41
  proxy = routeWithoutState;
42
42
  }
43
43
 
44
+ if (process.env.NODE_ENV !== 'production') {
45
+ // FIXME: since the state is updated with mutation, the route object cannot be frozen
46
+ // As a workaround, loop through the object and make the properties readonly
47
+ for (const key in proxy) {
48
+ // @ts-expect-error: this is fine since we are looping through the object
49
+ const value = proxy[key];
50
+
51
+ Object.defineProperty(proxy, key, {
52
+ enumerable: true,
53
+ configurable: true,
54
+ writable: false,
55
+ value,
56
+ });
57
+ }
58
+ }
59
+
44
60
  Object.defineProperty(proxy, CHILD_STATE, {
45
61
  enumerable: false,
46
62
  configurable: true,
@@ -1,14 +1,27 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { deepFreeze } from './deepFreeze';
4
+
3
5
  const createStore = <T,>(getInitialState: () => T) => {
4
6
  const listeners: (() => void)[] = [];
5
7
 
6
- let state: T = getInitialState();
8
+ let initialized = false;
9
+ let state: T;
10
+
11
+ const getState = () => {
12
+ if (initialized) {
13
+ return state;
14
+ }
7
15
 
8
- const getState = () => state;
16
+ initialized = true;
17
+ state = deepFreeze(getInitialState());
18
+
19
+ return state;
20
+ };
9
21
 
10
22
  const setState = (newState: T) => {
11
- state = newState;
23
+ state = deepFreeze(newState);
24
+
12
25
  listeners.forEach((listener) => listener());
13
26
  };
14
27