@react-navigation/core 8.0.0-alpha.24 → 8.0.0-alpha.25

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 (136) hide show
  1. package/lib/module/BaseNavigationContainer.js +5 -2
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/DataLoading.js +102 -0
  4. package/lib/module/DataLoading.js.map +1 -0
  5. package/lib/module/NavigationIndependentTree.js +7 -6
  6. package/lib/module/NavigationIndependentTree.js.map +1 -1
  7. package/lib/module/NavigationProvider.js +12 -12
  8. package/lib/module/NavigationProvider.js.map +1 -1
  9. package/lib/module/PreventRemoveContext.js.map +1 -1
  10. package/lib/module/PreventRemoveProvider.js +34 -24
  11. package/lib/module/PreventRemoveProvider.js.map +1 -1
  12. package/lib/module/StaticNavigation.js +14 -6
  13. package/lib/module/StaticNavigation.js.map +1 -1
  14. package/lib/module/StaticTreeContext.js +5 -0
  15. package/lib/module/StaticTreeContext.js.map +1 -0
  16. package/lib/module/checkSerializable.js +7 -9
  17. package/lib/module/checkSerializable.js.map +1 -1
  18. package/lib/module/createNavigationContainerRef.js +6 -8
  19. package/lib/module/createNavigationContainerRef.js.map +1 -1
  20. package/lib/module/createNavigatorFactory.js.map +1 -1
  21. package/lib/module/getActionFromState.js +11 -11
  22. package/lib/module/getActionFromState.js.map +1 -1
  23. package/lib/module/getPathFromState.js +38 -39
  24. package/lib/module/getPathFromState.js.map +1 -1
  25. package/lib/module/getPatternParts.js +2 -2
  26. package/lib/module/getPatternParts.js.map +1 -1
  27. package/lib/module/getStateFromPath.js +72 -45
  28. package/lib/module/getStateFromPath.js.map +1 -1
  29. package/lib/module/index.js +1 -0
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/module/types.js.map +1 -1
  32. package/lib/module/useEventEmitter.js +1 -1
  33. package/lib/module/useEventEmitter.js.map +1 -1
  34. package/lib/module/useKeyedChildListeners.js +4 -2
  35. package/lib/module/useKeyedChildListeners.js.map +1 -1
  36. package/lib/module/useNavigation.js +2 -15
  37. package/lib/module/useNavigation.js.map +1 -1
  38. package/lib/module/useNavigationBuilder.js +4 -14
  39. package/lib/module/useNavigationBuilder.js.map +1 -1
  40. package/lib/module/useNavigationCache.js +19 -14
  41. package/lib/module/useNavigationCache.js.map +1 -1
  42. package/lib/module/useNavigationHelpers.js +27 -9
  43. package/lib/module/useNavigationHelpers.js.map +1 -1
  44. package/lib/module/useNavigationState.js +69 -36
  45. package/lib/module/useNavigationState.js.map +1 -1
  46. package/lib/module/useOnAction.js +21 -2
  47. package/lib/module/useOnAction.js.map +1 -1
  48. package/lib/module/useOptionsGetters.js +3 -1
  49. package/lib/module/useOptionsGetters.js.map +1 -1
  50. package/lib/module/usePreventRemove.js +9 -2
  51. package/lib/module/usePreventRemove.js.map +1 -1
  52. package/lib/module/useRouteCache.js +14 -7
  53. package/lib/module/useRouteCache.js.map +1 -1
  54. package/lib/module/useScheduleUpdate.js +8 -8
  55. package/lib/module/useScheduleUpdate.js.map +1 -1
  56. package/lib/module/useSyncState.js +4 -1
  57. package/lib/module/useSyncState.js.map +1 -1
  58. package/lib/module/validatePathConfig.js.map +1 -1
  59. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  60. package/lib/typescript/src/DataLoading.d.ts +20 -0
  61. package/lib/typescript/src/DataLoading.d.ts.map +1 -0
  62. package/lib/typescript/src/NavigationProvider.d.ts +0 -1
  63. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  64. package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
  65. package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
  66. package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
  67. package/lib/typescript/src/StaticNavigation.d.ts +65 -39
  68. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  69. package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
  70. package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
  71. package/lib/typescript/src/checkSerializable.d.ts +4 -2
  72. package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
  73. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  74. package/lib/typescript/src/createNavigatorFactory.d.ts +9 -5
  75. package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
  76. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  77. package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
  78. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  79. package/lib/typescript/src/index.d.ts +2 -1
  80. package/lib/typescript/src/index.d.ts.map +1 -1
  81. package/lib/typescript/src/types.d.ts +19 -13
  82. package/lib/typescript/src/types.d.ts.map +1 -1
  83. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  84. package/lib/typescript/src/useNavigation.d.ts.map +1 -1
  85. package/lib/typescript/src/useNavigationBuilder.d.ts +1 -1
  86. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  87. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  88. package/lib/typescript/src/useNavigationHelpers.d.ts +3 -4
  89. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  90. package/lib/typescript/src/useNavigationState.d.ts +11 -1
  91. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  92. package/lib/typescript/src/useOnAction.d.ts.map +1 -1
  93. package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
  94. package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
  95. package/lib/typescript/src/usePreventRemoveContext.d.ts +1 -0
  96. package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
  97. package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
  98. package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
  99. package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
  100. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  101. package/lib/typescript/src/utilities.d.ts +17 -0
  102. package/lib/typescript/src/utilities.d.ts.map +1 -1
  103. package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
  104. package/package.json +3 -5
  105. package/src/BaseNavigationContainer.tsx +9 -2
  106. package/src/DataLoading.tsx +139 -0
  107. package/src/NavigationIndependentTree.tsx +11 -11
  108. package/src/NavigationProvider.tsx +13 -16
  109. package/src/PreventRemoveContext.tsx +1 -0
  110. package/src/PreventRemoveProvider.tsx +48 -43
  111. package/src/StaticNavigation.tsx +157 -93
  112. package/src/StaticTreeContext.tsx +7 -0
  113. package/src/checkSerializable.tsx +20 -14
  114. package/src/createNavigationContainerRef.tsx +12 -9
  115. package/src/createNavigatorFactory.tsx +16 -28
  116. package/src/getActionFromState.tsx +18 -16
  117. package/src/getPathFromState.tsx +69 -65
  118. package/src/getPatternParts.tsx +2 -2
  119. package/src/getStateFromPath.tsx +107 -66
  120. package/src/index.tsx +2 -0
  121. package/src/types.tsx +62 -50
  122. package/src/useEventEmitter.tsx +1 -1
  123. package/src/useKeyedChildListeners.tsx +4 -2
  124. package/src/useNavigation.tsx +2 -21
  125. package/src/useNavigationBuilder.tsx +6 -16
  126. package/src/useNavigationCache.tsx +26 -19
  127. package/src/useNavigationHelpers.tsx +26 -9
  128. package/src/useNavigationState.tsx +90 -60
  129. package/src/useOnAction.tsx +49 -1
  130. package/src/useOptionsGetters.tsx +4 -1
  131. package/src/usePreventRemove.tsx +11 -2
  132. package/src/useRouteCache.tsx +19 -11
  133. package/src/useScheduleUpdate.tsx +8 -7
  134. package/src/useSyncState.tsx +5 -1
  135. package/src/utilities.tsx +28 -0
  136. package/src/validatePathConfig.tsx +1 -0
@@ -1,16 +1,18 @@
1
- type Result =
2
- | { serializable: true }
3
- | {
4
- serializable: false;
5
- location: (string | number)[];
6
- reason: string;
7
- };
1
+ type Success = { serializable: true };
2
+
3
+ type Failure = {
4
+ serializable: false;
5
+ location: (string | number)[];
6
+ reason: string;
7
+ };
8
+
9
+ type Result = Success | Failure;
8
10
 
9
11
  const checkSerializableWithoutCircularReference = (
10
12
  o: { [key: string]: any },
11
13
  seen: Set<any>,
12
14
  location: (string | number)[]
13
- ): Result => {
15
+ ): Failure | undefined => {
14
16
  if (
15
17
  o === undefined ||
16
18
  o === null ||
@@ -18,7 +20,7 @@ const checkSerializableWithoutCircularReference = (
18
20
  typeof o === 'number' ||
19
21
  typeof o === 'string'
20
22
  ) {
21
- return { serializable: true };
23
+ return undefined;
22
24
  }
23
25
 
24
26
  if (
@@ -52,7 +54,7 @@ const checkSerializableWithoutCircularReference = (
52
54
  );
53
55
  location.pop();
54
56
 
55
- if (!childResult.serializable) {
57
+ if (childResult) {
56
58
  seen.delete(o);
57
59
  return childResult;
58
60
  }
@@ -67,7 +69,7 @@ const checkSerializableWithoutCircularReference = (
67
69
  );
68
70
  location.pop();
69
71
 
70
- if (!childResult.serializable) {
72
+ if (childResult) {
71
73
  seen.delete(o);
72
74
  return childResult;
73
75
  }
@@ -76,9 +78,13 @@ const checkSerializableWithoutCircularReference = (
76
78
 
77
79
  seen.delete(o);
78
80
 
79
- return { serializable: true };
81
+ return undefined;
80
82
  };
81
83
 
82
- export function checkSerializable(o: { [key: string]: any }) {
83
- return checkSerializableWithoutCircularReference(o, new Set<any>(), []);
84
+ export function checkSerializable(o: { [key: string]: any }): Result {
85
+ return (
86
+ checkSerializableWithoutCircularReference(o, new Set<any>(), []) ?? {
87
+ serializable: true,
88
+ }
89
+ );
84
90
  }
@@ -30,6 +30,8 @@ export function createNavigationContainerRef<
30
30
 
31
31
  const listeners: Record<string, ((...args: any[]) => void)[]> = {};
32
32
 
33
+ let current: NavigationContainerRef<ParamList> | null = null;
34
+
33
35
  const removeListener = (
34
36
  event: string,
35
37
  callback: (...args: any[]) => void
@@ -37,9 +39,12 @@ export function createNavigationContainerRef<
37
39
  if (listeners[event]) {
38
40
  listeners[event] = listeners[event].filter((cb) => cb !== callback);
39
41
  }
40
- };
41
42
 
42
- let current: NavigationContainerRef<ParamList> | null = null;
43
+ current?.removeListener(
44
+ event as keyof NavigationContainerEventMap,
45
+ callback
46
+ );
47
+ };
43
48
 
44
49
  const ref: NavigationContainerRefWithCurrent<ParamList> = {
45
50
  get current() {
@@ -68,7 +73,11 @@ export function createNavigationContainerRef<
68
73
  },
69
74
  ...methods.reduce<any>((acc, name) => {
70
75
  acc[name] = (...args: any[]) => {
71
- if (current == null) {
76
+ if (name === 'removeListener') {
77
+ const [event, callback] = args;
78
+
79
+ removeListener(event, callback);
80
+ } else if (current == null) {
72
81
  switch (name) {
73
82
  case 'addListener': {
74
83
  const [event, callback] = args;
@@ -78,12 +87,6 @@ export function createNavigationContainerRef<
78
87
 
79
88
  return () => removeListener(event, callback);
80
89
  }
81
- case 'removeListener': {
82
- const [event, callback] = args;
83
-
84
- removeListener(event, callback);
85
- break;
86
- }
87
90
  default:
88
91
  console.error(NOT_INITIALIZED_ERROR);
89
92
  }
@@ -5,6 +5,7 @@ import { Group } from './Group';
5
5
  import { Screen } from './Screen';
6
6
  import {
7
7
  createComponentForStaticConfig,
8
+ type NoExcessStaticConfig,
8
9
  type StaticConfig,
9
10
  type StaticParamList,
10
11
  } from './StaticNavigation';
@@ -14,25 +15,24 @@ import type {
14
15
  NestedNavigatorsForParamList,
15
16
  TypedNavigator,
16
17
  } from './types';
17
- import type { KeysOf } from './utilities';
18
+ import type { KeysOf, NoExcessObject } from './utilities';
18
19
 
19
- type ValidNavigatorNesting<
20
- ParamList extends ParamListBase,
21
- Nesting,
22
- > = Nesting extends Partial<Record<keyof ParamList, unknown>> &
23
- Record<Exclude<keyof Nesting, keyof ParamList>, never>
24
- ? Nesting
25
- : never;
20
+ type NavigatorNesting<ParamList extends ParamListBase, Nesting> = {
21
+ [RouteName in keyof ParamList]?: unknown;
22
+ } & Record<Exclude<KeysOf<Nesting>, keyof ParamList>, never>;
23
+
24
+ type ValidNavigatorNesting<ParamList extends ParamListBase, Nesting> =
25
+ Nesting extends NavigatorNesting<ParamList, Nesting> ? Nesting : never;
26
+
27
+ type AnyStaticConfig<TypeBag extends NavigatorTypeBagBase> = StaticConfig<
28
+ NavigatorTypeBagFor<TypeBag, ParamListBase>
29
+ >;
26
30
 
27
31
  export type TypedNavigatorFactory<in out TypeBag extends NavigatorTypeBagBase> =
28
32
  {
29
33
  <
30
34
  const ParamList extends ParamListBase,
31
- const Nesting extends Partial<Record<keyof ParamList, unknown>> &
32
- // Extra keys satisfy the structural constraint via width subtyping,
33
- // Force any key in `Nesting` that isn't in the param list to `never`.
34
- // So typos in the nesting config will cause an error.
35
- Record<Exclude<keyof Nesting, keyof ParamList>, never> =
35
+ const Nesting extends NavigatorNesting<ParamList, Nesting> =
36
36
  ValidNavigatorNesting<
37
37
  ParamList,
38
38
  NestedNavigatorsForParamList<ParamList>
@@ -43,22 +43,10 @@ export type TypedNavigatorFactory<in out TypeBag extends NavigatorTypeBagBase> =
43
43
  Nesting
44
44
  >;
45
45
  <
46
- const Config extends StaticConfig<
47
- NavigatorTypeBagFor<TypeBag, ParamListBase>
48
- > &
49
- // TS only checks for excess properties for non-generic object literal types.
50
- // Since `Config` is generic, extra keys satisfy the constraint and slip through.
51
- // So we force any key in `Config` that isn't a known key to have the type `never`,
52
- // Thus causing an error for any extra key.
53
- Record<
54
- Exclude<
55
- keyof Config,
56
- KeysOf<StaticConfig<NavigatorTypeBagFor<TypeBag, ParamListBase>>>
57
- >,
58
- never
59
- >,
46
+ const Config extends AnyStaticConfig<TypeBag> &
47
+ NoExcessObject<Config, AnyStaticConfig<TypeBag>>,
60
48
  >(
61
- config: Config
49
+ config: Config & NoExcessStaticConfig<NoInfer<Config>, TypeBag>
62
50
  ): TypedNavigator<
63
51
  NavigatorTypeBagFor<TypeBag, StaticParamList<{ config: Config }>>,
64
52
  Config
@@ -51,25 +51,27 @@ export function getActionFromState(
51
51
  normalizedConfig = {};
52
52
  }
53
53
 
54
- const routes =
55
- state.index != null ? state.routes.slice(0, state.index + 1) : state.routes;
54
+ const routesLength =
55
+ state.index == null || state.index >= state.routes.length
56
+ ? state.routes.length
57
+ : state.index + 1;
56
58
 
57
- if (routes.length === 0) {
59
+ if (routesLength === 0) {
58
60
  return undefined;
59
61
  }
60
62
 
61
- const firstRoute = routes[0];
63
+ const firstRoute = state.routes[0];
62
64
 
63
65
  if (firstRoute == null) {
64
66
  return undefined;
65
67
  }
66
68
 
67
- const secondRoute = routes[1];
69
+ const secondRoute = state.routes[1];
68
70
 
69
71
  if (
70
72
  !(
71
- (routes.length === 1 && firstRoute.key == null) ||
72
- (routes.length === 2 &&
73
+ (routesLength === 1 && firstRoute.key == null) ||
74
+ (routesLength === 2 &&
73
75
  firstRoute.key == null &&
74
76
  firstRoute.name === normalizedConfig?.initialRouteName &&
75
77
  secondRoute?.key == null)
@@ -121,24 +123,24 @@ export function getActionFromState(
121
123
  return undefined;
122
124
  }
123
125
 
124
- const routes =
125
- current.index != null
126
- ? current.routes.slice(0, current.index + 1)
127
- : current.routes;
126
+ const routesLength =
127
+ current.index == null || current.index >= current.routes.length
128
+ ? current.routes.length
129
+ : current.index + 1;
128
130
 
129
- const route = routes[routes.length - 1];
131
+ const route = current.routes[routesLength - 1];
130
132
 
131
133
  if (route == null) {
132
134
  return undefined;
133
135
  }
134
136
 
135
- const firstRoute = routes[0];
137
+ const firstRoute = current.routes[0];
136
138
 
137
139
  if (firstRoute == null) {
138
140
  return undefined;
139
141
  }
140
142
 
141
- const secondRoute = routes[1];
143
+ const secondRoute = current.routes[1];
142
144
 
143
145
  // Explicitly set to override existing value when merging params
144
146
  Object.assign(params, {
@@ -148,11 +150,11 @@ export function getActionFromState(
148
150
  state: undefined,
149
151
  });
150
152
 
151
- if (routes.length === 1 && firstRoute.key == null) {
153
+ if (routesLength === 1 && firstRoute.key == null) {
152
154
  params.initial = true;
153
155
  params.screen = route.name;
154
156
  } else if (
155
- routes.length === 2 &&
157
+ routesLength === 2 &&
156
158
  firstRoute.key == null &&
157
159
  firstRoute.name === config?.initialRouteName &&
158
160
  secondRoute?.key == null
@@ -40,7 +40,12 @@ const encodePathParam = (value: string) => {
40
40
  };
41
41
 
42
42
  const getActiveRoute = (
43
- state: State
43
+ state: State,
44
+ configs: Record<string, ConfigItem> | undefined,
45
+ getRouteState: (
46
+ route: State['routes'][number],
47
+ config: ConfigItem | undefined
48
+ ) => State | undefined
44
49
  ): { name: string; params?: object | undefined } => {
45
50
  const route =
46
51
  typeof state.index === 'number'
@@ -51,74 +56,41 @@ const getActiveRoute = (
51
56
  throw new Error(`Couldn't find the active route.`);
52
57
  }
53
58
 
54
- if (route.state) {
55
- return getActiveRoute(route.state);
59
+ const config = configs?.[route.name];
60
+ const routeState = getRouteState(route, config);
61
+
62
+ if (routeState) {
63
+ return getActiveRoute(routeState, config?.screens, getRouteState);
56
64
  }
57
65
 
58
66
  return route;
59
67
  };
60
68
 
61
69
  const cachedNormalizedConfigs = new WeakMap<
62
- PathConfigMap<{}>,
70
+ Options<{}>,
63
71
  Record<string, ConfigItem>
64
72
  >();
65
73
 
66
74
  const getNormalizedConfigs = (options?: Options<{}>) => {
67
- if (!options?.screens) return {};
75
+ if (!options) {
76
+ return {};
77
+ }
78
+
79
+ const cached = cachedNormalizedConfigs.get(options);
68
80
 
69
- const cached = cachedNormalizedConfigs.get(options?.screens);
81
+ if (cached) {
82
+ return cached;
83
+ }
70
84
 
71
- if (cached) return cached;
85
+ validatePathConfig(options);
72
86
 
73
87
  const normalizedConfigs = createNormalizedConfigs(options.screens);
74
88
 
75
- cachedNormalizedConfigs.set(options.screens, normalizedConfigs);
89
+ cachedNormalizedConfigs.set(options, normalizedConfigs);
76
90
 
77
91
  return normalizedConfigs;
78
92
  };
79
93
 
80
- const getTransformedState = (
81
- state: State,
82
- configs: Record<string, ConfigItem> | undefined
83
- ): Omit<PartialState<NavigationState>, 'stale'> => {
84
- const routes = state.routes.map(
85
- (route): Omit<PartialState<NavigationState>, 'stale'>['routes'][number] => {
86
- const config = configs?.[route.name];
87
-
88
- if (
89
- route.state ||
90
- (config?.screens &&
91
- route.params &&
92
- (('screen' in route.params &&
93
- typeof route.params.screen === 'string' &&
94
- config.screens[route.params.screen]) ||
95
- 'state' in route.params))
96
- ) {
97
- const nestedState: State | undefined =
98
- route.state ?? getStateFromRouteParams(route.params);
99
-
100
- if (nestedState) {
101
- return {
102
- ...route,
103
- state: getTransformedState(
104
- nestedState,
105
- configs?.[route.name]?.screens
106
- ),
107
- };
108
- }
109
- }
110
-
111
- // @ts-expect-error route.state is handled in previous condition
112
- return route;
113
- }
114
- );
115
-
116
- return {
117
- ...state,
118
- routes,
119
- };
120
- };
121
-
122
94
  /**
123
95
  * Utility to serialize a navigation state object to a path string.
124
96
  *
@@ -158,15 +130,45 @@ export function getPathFromState<ParamList extends {}>(
158
130
  );
159
131
  }
160
132
 
161
- if (options) {
162
- validatePathConfig(options);
163
- }
164
-
165
133
  const configs = getNormalizedConfigs(options);
166
- const transformedState = getTransformedState(state, configs);
134
+ const cachedRouteStates = new Map<object, State | undefined>();
135
+
136
+ const getRouteState = (
137
+ route: State['routes'][number],
138
+ config: ConfigItem | undefined
139
+ ) => {
140
+ if (route.state) {
141
+ return route.state;
142
+ }
143
+
144
+ const hasScreenParams =
145
+ route.params &&
146
+ 'screen' in route.params &&
147
+ typeof route.params.screen === 'string' &&
148
+ config?.screens?.[route.params.screen];
149
+
150
+ const hasStateParams =
151
+ route.params && 'state' in route.params && config?.screens;
152
+
153
+ if (
154
+ !route.params ||
155
+ !config?.screens ||
156
+ (!hasScreenParams && !hasStateParams)
157
+ ) {
158
+ return undefined;
159
+ }
160
+
161
+ if (!cachedRouteStates.has(route)) {
162
+ cachedRouteStates.set(route, getStateFromRouteParams(route.params));
163
+ }
164
+
165
+ return cachedRouteStates.get(route);
166
+ };
167
+
168
+ const focusedRoute = getActiveRoute(state, configs, getRouteState);
167
169
 
168
170
  let path = '/';
169
- let current: State | undefined = transformedState;
171
+ let current: State | undefined = state;
170
172
 
171
173
  const allParams: Record<string, string> = {};
172
174
 
@@ -187,8 +189,6 @@ export function getPathFromState<ParamList extends {}>(
187
189
  let focusedParams: Record<string, string> | undefined;
188
190
  let currentOptions = configs;
189
191
 
190
- const focusedRoute = getActiveRoute(transformedState);
191
-
192
192
  // Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
193
193
  const nestedRouteNames = [];
194
194
 
@@ -262,16 +262,18 @@ export function getPathFromState<ParamList extends {}>(
262
262
  }
263
263
 
264
264
  // If there is no `screens` property or no nested state, we return pattern
265
- if (!config.screens || route.state == null) {
265
+ const routeState = getRouteState(route, config);
266
+
267
+ if (!config.screens || routeState == null) {
266
268
  hasNext = false;
267
269
  } else {
268
270
  index =
269
- typeof route.state.index === 'number'
270
- ? route.state.index
271
- : route.state.routes.length - 1;
271
+ typeof routeState.index === 'number'
272
+ ? routeState.index
273
+ : routeState.routes.length - 1;
272
274
 
273
275
  const nextRoute: State['routes'][number] | undefined =
274
- route.state.routes[index];
276
+ routeState.routes[index];
275
277
 
276
278
  if (nextRoute == null) {
277
279
  throw new Error(`Couldn't find a route at index ${index}.`);
@@ -290,6 +292,8 @@ export function getPathFromState<ParamList extends {}>(
290
292
  }
291
293
  }
292
294
 
295
+ const routeState = getRouteState(route, currentOptions[route.name]);
296
+
293
297
  if (currentOptions[route.name] != null) {
294
298
  if (parts) {
295
299
  let index = 0;
@@ -345,7 +349,7 @@ export function getPathFromState<ParamList extends {}>(
345
349
  }
346
350
  }
347
351
 
348
- if (route.state) {
352
+ if (routeState) {
349
353
  path += '/';
350
354
  } else if (focusedParams) {
351
355
  const query = queryString.stringify(focusedParams, { sort: false });
@@ -355,7 +359,7 @@ export function getPathFromState<ParamList extends {}>(
355
359
  }
356
360
  }
357
361
 
358
- current = route.state;
362
+ current = routeState;
359
363
  }
360
364
 
361
365
  // Include the root path if specified
@@ -52,8 +52,8 @@ export function getPatternParts(path: string): PatternPart[] {
52
52
  if (regexInnerParens) {
53
53
  // The ')' is part of the regex if we're already inside one
54
54
  regexInnerParens--;
55
- current.regex += char;
56
55
  } else {
56
+ current.regex += char;
57
57
  isRegex = false;
58
58
  isParam = false;
59
59
  }
@@ -62,7 +62,7 @@ export function getPatternParts(path: string): PatternPart[] {
62
62
  `Encountered ')' without preceding '(' in path: ${path}`
63
63
  );
64
64
  }
65
- } else if (char === '?') {
65
+ } else if (char === '?' && !isRegex) {
66
66
  if (current.param) {
67
67
  isParam = false;
68
68