UNPKG

35.8 kBJavaScriptView Raw
1/**
2 * React Router v6.2.1
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 */
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';
16
17 function invariant(cond, message) {
18 if (!cond) throw new Error(message);
19 }
20
21 function warning(cond, message) {
22 if (!cond) {
23 // eslint-disable-next-line no-console
24 if (typeof console !== "undefined") console.warn(message);
25
26 try {
27 // Welcome to debugging React Router!
28 //
29 // This error is thrown as a convenience so you can more easily
30 // find the source for a warning that appears in the console by
31 // enabling "pause on exceptions" in your JavaScript debugger.
32 throw new Error(message); // eslint-disable-next-line no-empty
33 } catch (e) {}
34 }
35 }
36
37 const alreadyWarned = {};
38
39 function warningOnce(key, cond, message) {
40 if (!cond && !alreadyWarned[key]) {
41 alreadyWarned[key] = true;
42 warning(false, message) ;
43 }
44 } ///////////////////////////////////////////////////////////////////////////////
45 // CONTEXT
46 ///////////////////////////////////////////////////////////////////////////////
47
48 /**
49 * A Navigator is a "location changer"; it's how you get to different locations.
50 *
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.
56 */
57
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";
69 }
70
71 const RouteContext = /*#__PURE__*/React.createContext({
72 outlet: null,
73 matches: []
74 });
75
76 {
77 RouteContext.displayName = "Route";
78 } ///////////////////////////////////////////////////////////////////////////////
79 // COMPONENTS
80 ///////////////////////////////////////////////////////////////////////////////
81
82
83 /**
84 * A <Router> that stores all entries in memory.
85 *
86 * @see https://reactrouter.com/docs/en/v6/api#memoryrouter
87 */
88 function MemoryRouter(_ref) {
89 let {
90 basename,
91 children,
92 initialEntries,
93 initialIndex
94 } = _ref;
95 let historyRef = React.useRef();
96
97 if (historyRef.current == null) {
98 historyRef.current = history.createMemoryHistory({
99 initialEntries,
100 initialIndex
101 });
102 }
103
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 }
118
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 }
147
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);
155 }
156
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 }
165
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]);
191
192 if (typeof locationProp === "string") {
193 locationProp = history.parsePath(locationProp);
194 }
195
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);
205
206 if (trailingPathname == null) {
207 return null;
208 }
209
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.") ;
219
220 if (location == null) {
221 return null;
222 }
223
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
231 }
232 }));
233 }
234
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 ///////////////////////////////////////////////////////////////////////////////
250
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 */
257
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;
272
273 if (basename !== "/") {
274 let toPathname = getToPathname(to);
275 let endsWithSlash = toPathname != null && toPathname.endsWith("/");
276 joinedPathname = pathname === "/" ? basename + (endsWithSlash ? "/" : "") : joinPaths([basename, pathname]);
277 }
278
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 */
290
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 */
304
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;
310 }
311
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;
320 }
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
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;
333 let {
334 pathname
335 } = useLocation();
336 return React.useMemo(() => matchPath(pattern, pathname), [pathname, pattern]);
337 }
338 /**
339 * The interface for the navigate() function returned from useNavigate().
340 */
341
342 /**
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.
345 *
346 * @see https://reactrouter.com/docs/en/v6/api#usenavigate
347 */
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 = {};
370 }
371
372 warning(activeRef.current, "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered.") ;
373 if (!activeRef.current) return;
374
375 if (typeof to === "number") {
376 navigator.go(to);
377 return;
378 }
379
380 let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
381
382 if (basename !== "/") {
383 path.pathname = joinPaths([basename, path.pathname]);
384 }
385
386 (!!options.replace ? navigator.replace : navigator.push)(path, options.state);
387 }, [basename, navigator, routePathnamesJson, locationPathname]);
388 return navigate;
389 }
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
397 function useOutletContext() {
398 return React.useContext(OutletContext);
399 }
400 /**
401 * Returns the element for the child route at this level of the route
402 * hierarchy. Used internally by <Outlet> to render child routes.
403 *
404 * @see https://reactrouter.com/docs/en/v6/api#useoutlet
405 */
406
407 function useOutlet(context) {
408 let outlet = React.useContext(RouteContext).outlet;
409
410 if (outlet) {
411 return /*#__PURE__*/React.createElement(OutletContext.Provider, {
412 value: context
413 }, outlet);
414 }
415
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 let {
427 matches
428 } = React.useContext(RouteContext);
429 let routeMatch = matches[matches.length - 1];
430 return routeMatch ? routeMatch.params : {};
431 }
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
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]);
447 }
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
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;
469
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 + "/*") + "\">."));
493 }
494
495 let locationFromContext = useLocation();
496 let location;
497
498 if (locationArg) {
499 var _parsedLocationArg$pa;
500
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;
506 }
507
508 let pathname = location.pathname || "/";
509 let remainingPathname = parentPathnameBase === "/" ? pathname : pathname.slice(parentPathnameBase.length) || "/";
510 let matches = matchRoutes(routes, {
511 pathname: remainingPathname
512 });
513
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.") ;
517 }
518
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 ///////////////////////////////////////////////////////////////////////////////
527
528 /**
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.
532 *
533 * @see https://reactrouter.com/docs/en/v6/api#createroutesfromchildren
534 */
535
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 };
558
559 if (element.props.children) {
560 route.children = createRoutesFromChildren(element.props.children);
561 }
562
563 routes.push(route);
564 });
565 return routes;
566 }
567 /**
568 * The parameters that were parsed from the URL path.
569 */
570
571 /**
572 * Returns a path with params interpolated.
573 *
574 * @see https://reactrouter.com/docs/en/v6/api#generatepath
575 */
576 function generatePath(path, params) {
577 if (params === void 0) {
578 params = {};
579 }
580
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(/^\/*/, "/"));
585 }
586 /**
587 * A RouteMatch contains info about how a route matched a URL.
588 */
589
590 /**
591 * Matches the given routes to a location and returns the match data.
592 *
593 * @see https://reactrouter.com/docs/en/v6/api#matchroutes
594 */
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
615 return matches;
616 }
617
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);
642 }
643
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
655
656 if (route.path == null && !route.index) {
657 return;
658 }
659
660 branches.push({
661 path,
662 score: computeScore(path, route.index),
663 routesMeta
664 });
665 });
666 return branches;
667 }
668
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 }
673
674 const paramRe = /^:\w+$/;
675 const dynamicSegmentValue = 3;
676 const indexRouteValue = 2;
677 const emptySegmentValue = 1;
678 const staticSegmentValue = 10;
679 const splatPenalty = -2;
680
681 const isSplat = s => s === "*";
682
683 function computeScore(path, index) {
684 let segments = path.split("/");
685 let initialScore = segments.length;
686
687 if (segments.some(isSplat)) {
688 initialScore += splatPenalty;
689 }
690
691 if (index) {
692 initialScore += indexRouteValue;
693 }
694
695 return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
696 }
697
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;
707 }
708
709 function matchRouteBranch(branch, pathname) {
710 let {
711 routesMeta
712 } = branch;
713 let matchedParams = {};
714 let matchedPathname = "/";
715 let matches = [];
716
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: joinPaths([matchedPathname, match.pathnameBase]),
733 route
734 });
735
736 if (match.pathnameBase !== "/") {
737 matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
738 }
739 }
740
741 return matches;
742 }
743 /**
744 * Renders the result of `matchRoutes()` into a React element.
745 */
746
747
748 function renderMatches(matches) {
749 return _renderMatches(matches);
750 }
751
752 function _renderMatches(matches, parentMatches) {
753 if (parentMatches === void 0) {
754 parentMatches = [];
755 }
756
757 if (matches == null) return null;
758 return matches.reduceRight((outlet, match, index) => {
759 return /*#__PURE__*/React.createElement(RouteContext.Provider, {
760 children: match.route.element !== undefined ? match.route.element : /*#__PURE__*/React.createElement(Outlet, null),
761 value: {
762 outlet,
763 matches: parentMatches.concat(matches.slice(0, index + 1))
764 }
765 });
766 }, null);
767 }
768 /**
769 * A PathPattern is used to match on some portion of a URL pathname.
770 */
771
772
773 /**
774 * Performs pattern matching on a URL pathname and returns information about
775 * the match.
776 *
777 * @see https://reactrouter.com/docs/en/v6/api#matchpath
778 */
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 }
817
818 if (end === void 0) {
819 end = true;
820 }
821
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 "([^\\/]+)";
830 });
831
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 "(?:\\b|\\/|$)";
842 }
843
844 let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
845 return [matcher, paramNames];
846 }
847
848 function safelyDecodeURIComponent(value, paramName) {
849 try {
850 return decodeURIComponent(value);
851 } catch (error) {
852 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 + ").")) ;
853 return value;
854 }
855 }
856 /**
857 * Returns a resolved path object relative to the given pathname.
858 *
859 * @see https://reactrouter.com/docs/en/v6/api#resolvepath
860 */
861
862
863 function resolvePath(to, fromPathname) {
864 if (fromPathname === void 0) {
865 fromPathname = "/";
866 }
867
868 let {
869 pathname: toPathname,
870 search = "",
871 hash = ""
872 } = typeof to === "string" ? history.parsePath(to) : to;
873 let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
874 return {
875 pathname,
876 search: normalizeSearch(search),
877 hash: normalizeHash(hash)
878 };
879 }
880
881 function resolvePathname(relativePath, fromPathname) {
882 let segments = fromPathname.replace(/\/+$/, "").split("/");
883 let relativeSegments = relativePath.split("/");
884 relativeSegments.forEach(segment => {
885 if (segment === "..") {
886 // Keep the root "" segment so the pathname starts at /
887 if (segments.length > 1) segments.pop();
888 } else if (segment !== ".") {
889 segments.push(segment);
890 }
891 });
892 return segments.length > 1 ? segments.join("/") : "/";
893 }
894
895 function resolveTo(toArg, routePathnames, locationPathname) {
896 let to = typeof toArg === "string" ? history.parsePath(toArg) : toArg;
897 let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname; // If a pathname is explicitly provided in `to`, it should be relative to the
898 // route context. This is explained in `Note on `<Link to>` values` in our
899 // migration guide from v5 as a means of disambiguation between `to` values
900 // that begin with `/` and those that do not. However, this is problematic for
901 // `to` values that do not provide a pathname. `to` can simply be a search or
902 // hash string, in which case we should assume that the navigation is relative
903 // to the current location's pathname and *not* the route pathname.
904
905 let from;
906
907 if (toPathname == null) {
908 from = locationPathname;
909 } else {
910 let routePathnameIndex = routePathnames.length - 1;
911
912 if (toPathname.startsWith("..")) {
913 let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
914 // URL segment". This is a key difference from how <a href> works and a
915 // major reason we call this a "to" value instead of a "href".
916
917 while (toSegments[0] === "..") {
918 toSegments.shift();
919 routePathnameIndex -= 1;
920 }
921
922 to.pathname = toSegments.join("/");
923 } // If there are more ".." segments than parent routes, resolve relative to
924 // the root / URL.
925
926
927 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
928 }
929
930 let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original to value had one.
931
932 if (toPathname && toPathname !== "/" && toPathname.endsWith("/") && !path.pathname.endsWith("/")) {
933 path.pathname += "/";
934 }
935
936 return path;
937 }
938
939 function getToPathname(to) {
940 // Empty strings should be treated the same as / paths
941 return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? history.parsePath(to).pathname : to.pathname;
942 }
943
944 function stripBasename(pathname, basename) {
945 if (basename === "/") return pathname;
946
947 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
948 return null;
949 }
950
951 let nextChar = pathname.charAt(basename.length);
952
953 if (nextChar && nextChar !== "/") {
954 // pathname does not start with basename/
955 return null;
956 }
957
958 return pathname.slice(basename.length) || "/";
959 }
960
961 const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
962
963 const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
964
965 const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
966
967 const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash; ///////////////////////////////////////////////////////////////////////////////
968
969 exports.MemoryRouter = MemoryRouter;
970 exports.Navigate = Navigate;
971 exports.Outlet = Outlet;
972 exports.Route = Route;
973 exports.Router = Router;
974 exports.Routes = Routes;
975 exports.UNSAFE_LocationContext = LocationContext;
976 exports.UNSAFE_NavigationContext = NavigationContext;
977 exports.UNSAFE_RouteContext = RouteContext;
978 exports.createRoutesFromChildren = createRoutesFromChildren;
979 exports.generatePath = generatePath;
980 exports.matchPath = matchPath;
981 exports.matchRoutes = matchRoutes;
982 exports.renderMatches = renderMatches;
983 exports.resolvePath = resolvePath;
984 exports.useHref = useHref;
985 exports.useInRouterContext = useInRouterContext;
986 exports.useLocation = useLocation;
987 exports.useMatch = useMatch;
988 exports.useNavigate = useNavigate;
989 exports.useNavigationType = useNavigationType;
990 exports.useOutlet = useOutlet;
991 exports.useOutletContext = useOutletContext;
992 exports.useParams = useParams;
993 exports.useResolvedPath = useResolvedPath;
994 exports.useRoutes = useRoutes;
995
996 Object.defineProperty(exports, '__esModule', { value: true });
997
998})));
999//# sourceMappingURL=react-router.development.js.map