react-router 6.2.1 → 6.3.0
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/README.md +1 -1
- package/index.d.ts +13 -339
- package/index.js +724 -750
- package/index.js.map +1 -1
- package/lib/components.d.ts +110 -0
- package/lib/context.d.ts +31 -0
- package/lib/hooks.d.ts +99 -0
- package/lib/router.d.ts +120 -0
- package/main.js +1 -1
- package/package.json +1 -1
- package/react-router.development.js +509 -535
- package/react-router.development.js.map +1 -1
- package/react-router.production.min.js +2 -2
- package/react-router.production.min.js.map +1 -1
- package/umd/react-router.development.js +740 -749
- package/umd/react-router.development.js.map +1 -1
- package/umd/react-router.production.min.js +2 -2
- package/umd/react-router.production.min.js.map +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React Router v6.
|
|
2
|
+
* React Router v6.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,13 +8,34 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import { parsePath, createMemoryHistory, Action } from 'history';
|
|
12
|
+
export { Action as NavigationType, createPath, parsePath } from 'history';
|
|
13
|
+
import { createContext, useContext, useMemo, useRef, useEffect, useCallback, createElement, useState, useLayoutEffect, Children, isValidElement, Fragment } from 'react';
|
|
14
|
+
|
|
15
|
+
const NavigationContext = /*#__PURE__*/createContext(null);
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
NavigationContext.displayName = "Navigation";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const LocationContext = /*#__PURE__*/createContext(null);
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
LocationContext.displayName = "Location";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const RouteContext = /*#__PURE__*/createContext({
|
|
28
|
+
outlet: null,
|
|
29
|
+
matches: []
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
RouteContext.displayName = "Route";
|
|
34
|
+
}
|
|
13
35
|
|
|
14
36
|
function invariant(cond, message) {
|
|
15
37
|
if (!cond) throw new Error(message);
|
|
16
38
|
}
|
|
17
|
-
|
|
18
39
|
function warning(cond, message) {
|
|
19
40
|
if (!cond) {
|
|
20
41
|
// eslint-disable-next-line no-console
|
|
@@ -30,216 +51,353 @@ function warning(cond, message) {
|
|
|
30
51
|
} catch (e) {}
|
|
31
52
|
}
|
|
32
53
|
}
|
|
33
|
-
|
|
34
54
|
const alreadyWarned = {};
|
|
35
|
-
|
|
36
55
|
function warningOnce(key, cond, message) {
|
|
37
56
|
if (!cond && !alreadyWarned[key]) {
|
|
38
57
|
alreadyWarned[key] = true;
|
|
39
58
|
warning(false, message) ;
|
|
40
59
|
}
|
|
41
|
-
}
|
|
42
|
-
// CONTEXT
|
|
43
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
60
|
+
}
|
|
44
61
|
|
|
45
62
|
/**
|
|
46
|
-
*
|
|
63
|
+
* Returns a path with params interpolated.
|
|
47
64
|
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
* @see https://reactrouter.com/docs/en/v6/api#generatepath
|
|
66
|
+
*/
|
|
67
|
+
function generatePath(path, params = {}) {
|
|
68
|
+
return path.replace(/:(\w+)/g, (_, key) => {
|
|
69
|
+
!(params[key] != null) ? invariant(false, `Missing ":${key}" param`) : void 0;
|
|
70
|
+
return params[key];
|
|
71
|
+
}).replace(/\/*\*$/, _ => params["*"] == null ? "" : params["*"].replace(/^\/*/, "/"));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A RouteMatch contains info about how a route matched a URL.
|
|
53
75
|
*/
|
|
54
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Matches the given routes to a location and returns the match data.
|
|
79
|
+
*
|
|
80
|
+
* @see https://reactrouter.com/docs/en/v6/api#matchroutes
|
|
81
|
+
*/
|
|
82
|
+
function matchRoutes(routes, locationArg, basename = "/") {
|
|
83
|
+
let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
|
84
|
+
let pathname = stripBasename(location.pathname || "/", basename);
|
|
55
85
|
|
|
56
|
-
|
|
86
|
+
if (pathname == null) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
57
89
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
90
|
+
let branches = flattenRoutes(routes);
|
|
91
|
+
rankRouteBranches(branches);
|
|
92
|
+
let matches = null;
|
|
61
93
|
|
|
62
|
-
|
|
94
|
+
for (let i = 0; matches == null && i < branches.length; ++i) {
|
|
95
|
+
matches = matchRouteBranch(branches[i], pathname);
|
|
96
|
+
}
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
LocationContext.displayName = "Location";
|
|
98
|
+
return matches;
|
|
66
99
|
}
|
|
67
100
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
101
|
+
function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "") {
|
|
102
|
+
routes.forEach((route, index) => {
|
|
103
|
+
let meta = {
|
|
104
|
+
relativePath: route.path || "",
|
|
105
|
+
caseSensitive: route.caseSensitive === true,
|
|
106
|
+
childrenIndex: index,
|
|
107
|
+
route
|
|
108
|
+
};
|
|
72
109
|
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
110
|
+
if (meta.relativePath.startsWith("/")) {
|
|
111
|
+
!meta.relativePath.startsWith(parentPath) ? invariant(false, `Absolute route path "${meta.relativePath}" nested under path ` + `"${parentPath}" is not valid. An absolute child route path ` + `must start with the combined path of all its parent routes.`) : void 0;
|
|
112
|
+
meta.relativePath = meta.relativePath.slice(parentPath.length);
|
|
113
|
+
}
|
|
78
114
|
|
|
115
|
+
let path = joinPaths([parentPath, meta.relativePath]);
|
|
116
|
+
let routesMeta = parentsMeta.concat(meta); // Add the children before adding this route to the array so we traverse the
|
|
117
|
+
// route tree depth-first and child routes appear before their parents in
|
|
118
|
+
// the "flattened" version.
|
|
79
119
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function MemoryRouter({
|
|
86
|
-
basename,
|
|
87
|
-
children,
|
|
88
|
-
initialEntries,
|
|
89
|
-
initialIndex
|
|
90
|
-
}) {
|
|
91
|
-
let historyRef = useRef();
|
|
120
|
+
if (route.children && route.children.length > 0) {
|
|
121
|
+
!(route.index !== true) ? invariant(false, `Index routes must not have child routes. Please remove ` + `all child routes from route path "${path}".`) : void 0;
|
|
122
|
+
flattenRoutes(route.children, branches, routesMeta, path);
|
|
123
|
+
} // Routes without a path shouldn't ever match by themselves unless they are
|
|
124
|
+
// index routes, so don't add them to the list of possible branches.
|
|
92
125
|
|
|
93
|
-
if (historyRef.current == null) {
|
|
94
|
-
historyRef.current = createMemoryHistory({
|
|
95
|
-
initialEntries,
|
|
96
|
-
initialIndex
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
126
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
location: history.location
|
|
104
|
-
});
|
|
105
|
-
useLayoutEffect(() => history.listen(setState), [history]);
|
|
106
|
-
return /*#__PURE__*/createElement(Router, {
|
|
107
|
-
basename: basename,
|
|
108
|
-
children: children,
|
|
109
|
-
location: state.location,
|
|
110
|
-
navigationType: state.action,
|
|
111
|
-
navigator: history
|
|
112
|
-
});
|
|
113
|
-
}
|
|
127
|
+
if (route.path == null && !route.index) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
114
130
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* able to use hooks. In functional components, we recommend you use the
|
|
120
|
-
* `useNavigate` hook instead.
|
|
121
|
-
*
|
|
122
|
-
* @see https://reactrouter.com/docs/en/v6/api#navigate
|
|
123
|
-
*/
|
|
124
|
-
function Navigate({
|
|
125
|
-
to,
|
|
126
|
-
replace,
|
|
127
|
-
state
|
|
128
|
-
}) {
|
|
129
|
-
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of
|
|
130
|
-
// the router loaded. We can help them understand how to avoid that.
|
|
131
|
-
`<Navigate> may be used only in the context of a <Router> component.`) : void 0;
|
|
132
|
-
warning(!useContext(NavigationContext).static, `<Navigate> must not be used on the initial render in a <StaticRouter>. ` + `This is a no-op, but you should modify your code so the <Navigate> is ` + `only ever rendered in response to some user interaction or state change.`) ;
|
|
133
|
-
let navigate = useNavigate();
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
navigate(to, {
|
|
136
|
-
replace,
|
|
137
|
-
state
|
|
131
|
+
branches.push({
|
|
132
|
+
path,
|
|
133
|
+
score: computeScore(path, route.index),
|
|
134
|
+
routesMeta
|
|
138
135
|
});
|
|
139
136
|
});
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Renders the child route's element, if there is one.
|
|
145
|
-
*
|
|
146
|
-
* @see https://reactrouter.com/docs/en/v6/api#outlet
|
|
147
|
-
*/
|
|
148
|
-
function Outlet(props) {
|
|
149
|
-
return useOutlet(props.context);
|
|
137
|
+
return branches;
|
|
150
138
|
}
|
|
151
139
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
* @see https://reactrouter.com/docs/en/v6/api#route
|
|
156
|
-
*/
|
|
157
|
-
function Route(_props) {
|
|
158
|
-
invariant(false, `A <Route> is only ever to be used as the child of <Routes> element, ` + `never rendered directly. Please wrap your <Route> in a <Routes>.`) ;
|
|
140
|
+
function rankRouteBranches(branches) {
|
|
141
|
+
branches.sort((a, b) => a.score !== b.score ? b.score - a.score // Higher score first
|
|
142
|
+
: compareIndexes(a.routesMeta.map(meta => meta.childrenIndex), b.routesMeta.map(meta => meta.childrenIndex)));
|
|
159
143
|
}
|
|
160
144
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
*
|
|
168
|
-
* @see https://reactrouter.com/docs/en/v6/api#router
|
|
169
|
-
*/
|
|
170
|
-
function Router({
|
|
171
|
-
basename: basenameProp = "/",
|
|
172
|
-
children = null,
|
|
173
|
-
location: locationProp,
|
|
174
|
-
navigationType = Action.Pop,
|
|
175
|
-
navigator,
|
|
176
|
-
static: staticProp = false
|
|
177
|
-
}) {
|
|
178
|
-
!!useInRouterContext() ? invariant(false, `You cannot render a <Router> inside another <Router>.` + ` You should never have more than one in your app.`) : void 0;
|
|
179
|
-
let basename = normalizePathname(basenameProp);
|
|
180
|
-
let navigationContext = useMemo(() => ({
|
|
181
|
-
basename,
|
|
182
|
-
navigator,
|
|
183
|
-
static: staticProp
|
|
184
|
-
}), [basename, navigator, staticProp]);
|
|
185
|
-
|
|
186
|
-
if (typeof locationProp === "string") {
|
|
187
|
-
locationProp = parsePath(locationProp);
|
|
188
|
-
}
|
|
145
|
+
const paramRe = /^:\w+$/;
|
|
146
|
+
const dynamicSegmentValue = 3;
|
|
147
|
+
const indexRouteValue = 2;
|
|
148
|
+
const emptySegmentValue = 1;
|
|
149
|
+
const staticSegmentValue = 10;
|
|
150
|
+
const splatPenalty = -2;
|
|
189
151
|
|
|
190
|
-
|
|
191
|
-
pathname = "/",
|
|
192
|
-
search = "",
|
|
193
|
-
hash = "",
|
|
194
|
-
state = null,
|
|
195
|
-
key = "default"
|
|
196
|
-
} = locationProp;
|
|
197
|
-
let location = useMemo(() => {
|
|
198
|
-
let trailingPathname = stripBasename(pathname, basename);
|
|
152
|
+
const isSplat = s => s === "*";
|
|
199
153
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
154
|
+
function computeScore(path, index) {
|
|
155
|
+
let segments = path.split("/");
|
|
156
|
+
let initialScore = segments.length;
|
|
203
157
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
hash,
|
|
208
|
-
state,
|
|
209
|
-
key
|
|
210
|
-
};
|
|
211
|
-
}, [basename, pathname, search, hash, state, key]);
|
|
212
|
-
warning(location != null, `<Router basename="${basename}"> is not able to match the URL ` + `"${pathname}${search}${hash}" because it does not start with the ` + `basename, so the <Router> won't render anything.`) ;
|
|
158
|
+
if (segments.some(isSplat)) {
|
|
159
|
+
initialScore += splatPenalty;
|
|
160
|
+
}
|
|
213
161
|
|
|
214
|
-
if (
|
|
215
|
-
|
|
162
|
+
if (index) {
|
|
163
|
+
initialScore += indexRouteValue;
|
|
216
164
|
}
|
|
217
165
|
|
|
218
|
-
return
|
|
219
|
-
value: navigationContext
|
|
220
|
-
}, /*#__PURE__*/createElement(LocationContext.Provider, {
|
|
221
|
-
children: children,
|
|
222
|
-
value: {
|
|
223
|
-
location,
|
|
224
|
-
navigationType
|
|
225
|
-
}
|
|
226
|
-
}));
|
|
166
|
+
return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
|
|
227
167
|
}
|
|
228
168
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
169
|
+
function compareIndexes(a, b) {
|
|
170
|
+
let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
|
|
171
|
+
return siblings ? // If two routes are siblings, we should try to match the earlier sibling
|
|
172
|
+
// first. This allows people to have fine-grained control over the matching
|
|
173
|
+
// behavior by simply putting routes with identical paths in the order they
|
|
174
|
+
// want them tried.
|
|
175
|
+
a[a.length - 1] - b[b.length - 1] : // Otherwise, it doesn't really make sense to rank non-siblings by index,
|
|
176
|
+
// so they sort equally.
|
|
177
|
+
0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function matchRouteBranch(branch, pathname) {
|
|
181
|
+
let {
|
|
182
|
+
routesMeta
|
|
183
|
+
} = branch;
|
|
184
|
+
let matchedParams = {};
|
|
185
|
+
let matchedPathname = "/";
|
|
186
|
+
let matches = [];
|
|
187
|
+
|
|
188
|
+
for (let i = 0; i < routesMeta.length; ++i) {
|
|
189
|
+
let meta = routesMeta[i];
|
|
190
|
+
let end = i === routesMeta.length - 1;
|
|
191
|
+
let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
|
192
|
+
let match = matchPath({
|
|
193
|
+
path: meta.relativePath,
|
|
194
|
+
caseSensitive: meta.caseSensitive,
|
|
195
|
+
end
|
|
196
|
+
}, remainingPathname);
|
|
197
|
+
if (!match) return null;
|
|
198
|
+
Object.assign(matchedParams, match.params);
|
|
199
|
+
let route = meta.route;
|
|
200
|
+
matches.push({
|
|
201
|
+
params: matchedParams,
|
|
202
|
+
pathname: joinPaths([matchedPathname, match.pathname]),
|
|
203
|
+
pathnameBase: normalizePathname(joinPaths([matchedPathname, match.pathnameBase])),
|
|
204
|
+
route
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (match.pathnameBase !== "/") {
|
|
208
|
+
matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return matches;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A PathPattern is used to match on some portion of a URL pathname.
|
|
234
216
|
*/
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Performs pattern matching on a URL pathname and returns information about
|
|
221
|
+
* the match.
|
|
222
|
+
*
|
|
223
|
+
* @see https://reactrouter.com/docs/en/v6/api#matchpath
|
|
224
|
+
*/
|
|
225
|
+
function matchPath(pattern, pathname) {
|
|
226
|
+
if (typeof pattern === "string") {
|
|
227
|
+
pattern = {
|
|
228
|
+
path: pattern,
|
|
229
|
+
caseSensitive: false,
|
|
230
|
+
end: true
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let [matcher, paramNames] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
|
|
235
|
+
let match = pathname.match(matcher);
|
|
236
|
+
if (!match) return null;
|
|
237
|
+
let matchedPathname = match[0];
|
|
238
|
+
let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
|
239
|
+
let captureGroups = match.slice(1);
|
|
240
|
+
let params = paramNames.reduce((memo, paramName, index) => {
|
|
241
|
+
// We need to compute the pathnameBase here using the raw splat value
|
|
242
|
+
// instead of using params["*"] later because it will be decoded then
|
|
243
|
+
if (paramName === "*") {
|
|
244
|
+
let splatValue = captureGroups[index] || "";
|
|
245
|
+
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
memo[paramName] = safelyDecodeURIComponent(captureGroups[index] || "", paramName);
|
|
249
|
+
return memo;
|
|
250
|
+
}, {});
|
|
251
|
+
return {
|
|
252
|
+
params,
|
|
253
|
+
pathname: matchedPathname,
|
|
254
|
+
pathnameBase,
|
|
255
|
+
pattern
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function compilePath(path, caseSensitive = false, end = true) {
|
|
260
|
+
warning(path === "*" || !path.endsWith("*") || path.endsWith("/*"), `Route path "${path}" will be treated as if it were ` + `"${path.replace(/\*$/, "/*")}" because the \`*\` character must ` + `always follow a \`/\` in the pattern. To get rid of this warning, ` + `please change the route path to "${path.replace(/\*$/, "/*")}".`) ;
|
|
261
|
+
let paramNames = [];
|
|
262
|
+
let regexpSource = "^" + path.replace(/\/*\*?$/, "") // Ignore trailing / and /*, we'll handle it below
|
|
263
|
+
.replace(/^\/*/, "/") // Make sure it has a leading /
|
|
264
|
+
.replace(/[\\.*+^$?{}|()[\]]/g, "\\$&") // Escape special regex chars
|
|
265
|
+
.replace(/:(\w+)/g, (_, paramName) => {
|
|
266
|
+
paramNames.push(paramName);
|
|
267
|
+
return "([^\\/]+)";
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
if (path.endsWith("*")) {
|
|
271
|
+
paramNames.push("*");
|
|
272
|
+
regexpSource += path === "*" || path === "/*" ? "(.*)$" // Already matched the initial /, just match the rest
|
|
273
|
+
: "(?:\\/(.+)|\\/*)$"; // Don't include the / in params["*"]
|
|
274
|
+
} else {
|
|
275
|
+
regexpSource += end ? "\\/*$" // When matching to the end, ignore trailing slashes
|
|
276
|
+
: // Otherwise, match a word boundary or a proceeding /. The word boundary restricts
|
|
277
|
+
// parent routes to matching only their own words and nothing more, e.g. parent
|
|
278
|
+
// route "/home" should not match "/home2".
|
|
279
|
+
// Additionally, allow paths starting with `.`, `-`, `~`, and url-encoded entities,
|
|
280
|
+
// but do not consume the character in the matched path so they can match against
|
|
281
|
+
// nested paths.
|
|
282
|
+
"(?:(?=[.~-]|%[0-9A-F]{2})|\\b|\\/|$)";
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
|
|
286
|
+
return [matcher, paramNames];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function safelyDecodeURIComponent(value, paramName) {
|
|
290
|
+
try {
|
|
291
|
+
return decodeURIComponent(value);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
warning(false, `The value for the URL param "${paramName}" will not be decoded because` + ` the string "${value}" is a malformed URL segment. This is probably` + ` due to a bad percent encoding (${error}).`) ;
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Returns a resolved path object relative to the given pathname.
|
|
299
|
+
*
|
|
300
|
+
* @see https://reactrouter.com/docs/en/v6/api#resolvepath
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
function resolvePath(to, fromPathname = "/") {
|
|
305
|
+
let {
|
|
306
|
+
pathname: toPathname,
|
|
307
|
+
search = "",
|
|
308
|
+
hash = ""
|
|
309
|
+
} = typeof to === "string" ? parsePath(to) : to;
|
|
310
|
+
let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
|
|
311
|
+
return {
|
|
312
|
+
pathname,
|
|
313
|
+
search: normalizeSearch(search),
|
|
314
|
+
hash: normalizeHash(hash)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function resolvePathname(relativePath, fromPathname) {
|
|
319
|
+
let segments = fromPathname.replace(/\/+$/, "").split("/");
|
|
320
|
+
let relativeSegments = relativePath.split("/");
|
|
321
|
+
relativeSegments.forEach(segment => {
|
|
322
|
+
if (segment === "..") {
|
|
323
|
+
// Keep the root "" segment so the pathname starts at /
|
|
324
|
+
if (segments.length > 1) segments.pop();
|
|
325
|
+
} else if (segment !== ".") {
|
|
326
|
+
segments.push(segment);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
return segments.length > 1 ? segments.join("/") : "/";
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function resolveTo(toArg, routePathnames, locationPathname) {
|
|
333
|
+
let to = typeof toArg === "string" ? parsePath(toArg) : toArg;
|
|
334
|
+
let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; // If a pathname is explicitly provided in `to`, it should be relative to the
|
|
335
|
+
// route context. This is explained in `Note on `<Link to>` values` in our
|
|
336
|
+
// migration guide from v5 as a means of disambiguation between `to` values
|
|
337
|
+
// that begin with `/` and those that do not. However, this is problematic for
|
|
338
|
+
// `to` values that do not provide a pathname. `to` can simply be a search or
|
|
339
|
+
// hash string, in which case we should assume that the navigation is relative
|
|
340
|
+
// to the current location's pathname and *not* the route pathname.
|
|
341
|
+
|
|
342
|
+
let from;
|
|
343
|
+
|
|
344
|
+
if (toPathname == null) {
|
|
345
|
+
from = locationPathname;
|
|
346
|
+
} else {
|
|
347
|
+
let routePathnameIndex = routePathnames.length - 1;
|
|
348
|
+
|
|
349
|
+
if (toPathname.startsWith("..")) {
|
|
350
|
+
let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
|
|
351
|
+
// URL segment". This is a key difference from how <a href> works and a
|
|
352
|
+
// major reason we call this a "to" value instead of a "href".
|
|
353
|
+
|
|
354
|
+
while (toSegments[0] === "..") {
|
|
355
|
+
toSegments.shift();
|
|
356
|
+
routePathnameIndex -= 1;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
to.pathname = toSegments.join("/");
|
|
360
|
+
} // If there are more ".." segments than parent routes, resolve relative to
|
|
361
|
+
// the root / URL.
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
|
|
368
|
+
|
|
369
|
+
if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
|
|
370
|
+
path.pathname += "/";
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return path;
|
|
374
|
+
}
|
|
375
|
+
function getToPathname(to) {
|
|
376
|
+
// Empty strings should be treated the same as / paths
|
|
377
|
+
return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? parsePath(to).pathname : to.pathname;
|
|
378
|
+
}
|
|
379
|
+
function stripBasename(pathname, basename) {
|
|
380
|
+
if (basename === "/") return pathname;
|
|
381
|
+
|
|
382
|
+
if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
let nextChar = pathname.charAt(basename.length);
|
|
387
|
+
|
|
388
|
+
if (nextChar && nextChar !== "/") {
|
|
389
|
+
// pathname does not start with basename/
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return pathname.slice(basename.length) || "/";
|
|
394
|
+
}
|
|
395
|
+
const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
|
|
396
|
+
const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
|
|
397
|
+
|
|
398
|
+
const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
399
|
+
|
|
400
|
+
const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
|
243
401
|
|
|
244
402
|
/**
|
|
245
403
|
* Returns the full href for the given "to" value. This is useful for building
|
|
@@ -301,13 +459,13 @@ function useLocation() {
|
|
|
301
459
|
`useLocation() may be used only in the context of a <Router> component.`) : void 0;
|
|
302
460
|
return useContext(LocationContext).location;
|
|
303
461
|
}
|
|
304
|
-
|
|
305
462
|
/**
|
|
306
463
|
* Returns the current navigation action which describes how the router came to
|
|
307
464
|
* the current location, either by a pop, push, or replace on the history stack.
|
|
308
465
|
*
|
|
309
466
|
* @see https://reactrouter.com/docs/en/v6/api#usenavigationtype
|
|
310
467
|
*/
|
|
468
|
+
|
|
311
469
|
function useNavigationType() {
|
|
312
470
|
return useContext(LocationContext).navigationType;
|
|
313
471
|
}
|
|
@@ -508,414 +666,230 @@ function useRoutes(routes, locationArg) {
|
|
|
508
666
|
pathname: joinPaths([parentPathnameBase, match.pathname]),
|
|
509
667
|
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, match.pathnameBase])
|
|
510
668
|
})), parentMatches);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
|
|
669
|
+
}
|
|
670
|
+
function _renderMatches(matches, parentMatches = []) {
|
|
671
|
+
if (matches == null) return null;
|
|
672
|
+
return matches.reduceRight((outlet, match, index) => {
|
|
673
|
+
return /*#__PURE__*/createElement(RouteContext.Provider, {
|
|
674
|
+
children: match.route.element !== undefined ? match.route.element : outlet,
|
|
675
|
+
value: {
|
|
676
|
+
outlet,
|
|
677
|
+
matches: parentMatches.concat(matches.slice(0, index + 1))
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
}, null);
|
|
681
|
+
}
|
|
514
682
|
|
|
515
683
|
/**
|
|
516
|
-
*
|
|
517
|
-
* either a `<Route>` element or an array of them. Used internally by
|
|
518
|
-
* `<Routes>` to create a route config from its children.
|
|
684
|
+
* A <Router> that stores all entries in memory.
|
|
519
685
|
*
|
|
520
|
-
* @see https://reactrouter.com/docs/en/v6/api#
|
|
686
|
+
* @see https://reactrouter.com/docs/en/v6/api#memoryrouter
|
|
521
687
|
*/
|
|
688
|
+
function MemoryRouter({
|
|
689
|
+
basename,
|
|
690
|
+
children,
|
|
691
|
+
initialEntries,
|
|
692
|
+
initialIndex
|
|
693
|
+
}) {
|
|
694
|
+
let historyRef = useRef();
|
|
522
695
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (element.type === Fragment) {
|
|
533
|
-
// Transparently support React.Fragment and its children.
|
|
534
|
-
routes.push.apply(routes, createRoutesFromChildren(element.props.children));
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
!(element.type === Route) ? invariant(false, `[${typeof element.type === "string" ? element.type : element.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`) : void 0;
|
|
539
|
-
let route = {
|
|
540
|
-
caseSensitive: element.props.caseSensitive,
|
|
541
|
-
element: element.props.element,
|
|
542
|
-
index: element.props.index,
|
|
543
|
-
path: element.props.path
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
if (element.props.children) {
|
|
547
|
-
route.children = createRoutesFromChildren(element.props.children);
|
|
548
|
-
}
|
|
696
|
+
if (historyRef.current == null) {
|
|
697
|
+
historyRef.current = createMemoryHistory({
|
|
698
|
+
initialEntries,
|
|
699
|
+
initialIndex
|
|
700
|
+
});
|
|
701
|
+
}
|
|
549
702
|
|
|
550
|
-
|
|
703
|
+
let history = historyRef.current;
|
|
704
|
+
let [state, setState] = useState({
|
|
705
|
+
action: history.action,
|
|
706
|
+
location: history.location
|
|
707
|
+
});
|
|
708
|
+
useLayoutEffect(() => history.listen(setState), [history]);
|
|
709
|
+
return /*#__PURE__*/createElement(Router, {
|
|
710
|
+
basename: basename,
|
|
711
|
+
children: children,
|
|
712
|
+
location: state.location,
|
|
713
|
+
navigationType: state.action,
|
|
714
|
+
navigator: history
|
|
551
715
|
});
|
|
552
|
-
return routes;
|
|
553
716
|
}
|
|
717
|
+
|
|
554
718
|
/**
|
|
555
|
-
*
|
|
719
|
+
* Changes the current location.
|
|
720
|
+
*
|
|
721
|
+
* Note: This API is mostly useful in React.Component subclasses that are not
|
|
722
|
+
* able to use hooks. In functional components, we recommend you use the
|
|
723
|
+
* `useNavigate` hook instead.
|
|
724
|
+
*
|
|
725
|
+
* @see https://reactrouter.com/docs/en/v6/api#navigate
|
|
556
726
|
*/
|
|
727
|
+
function Navigate({
|
|
728
|
+
to,
|
|
729
|
+
replace,
|
|
730
|
+
state
|
|
731
|
+
}) {
|
|
732
|
+
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of
|
|
733
|
+
// the router loaded. We can help them understand how to avoid that.
|
|
734
|
+
`<Navigate> may be used only in the context of a <Router> component.`) : void 0;
|
|
735
|
+
warning(!useContext(NavigationContext).static, `<Navigate> must not be used on the initial render in a <StaticRouter>. ` + `This is a no-op, but you should modify your code so the <Navigate> is ` + `only ever rendered in response to some user interaction or state change.`) ;
|
|
736
|
+
let navigate = useNavigate();
|
|
737
|
+
useEffect(() => {
|
|
738
|
+
navigate(to, {
|
|
739
|
+
replace,
|
|
740
|
+
state
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
557
745
|
|
|
558
746
|
/**
|
|
559
|
-
*
|
|
747
|
+
* Renders the child route's element, if there is one.
|
|
560
748
|
*
|
|
561
|
-
* @see https://reactrouter.com/docs/en/v6/api#
|
|
749
|
+
* @see https://reactrouter.com/docs/en/v6/api#outlet
|
|
562
750
|
*/
|
|
563
|
-
function
|
|
564
|
-
return
|
|
565
|
-
!(params[key] != null) ? invariant(false, `Missing ":${key}" param`) : void 0;
|
|
566
|
-
return params[key];
|
|
567
|
-
}).replace(/\/*\*$/, _ => params["*"] == null ? "" : params["*"].replace(/^\/*/, "/"));
|
|
751
|
+
function Outlet(props) {
|
|
752
|
+
return useOutlet(props.context);
|
|
568
753
|
}
|
|
754
|
+
|
|
569
755
|
/**
|
|
570
|
-
*
|
|
756
|
+
* Declares an element that should be rendered at a certain URL path.
|
|
757
|
+
*
|
|
758
|
+
* @see https://reactrouter.com/docs/en/v6/api#route
|
|
571
759
|
*/
|
|
760
|
+
function Route(_props) {
|
|
761
|
+
invariant(false, `A <Route> is only ever to be used as the child of <Routes> element, ` + `never rendered directly. Please wrap your <Route> in a <Routes>.`) ;
|
|
762
|
+
}
|
|
572
763
|
|
|
573
764
|
/**
|
|
574
|
-
*
|
|
765
|
+
* Provides location context for the rest of the app.
|
|
575
766
|
*
|
|
576
|
-
*
|
|
767
|
+
* Note: You usually won't render a <Router> directly. Instead, you'll render a
|
|
768
|
+
* router that is more specific to your environment such as a <BrowserRouter>
|
|
769
|
+
* in web browsers or a <StaticRouter> for server rendering.
|
|
770
|
+
*
|
|
771
|
+
* @see https://reactrouter.com/docs/en/v6/api#router
|
|
577
772
|
*/
|
|
578
|
-
function
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
let
|
|
773
|
+
function Router({
|
|
774
|
+
basename: basenameProp = "/",
|
|
775
|
+
children = null,
|
|
776
|
+
location: locationProp,
|
|
777
|
+
navigationType = Action.Pop,
|
|
778
|
+
navigator,
|
|
779
|
+
static: staticProp = false
|
|
780
|
+
}) {
|
|
781
|
+
!!useInRouterContext() ? invariant(false, `You cannot render a <Router> inside another <Router>.` + ` You should never have more than one in your app.`) : void 0;
|
|
782
|
+
let basename = normalizePathname(basenameProp);
|
|
783
|
+
let navigationContext = useMemo(() => ({
|
|
784
|
+
basename,
|
|
785
|
+
navigator,
|
|
786
|
+
static: staticProp
|
|
787
|
+
}), [basename, navigator, staticProp]);
|
|
589
788
|
|
|
590
|
-
|
|
591
|
-
|
|
789
|
+
if (typeof locationProp === "string") {
|
|
790
|
+
locationProp = parsePath(locationProp);
|
|
592
791
|
}
|
|
593
792
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
route
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
if (meta.relativePath.startsWith("/")) {
|
|
607
|
-
!meta.relativePath.startsWith(parentPath) ? invariant(false, `Absolute route path "${meta.relativePath}" nested under path ` + `"${parentPath}" is not valid. An absolute child route path ` + `must start with the combined path of all its parent routes.`) : void 0;
|
|
608
|
-
meta.relativePath = meta.relativePath.slice(parentPath.length);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
let path = joinPaths([parentPath, meta.relativePath]);
|
|
612
|
-
let routesMeta = parentsMeta.concat(meta); // Add the children before adding this route to the array so we traverse the
|
|
613
|
-
// route tree depth-first and child routes appear before their parents in
|
|
614
|
-
// the "flattened" version.
|
|
615
|
-
|
|
616
|
-
if (route.children && route.children.length > 0) {
|
|
617
|
-
!(route.index !== true) ? invariant(false, `Index routes must not have child routes. Please remove ` + `all child routes from route path "${path}".`) : void 0;
|
|
618
|
-
flattenRoutes(route.children, branches, routesMeta, path);
|
|
619
|
-
} // Routes without a path shouldn't ever match by themselves unless they are
|
|
620
|
-
// index routes, so don't add them to the list of possible branches.
|
|
621
|
-
|
|
793
|
+
let {
|
|
794
|
+
pathname = "/",
|
|
795
|
+
search = "",
|
|
796
|
+
hash = "",
|
|
797
|
+
state = null,
|
|
798
|
+
key = "default"
|
|
799
|
+
} = locationProp;
|
|
800
|
+
let location = useMemo(() => {
|
|
801
|
+
let trailingPathname = stripBasename(pathname, basename);
|
|
622
802
|
|
|
623
|
-
if (
|
|
624
|
-
return;
|
|
803
|
+
if (trailingPathname == null) {
|
|
804
|
+
return null;
|
|
625
805
|
}
|
|
626
806
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
function rankRouteBranches(branches) {
|
|
637
|
-
branches.sort((a, b) => a.score !== b.score ? b.score - a.score // Higher score first
|
|
638
|
-
: compareIndexes(a.routesMeta.map(meta => meta.childrenIndex), b.routesMeta.map(meta => meta.childrenIndex)));
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const paramRe = /^:\w+$/;
|
|
642
|
-
const dynamicSegmentValue = 3;
|
|
643
|
-
const indexRouteValue = 2;
|
|
644
|
-
const emptySegmentValue = 1;
|
|
645
|
-
const staticSegmentValue = 10;
|
|
646
|
-
const splatPenalty = -2;
|
|
647
|
-
|
|
648
|
-
const isSplat = s => s === "*";
|
|
649
|
-
|
|
650
|
-
function computeScore(path, index) {
|
|
651
|
-
let segments = path.split("/");
|
|
652
|
-
let initialScore = segments.length;
|
|
653
|
-
|
|
654
|
-
if (segments.some(isSplat)) {
|
|
655
|
-
initialScore += splatPenalty;
|
|
656
|
-
}
|
|
807
|
+
return {
|
|
808
|
+
pathname: trailingPathname,
|
|
809
|
+
search,
|
|
810
|
+
hash,
|
|
811
|
+
state,
|
|
812
|
+
key
|
|
813
|
+
};
|
|
814
|
+
}, [basename, pathname, search, hash, state, key]);
|
|
815
|
+
warning(location != null, `<Router basename="${basename}"> is not able to match the URL ` + `"${pathname}${search}${hash}" because it does not start with the ` + `basename, so the <Router> won't render anything.`) ;
|
|
657
816
|
|
|
658
|
-
if (
|
|
659
|
-
|
|
817
|
+
if (location == null) {
|
|
818
|
+
return null;
|
|
660
819
|
}
|
|
661
820
|
|
|
662
|
-
return
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
// behavior by simply putting routes with identical paths in the order they
|
|
670
|
-
// want them tried.
|
|
671
|
-
a[a.length - 1] - b[b.length - 1] : // Otherwise, it doesn't really make sense to rank non-siblings by index,
|
|
672
|
-
// so they sort equally.
|
|
673
|
-
0;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function matchRouteBranch(branch, pathname) {
|
|
677
|
-
let {
|
|
678
|
-
routesMeta
|
|
679
|
-
} = branch;
|
|
680
|
-
let matchedParams = {};
|
|
681
|
-
let matchedPathname = "/";
|
|
682
|
-
let matches = [];
|
|
683
|
-
|
|
684
|
-
for (let i = 0; i < routesMeta.length; ++i) {
|
|
685
|
-
let meta = routesMeta[i];
|
|
686
|
-
let end = i === routesMeta.length - 1;
|
|
687
|
-
let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
|
688
|
-
let match = matchPath({
|
|
689
|
-
path: meta.relativePath,
|
|
690
|
-
caseSensitive: meta.caseSensitive,
|
|
691
|
-
end
|
|
692
|
-
}, remainingPathname);
|
|
693
|
-
if (!match) return null;
|
|
694
|
-
Object.assign(matchedParams, match.params);
|
|
695
|
-
let route = meta.route;
|
|
696
|
-
matches.push({
|
|
697
|
-
params: matchedParams,
|
|
698
|
-
pathname: joinPaths([matchedPathname, match.pathname]),
|
|
699
|
-
pathnameBase: joinPaths([matchedPathname, match.pathnameBase]),
|
|
700
|
-
route
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
if (match.pathnameBase !== "/") {
|
|
704
|
-
matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
|
821
|
+
return /*#__PURE__*/createElement(NavigationContext.Provider, {
|
|
822
|
+
value: navigationContext
|
|
823
|
+
}, /*#__PURE__*/createElement(LocationContext.Provider, {
|
|
824
|
+
children: children,
|
|
825
|
+
value: {
|
|
826
|
+
location,
|
|
827
|
+
navigationType
|
|
705
828
|
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
return matches;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Renders the result of `matchRoutes()` into a React element.
|
|
712
|
-
*/
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
function renderMatches(matches) {
|
|
716
|
-
return _renderMatches(matches);
|
|
829
|
+
}));
|
|
717
830
|
}
|
|
718
831
|
|
|
719
|
-
function _renderMatches(matches, parentMatches = []) {
|
|
720
|
-
if (matches == null) return null;
|
|
721
|
-
return matches.reduceRight((outlet, match, index) => {
|
|
722
|
-
return /*#__PURE__*/createElement(RouteContext.Provider, {
|
|
723
|
-
children: match.route.element !== undefined ? match.route.element : /*#__PURE__*/createElement(Outlet, null),
|
|
724
|
-
value: {
|
|
725
|
-
outlet,
|
|
726
|
-
matches: parentMatches.concat(matches.slice(0, index + 1))
|
|
727
|
-
}
|
|
728
|
-
});
|
|
729
|
-
}, null);
|
|
730
|
-
}
|
|
731
832
|
/**
|
|
732
|
-
* A
|
|
833
|
+
* A container for a nested tree of <Route> elements that renders the branch
|
|
834
|
+
* that best matches the current location.
|
|
835
|
+
*
|
|
836
|
+
* @see https://reactrouter.com/docs/en/v6/api#routes
|
|
733
837
|
*/
|
|
734
|
-
|
|
838
|
+
function Routes({
|
|
839
|
+
children,
|
|
840
|
+
location
|
|
841
|
+
}) {
|
|
842
|
+
return useRoutes(createRoutesFromChildren(children), location);
|
|
843
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
844
|
+
// UTILS
|
|
845
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
735
846
|
|
|
736
847
|
/**
|
|
737
|
-
*
|
|
738
|
-
*
|
|
848
|
+
* Creates a route config from a React "children" object, which is usually
|
|
849
|
+
* either a `<Route>` element or an array of them. Used internally by
|
|
850
|
+
* `<Routes>` to create a route config from its children.
|
|
739
851
|
*
|
|
740
|
-
* @see https://reactrouter.com/docs/en/v6/api#
|
|
852
|
+
* @see https://reactrouter.com/docs/en/v6/api#createroutesfromchildren
|
|
741
853
|
*/
|
|
742
|
-
function matchPath(pattern, pathname) {
|
|
743
|
-
if (typeof pattern === "string") {
|
|
744
|
-
pattern = {
|
|
745
|
-
path: pattern,
|
|
746
|
-
caseSensitive: false,
|
|
747
|
-
end: true
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
854
|
|
|
751
|
-
|
|
752
|
-
let
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
// We need to compute the pathnameBase here using the raw splat value
|
|
759
|
-
// instead of using params["*"] later because it will be decoded then
|
|
760
|
-
if (paramName === "*") {
|
|
761
|
-
let splatValue = captureGroups[index] || "";
|
|
762
|
-
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
855
|
+
function createRoutesFromChildren(children) {
|
|
856
|
+
let routes = [];
|
|
857
|
+
Children.forEach(children, element => {
|
|
858
|
+
if (! /*#__PURE__*/isValidElement(element)) {
|
|
859
|
+
// Ignore non-elements. This allows people to more easily inline
|
|
860
|
+
// conditionals in their route config.
|
|
861
|
+
return;
|
|
763
862
|
}
|
|
764
863
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
pathname: matchedPathname,
|
|
771
|
-
pathnameBase,
|
|
772
|
-
pattern
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
function compilePath(path, caseSensitive = false, end = true) {
|
|
777
|
-
warning(path === "*" || !path.endsWith("*") || path.endsWith("/*"), `Route path "${path}" will be treated as if it were ` + `"${path.replace(/\*$/, "/*")}" because the \`*\` character must ` + `always follow a \`/\` in the pattern. To get rid of this warning, ` + `please change the route path to "${path.replace(/\*$/, "/*")}".`) ;
|
|
778
|
-
let paramNames = [];
|
|
779
|
-
let regexpSource = "^" + path.replace(/\/*\*?$/, "") // Ignore trailing / and /*, we'll handle it below
|
|
780
|
-
.replace(/^\/*/, "/") // Make sure it has a leading /
|
|
781
|
-
.replace(/[\\.*+^$?{}|()[\]]/g, "\\$&") // Escape special regex chars
|
|
782
|
-
.replace(/:(\w+)/g, (_, paramName) => {
|
|
783
|
-
paramNames.push(paramName);
|
|
784
|
-
return "([^\\/]+)";
|
|
785
|
-
});
|
|
864
|
+
if (element.type === Fragment) {
|
|
865
|
+
// Transparently support React.Fragment and its children.
|
|
866
|
+
routes.push.apply(routes, createRoutesFromChildren(element.props.children));
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
786
869
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
// parent routes to matching only their own words and nothing more, e.g. parent
|
|
795
|
-
// route "/home" should not match "/home2".
|
|
796
|
-
"(?:\\b|\\/|$)";
|
|
797
|
-
}
|
|
870
|
+
!(element.type === Route) ? invariant(false, `[${typeof element.type === "string" ? element.type : element.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`) : void 0;
|
|
871
|
+
let route = {
|
|
872
|
+
caseSensitive: element.props.caseSensitive,
|
|
873
|
+
element: element.props.element,
|
|
874
|
+
index: element.props.index,
|
|
875
|
+
path: element.props.path
|
|
876
|
+
};
|
|
798
877
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
878
|
+
if (element.props.children) {
|
|
879
|
+
route.children = createRoutesFromChildren(element.props.children);
|
|
880
|
+
}
|
|
802
881
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
} catch (error) {
|
|
807
|
-
warning(false, `The value for the URL param "${paramName}" will not be decoded because` + ` the string "${value}" is a malformed URL segment. This is probably` + ` due to a bad percent encoding (${error}).`) ;
|
|
808
|
-
return value;
|
|
809
|
-
}
|
|
882
|
+
routes.push(route);
|
|
883
|
+
});
|
|
884
|
+
return routes;
|
|
810
885
|
}
|
|
811
886
|
/**
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* @see https://reactrouter.com/docs/en/v6/api#resolvepath
|
|
887
|
+
* Renders the result of `matchRoutes()` into a React element.
|
|
815
888
|
*/
|
|
816
889
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
let {
|
|
820
|
-
pathname: toPathname,
|
|
821
|
-
search = "",
|
|
822
|
-
hash = ""
|
|
823
|
-
} = typeof to === "string" ? parsePath(to) : to;
|
|
824
|
-
let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
|
|
825
|
-
return {
|
|
826
|
-
pathname,
|
|
827
|
-
search: normalizeSearch(search),
|
|
828
|
-
hash: normalizeHash(hash)
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
function resolvePathname(relativePath, fromPathname) {
|
|
833
|
-
let segments = fromPathname.replace(/\/+$/, "").split("/");
|
|
834
|
-
let relativeSegments = relativePath.split("/");
|
|
835
|
-
relativeSegments.forEach(segment => {
|
|
836
|
-
if (segment === "..") {
|
|
837
|
-
// Keep the root "" segment so the pathname starts at /
|
|
838
|
-
if (segments.length > 1) segments.pop();
|
|
839
|
-
} else if (segment !== ".") {
|
|
840
|
-
segments.push(segment);
|
|
841
|
-
}
|
|
842
|
-
});
|
|
843
|
-
return segments.length > 1 ? segments.join("/") : "/";
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
function resolveTo(toArg, routePathnames, locationPathname) {
|
|
847
|
-
let to = typeof toArg === "string" ? parsePath(toArg) : toArg;
|
|
848
|
-
let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; // If a pathname is explicitly provided in `to`, it should be relative to the
|
|
849
|
-
// route context. This is explained in `Note on `<Link to>` values` in our
|
|
850
|
-
// migration guide from v5 as a means of disambiguation between `to` values
|
|
851
|
-
// that begin with `/` and those that do not. However, this is problematic for
|
|
852
|
-
// `to` values that do not provide a pathname. `to` can simply be a search or
|
|
853
|
-
// hash string, in which case we should assume that the navigation is relative
|
|
854
|
-
// to the current location's pathname and *not* the route pathname.
|
|
855
|
-
|
|
856
|
-
let from;
|
|
857
|
-
|
|
858
|
-
if (toPathname == null) {
|
|
859
|
-
from = locationPathname;
|
|
860
|
-
} else {
|
|
861
|
-
let routePathnameIndex = routePathnames.length - 1;
|
|
862
|
-
|
|
863
|
-
if (toPathname.startsWith("..")) {
|
|
864
|
-
let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
|
|
865
|
-
// URL segment". This is a key difference from how <a href> works and a
|
|
866
|
-
// major reason we call this a "to" value instead of a "href".
|
|
867
|
-
|
|
868
|
-
while (toSegments[0] === "..") {
|
|
869
|
-
toSegments.shift();
|
|
870
|
-
routePathnameIndex -= 1;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
to.pathname = toSegments.join("/");
|
|
874
|
-
} // If there are more ".." segments than parent routes, resolve relative to
|
|
875
|
-
// the root / URL.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
|
|
882
|
-
|
|
883
|
-
if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
|
|
884
|
-
path.pathname += "/";
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
return path;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
function getToPathname(to) {
|
|
891
|
-
// Empty strings should be treated the same as / paths
|
|
892
|
-
return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? parsePath(to).pathname : to.pathname;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
function stripBasename(pathname, basename) {
|
|
896
|
-
if (basename === "/") return pathname;
|
|
897
|
-
|
|
898
|
-
if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
|
899
|
-
return null;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
let nextChar = pathname.charAt(basename.length);
|
|
903
|
-
|
|
904
|
-
if (nextChar && nextChar !== "/") {
|
|
905
|
-
// pathname does not start with basename/
|
|
906
|
-
return null;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
return pathname.slice(basename.length) || "/";
|
|
890
|
+
function renderMatches(matches) {
|
|
891
|
+
return _renderMatches(matches);
|
|
910
892
|
}
|
|
911
893
|
|
|
912
|
-
const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
|
|
913
|
-
|
|
914
|
-
const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
|
|
915
|
-
|
|
916
|
-
const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
917
|
-
|
|
918
|
-
const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash; ///////////////////////////////////////////////////////////////////////////////
|
|
919
|
-
|
|
920
894
|
export { MemoryRouter, Navigate, Outlet, Route, Router, Routes, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, createRoutesFromChildren, generatePath, matchPath, matchRoutes, renderMatches, resolvePath, useHref, useInRouterContext, useLocation, useMatch, useNavigate, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRoutes };
|
|
921
895
|
//# sourceMappingURL=react-router.development.js.map
|