expo-router 2.0.8 → 2.0.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/build/getRoutes.d.ts.map +1 -1
- package/build/useDeprecated.d.ts +7 -1
- package/build/useDeprecated.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/getRoutes.ts +46 -37
- package/src/global-state/routing.ts +15 -14
- package/src/matchers.tsx +1 -1
- package/src/useDeprecated.ts +4 -1
- package/src/views/Screen.tsx +1 -1
package/build/getRoutes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRoutes.d.ts","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAW5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC,GAAG;IACnE,yBAAyB;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8CAA8C;IAC9C,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,KAAK,OAAO,GAAG;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,QAAQ,CA+C5D;AAyBD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,GACX,iBAAiB,GAAG,IAAI,CAK1B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAMlE;
|
|
1
|
+
{"version":3,"file":"getRoutes.d.ts","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAW5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,WAAW,CAAC,GAAG;IACnE,yBAAyB;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8CAA8C;IAC9C,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,KAAK,OAAO,GAAG;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,QAAQ,CA+C5D;AAyBD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,GACX,iBAAiB,GAAG,IAAI,CAK1B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAMlE;AA+ND;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,QAiBxD;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CACvB,aAAa,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,OAAO,GAChB,SAAS,GAAG,IAAI,CAclB;AAED,wBAAsB,cAAc,CAClC,aAAa,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAY3B;AAUD,+CAA+C;AAC/C,wBAAgB,cAAc,CAC5B,aAAa,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,OAAO,GAChB,SAAS,GAAG,IAAI,CAIlB;AAYD,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,cAAc,EAC7B,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAI3B;AA4CD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,SAAS,GAChB,SAAS,GAAG,IAAI,CAkBlB"}
|
package/build/useDeprecated.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export declare function useWarnOnce(message: string, guard?: unknown, key?: string): void;
|
|
2
|
-
export declare function useDeprecated(
|
|
2
|
+
export declare function useDeprecated(
|
|
3
|
+
/** The deprecated message to display */
|
|
4
|
+
message: string,
|
|
5
|
+
/** The guard to cause the warning to being displayed */
|
|
6
|
+
guard?: unknown,
|
|
7
|
+
/** The key to use for the warning. Used to detect if the warning has already been shown. */
|
|
8
|
+
key?: string): void;
|
|
3
9
|
//# sourceMappingURL=useDeprecated.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDeprecated.d.ts","sourceRoot":"","sources":["../src/useDeprecated.ts"],"names":[],"mappings":"AAaA,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,OAAc,EACrB,GAAG,SAAU,QAUd;AAED,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"useDeprecated.d.ts","sourceRoot":"","sources":["../src/useDeprecated.ts"],"names":[],"mappings":"AAaA,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,OAAc,EACrB,GAAG,SAAU,QAUd;AAED,wBAAgB,aAAa;AAC3B,wCAAwC;AACxC,OAAO,EAAE,MAAM;AACf,wDAAwD;AACxD,KAAK,GAAE,OAAc;AACrB,4FAA4F;AAC5F,GAAG,SAAU,QAGd"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-router",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"main": "src/index.tsx",
|
|
5
5
|
"types": "build/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -105,12 +105,12 @@
|
|
|
105
105
|
},
|
|
106
106
|
"dependencies": {
|
|
107
107
|
"@bacons/react-views": "^1.1.3",
|
|
108
|
-
"@expo/metro-runtime": "2.2.
|
|
108
|
+
"@expo/metro-runtime": "2.2.12",
|
|
109
109
|
"@radix-ui/react-slot": "1.0.1",
|
|
110
110
|
"@react-navigation/bottom-tabs": "~6.5.7",
|
|
111
111
|
"@react-navigation/native": "~6.1.6",
|
|
112
112
|
"@react-navigation/native-stack": "~6.9.12",
|
|
113
|
-
"expo-head": "0.0.
|
|
113
|
+
"expo-head": "0.0.16",
|
|
114
114
|
"expo-splash-screen": "~0.20.2",
|
|
115
115
|
"query-string": "7.1.3",
|
|
116
116
|
"react-helmet-async": "^1.3.0",
|
package/src/getRoutes.ts
CHANGED
|
@@ -169,21 +169,6 @@ function applyDefaultInitialRouteName(node: RouteNode): RouteNode {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
function cloneGroupRoute(
|
|
173
|
-
node: RouteNode,
|
|
174
|
-
{ name: nextName }: { name: string }
|
|
175
|
-
): RouteNode {
|
|
176
|
-
const groupName = `(${nextName})`;
|
|
177
|
-
const parts = node.contextKey.split("/");
|
|
178
|
-
parts[parts.length - 2] = groupName;
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
...node,
|
|
182
|
-
route: groupName,
|
|
183
|
-
contextKey: parts.join("/"),
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
172
|
function folderNodeToRouteNode({
|
|
188
173
|
name,
|
|
189
174
|
children,
|
|
@@ -212,25 +197,8 @@ function fileNodeToRouteNode(tree: TreeNode): RouteNode[] | null {
|
|
|
212
197
|
|
|
213
198
|
const dynamic = generateDynamic(name);
|
|
214
199
|
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const clones = multiGroup
|
|
219
|
-
? groupName!.split(",").map((v) => ({ name: v.trim() }))
|
|
220
|
-
: null;
|
|
221
|
-
|
|
222
|
-
// Assert duplicates:
|
|
223
|
-
if (clones) {
|
|
224
|
-
const names = new Set<string>();
|
|
225
|
-
for (const clone of clones) {
|
|
226
|
-
if (names.has(clone.name)) {
|
|
227
|
-
throw new Error(
|
|
228
|
-
`Array syntax cannot contain duplicate group name "${clone.name}" in "${node.contextKey}".`
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
names.add(clone.name);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
200
|
+
const clones = extrapolateGroupRoutes(name, node.contextKey);
|
|
201
|
+
clones.delete(name);
|
|
234
202
|
|
|
235
203
|
const output = {
|
|
236
204
|
loadRoute: node.loadRoute,
|
|
@@ -240,9 +208,13 @@ function fileNodeToRouteNode(tree: TreeNode): RouteNode[] | null {
|
|
|
240
208
|
dynamic,
|
|
241
209
|
};
|
|
242
210
|
|
|
243
|
-
if (
|
|
244
|
-
return clones.map((clone) =>
|
|
245
|
-
applyDefaultInitialRouteName(
|
|
211
|
+
if (clones.size) {
|
|
212
|
+
return [...clones].map((clone) =>
|
|
213
|
+
applyDefaultInitialRouteName({
|
|
214
|
+
...output,
|
|
215
|
+
contextKey: node.contextKey.replace(output.route, clone),
|
|
216
|
+
route: clone,
|
|
217
|
+
})
|
|
246
218
|
);
|
|
247
219
|
}
|
|
248
220
|
|
|
@@ -257,6 +229,43 @@ function fileNodeToRouteNode(tree: TreeNode): RouteNode[] | null {
|
|
|
257
229
|
];
|
|
258
230
|
}
|
|
259
231
|
|
|
232
|
+
function extrapolateGroupRoutes(
|
|
233
|
+
route: string,
|
|
234
|
+
contextKey: string,
|
|
235
|
+
routes: Set<string> = new Set()
|
|
236
|
+
): Set<string> {
|
|
237
|
+
const match = matchGroupName(route);
|
|
238
|
+
|
|
239
|
+
if (!match) {
|
|
240
|
+
routes.add(route);
|
|
241
|
+
return routes;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const groups = match?.split(",");
|
|
245
|
+
const groupsSet = new Set(groups);
|
|
246
|
+
|
|
247
|
+
if (groupsSet.size !== groups.length) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Array syntax cannot contain duplicate group name "${groups}" in "${contextKey}".`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (groups.length === 1) {
|
|
254
|
+
routes.add(route);
|
|
255
|
+
return routes;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (const group of groups) {
|
|
259
|
+
extrapolateGroupRoutes(
|
|
260
|
+
route.replace(match, group.trim()),
|
|
261
|
+
contextKey,
|
|
262
|
+
routes
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return routes;
|
|
267
|
+
}
|
|
268
|
+
|
|
260
269
|
function treeNodeToRouteNode(tree: TreeNode): RouteNode[] | null {
|
|
261
270
|
if (tree.node) {
|
|
262
271
|
return fileNodeToRouteNode(tree);
|
|
@@ -75,9 +75,11 @@ export function linkTo(this: RouterStore, href: string, event?: string) {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
const rootState = navigationRef.getRootState();
|
|
79
|
+
|
|
78
80
|
if (href.startsWith(".")) {
|
|
79
81
|
let base =
|
|
80
|
-
this.linking.getPathFromState?.(
|
|
82
|
+
this.linking.getPathFromState?.(rootState, {
|
|
81
83
|
screens: [],
|
|
82
84
|
preserveGroups: true,
|
|
83
85
|
}) ?? "";
|
|
@@ -99,11 +101,9 @@ export function linkTo(this: RouterStore, href: string, event?: string) {
|
|
|
99
101
|
|
|
100
102
|
switch (event) {
|
|
101
103
|
case "REPLACE":
|
|
102
|
-
return navigationRef.dispatch(
|
|
103
|
-
getNavigateReplaceAction(state, navigationRef.getRootState())
|
|
104
|
-
);
|
|
104
|
+
return navigationRef.dispatch(getNavigateReplaceAction(state, rootState));
|
|
105
105
|
default:
|
|
106
|
-
return navigationRef.dispatch(getNavigatePushAction(state));
|
|
106
|
+
return navigationRef.dispatch(getNavigatePushAction(state, rootState));
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -132,10 +132,11 @@ function rewriteNavigationStateToParams(
|
|
|
132
132
|
return JSON.parse(JSON.stringify(params));
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
function getNavigatePushAction(state: ResultState) {
|
|
135
|
+
function getNavigatePushAction(state: ResultState, rootState: NavigationState) {
|
|
136
136
|
const { screen, params } = rewriteNavigationStateToParams(state);
|
|
137
137
|
return {
|
|
138
138
|
type: "NAVIGATE",
|
|
139
|
+
target: rootState.key,
|
|
139
140
|
payload: {
|
|
140
141
|
name: screen,
|
|
141
142
|
params,
|
|
@@ -144,12 +145,12 @@ function getNavigatePushAction(state: ResultState) {
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
function getNavigateReplaceAction(
|
|
147
|
-
|
|
148
|
+
state: ResultState,
|
|
148
149
|
parentState: NavigationState,
|
|
149
150
|
lastNavigatorSupportingReplace: NavigationState = parentState
|
|
150
151
|
): NavigationAction {
|
|
151
152
|
// We should always have at least one route in the state
|
|
152
|
-
const
|
|
153
|
+
const route = state.routes.at(-1)!;
|
|
153
154
|
|
|
154
155
|
// Only these navigators support replace
|
|
155
156
|
if (parentState.type === "stack" || parentState.type === "tab") {
|
|
@@ -157,29 +158,29 @@ function getNavigateReplaceAction(
|
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
const currentRoute = parentState.routes.find(
|
|
160
|
-
(
|
|
161
|
+
(parentRoute) => parentRoute.name === route.name
|
|
161
162
|
);
|
|
162
163
|
const routesAreEqual = parentState.routes[parentState.index] === currentRoute;
|
|
163
164
|
|
|
164
165
|
// If there is nested state and the routes are equal, we should keep going down the tree
|
|
165
|
-
if (
|
|
166
|
+
if (route.state && routesAreEqual && currentRoute.state) {
|
|
166
167
|
return getNavigateReplaceAction(
|
|
167
|
-
|
|
168
|
+
route.state,
|
|
168
169
|
currentRoute.state as any,
|
|
169
170
|
lastNavigatorSupportingReplace
|
|
170
171
|
);
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
// Either we reached the bottom of the state or the point where the routes diverged
|
|
174
|
-
const { screen, params } = rewriteNavigationStateToParams(
|
|
175
|
+
const { screen, params } = rewriteNavigationStateToParams(state);
|
|
176
|
+
|
|
175
177
|
return {
|
|
176
178
|
type:
|
|
177
179
|
lastNavigatorSupportingReplace.type === "stack" ? "REPLACE" : "JUMP_TO",
|
|
180
|
+
target: lastNavigatorSupportingReplace?.key,
|
|
178
181
|
payload: {
|
|
179
182
|
name: screen,
|
|
180
183
|
params,
|
|
181
|
-
// Ensure that the last navigator supporting replace is the one that handles the action
|
|
182
|
-
source: lastNavigatorSupportingReplace?.key,
|
|
183
184
|
},
|
|
184
185
|
};
|
|
185
186
|
}
|
package/src/matchers.tsx
CHANGED
|
@@ -12,7 +12,7 @@ export function matchDeepDynamicRouteName(name: string): string | undefined {
|
|
|
12
12
|
|
|
13
13
|
/** Match `(page)` -> `page` */
|
|
14
14
|
export function matchGroupName(name: string): string | undefined {
|
|
15
|
-
return name.match(
|
|
15
|
+
return name.match(/^(?:[^\\(\\)])*?\(([^\\/]+)\).*?$/)?.[1];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function getNameFromFilePath(name: string): string {
|
package/src/useDeprecated.ts
CHANGED
|
@@ -17,7 +17,7 @@ export function useWarnOnce(
|
|
|
17
17
|
key = message
|
|
18
18
|
) {
|
|
19
19
|
// useLayoutEffect typically doesn't run in node environments.
|
|
20
|
-
// Combined with skipWarn, this should prevent unwanted warnings
|
|
20
|
+
// Combined with skipWarn, this should prevent unwanted warnings during SSR rendering
|
|
21
21
|
useLayoutEffect(() => {
|
|
22
22
|
if (guard && canWarn && !warned.has(key)) {
|
|
23
23
|
warned.add(key);
|
|
@@ -27,8 +27,11 @@ export function useWarnOnce(
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function useDeprecated(
|
|
30
|
+
/** The deprecated message to display */
|
|
30
31
|
message: string,
|
|
32
|
+
/** The guard to cause the warning to being displayed */
|
|
31
33
|
guard: unknown = true,
|
|
34
|
+
/** The key to use for the warning. Used to detect if the warning has already been shown. */
|
|
32
35
|
key = message
|
|
33
36
|
) {
|
|
34
37
|
return useWarnOnce(key, guard, `Expo Router: ${message}`);
|
package/src/views/Screen.tsx
CHANGED
|
@@ -48,7 +48,7 @@ export function Screen<TOptions extends object = object>({
|
|
|
48
48
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
49
49
|
useDeprecated(
|
|
50
50
|
"The `redirect` prop on <Screen /> is deprecated and will be removed. Please use `router.redirect` instead",
|
|
51
|
-
redirect
|
|
51
|
+
Boolean(redirect)
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
|