UNPKG

53.7 kBJavaScriptView Raw
1/**
2 * React Router v6.26.2
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 * as React from 'react';
12import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_decodePath, UNSAFE_getResolveToMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router';
13export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, resolvePath } from '@remix-run/router';
14
15const DataRouterContext = /*#__PURE__*/React.createContext(null);
16{
17 DataRouterContext.displayName = "DataRouter";
18}
19const DataRouterStateContext = /*#__PURE__*/React.createContext(null);
20{
21 DataRouterStateContext.displayName = "DataRouterState";
22}
23const AwaitContext = /*#__PURE__*/React.createContext(null);
24{
25 AwaitContext.displayName = "Await";
26}
27const NavigationContext = /*#__PURE__*/React.createContext(null);
28{
29 NavigationContext.displayName = "Navigation";
30}
31const LocationContext = /*#__PURE__*/React.createContext(null);
32{
33 LocationContext.displayName = "Location";
34}
35const RouteContext = /*#__PURE__*/React.createContext({
36 outlet: null,
37 matches: [],
38 isDataRoute: false
39});
40{
41 RouteContext.displayName = "Route";
42}
43const RouteErrorContext = /*#__PURE__*/React.createContext(null);
44{
45 RouteErrorContext.displayName = "RouteError";
46}
47
48/**
49 * Returns the full href for the given "to" value. This is useful for building
50 * custom links that are also accessible and preserve right-click behavior.
51 *
52 * @see https://reactrouter.com/hooks/use-href
53 */
54function useHref(to, {
55 relative
56} = {}) {
57 !useInRouterContext() ? UNSAFE_invariant(false,
58 // TODO: This error is probably because they somehow have 2 versions of the
59 // router loaded. We can help them understand how to avoid that.
60 `useHref() may be used only in the context of a <Router> component.`) : void 0;
61 let {
62 basename,
63 navigator
64 } = React.useContext(NavigationContext);
65 let {
66 hash,
67 pathname,
68 search
69 } = useResolvedPath(to, {
70 relative
71 });
72 let joinedPathname = pathname;
73 // If we're operating within a basename, prepend it to the pathname prior
74 // to creating the href. If this is a root navigation, then just use the raw
75 // basename which allows the basename to have full control over the presence
76 // of a trailing slash on root links
77 if (basename !== "/") {
78 joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
79 }
80 return navigator.createHref({
81 pathname: joinedPathname,
82 search,
83 hash
84 });
85}
86/**
87 * Returns true if this component is a descendant of a `<Router>`.
88 *
89 * @see https://reactrouter.com/hooks/use-in-router-context
90 */
91function useInRouterContext() {
92 return React.useContext(LocationContext) != null;
93}
94/**
95 * Returns the current location object, which represents the current URL in web
96 * browsers.
97 *
98 * Note: If you're using this it may mean you're doing some of your own
99 * "routing" in your app, and we'd like to know what your use case is. We may
100 * be able to provide something higher-level to better suit your needs.
101 *
102 * @see https://reactrouter.com/hooks/use-location
103 */
104function useLocation() {
105 !useInRouterContext() ? UNSAFE_invariant(false,
106 // TODO: This error is probably because they somehow have 2 versions of the
107 // router loaded. We can help them understand how to avoid that.
108 `useLocation() may be used only in the context of a <Router> component.`) : void 0;
109 return React.useContext(LocationContext).location;
110}
111/**
112 * Returns the current navigation action which describes how the router came to
113 * the current location, either by a pop, push, or replace on the history stack.
114 *
115 * @see https://reactrouter.com/hooks/use-navigation-type
116 */
117function useNavigationType() {
118 return React.useContext(LocationContext).navigationType;
119}
120/**
121 * Returns a PathMatch object if the given pattern matches the current URL.
122 * This is useful for components that need to know "active" state, e.g.
123 * `<NavLink>`.
124 *
125 * @see https://reactrouter.com/hooks/use-match
126 */
127function useMatch(pattern) {
128 !useInRouterContext() ? UNSAFE_invariant(false,
129 // TODO: This error is probably because they somehow have 2 versions of the
130 // router loaded. We can help them understand how to avoid that.
131 `useMatch() may be used only in the context of a <Router> component.`) : void 0;
132 let {
133 pathname
134 } = useLocation();
135 return React.useMemo(() => matchPath(pattern, UNSAFE_decodePath(pathname)), [pathname, pattern]);
136}
137const navigateEffectWarning = `You should call navigate() in a React.useEffect(), not when ` + `your component is first rendered.`;
138// Mute warnings for calls to useNavigate in SSR environments
139function useIsomorphicLayoutEffect(cb) {
140 let isStatic = React.useContext(NavigationContext).static;
141 if (!isStatic) {
142 // We should be able to get rid of this once react 18.3 is released
143 // See: https://github.com/facebook/react/pull/26395
144 // eslint-disable-next-line react-hooks/rules-of-hooks
145 React.useLayoutEffect(cb);
146 }
147}
148/**
149 * Returns an imperative method for changing the location. Used by `<Link>`s, but
150 * may also be used by other elements to change the location.
151 *
152 * @see https://reactrouter.com/hooks/use-navigate
153 */
154function useNavigate() {
155 let {
156 isDataRoute
157 } = React.useContext(RouteContext);
158 // Conditional usage is OK here because the usage of a data router is static
159 // eslint-disable-next-line react-hooks/rules-of-hooks
160 return isDataRoute ? useNavigateStable() : useNavigateUnstable();
161}
162function useNavigateUnstable() {
163 !useInRouterContext() ? UNSAFE_invariant(false,
164 // TODO: This error is probably because they somehow have 2 versions of the
165 // router loaded. We can help them understand how to avoid that.
166 `useNavigate() may be used only in the context of a <Router> component.`) : void 0;
167 let dataRouterContext = React.useContext(DataRouterContext);
168 let {
169 basename,
170 future,
171 navigator
172 } = React.useContext(NavigationContext);
173 let {
174 matches
175 } = React.useContext(RouteContext);
176 let {
177 pathname: locationPathname
178 } = useLocation();
179 let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
180 let activeRef = React.useRef(false);
181 useIsomorphicLayoutEffect(() => {
182 activeRef.current = true;
183 });
184 let navigate = React.useCallback((to, options = {}) => {
185 UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
186 // Short circuit here since if this happens on first render the navigate
187 // is useless because we haven't wired up our history listener yet
188 if (!activeRef.current) return;
189 if (typeof to === "number") {
190 navigator.go(to);
191 return;
192 }
193 let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
194 // If we're operating within a basename, prepend it to the pathname prior
195 // to handing off to history (but only if we're not in a data router,
196 // otherwise it'll prepend the basename inside of the router).
197 // If this is a root navigation, then we navigate to the raw basename
198 // which allows the basename to have full control over the presence of a
199 // trailing slash on root links
200 if (dataRouterContext == null && basename !== "/") {
201 path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
202 }
203 (!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
204 }, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]);
205 return navigate;
206}
207const OutletContext = /*#__PURE__*/React.createContext(null);
208/**
209 * Returns the context (if provided) for the child route at this level of the route
210 * hierarchy.
211 * @see https://reactrouter.com/hooks/use-outlet-context
212 */
213function useOutletContext() {
214 return React.useContext(OutletContext);
215}
216/**
217 * Returns the element for the child route at this level of the route
218 * hierarchy. Used internally by `<Outlet>` to render child routes.
219 *
220 * @see https://reactrouter.com/hooks/use-outlet
221 */
222function useOutlet(context) {
223 let outlet = React.useContext(RouteContext).outlet;
224 if (outlet) {
225 return /*#__PURE__*/React.createElement(OutletContext.Provider, {
226 value: context
227 }, outlet);
228 }
229 return outlet;
230}
231/**
232 * Returns an object of key/value pairs of the dynamic params from the current
233 * URL that were matched by the route path.
234 *
235 * @see https://reactrouter.com/hooks/use-params
236 */
237function useParams() {
238 let {
239 matches
240 } = React.useContext(RouteContext);
241 let routeMatch = matches[matches.length - 1];
242 return routeMatch ? routeMatch.params : {};
243}
244/**
245 * Resolves the pathname of the given `to` value against the current location.
246 *
247 * @see https://reactrouter.com/hooks/use-resolved-path
248 */
249function useResolvedPath(to, {
250 relative
251} = {}) {
252 let {
253 future
254 } = React.useContext(NavigationContext);
255 let {
256 matches
257 } = React.useContext(RouteContext);
258 let {
259 pathname: locationPathname
260 } = useLocation();
261 let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
262 return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
263}
264/**
265 * Returns the element of the route that matched the current location, prepared
266 * with the correct context to render the remainder of the route tree. Route
267 * elements in the tree must render an `<Outlet>` to render their child route's
268 * element.
269 *
270 * @see https://reactrouter.com/hooks/use-routes
271 */
272function useRoutes(routes, locationArg) {
273 return useRoutesImpl(routes, locationArg);
274}
275// Internal implementation with accept optional param for RouterProvider usage
276function useRoutesImpl(routes, locationArg, dataRouterState, future) {
277 !useInRouterContext() ? UNSAFE_invariant(false,
278 // TODO: This error is probably because they somehow have 2 versions of the
279 // router loaded. We can help them understand how to avoid that.
280 `useRoutes() may be used only in the context of a <Router> component.`) : void 0;
281 let {
282 navigator
283 } = React.useContext(NavigationContext);
284 let {
285 matches: parentMatches
286 } = React.useContext(RouteContext);
287 let routeMatch = parentMatches[parentMatches.length - 1];
288 let parentParams = routeMatch ? routeMatch.params : {};
289 let parentPathname = routeMatch ? routeMatch.pathname : "/";
290 let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
291 let parentRoute = routeMatch && routeMatch.route;
292 {
293 // You won't get a warning about 2 different <Routes> under a <Route>
294 // without a trailing *, but this is a best-effort warning anyway since we
295 // cannot even give the warning unless they land at the parent route.
296 //
297 // Example:
298 //
299 // <Routes>
300 // {/* This route path MUST end with /* because otherwise
301 // it will never match /blog/post/123 */}
302 // <Route path="blog" element={<Blog />} />
303 // <Route path="blog/feed" element={<BlogFeed />} />
304 // </Routes>
305 //
306 // function Blog() {
307 // return (
308 // <Routes>
309 // <Route path="post/:id" element={<Post />} />
310 // </Routes>
311 // );
312 // }
313 let parentPath = parentRoute && parentRoute.path || "";
314 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}/*`}">.`);
315 }
316 let locationFromContext = useLocation();
317 let location;
318 if (locationArg) {
319 let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
320 !(parentPathnameBase === "/" || parsedLocationArg.pathname?.startsWith(parentPathnameBase)) ? UNSAFE_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;
321 location = parsedLocationArg;
322 } else {
323 location = locationFromContext;
324 }
325 let pathname = location.pathname || "/";
326 let remainingPathname = pathname;
327 if (parentPathnameBase !== "/") {
328 // Determine the remaining pathname by removing the # of URL segments the
329 // parentPathnameBase has, instead of removing based on character count.
330 // This is because we can't guarantee that incoming/outgoing encodings/
331 // decodings will match exactly.
332 // We decode paths before matching on a per-segment basis with
333 // decodeURIComponent(), but we re-encode pathnames via `new URL()` so they
334 // match what `window.location.pathname` would reflect. Those don't 100%
335 // align when it comes to encoded URI characters such as % and &.
336 //
337 // So we may end up with:
338 // pathname: "/descendant/a%25b/match"
339 // parentPathnameBase: "/descendant/a%b"
340 //
341 // And the direct substring removal approach won't work :/
342 let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
343 let segments = pathname.replace(/^\//, "").split("/");
344 remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
345 }
346 let matches = matchRoutes(routes, {
347 pathname: remainingPathname
348 });
349 {
350 UNSAFE_warning(parentRoute || matches != null, `No routes matched location "${location.pathname}${location.search}${location.hash}" `) ;
351 UNSAFE_warning(matches == null || matches[matches.length - 1].route.element !== undefined || matches[matches.length - 1].route.Component !== undefined || matches[matches.length - 1].route.lazy !== undefined, `Matched leaf route at location "${location.pathname}${location.search}${location.hash}" ` + `does not have an element or Component. This means it will render an <Outlet /> with a ` + `null value by default resulting in an "empty" page.`) ;
352 }
353 let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, {
354 params: Object.assign({}, parentParams, match.params),
355 pathname: joinPaths([parentPathnameBase,
356 // Re-encode pathnames that were decoded inside matchRoutes
357 navigator.encodeLocation ? navigator.encodeLocation(match.pathname).pathname : match.pathname]),
358 pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase,
359 // Re-encode pathnames that were decoded inside matchRoutes
360 navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
361 })), parentMatches, dataRouterState, future);
362 // When a user passes in a `locationArg`, the associated routes need to
363 // be wrapped in a new `LocationContext.Provider` in order for `useLocation`
364 // to use the scoped location instead of the global location.
365 if (locationArg && renderedMatches) {
366 return /*#__PURE__*/React.createElement(LocationContext.Provider, {
367 value: {
368 location: {
369 pathname: "/",
370 search: "",
371 hash: "",
372 state: null,
373 key: "default",
374 ...location
375 },
376 navigationType: Action.Pop
377 }
378 }, renderedMatches);
379 }
380 return renderedMatches;
381}
382function DefaultErrorComponent() {
383 let error = useRouteError();
384 let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
385 let stack = error instanceof Error ? error.stack : null;
386 let lightgrey = "rgba(200,200,200, 0.5)";
387 let preStyles = {
388 padding: "0.5rem",
389 backgroundColor: lightgrey
390 };
391 let codeStyles = {
392 padding: "2px 4px",
393 backgroundColor: lightgrey
394 };
395 let devInfo = null;
396 {
397 console.error("Error handled by React Router default ErrorBoundary:", error);
398 devInfo = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", null, "\uD83D\uDCBF Hey developer \uD83D\uDC4B"), /*#__PURE__*/React.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own ", /*#__PURE__*/React.createElement("code", {
399 style: codeStyles
400 }, "ErrorBoundary"), " or", " ", /*#__PURE__*/React.createElement("code", {
401 style: codeStyles
402 }, "errorElement"), " prop on your route."));
403 }
404 return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h2", null, "Unexpected Application Error!"), /*#__PURE__*/React.createElement("h3", {
405 style: {
406 fontStyle: "italic"
407 }
408 }, message), stack ? /*#__PURE__*/React.createElement("pre", {
409 style: preStyles
410 }, stack) : null, devInfo);
411}
412const defaultErrorElement = /*#__PURE__*/React.createElement(DefaultErrorComponent, null);
413class RenderErrorBoundary extends React.Component {
414 constructor(props) {
415 super(props);
416 this.state = {
417 location: props.location,
418 revalidation: props.revalidation,
419 error: props.error
420 };
421 }
422 static getDerivedStateFromError(error) {
423 return {
424 error: error
425 };
426 }
427 static getDerivedStateFromProps(props, state) {
428 // When we get into an error state, the user will likely click "back" to the
429 // previous page that didn't have an error. Because this wraps the entire
430 // application, that will have no effect--the error page continues to display.
431 // This gives us a mechanism to recover from the error when the location changes.
432 //
433 // Whether we're in an error state or not, we update the location in state
434 // so that when we are in an error state, it gets reset when a new location
435 // comes in and the user recovers from the error.
436 if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
437 return {
438 error: props.error,
439 location: props.location,
440 revalidation: props.revalidation
441 };
442 }
443 // If we're not changing locations, preserve the location but still surface
444 // any new errors that may come through. We retain the existing error, we do
445 // this because the error provided from the app state may be cleared without
446 // the location changing.
447 return {
448 error: props.error !== undefined ? props.error : state.error,
449 location: state.location,
450 revalidation: props.revalidation || state.revalidation
451 };
452 }
453 componentDidCatch(error, errorInfo) {
454 console.error("React Router caught the following error during render", error, errorInfo);
455 }
456 render() {
457 return this.state.error !== undefined ? /*#__PURE__*/React.createElement(RouteContext.Provider, {
458 value: this.props.routeContext
459 }, /*#__PURE__*/React.createElement(RouteErrorContext.Provider, {
460 value: this.state.error,
461 children: this.props.component
462 })) : this.props.children;
463 }
464}
465function RenderedRoute({
466 routeContext,
467 match,
468 children
469}) {
470 let dataRouterContext = React.useContext(DataRouterContext);
471 // Track how deep we got in our render pass to emulate SSR componentDidCatch
472 // in a DataStaticRouter
473 if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
474 dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
475 }
476 return /*#__PURE__*/React.createElement(RouteContext.Provider, {
477 value: routeContext
478 }, children);
479}
480function _renderMatches(matches, parentMatches = [], dataRouterState = null, future = null) {
481 if (matches == null) {
482 if (!dataRouterState) {
483 return null;
484 }
485 if (dataRouterState.errors) {
486 // Don't bail if we have data router errors so we can render them in the
487 // boundary. Use the pre-matched (or shimmed) matches
488 matches = dataRouterState.matches;
489 } else if (future?.v7_partialHydration && parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
490 // Don't bail if we're initializing with partial hydration and we have
491 // router matches. That means we're actively running `patchRoutesOnNavigation`
492 // so we should render down the partial matches to the appropriate
493 // `HydrateFallback`. We only do this if `parentMatches` is empty so it
494 // only impacts the root matches for `RouterProvider` and no descendant
495 // `<Routes>`
496 matches = dataRouterState.matches;
497 } else {
498 return null;
499 }
500 }
501 let renderedMatches = matches;
502 // If we have data errors, trim matches to the highest error boundary
503 let errors = dataRouterState?.errors;
504 if (errors != null) {
505 let errorIndex = renderedMatches.findIndex(m => m.route.id && errors?.[m.route.id] !== undefined);
506 !(errorIndex >= 0) ? UNSAFE_invariant(false, `Could not find a matching route for errors on route IDs: ${Object.keys(errors).join(",")}`) : void 0;
507 renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
508 }
509 // If we're in a partial hydration mode, detect if we need to render down to
510 // a given HydrateFallback while we load the rest of the hydration data
511 let renderFallback = false;
512 let fallbackIndex = -1;
513 if (dataRouterState && future && future.v7_partialHydration) {
514 for (let i = 0; i < renderedMatches.length; i++) {
515 let match = renderedMatches[i];
516 // Track the deepest fallback up until the first route without data
517 if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
518 fallbackIndex = i;
519 }
520 if (match.route.id) {
521 let {
522 loaderData,
523 errors: _errors
524 } = dataRouterState;
525 let needsToRunLoader = match.route.loader && loaderData[match.route.id] === undefined && (!_errors || _errors[match.route.id] === undefined);
526 if (match.route.lazy || needsToRunLoader) {
527 // We found the first route that's not ready to render (waiting on
528 // lazy, or has a loader that hasn't run yet). Flag that we need to
529 // render a fallback and render up until the appropriate fallback
530 renderFallback = true;
531 if (fallbackIndex >= 0) {
532 renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
533 } else {
534 renderedMatches = [renderedMatches[0]];
535 }
536 break;
537 }
538 }
539 }
540 }
541 return renderedMatches.reduceRight((outlet, match, index) => {
542 // Only data routers handle errors/fallbacks
543 let error;
544 let shouldRenderHydrateFallback = false;
545 let errorElement = null;
546 let hydrateFallbackElement = null;
547 if (dataRouterState) {
548 error = errors && match.route.id ? errors[match.route.id] : undefined;
549 errorElement = match.route.errorElement || defaultErrorElement;
550 if (renderFallback) {
551 if (fallbackIndex < 0 && index === 0) {
552 warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration");
553 shouldRenderHydrateFallback = true;
554 hydrateFallbackElement = null;
555 } else if (fallbackIndex === index) {
556 shouldRenderHydrateFallback = true;
557 hydrateFallbackElement = match.route.hydrateFallbackElement || null;
558 }
559 }
560 }
561 let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
562 let getChildren = () => {
563 let children;
564 if (error) {
565 children = errorElement;
566 } else if (shouldRenderHydrateFallback) {
567 children = hydrateFallbackElement;
568 } else if (match.route.Component) {
569 // Note: This is a de-optimized path since React won't re-use the
570 // ReactElement since it's identity changes with each new
571 // React.createElement call. We keep this so folks can use
572 // `<Route Component={...}>` in `<Routes>` but generally `Component`
573 // usage is only advised in `RouterProvider` when we can convert it to
574 // `element` ahead of time.
575 children = /*#__PURE__*/React.createElement(match.route.Component, null);
576 } else if (match.route.element) {
577 children = match.route.element;
578 } else {
579 children = outlet;
580 }
581 return /*#__PURE__*/React.createElement(RenderedRoute, {
582 match: match,
583 routeContext: {
584 outlet,
585 matches,
586 isDataRoute: dataRouterState != null
587 },
588 children: children
589 });
590 };
591 // Only wrap in an error boundary within data router usages when we have an
592 // ErrorBoundary/errorElement on this route. Otherwise let it bubble up to
593 // an ancestor ErrorBoundary/errorElement
594 return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /*#__PURE__*/React.createElement(RenderErrorBoundary, {
595 location: dataRouterState.location,
596 revalidation: dataRouterState.revalidation,
597 component: errorElement,
598 error: error,
599 children: getChildren(),
600 routeContext: {
601 outlet: null,
602 matches,
603 isDataRoute: true
604 }
605 }) : getChildren();
606 }, null);
607}
608var DataRouterHook;
609(function (DataRouterHook) {
610 DataRouterHook["UseBlocker"] = "useBlocker";
611 DataRouterHook["UseRevalidator"] = "useRevalidator";
612 DataRouterHook["UseNavigateStable"] = "useNavigate";
613})(DataRouterHook || (DataRouterHook = {}));
614var DataRouterStateHook;
615(function (DataRouterStateHook) {
616 DataRouterStateHook["UseBlocker"] = "useBlocker";
617 DataRouterStateHook["UseLoaderData"] = "useLoaderData";
618 DataRouterStateHook["UseActionData"] = "useActionData";
619 DataRouterStateHook["UseRouteError"] = "useRouteError";
620 DataRouterStateHook["UseNavigation"] = "useNavigation";
621 DataRouterStateHook["UseRouteLoaderData"] = "useRouteLoaderData";
622 DataRouterStateHook["UseMatches"] = "useMatches";
623 DataRouterStateHook["UseRevalidator"] = "useRevalidator";
624 DataRouterStateHook["UseNavigateStable"] = "useNavigate";
625 DataRouterStateHook["UseRouteId"] = "useRouteId";
626})(DataRouterStateHook || (DataRouterStateHook = {}));
627function getDataRouterConsoleError(hookName) {
628 return `${hookName} must be used within a data router. See https://reactrouter.com/routers/picking-a-router.`;
629}
630function useDataRouterContext(hookName) {
631 let ctx = React.useContext(DataRouterContext);
632 !ctx ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
633 return ctx;
634}
635function useDataRouterState(hookName) {
636 let state = React.useContext(DataRouterStateContext);
637 !state ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
638 return state;
639}
640function useRouteContext(hookName) {
641 let route = React.useContext(RouteContext);
642 !route ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
643 return route;
644}
645// Internal version with hookName-aware debugging
646function useCurrentRouteId(hookName) {
647 let route = useRouteContext(hookName);
648 let thisRoute = route.matches[route.matches.length - 1];
649 !thisRoute.route.id ? UNSAFE_invariant(false, `${hookName} can only be used on routes that contain a unique "id"`) : void 0;
650 return thisRoute.route.id;
651}
652/**
653 * Returns the ID for the nearest contextual route
654 */
655function useRouteId() {
656 return useCurrentRouteId(DataRouterStateHook.UseRouteId);
657}
658/**
659 * Returns the current navigation, defaulting to an "idle" navigation when
660 * no navigation is in progress
661 */
662function useNavigation() {
663 let state = useDataRouterState(DataRouterStateHook.UseNavigation);
664 return state.navigation;
665}
666/**
667 * Returns a revalidate function for manually triggering revalidation, as well
668 * as the current state of any manual revalidations
669 */
670function useRevalidator() {
671 let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);
672 let state = useDataRouterState(DataRouterStateHook.UseRevalidator);
673 return React.useMemo(() => ({
674 revalidate: dataRouterContext.router.revalidate,
675 state: state.revalidation
676 }), [dataRouterContext.router.revalidate, state.revalidation]);
677}
678/**
679 * Returns the active route matches, useful for accessing loaderData for
680 * parent/child routes or the route "handle" property
681 */
682function useMatches() {
683 let {
684 matches,
685 loaderData
686 } = useDataRouterState(DataRouterStateHook.UseMatches);
687 return React.useMemo(() => matches.map(m => UNSAFE_convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
688}
689/**
690 * Returns the loader data for the nearest ancestor Route loader
691 */
692function useLoaderData() {
693 let state = useDataRouterState(DataRouterStateHook.UseLoaderData);
694 let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
695 if (state.errors && state.errors[routeId] != null) {
696 console.error(`You cannot \`useLoaderData\` in an errorElement (routeId: ${routeId})`);
697 return undefined;
698 }
699 return state.loaderData[routeId];
700}
701/**
702 * Returns the loaderData for the given routeId
703 */
704function useRouteLoaderData(routeId) {
705 let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);
706 return state.loaderData[routeId];
707}
708/**
709 * Returns the action data for the nearest ancestor Route action
710 */
711function useActionData() {
712 let state = useDataRouterState(DataRouterStateHook.UseActionData);
713 let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
714 return state.actionData ? state.actionData[routeId] : undefined;
715}
716/**
717 * Returns the nearest ancestor Route error, which could be a loader/action
718 * error or a render error. This is intended to be called from your
719 * ErrorBoundary/errorElement to display a proper error message.
720 */
721function useRouteError() {
722 let error = React.useContext(RouteErrorContext);
723 let state = useDataRouterState(DataRouterStateHook.UseRouteError);
724 let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);
725 // If this was a render error, we put it in a RouteError context inside
726 // of RenderErrorBoundary
727 if (error !== undefined) {
728 return error;
729 }
730 // Otherwise look for errors from our data router state
731 return state.errors?.[routeId];
732}
733/**
734 * Returns the happy-path data from the nearest ancestor `<Await />` value
735 */
736function useAsyncValue() {
737 let value = React.useContext(AwaitContext);
738 return value?._data;
739}
740/**
741 * Returns the error from the nearest ancestor `<Await />` value
742 */
743function useAsyncError() {
744 let value = React.useContext(AwaitContext);
745 return value?._error;
746}
747let blockerId = 0;
748/**
749 * Allow the application to block navigations within the SPA and present the
750 * user a confirmation dialog to confirm the navigation. Mostly used to avoid
751 * using half-filled form data. This does not handle hard-reloads or
752 * cross-origin navigations.
753 */
754function useBlocker(shouldBlock) {
755 let {
756 router,
757 basename
758 } = useDataRouterContext(DataRouterHook.UseBlocker);
759 let state = useDataRouterState(DataRouterStateHook.UseBlocker);
760 let [blockerKey, setBlockerKey] = React.useState("");
761 let blockerFunction = React.useCallback(arg => {
762 if (typeof shouldBlock !== "function") {
763 return !!shouldBlock;
764 }
765 if (basename === "/") {
766 return shouldBlock(arg);
767 }
768 // If they provided us a function and we've got an active basename, strip
769 // it from the locations we expose to the user to match the behavior of
770 // useLocation
771 let {
772 currentLocation,
773 nextLocation,
774 historyAction
775 } = arg;
776 return shouldBlock({
777 currentLocation: {
778 ...currentLocation,
779 pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
780 },
781 nextLocation: {
782 ...nextLocation,
783 pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
784 },
785 historyAction
786 });
787 }, [basename, shouldBlock]);
788 // This effect is in charge of blocker key assignment and deletion (which is
789 // tightly coupled to the key)
790 React.useEffect(() => {
791 let key = String(++blockerId);
792 setBlockerKey(key);
793 return () => router.deleteBlocker(key);
794 }, [router]);
795 // This effect handles assigning the blockerFunction. This is to handle
796 // unstable blocker function identities, and happens only after the prior
797 // effect so we don't get an orphaned blockerFunction in the router with a
798 // key of "". Until then we just have the IDLE_BLOCKER.
799 React.useEffect(() => {
800 if (blockerKey !== "") {
801 router.getBlocker(blockerKey, blockerFunction);
802 }
803 }, [router, blockerKey, blockerFunction]);
804 // Prefer the blocker from `state` not `router.state` since DataRouterContext
805 // is memoized so this ensures we update on blocker state updates
806 return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
807}
808/**
809 * Stable version of useNavigate that is used when we are in the context of
810 * a RouterProvider.
811 */
812function useNavigateStable() {
813 let {
814 router
815 } = useDataRouterContext(DataRouterHook.UseNavigateStable);
816 let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
817 let activeRef = React.useRef(false);
818 useIsomorphicLayoutEffect(() => {
819 activeRef.current = true;
820 });
821 let navigate = React.useCallback((to, options = {}) => {
822 UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
823 // Short circuit here since if this happens on first render the navigate
824 // is useless because we haven't wired up our router subscriber yet
825 if (!activeRef.current) return;
826 if (typeof to === "number") {
827 router.navigate(to);
828 } else {
829 router.navigate(to, {
830 fromRouteId: id,
831 ...options
832 });
833 }
834 }, [router, id]);
835 return navigate;
836}
837const alreadyWarned = {};
838function warningOnce(key, cond, message) {
839 if (!cond && !alreadyWarned[key]) {
840 alreadyWarned[key] = true;
841 UNSAFE_warning(false, message) ;
842 }
843}
844
845/**
846 Webpack + React 17 fails to compile on any of the following because webpack
847 complains that `startTransition` doesn't exist in `React`:
848 * import { startTransition } from "react"
849 * import * as React from from "react";
850 "startTransition" in React ? React.startTransition(() => setState()) : setState()
851 * import * as React from from "react";
852 "startTransition" in React ? React["startTransition"](() => setState()) : setState()
853
854 Moving it to a constant such as the following solves the Webpack/React 17 issue:
855 * import * as React from from "react";
856 const START_TRANSITION = "startTransition";
857 START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()
858
859 However, that introduces webpack/terser minification issues in production builds
860 in React 18 where minification/obfuscation ends up removing the call of
861 React.startTransition entirely from the first half of the ternary. Grabbing
862 this exported reference once up front resolves that issue.
863
864 See https://github.com/remix-run/react-router/issues/10579
865*/
866const START_TRANSITION = "startTransition";
867const startTransitionImpl = React[START_TRANSITION];
868/**
869 * Given a Remix Router instance, render the appropriate UI
870 */
871function RouterProvider({
872 fallbackElement,
873 router,
874 future
875}) {
876 let [state, setStateImpl] = React.useState(router.state);
877 let {
878 v7_startTransition
879 } = future || {};
880 let setState = React.useCallback(newState => {
881 if (v7_startTransition && startTransitionImpl) {
882 startTransitionImpl(() => setStateImpl(newState));
883 } else {
884 setStateImpl(newState);
885 }
886 }, [setStateImpl, v7_startTransition]);
887 // Need to use a layout effect here so we are subscribed early enough to
888 // pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
889 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
890 React.useEffect(() => {
891 UNSAFE_warning(fallbackElement == null || !router.future.v7_partialHydration, "`<RouterProvider fallbackElement>` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead") ;
892 // Only log this once on initial mount
893 // eslint-disable-next-line react-hooks/exhaustive-deps
894 }, []);
895 let navigator = React.useMemo(() => {
896 return {
897 createHref: router.createHref,
898 encodeLocation: router.encodeLocation,
899 go: n => router.navigate(n),
900 push: (to, state, opts) => router.navigate(to, {
901 state,
902 preventScrollReset: opts?.preventScrollReset
903 }),
904 replace: (to, state, opts) => router.navigate(to, {
905 replace: true,
906 state,
907 preventScrollReset: opts?.preventScrollReset
908 })
909 };
910 }, [router]);
911 let basename = router.basename || "/";
912 let dataRouterContext = React.useMemo(() => ({
913 router,
914 navigator,
915 static: false,
916 basename
917 }), [router, navigator, basename]);
918 // The fragment and {null} here are important! We need them to keep React 18's
919 // useId happy when we are server-rendering since we may have a <script> here
920 // containing the hydrated server-side staticContext (from StaticRouterProvider).
921 // useId relies on the component tree structure to generate deterministic id's
922 // so we need to ensure it remains the same on the client even though
923 // we don't need the <script> tag
924 return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DataRouterContext.Provider, {
925 value: dataRouterContext
926 }, /*#__PURE__*/React.createElement(DataRouterStateContext.Provider, {
927 value: state
928 }, /*#__PURE__*/React.createElement(Router, {
929 basename: basename,
930 location: state.location,
931 navigationType: state.historyAction,
932 navigator: navigator,
933 future: {
934 v7_relativeSplatPath: router.future.v7_relativeSplatPath
935 }
936 }, state.initialized || router.future.v7_partialHydration ? /*#__PURE__*/React.createElement(DataRoutes, {
937 routes: router.routes,
938 future: router.future,
939 state: state
940 }) : fallbackElement))), null);
941}
942function DataRoutes({
943 routes,
944 future,
945 state
946}) {
947 return useRoutesImpl(routes, undefined, state, future);
948}
949/**
950 * A `<Router>` that stores all entries in memory.
951 *
952 * @see https://reactrouter.com/router-components/memory-router
953 */
954function MemoryRouter({
955 basename,
956 children,
957 initialEntries,
958 initialIndex,
959 future
960}) {
961 let historyRef = React.useRef();
962 if (historyRef.current == null) {
963 historyRef.current = createMemoryHistory({
964 initialEntries,
965 initialIndex,
966 v5Compat: true
967 });
968 }
969 let history = historyRef.current;
970 let [state, setStateImpl] = React.useState({
971 action: history.action,
972 location: history.location
973 });
974 let {
975 v7_startTransition
976 } = future || {};
977 let setState = React.useCallback(newState => {
978 v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
979 }, [setStateImpl, v7_startTransition]);
980 React.useLayoutEffect(() => history.listen(setState), [history, setState]);
981 return /*#__PURE__*/React.createElement(Router, {
982 basename: basename,
983 children: children,
984 location: state.location,
985 navigationType: state.action,
986 navigator: history,
987 future: future
988 });
989}
990/**
991 * Changes the current location.
992 *
993 * Note: This API is mostly useful in React.Component subclasses that are not
994 * able to use hooks. In functional components, we recommend you use the
995 * `useNavigate` hook instead.
996 *
997 * @see https://reactrouter.com/components/navigate
998 */
999function Navigate({
1000 to,
1001 replace,
1002 state,
1003 relative
1004}) {
1005 !useInRouterContext() ? UNSAFE_invariant(false,
1006 // TODO: This error is probably because they somehow have 2 versions of
1007 // the router loaded. We can help them understand how to avoid that.
1008 `<Navigate> may be used only in the context of a <Router> component.`) : void 0;
1009 let {
1010 future,
1011 static: isStatic
1012 } = React.useContext(NavigationContext);
1013 UNSAFE_warning(!isStatic, `<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.`) ;
1014 let {
1015 matches
1016 } = React.useContext(RouteContext);
1017 let {
1018 pathname: locationPathname
1019 } = useLocation();
1020 let navigate = useNavigate();
1021 // Resolve the path outside of the effect so that when effects run twice in
1022 // StrictMode they navigate to the same place
1023 let path = resolveTo(to, UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath), locationPathname, relative === "path");
1024 let jsonPath = JSON.stringify(path);
1025 React.useEffect(() => navigate(JSON.parse(jsonPath), {
1026 replace,
1027 state,
1028 relative
1029 }), [navigate, jsonPath, relative, replace, state]);
1030 return null;
1031}
1032/**
1033 * Renders the child route's element, if there is one.
1034 *
1035 * @see https://reactrouter.com/components/outlet
1036 */
1037function Outlet(props) {
1038 return useOutlet(props.context);
1039}
1040/**
1041 * Declares an element that should be rendered at a certain URL path.
1042 *
1043 * @see https://reactrouter.com/components/route
1044 */
1045function Route(_props) {
1046 UNSAFE_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>.`) ;
1047}
1048/**
1049 * Provides location context for the rest of the app.
1050 *
1051 * Note: You usually won't render a `<Router>` directly. Instead, you'll render a
1052 * router that is more specific to your environment such as a `<BrowserRouter>`
1053 * in web browsers or a `<StaticRouter>` for server rendering.
1054 *
1055 * @see https://reactrouter.com/router-components/router
1056 */
1057function Router({
1058 basename: basenameProp = "/",
1059 children = null,
1060 location: locationProp,
1061 navigationType = Action.Pop,
1062 navigator,
1063 static: staticProp = false,
1064 future
1065}) {
1066 !!useInRouterContext() ? UNSAFE_invariant(false, `You cannot render a <Router> inside another <Router>.` + ` You should never have more than one in your app.`) : void 0;
1067 // Preserve trailing slashes on basename, so we can let the user control
1068 // the enforcement of trailing slashes throughout the app
1069 let basename = basenameProp.replace(/^\/*/, "/");
1070 let navigationContext = React.useMemo(() => ({
1071 basename,
1072 navigator,
1073 static: staticProp,
1074 future: {
1075 v7_relativeSplatPath: false,
1076 ...future
1077 }
1078 }), [basename, future, navigator, staticProp]);
1079 if (typeof locationProp === "string") {
1080 locationProp = parsePath(locationProp);
1081 }
1082 let {
1083 pathname = "/",
1084 search = "",
1085 hash = "",
1086 state = null,
1087 key = "default"
1088 } = locationProp;
1089 let locationContext = React.useMemo(() => {
1090 let trailingPathname = stripBasename(pathname, basename);
1091 if (trailingPathname == null) {
1092 return null;
1093 }
1094 return {
1095 location: {
1096 pathname: trailingPathname,
1097 search,
1098 hash,
1099 state,
1100 key
1101 },
1102 navigationType
1103 };
1104 }, [basename, pathname, search, hash, state, key, navigationType]);
1105 UNSAFE_warning(locationContext != 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.`) ;
1106 if (locationContext == null) {
1107 return null;
1108 }
1109 return /*#__PURE__*/React.createElement(NavigationContext.Provider, {
1110 value: navigationContext
1111 }, /*#__PURE__*/React.createElement(LocationContext.Provider, {
1112 children: children,
1113 value: locationContext
1114 }));
1115}
1116/**
1117 * A container for a nested tree of `<Route>` elements that renders the branch
1118 * that best matches the current location.
1119 *
1120 * @see https://reactrouter.com/components/routes
1121 */
1122function Routes({
1123 children,
1124 location
1125}) {
1126 return useRoutes(createRoutesFromChildren(children), location);
1127}
1128/**
1129 * Component to use for rendering lazily loaded data from returning defer()
1130 * in a loader function
1131 */
1132function Await({
1133 children,
1134 errorElement,
1135 resolve
1136}) {
1137 return /*#__PURE__*/React.createElement(AwaitErrorBoundary, {
1138 resolve: resolve,
1139 errorElement: errorElement
1140 }, /*#__PURE__*/React.createElement(ResolveAwait, null, children));
1141}
1142var AwaitRenderStatus;
1143(function (AwaitRenderStatus) {
1144 AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
1145 AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
1146 AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
1147})(AwaitRenderStatus || (AwaitRenderStatus = {}));
1148const neverSettledPromise = new Promise(() => {});
1149class AwaitErrorBoundary extends React.Component {
1150 constructor(props) {
1151 super(props);
1152 this.state = {
1153 error: null
1154 };
1155 }
1156 static getDerivedStateFromError(error) {
1157 return {
1158 error
1159 };
1160 }
1161 componentDidCatch(error, errorInfo) {
1162 console.error("<Await> caught the following error during render", error, errorInfo);
1163 }
1164 render() {
1165 let {
1166 children,
1167 errorElement,
1168 resolve
1169 } = this.props;
1170 let promise = null;
1171 let status = AwaitRenderStatus.pending;
1172 if (!(resolve instanceof Promise)) {
1173 // Didn't get a promise - provide as a resolved promise
1174 status = AwaitRenderStatus.success;
1175 promise = Promise.resolve();
1176 Object.defineProperty(promise, "_tracked", {
1177 get: () => true
1178 });
1179 Object.defineProperty(promise, "_data", {
1180 get: () => resolve
1181 });
1182 } else if (this.state.error) {
1183 // Caught a render error, provide it as a rejected promise
1184 status = AwaitRenderStatus.error;
1185 let renderError = this.state.error;
1186 promise = Promise.reject().catch(() => {}); // Avoid unhandled rejection warnings
1187 Object.defineProperty(promise, "_tracked", {
1188 get: () => true
1189 });
1190 Object.defineProperty(promise, "_error", {
1191 get: () => renderError
1192 });
1193 } else if (resolve._tracked) {
1194 // Already tracked promise - check contents
1195 promise = resolve;
1196 status = "_error" in promise ? AwaitRenderStatus.error : "_data" in promise ? AwaitRenderStatus.success : AwaitRenderStatus.pending;
1197 } else {
1198 // Raw (untracked) promise - track it
1199 status = AwaitRenderStatus.pending;
1200 Object.defineProperty(resolve, "_tracked", {
1201 get: () => true
1202 });
1203 promise = resolve.then(data => Object.defineProperty(resolve, "_data", {
1204 get: () => data
1205 }), error => Object.defineProperty(resolve, "_error", {
1206 get: () => error
1207 }));
1208 }
1209 if (status === AwaitRenderStatus.error && promise._error instanceof AbortedDeferredError) {
1210 // Freeze the UI by throwing a never resolved promise
1211 throw neverSettledPromise;
1212 }
1213 if (status === AwaitRenderStatus.error && !errorElement) {
1214 // No errorElement, throw to the nearest route-level error boundary
1215 throw promise._error;
1216 }
1217 if (status === AwaitRenderStatus.error) {
1218 // Render via our errorElement
1219 return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
1220 value: promise,
1221 children: errorElement
1222 });
1223 }
1224 if (status === AwaitRenderStatus.success) {
1225 // Render children with resolved value
1226 return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
1227 value: promise,
1228 children: children
1229 });
1230 }
1231 // Throw to the suspense boundary
1232 throw promise;
1233 }
1234}
1235/**
1236 * @private
1237 * Indirection to leverage useAsyncValue for a render-prop API on `<Await>`
1238 */
1239function ResolveAwait({
1240 children
1241}) {
1242 let data = useAsyncValue();
1243 let toRender = typeof children === "function" ? children(data) : children;
1244 return /*#__PURE__*/React.createElement(React.Fragment, null, toRender);
1245}
1246///////////////////////////////////////////////////////////////////////////////
1247// UTILS
1248///////////////////////////////////////////////////////////////////////////////
1249/**
1250 * Creates a route config from a React "children" object, which is usually
1251 * either a `<Route>` element or an array of them. Used internally by
1252 * `<Routes>` to create a route config from its children.
1253 *
1254 * @see https://reactrouter.com/utils/create-routes-from-children
1255 */
1256function createRoutesFromChildren(children, parentPath = []) {
1257 let routes = [];
1258 React.Children.forEach(children, (element, index) => {
1259 if (! /*#__PURE__*/React.isValidElement(element)) {
1260 // Ignore non-elements. This allows people to more easily inline
1261 // conditionals in their route config.
1262 return;
1263 }
1264 let treePath = [...parentPath, index];
1265 if (element.type === React.Fragment) {
1266 // Transparently support React.Fragment and its children.
1267 routes.push.apply(routes, createRoutesFromChildren(element.props.children, treePath));
1268 return;
1269 }
1270 !(element.type === Route) ? UNSAFE_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;
1271 !(!element.props.index || !element.props.children) ? UNSAFE_invariant(false, "An index route cannot have child routes.") : void 0;
1272 let route = {
1273 id: element.props.id || treePath.join("-"),
1274 caseSensitive: element.props.caseSensitive,
1275 element: element.props.element,
1276 Component: element.props.Component,
1277 index: element.props.index,
1278 path: element.props.path,
1279 loader: element.props.loader,
1280 action: element.props.action,
1281 errorElement: element.props.errorElement,
1282 ErrorBoundary: element.props.ErrorBoundary,
1283 hasErrorBoundary: element.props.ErrorBoundary != null || element.props.errorElement != null,
1284 shouldRevalidate: element.props.shouldRevalidate,
1285 handle: element.props.handle,
1286 lazy: element.props.lazy
1287 };
1288 if (element.props.children) {
1289 route.children = createRoutesFromChildren(element.props.children, treePath);
1290 }
1291 routes.push(route);
1292 });
1293 return routes;
1294}
1295/**
1296 * Renders the result of `matchRoutes()` into a React element.
1297 */
1298function renderMatches(matches) {
1299 return _renderMatches(matches);
1300}
1301
1302function mapRouteProperties(route) {
1303 let updates = {
1304 // Note: this check also occurs in createRoutesFromChildren so update
1305 // there if you change this -- please and thank you!
1306 hasErrorBoundary: route.ErrorBoundary != null || route.errorElement != null
1307 };
1308 if (route.Component) {
1309 {
1310 if (route.element) {
1311 UNSAFE_warning(false, "You should not include both `Component` and `element` on your route - " + "`Component` will be used.") ;
1312 }
1313 }
1314 Object.assign(updates, {
1315 element: /*#__PURE__*/React.createElement(route.Component),
1316 Component: undefined
1317 });
1318 }
1319 if (route.HydrateFallback) {
1320 {
1321 if (route.hydrateFallbackElement) {
1322 UNSAFE_warning(false, "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - " + "`HydrateFallback` will be used.") ;
1323 }
1324 }
1325 Object.assign(updates, {
1326 hydrateFallbackElement: /*#__PURE__*/React.createElement(route.HydrateFallback),
1327 HydrateFallback: undefined
1328 });
1329 }
1330 if (route.ErrorBoundary) {
1331 {
1332 if (route.errorElement) {
1333 UNSAFE_warning(false, "You should not include both `ErrorBoundary` and `errorElement` on your route - " + "`ErrorBoundary` will be used.") ;
1334 }
1335 }
1336 Object.assign(updates, {
1337 errorElement: /*#__PURE__*/React.createElement(route.ErrorBoundary),
1338 ErrorBoundary: undefined
1339 });
1340 }
1341 return updates;
1342}
1343function createMemoryRouter(routes, opts) {
1344 return createRouter({
1345 basename: opts?.basename,
1346 future: {
1347 ...opts?.future,
1348 v7_prependBasename: true
1349 },
1350 history: createMemoryHistory({
1351 initialEntries: opts?.initialEntries,
1352 initialIndex: opts?.initialIndex
1353 }),
1354 hydrationData: opts?.hydrationData,
1355 routes,
1356 mapRouteProperties,
1357 unstable_dataStrategy: opts?.unstable_dataStrategy,
1358 unstable_patchRoutesOnNavigation: opts?.unstable_patchRoutesOnNavigation
1359 }).initialize();
1360}
1361
1362export { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, mapRouteProperties as UNSAFE_mapRouteProperties, useRouteId as UNSAFE_useRouteId, useRoutesImpl as UNSAFE_useRoutesImpl, createMemoryRouter, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes };
1363//# sourceMappingURL=react-router.development.js.map