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