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