@react-navigation/core 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.
Files changed (168) hide show
  1. package/lib/module/BaseNavigationContainer.js +14 -7
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/ConsumedParamsContext.js +5 -0
  4. package/lib/module/ConsumedParamsContext.js.map +1 -0
  5. package/lib/module/NavigationBuilderContext.js +1 -0
  6. package/lib/module/NavigationBuilderContext.js.map +1 -1
  7. package/lib/module/NavigationIndependentTree.js +8 -4
  8. package/lib/module/NavigationIndependentTree.js.map +1 -1
  9. package/lib/module/NavigationMetaContext.js +15 -0
  10. package/lib/module/NavigationMetaContext.js.map +1 -0
  11. package/lib/module/NavigationProvider.js +14 -3
  12. package/lib/module/NavigationProvider.js.map +1 -1
  13. package/lib/module/NavigationStateContext.js.map +1 -1
  14. package/lib/module/PreventRemoveProvider.js +3 -3
  15. package/lib/module/PreventRemoveProvider.js.map +1 -1
  16. package/lib/module/SceneView.js +46 -56
  17. package/lib/module/SceneView.js.map +1 -1
  18. package/lib/module/StaticNavigation.js +30 -4
  19. package/lib/module/StaticNavigation.js.map +1 -1
  20. package/lib/module/createNavigatorFactory.js +22 -1
  21. package/lib/module/createNavigatorFactory.js.map +1 -1
  22. package/lib/module/getPathFromState.js +25 -3
  23. package/lib/module/getPathFromState.js.map +1 -1
  24. package/lib/module/getStateFromPath.js +158 -73
  25. package/lib/module/getStateFromPath.js.map +1 -1
  26. package/lib/module/getStateFromRouteParams.js +24 -0
  27. package/lib/module/getStateFromRouteParams.js.map +1 -0
  28. package/lib/module/index.js +2 -1
  29. package/lib/module/index.js.map +1 -1
  30. package/lib/module/theming/useTheme.js +1 -1
  31. package/lib/module/theming/useTheme.js.map +1 -1
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/useCurrentRender.js +1 -1
  34. package/lib/module/useCurrentRender.js.map +1 -1
  35. package/lib/module/useDescriptors.js +12 -43
  36. package/lib/module/useDescriptors.js.map +1 -1
  37. package/lib/module/useFocusEvents.js +1 -1
  38. package/lib/module/useFocusEvents.js.map +1 -1
  39. package/lib/module/useFocusedListenersChildrenAdapter.js +1 -1
  40. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -1
  41. package/lib/module/useIsFocused.js +7 -12
  42. package/lib/module/useIsFocused.js.map +1 -1
  43. package/lib/module/useNavigationBuilder.js +92 -42
  44. package/lib/module/useNavigationBuilder.js.map +1 -1
  45. package/lib/module/useNavigationCache.js +14 -56
  46. package/lib/module/useNavigationCache.js.map +1 -1
  47. package/lib/module/useNavigationHelpers.js +1 -1
  48. package/lib/module/useNavigationHelpers.js.map +1 -1
  49. package/lib/module/useNavigationIndependentTree.js +1 -1
  50. package/lib/module/useNavigationIndependentTree.js.map +1 -1
  51. package/lib/module/useNavigationState.js +4 -2
  52. package/lib/module/useNavigationState.js.map +1 -1
  53. package/lib/module/useOnAction.js +1 -1
  54. package/lib/module/useOnAction.js.map +1 -1
  55. package/lib/module/useOnGetState.js +2 -2
  56. package/lib/module/useOnGetState.js.map +1 -1
  57. package/lib/module/useOnPreventRemove.js +2 -2
  58. package/lib/module/useOnPreventRemove.js.map +1 -1
  59. package/lib/module/useOnRouteFocus.js +1 -1
  60. package/lib/module/useOnRouteFocus.js.map +1 -1
  61. package/lib/module/useOptionsGetters.js +2 -2
  62. package/lib/module/useOptionsGetters.js.map +1 -1
  63. package/lib/module/usePreventRemoveContext.js +1 -1
  64. package/lib/module/usePreventRemoveContext.js.map +1 -1
  65. package/lib/module/useRegisterNavigator.js +1 -1
  66. package/lib/module/useRegisterNavigator.js.map +1 -1
  67. package/lib/module/useScheduleUpdate.js +1 -1
  68. package/lib/module/useScheduleUpdate.js.map +1 -1
  69. package/lib/module/useStateForPath.js +1 -1
  70. package/lib/module/useStateForPath.js.map +1 -1
  71. package/lib/typescript/src/BaseNavigationContainer.d.ts +6 -3
  72. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  73. package/lib/typescript/src/ConsumedParamsContext.d.ts +8 -0
  74. package/lib/typescript/src/ConsumedParamsContext.d.ts.map +1 -0
  75. package/lib/typescript/src/NavigationBuilderContext.d.ts +11 -5
  76. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  77. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts +4 -4
  78. package/lib/typescript/src/NavigationFocusedRouteStateContext.d.ts.map +1 -1
  79. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  80. package/lib/typescript/src/NavigationMetaContext.d.ts +12 -0
  81. package/lib/typescript/src/NavigationMetaContext.d.ts.map +1 -0
  82. package/lib/typescript/src/NavigationProvider.d.ts +4 -4
  83. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  84. package/lib/typescript/src/NavigationStateContext.d.ts +3 -3
  85. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  86. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  87. package/lib/typescript/src/StaticContainer.d.ts +1 -1
  88. package/lib/typescript/src/StaticContainer.d.ts.map +1 -1
  89. package/lib/typescript/src/StaticNavigation.d.ts +33 -19
  90. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  91. package/lib/typescript/src/createNavigatorFactory.d.ts +1 -1
  92. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  93. package/lib/typescript/src/findFocusedRoute.d.ts +3 -3
  94. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  95. package/lib/typescript/src/getActionFromState.d.ts +3 -3
  96. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  97. package/lib/typescript/src/getPathFromState.d.ts +2 -2
  98. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  99. package/lib/typescript/src/getStateFromPath.d.ts +3 -3
  100. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  101. package/lib/typescript/src/getStateFromRouteParams.d.ts +3 -0
  102. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -0
  103. package/lib/typescript/src/index.d.ts +3 -1
  104. package/lib/typescript/src/index.d.ts.map +1 -1
  105. package/lib/typescript/src/types.d.ts +144 -82
  106. package/lib/typescript/src/types.d.ts.map +1 -1
  107. package/lib/typescript/src/useDescriptors.d.ts +12 -25
  108. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  109. package/lib/typescript/src/useIsFocused.d.ts +3 -0
  110. package/lib/typescript/src/useIsFocused.d.ts.map +1 -1
  111. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  112. package/lib/typescript/src/useNavigationBuilder.d.ts +20 -29
  113. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  114. package/lib/typescript/src/useNavigationCache.d.ts +2 -42
  115. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  116. package/lib/typescript/src/useNavigationHelpers.d.ts +18 -16
  117. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  118. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  119. package/lib/typescript/src/useOnAction.d.ts +6 -6
  120. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  121. package/lib/typescript/src/useOnRouteFocus.d.ts +6 -6
  122. package/lib/typescript/src/useOnRouteFocus.d.ts.map +1 -1
  123. package/lib/typescript/src/useRouteCache.d.ts +2 -2
  124. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  125. package/lib/typescript/src/utilities.d.ts +35 -3
  126. package/lib/typescript/src/utilities.d.ts.map +1 -1
  127. package/package.json +20 -18
  128. package/src/BaseNavigationContainer.tsx +332 -326
  129. package/src/ConsumedParamsContext.tsx +10 -0
  130. package/src/NavigationBuilderContext.tsx +14 -8
  131. package/src/NavigationFocusedRouteStateContext.tsx +4 -4
  132. package/src/NavigationIndependentTree.tsx +8 -5
  133. package/src/NavigationMetaContext.tsx +14 -0
  134. package/src/NavigationProvider.tsx +17 -3
  135. package/src/NavigationStateContext.tsx +5 -6
  136. package/src/PreventRemoveProvider.tsx +3 -3
  137. package/src/SceneView.tsx +58 -56
  138. package/src/StaticNavigation.tsx +100 -30
  139. package/src/createNavigatorFactory.tsx +35 -4
  140. package/src/findFocusedRoute.tsx +3 -3
  141. package/src/getActionFromState.tsx +7 -7
  142. package/src/getPathFromState.tsx +53 -9
  143. package/src/getStateFromPath.tsx +255 -97
  144. package/src/getStateFromRouteParams.tsx +60 -0
  145. package/src/index.tsx +2 -1
  146. package/src/theming/useTheme.tsx +1 -1
  147. package/src/types.tsx +330 -187
  148. package/src/useCurrentRender.tsx +1 -1
  149. package/src/useDescriptors.tsx +13 -48
  150. package/src/useFocusEvents.tsx +1 -1
  151. package/src/useFocusedListenersChildrenAdapter.tsx +1 -1
  152. package/src/useIsFocused.tsx +14 -21
  153. package/src/useNavigation.tsx +2 -2
  154. package/src/useNavigationBuilder.tsx +138 -53
  155. package/src/useNavigationCache.tsx +12 -73
  156. package/src/useNavigationHelpers.tsx +1 -1
  157. package/src/useNavigationIndependentTree.tsx +1 -1
  158. package/src/useNavigationState.tsx +6 -4
  159. package/src/useOnAction.tsx +8 -8
  160. package/src/useOnGetState.tsx +2 -2
  161. package/src/useOnPreventRemove.tsx +2 -2
  162. package/src/useOnRouteFocus.tsx +10 -12
  163. package/src/useOptionsGetters.tsx +2 -2
  164. package/src/usePreventRemoveContext.tsx +1 -1
  165. package/src/useRegisterNavigator.tsx +1 -1
  166. package/src/useScheduleUpdate.tsx +1 -3
  167. package/src/useStateForPath.tsx +1 -1
  168. package/src/utilities.tsx +72 -4
@@ -17,7 +17,7 @@ type Options<
17
17
  ScreenOptions extends {},
18
18
  EventMap extends Record<string, any>,
19
19
  > = {
20
- state: State;
20
+ routes: State['routes'];
21
21
  getState: () => State;
22
22
  navigation: NavigationHelpers<ParamListBase> &
23
23
  Partial<NavigationProp<ParamListBase, string, any, any, any>>;
@@ -65,76 +65,15 @@ export function useNavigationCache<
65
65
  EventMap extends Record<string, any>,
66
66
  ActionHelpers extends Record<string, (...args: any) => void>,
67
67
  >({
68
- state,
68
+ routes,
69
69
  getState,
70
70
  navigation,
71
71
  setOptions,
72
72
  router,
73
73
  emitter,
74
74
  }: Options<State, ScreenOptions, EventMap>) {
75
- const parentNavigationHelpers = React.useContext(NavigationContext);
76
- const { stackRef } = React.useContext(NavigationBuilderContext);
77
-
78
- const base = React.useMemo((): NavigationItem<
79
- State,
80
- ScreenOptions,
81
- EventMap,
82
- ActionHelpers
83
- > &
84
- ActionHelpers => {
85
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
86
- const { emit, ...rest } = navigation;
87
-
88
- const actions = {
89
- ...router.actionCreators,
90
- ...CommonActions,
91
- };
92
-
93
- const dispatch = () => {
94
- throw new Error(
95
- 'Actions cannot be dispatched from a placeholder screen.'
96
- );
97
- };
98
-
99
- const helpers = Object.keys(actions).reduce<Record<string, () => void>>(
100
- (acc, name) => {
101
- acc[name] = dispatch;
102
-
103
- return acc;
104
- },
105
- {}
106
- ) as ActionHelpers;
107
-
108
- // @ts-expect-error: type of getParent does not match
109
- return {
110
- ...rest,
111
- ...helpers,
112
- addListener: () => {
113
- // Event listeners are not supported for placeholder screens
114
-
115
- return () => {
116
- // Empty function
117
- };
118
- },
119
- removeListener: () => {
120
- // Event listeners are not supported for placeholder screens
121
- },
122
- dispatch,
123
- getParent: (routeName) => {
124
- if (routeName !== undefined) {
125
- throw new Error(
126
- 'Getting parent by route name is not supported from a placeholder screen.'
127
- );
128
- }
129
-
130
- return parentNavigationHelpers;
131
- },
132
- setOptions: () => {
133
- throw new Error('Options cannot be set from a placeholder screen.');
134
- },
135
- isFocused: () => false,
136
- };
137
- }, [parentNavigationHelpers, navigation, router.actionCreators]);
75
+ const parentNavigationHelpers = React.use(NavigationContext);
76
+ const { stackRef } = React.use(NavigationBuilderContext);
138
77
 
139
78
  // Cache object which holds navigation objects for each screen
140
79
  // We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
@@ -149,10 +88,10 @@ export function useNavigationCache<
149
88
  >,
150
89
  }),
151
90
  // eslint-disable-next-line react-hooks/exhaustive-deps
152
- [base, getState, parentNavigationHelpers, navigation, setOptions, emitter]
91
+ [getState, parentNavigationHelpers, navigation, setOptions, emitter]
153
92
  );
154
93
 
155
- cache.current = state.routes.reduce<
94
+ cache.current = routes.reduce<
156
95
  NavigationCache<State, ScreenOptions, EventMap, ActionHelpers>
157
96
  >((acc, route) => {
158
97
  const previous = cache.current[route.key];
@@ -213,8 +152,11 @@ export function useNavigationCache<
213
152
  {}
214
153
  );
215
154
 
155
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
156
+ const { emit, ...rest } = navigation;
157
+
216
158
  acc[route.key] = {
217
- ...base,
159
+ ...rest,
218
160
  ...helpers,
219
161
  // FIXME: too much work to fix the types for now
220
162
  ...(emitter.create(route.key) as any),
@@ -239,7 +181,7 @@ export function useNavigationCache<
239
181
  }));
240
182
  },
241
183
  isFocused: () => {
242
- const state = base.getState();
184
+ const state = rest.getState();
243
185
 
244
186
  if (state.routes[state.index].key !== route.key) {
245
187
  return false;
@@ -255,8 +197,5 @@ export function useNavigationCache<
255
197
  return acc;
256
198
  }, {});
257
199
 
258
- return {
259
- base,
260
- navigations: cache.current,
261
- };
200
+ return cache.current;
262
201
  }
@@ -41,7 +41,7 @@ export function useNavigationHelpers<
41
41
  router,
42
42
  stateRef,
43
43
  }: Options<State, Action>) {
44
- const parentNavigationHelpers = React.useContext(NavigationContext);
44
+ const parentNavigationHelpers = React.use(NavigationContext);
45
45
 
46
46
  return React.useMemo(() => {
47
47
  const dispatch = (op: Action | ((state: State) => Action)) => {
@@ -3,5 +3,5 @@ import * as React from 'react';
3
3
  import { NavigationIndependentTreeContext } from './NavigationIndependentTreeContext';
4
4
 
5
5
  export function useNavigationIndependentTree() {
6
- return React.useContext(NavigationIndependentTreeContext);
6
+ return React.use(NavigationIndependentTreeContext);
7
7
  }
@@ -35,8 +35,8 @@ type NavigationStateForNested<
35
35
  export function useNavigationState<
36
36
  const T,
37
37
  const Navigator = RootNavigator,
38
- const RouteName extends
39
- keyof NavigationListForNested<Navigator> = keyof NavigationListForNested<Navigator>,
38
+ const RouteName extends keyof NavigationListForNested<Navigator> =
39
+ keyof NavigationListForNested<Navigator>,
40
40
  >(
41
41
  routeName: RouteName,
42
42
  selector: (state: NavigationStateForNested<Navigator, RouteName>) => T
@@ -117,8 +117,9 @@ export function NavigationStateListenerProvider({
117
117
  children: React.ReactNode;
118
118
  }) {
119
119
  const listeners = React.useRef<(() => void)[]>([]);
120
+ const stateRef = React.useRef(state);
120
121
 
121
- const getState = useLatestCallback(() => state);
122
+ const getState = useLatestCallback(() => stateRef.current);
122
123
 
123
124
  const subscribe = useLatestCallback((callback: () => void) => {
124
125
  listeners.current.push(callback);
@@ -128,7 +129,8 @@ export function NavigationStateListenerProvider({
128
129
  };
129
130
  });
130
131
 
131
- React.useEffect(() => {
132
+ React.useLayoutEffect(() => {
133
+ stateRef.current = state;
132
134
  listeners.current.forEach((callback) => callback());
133
135
  }, [state]);
134
136
 
@@ -16,11 +16,11 @@ import type { EventMapCore } from './types';
16
16
  import type { NavigationEventEmitter } from './useEventEmitter';
17
17
  import { shouldPreventRemove, useOnPreventRemove } from './useOnPreventRemove';
18
18
 
19
- type Options = {
20
- router: Router<NavigationState, NavigationAction>;
21
- key?: string;
22
- getState: () => NavigationState;
23
- setState: (state: NavigationState | PartialState<NavigationState>) => void;
19
+ type Options<State extends NavigationState> = {
20
+ router: Router<State, NavigationAction>;
21
+ key?: string | undefined;
22
+ getState: () => State;
23
+ setState: (state: State | PartialState<State>) => void;
24
24
  actionListeners: ChildActionListener[];
25
25
  beforeRemoveListeners: Record<string, ChildBeforeRemoveListener | undefined>;
26
26
  routerConfigOptions: RouterConfigOptions;
@@ -36,7 +36,7 @@ type Options = {
36
36
  *
37
37
  * When the action handler handles as action, it returns `true`, otherwise `false`.
38
38
  */
39
- export function useOnAction({
39
+ export function useOnAction<State extends NavigationState>({
40
40
  router,
41
41
  getState,
42
42
  setState,
@@ -45,13 +45,13 @@ export function useOnAction({
45
45
  beforeRemoveListeners,
46
46
  routerConfigOptions,
47
47
  emitter,
48
- }: Options) {
48
+ }: Options<State>) {
49
49
  const {
50
50
  onAction: onActionParent,
51
51
  onRouteFocus: onRouteFocusParent,
52
52
  addListener: addListenerParent,
53
53
  onDispatchAction,
54
- } = React.useContext(NavigationBuilderContext);
54
+ } = React.use(NavigationBuilderContext);
55
55
 
56
56
  const routerConfigOptionsRef =
57
57
  React.useRef<RouterConfigOptions>(routerConfigOptions);
@@ -14,8 +14,8 @@ type Options = {
14
14
  };
15
15
 
16
16
  export function useOnGetState({ getState, getStateListeners }: Options) {
17
- const { addKeyedListener } = React.useContext(NavigationBuilderContext);
18
- const route = React.useContext(NavigationRouteContext);
17
+ const { addKeyedListener } = React.use(NavigationBuilderContext);
18
+ const route = React.use(NavigationRouteContext);
19
19
  const key = route ? route.key : 'root';
20
20
 
21
21
  const getRehydratedState = React.useCallback(() => {
@@ -78,8 +78,8 @@ export function useOnPreventRemove({
78
78
  emitter,
79
79
  beforeRemoveListeners,
80
80
  }: Options) {
81
- const { addKeyedListener } = React.useContext(NavigationBuilderContext);
82
- const route = React.useContext(NavigationRouteContext);
81
+ const { addKeyedListener } = React.use(NavigationBuilderContext);
82
+ const route = React.use(NavigationRouteContext);
83
83
  const routeKey = route?.key;
84
84
 
85
85
  React.useEffect(() => {
@@ -7,11 +7,11 @@ import * as React from 'react';
7
7
 
8
8
  import { NavigationBuilderContext } from './NavigationBuilderContext';
9
9
 
10
- type Options<Action extends NavigationAction> = {
11
- router: Router<NavigationState, Action>;
12
- getState: () => NavigationState;
13
- setState: (state: NavigationState) => void;
14
- key?: string;
10
+ type Options<State extends NavigationState, Action extends NavigationAction> = {
11
+ router: Router<State, Action>;
12
+ getState: () => State;
13
+ setState: (state: State) => void;
14
+ key?: string | undefined;
15
15
  };
16
16
 
17
17
  /**
@@ -19,13 +19,11 @@ type Options<Action extends NavigationAction> = {
19
19
  * Focus action needs to be treated specially, coz when a nested route is focused,
20
20
  * the parent navigators also needs to be focused.
21
21
  */
22
- export function useOnRouteFocus<Action extends NavigationAction>({
23
- router,
24
- getState,
25
- key: sourceRouteKey,
26
- setState,
27
- }: Options<Action>) {
28
- const { onRouteFocus: onRouteFocusParent } = React.useContext(
22
+ export function useOnRouteFocus<
23
+ State extends NavigationState,
24
+ Action extends NavigationAction,
25
+ >({ router, getState, key: sourceRouteKey, setState }: Options<State, Action>) {
26
+ const { onRouteFocus: onRouteFocusParent } = React.use(
29
27
  NavigationBuilderContext
30
28
  );
31
29
 
@@ -17,8 +17,8 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
17
17
  Record<string, () => object | undefined | null>
18
18
  >({});
19
19
 
20
- const { onOptionsChange } = React.useContext(NavigationBuilderContext);
21
- const { addOptionsGetter: parentAddOptionsGetter } = React.useContext(
20
+ const { onOptionsChange } = React.use(NavigationBuilderContext);
21
+ const { addOptionsGetter: parentAddOptionsGetter } = React.use(
22
22
  NavigationStateContext
23
23
  );
24
24
 
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { PreventRemoveContext } from './PreventRemoveContext';
4
4
 
5
5
  export function usePreventRemoveContext() {
6
- const value = React.useContext(PreventRemoveContext);
6
+ const value = React.use(PreventRemoveContext);
7
7
 
8
8
  if (value == null) {
9
9
  throw new Error(
@@ -9,7 +9,7 @@ import { SingleNavigatorContext } from './EnsureSingleNavigator';
9
9
  */
10
10
  export function useRegisterNavigator() {
11
11
  const [key] = React.useState(() => nanoid());
12
- const container = React.useContext(SingleNavigatorContext);
12
+ const container = React.use(SingleNavigatorContext);
13
13
 
14
14
  if (container === undefined) {
15
15
  throw new Error(
@@ -10,9 +10,7 @@ import { NavigationBuilderContext } from './NavigationBuilderContext';
10
10
  * Then we call setState during after the component updates.
11
11
  */
12
12
  export function useScheduleUpdate(callback: () => void) {
13
- const { scheduleUpdate, flushUpdates } = React.useContext(
14
- NavigationBuilderContext
15
- );
13
+ const { scheduleUpdate, flushUpdates } = React.use(NavigationBuilderContext);
16
14
 
17
15
  // FIXME: This is potentially unsafe
18
16
  // However, since we are using sync store, it might be fine
@@ -9,7 +9,7 @@ import { NavigationFocusedRouteStateContext } from './NavigationFocusedRouteStat
9
9
  * @returns Minimal state to build a path for the current route.
10
10
  */
11
11
  export function useStateForPath() {
12
- const state = React.useContext(NavigationFocusedRouteStateContext);
12
+ const state = React.use(NavigationFocusedRouteStateContext);
13
13
 
14
14
  return state;
15
15
  }
package/src/utilities.tsx CHANGED
@@ -66,6 +66,24 @@ type ExtractSegmentParam<Segment extends string> =
66
66
  ? { [K in StripRegex<Param>]: string }
67
67
  : {};
68
68
 
69
+ export type StandardSchemaValidationResult<Output> =
70
+ | { value: Output; issues?: undefined }
71
+ | { value?: undefined; issues: readonly unknown[] };
72
+
73
+ export type StandardSchemaV1<Input = unknown, Output = Input> = {
74
+ readonly '~standard': {
75
+ readonly version: 1;
76
+ readonly vendor: string;
77
+ readonly validate: (
78
+ value: Input
79
+ ) =>
80
+ | StandardSchemaValidationResult<Output>
81
+ | Promise<StandardSchemaValidationResult<Output>>;
82
+ };
83
+ };
84
+
85
+ export type QueryParamInput = string | string[] | null | undefined;
86
+
69
87
  /**
70
88
  * Extract path params from a path string.
71
89
  * e.g. `/foo/:userId/:postId` -> `{ userId: string; postId: string }`
@@ -78,17 +96,67 @@ export type ExtractParamStrings<Path extends string> =
78
96
  : ExtractSegmentParam<Path>;
79
97
 
80
98
  /**
81
- * Extract the parsed params type from base params and parse functions.
82
- * Applies the return type of parse functions to the corresponding params.
99
+ * Get the type of params based on the `parse` config and the path pattern.
83
100
  */
84
101
  export type ExtractParamsType<Params, Parse> = {
102
+ /**
103
+ * Base param types from path pattern
104
+ * Refine the type based on standard schema, then parse function
105
+ * Otherwise, use the type from path pattern
106
+ */
85
107
  [K in keyof Params]: K extends keyof Parse
86
- ? Parse[K] extends (value: string) => infer R
108
+ ? Parse[K] extends StandardSchemaV1<unknown, infer R>
87
109
  ? R
88
- : Params[K]
110
+ : Parse[K] extends (value: string) => infer R
111
+ ? R
112
+ : Params[K]
89
113
  : Params[K];
114
+ } & {
115
+ /**
116
+ * Optional param types not in path pattern (for query params)
117
+ */
118
+ [K in QueryParamOptionalKeys<Params, Parse>]?: QueryParamValue<Parse[K]>;
119
+ } & {
120
+ /**
121
+ * Required param types not in path pattern (for query params)
122
+ */
123
+ [K in QueryParamRequiredKeys<Params, Parse>]: QueryParamValue<Parse[K]>;
90
124
  };
91
125
 
126
+ type QueryParamValue<ParseValue> =
127
+ ParseValue extends StandardSchemaV1<unknown, infer R>
128
+ ? R
129
+ : ParseValue extends (value: string) => infer R
130
+ ? R
131
+ : never;
132
+
133
+ /**
134
+ * For schema, it's optional if the output has `undefined`, otherwise required
135
+ * For parse function, it's always optional as it can't say if it's required or not
136
+ */
137
+ type QueryParamOptionalKeys<Params, Parse> = {
138
+ [K in Exclude<keyof Parse, keyof Params>]: Parse[K] extends StandardSchemaV1<
139
+ unknown,
140
+ infer R
141
+ >
142
+ ? undefined extends R
143
+ ? K
144
+ : never
145
+ : Parse[K] extends (value: string) => unknown
146
+ ? K
147
+ : never;
148
+ }[Exclude<keyof Parse, keyof Params>];
149
+
150
+ /**
151
+ * Exclude optional keys to get required keys
152
+ * For schema, it's required if the output doesn't have `undefined`, otherwise optional
153
+ * It doesn't include parse functions (as they are always optional)
154
+ */
155
+ type QueryParamRequiredKeys<Params, Parse> = Exclude<
156
+ Exclude<keyof Parse, keyof Params>,
157
+ QueryParamOptionalKeys<Params, Parse>
158
+ >;
159
+
92
160
  /**
93
161
  * Infer the path string from a linking config.
94
162
  */