UNPKG

33.5 kBJavaScriptView Raw
1/**
2 * React Router v6.3.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { parsePath, createMemoryHistory, Action } from 'history';
12export { Action as NavigationType, createPath, parsePath } from 'history';
13import { createContext, useContext, useMemo, useRef, useEffect, useCallback, createElement, useState, useLayoutEffect, Children, isValidElement, Fragment } from 'react';
14
15const NavigationContext = /*#__PURE__*/createContext(null);
16
17if (process.env.NODE_ENV !== "production") {
18 NavigationContext.displayName = "Navigation";
19}
20
21const LocationContext = /*#__PURE__*/createContext(null);
22
23if (process.env.NODE_ENV !== "production") {
24 LocationContext.displayName = "Location";
25}
26
27const RouteContext = /*#__PURE__*/createContext({
28 outlet: null,
29 matches: []
30});
31
32if (process.env.NODE_ENV !== "production") {
33 RouteContext.displayName = "Route";
34}
35
36function invariant(cond, message) {
37 if (!cond) throw new Error(message);
38}
39function warning(cond, message) {
40 if (!cond) {
41 // eslint-disable-next-line no-console
42 if (typeof console !== "undefined") console.warn(message);
43
44 try {
45 // Welcome to debugging React Router!
46 //
47 // This error is thrown as a convenience so you can more easily
48 // find the source for a warning that appears in the console by
49 // enabling "pause on exceptions" in your JavaScript debugger.
50 throw new Error(message); // eslint-disable-next-line no-empty
51 } catch (e) {}
52 }
53}
54const alreadyWarned = {};
55function warningOnce(key, cond, message) {
56 if (!cond && !alreadyWarned[key]) {
57 alreadyWarned[key] = true;
58 process.env.NODE_ENV !== "production" ? warning(false, message) : void 0;
59 }
60}
61
62/**
63 * Returns a path with params interpolated.
64 *
65 * @see https://reactrouter.com/docs/en/v6/api#generatepath
66 */
67function generatePath(path, params) {
68 if (params === void 0) {
69 params = {};
70 }
71
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(/^\/*/, "/"));
76}
77/**
78 * A RouteMatch contains info about how a route matched a URL.
79 */
80
81/**
82 * Matches the given routes to a location and returns the match data.
83 *
84 * @see https://reactrouter.com/docs/en/v6/api#matchroutes
85 */
86function matchRoutes(routes, locationArg, basename) {
87 if (basename === void 0) {
88 basename = "/";
89 }
90
91 let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
92 let pathname = stripBasename(location.pathname || "/", basename);
93
94 if (pathname == null) {
95 return null;
96 }
97
98 let branches = flattenRoutes(routes);
99 rankRouteBranches(branches);
100 let matches = null;
101
102 for (let i = 0; matches == null && i < branches.length; ++i) {
103 matches = matchRouteBranch(branches[i], pathname);
104 }
105
106 return matches;
107}
108
109function flattenRoutes(routes, branches, parentsMeta, parentPath) {
110 if (branches === void 0) {
111 branches = [];
112 }
113
114 if (parentsMeta === void 0) {
115 parentsMeta = [];
116 }
117
118 if (parentPath === void 0) {
119 parentPath = "";
120 }
121
122 routes.forEach((route, index) => {
123 let meta = {
124 relativePath: route.path || "",
125 caseSensitive: route.caseSensitive === true,
126 childrenIndex: index,
127 route
128 };
129
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);
133 }
134
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.
139
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.
145
146
147 if (route.path == null && !route.index) {
148 return;
149 }
150
151 branches.push({
152 path,
153 score: computeScore(path, route.index),
154 routesMeta
155 });
156 });
157 return branches;
158}
159
160function 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}
164
165const paramRe = /^:\w+$/;
166const dynamicSegmentValue = 3;
167const indexRouteValue = 2;
168const emptySegmentValue = 1;
169const staticSegmentValue = 10;
170const splatPenalty = -2;
171
172const isSplat = s => s === "*";
173
174function computeScore(path, index) {
175 let segments = path.split("/");
176 let initialScore = segments.length;
177
178 if (segments.some(isSplat)) {
179 initialScore += splatPenalty;
180 }
181
182 if (index) {
183 initialScore += indexRouteValue;
184 }
185
186 return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
187}
188
189function 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;
198}
199
200function matchRouteBranch(branch, pathname) {
201 let {
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;
233}
234/**
235 * A PathPattern is used to match on some portion of a URL pathname.
236 */
237
238
239/**
240 * Performs pattern matching on a URL pathname and returns information about
241 * the match.
242 *
243 * @see https://reactrouter.com/docs/en/v6/api#matchpath
244 */
245function 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");
266 }
267
268 memo[paramName] = safelyDecodeURIComponent(captureGroups[index] || "", paramName);
269 return memo;
270 }, {});
271 return {
272 params,
273 pathname: matchedPathname,
274 pathnameBase,
275 pattern
276 };
277}
278
279function compilePath(path, caseSensitive, end) {
280 if (caseSensitive === void 0) {
281 caseSensitive = false;
282 }
283
284 if (end === void 0) {
285 end = true;
286 }
287
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 });
297
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];
315}
316
317function 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 }
324}
325/**
326 * Returns a resolved path object relative to the given pathname.
327 *
328 * @see https://reactrouter.com/docs/en/v6/api#resolvepath
329 */
330
331
332function resolvePath(to, fromPathname) {
333 if (fromPathname === void 0) {
334 fromPathname = "/";
335 }
336
337 let {
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 };
348}
349
350function 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("/") : "/";
362}
363
364function 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.
373
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] : "/";
397 }
398
399 let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
400
401 if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
402 path.pathname += "/";
403 }
404
405 return path;
406}
407function 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}
411function stripBasename(pathname, basename) {
412 if (basename === "/") return pathname;
413
414 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
415 return null;
416 }
417
418 let nextChar = pathname.charAt(basename.length);
419
420 if (nextChar && nextChar !== "/") {
421 // pathname does not start with basename/
422 return null;
423 }
424
425 return pathname.slice(basename.length) || "/";
426}
427const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
428const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
429
430const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
431
432const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
433
434/**
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.
437 *
438 * @see https://reactrouter.com/docs/en/v6/api#usehref
439 */
440
441function 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;
455
456 if (basename !== "/") {
457 let toPathname = getToPathname(to);
458 let endsWithSlash = toPathname != null && toPathname.endsWith("/");
459 joinedPathname = pathname === "/" ? basename + (endsWithSlash ? "/" : "") : joinPaths([basename, pathname]);
460 }
461
462 return navigator.createHref({
463 pathname: joinedPathname,
464 search,
465 hash
466 });
467}
468/**
469 * Returns true if this component is a descendant of a <Router>.
470 *
471 * @see https://reactrouter.com/docs/en/v6/api#useinroutercontext
472 */
473
474function useInRouterContext() {
475 return useContext(LocationContext) != null;
476}
477/**
478 * Returns the current location object, which represents the current URL in web
479 * browsers.
480 *
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
486 */
487
488function 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;
493}
494/**
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
499 */
500
501function useNavigationType() {
502 return useContext(LocationContext).navigationType;
503}
504/**
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>.
508 *
509 * @see https://reactrouter.com/docs/en/v6/api#usematch
510 */
511
512function 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]);
520}
521/**
522 * The interface for the navigate() function returned from useNavigate().
523 */
524
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 */
531function 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 = {};
553 }
554
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;
557
558 if (typeof to === "number") {
559 navigator.go(to);
560 return;
561 }
562
563 let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
564
565 if (basename !== "/") {
566 path.pathname = joinPaths([basename, path.pathname]);
567 }
568
569 (!!options.replace ? navigator.replace : navigator.push)(path, options.state);
570 }, [basename, navigator, routePathnamesJson, locationPathname]);
571 return navigate;
572}
573const 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 */
579
580function 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 */
589
590function useOutlet(context) {
591 let outlet = useContext(RouteContext).outlet;
592
593 if (outlet) {
594 return /*#__PURE__*/createElement(OutletContext.Provider, {
595 value: context
596 }, outlet);
597 }
598
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 */
607
608function useParams() {
609 let {
610 matches
611 } = useContext(RouteContext);
612 let routeMatch = matches[matches.length - 1];
613 return routeMatch ? routeMatch.params : {};
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 */
620
621function 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]);
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 */
639
640function 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;
644 let {
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;
652
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 }
677
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;
689 }
690
691 let pathname = location.pathname || "/";
692 let remainingPathname = parentPathnameBase === "/" ? pathname : pathname.slice(parentPathnameBase.length) || "/";
693 let matches = matchRoutes(routes, {
694 pathname: remainingPathname
695 });
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 }
701
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);
707}
708function _renderMatches(matches, parentMatches) {
709 if (parentMatches === void 0) {
710 parentMatches = [];
711 }
712
713 if (matches == null) return null;
714 return matches.reduceRight((outlet, match, index) => {
715 return /*#__PURE__*/createElement(RouteContext.Provider, {
716 children: match.route.element !== undefined ? match.route.element : outlet,
717 value: {
718 outlet,
719 matches: parentMatches.concat(matches.slice(0, index + 1))
720 }
721 });
722 }, null);
723}
724
725/**
726 * A <Router> that stores all entries in memory.
727 *
728 * @see https://reactrouter.com/docs/en/v6/api#memoryrouter
729 */
730function MemoryRouter(_ref) {
731 let {
732 basename,
733 children,
734 initialEntries,
735 initialIndex
736 } = _ref;
737 let historyRef = useRef();
738
739 if (historyRef.current == null) {
740 historyRef.current = createMemoryHistory({
741 initialEntries,
742 initialIndex
743 });
744 }
745
746 let history = historyRef.current;
747 let [state, setState] = useState({
748 action: history.action,
749 location: history.location
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}
760
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 */
770function 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;
788}
789
790/**
791 * Renders the child route's element, if there is one.
792 *
793 * @see https://reactrouter.com/docs/en/v6/api#outlet
794 */
795function Outlet(props) {
796 return useOutlet(props.context);
797}
798
799/**
800 * Declares an element that should be rendered at a certain URL path.
801 *
802 * @see https://reactrouter.com/docs/en/v6/api#route
803 */
804function 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}
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 */
817function 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]);
833
834 if (typeof locationProp === "string") {
835 locationProp = parsePath(locationProp);
836 }
837
838 let {
839 pathname = "/",
840 search = "",
841 hash = "",
842 state = null,
843 key = "default"
844 } = locationProp;
845 let location = useMemo(() => {
846 let trailingPathname = stripBasename(pathname, basename);
847
848 if (trailingPathname == null) {
849 return null;
850 }
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;
861
862 if (location == null) {
863 return null;
864 }
865
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 }));
875}
876
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 */
883function Routes(_ref4) {
884 let {
885 children,
886 location
887 } = _ref4;
888 return useRoutes(createRoutesFromChildren(children), location);
889} ///////////////////////////////////////////////////////////////////////////////
890// UTILS
891///////////////////////////////////////////////////////////////////////////////
892
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 */
900
901function 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 }
909
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 }
915
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 };
923
924 if (element.props.children) {
925 route.children = createRoutesFromChildren(element.props.children);
926 }
927
928 routes.push(route);
929 });
930 return routes;
931}
932/**
933 * Renders the result of `matchRoutes()` into a React element.
934 */
935
936function renderMatches(matches) {
937 return _renderMatches(matches);
938}
939
940export { 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 };
941//# sourceMappingURL=index.js.map