UNPKG

48.2 kBJavaScriptView Raw
1/**
2 * react-router v8.2.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 { invariant, parsePath, warning } from "./router/history.js";
12import { convertRouteMatchToUiMatch, decodePath, getResolveToMatches, getRoutePattern, isBrowser, isRouteErrorResponse, joinPaths, matchPath, matchRoutes, parseToInfo, resolveTo, stripBasename } from "./router/utils.js";
13import { IDLE_BLOCKER, hasInvalidProtocol } from "./router/router.js";
14import { AwaitContext, DataRouterContext, DataRouterStateContext, LocationContext, NavigationContext, RSCRouterContext, RouteContext, RouteErrorContext } from "./context.js";
15import { decodeRedirectErrorDigest, decodeRouteErrorResponseDigest } from "./errors.js";
16import * as React$1 from "react";
17//#region lib/hooks.tsx
18/**
19* Resolves a URL against the current {@link Location}.
20*
21* @example
22* import { useHref } from "react-router";
23*
24* function SomeComponent() {
25* let href = useHref("some/where");
26* // "/resolved/some/where"
27* }
28*
29* @public
30* @category Hooks
31* @param to The path to resolve
32* @param options Options
33* @param options.relative Defaults to `"route"` so routing is relative to the
34* route tree.
35* Set to `"path"` to make relative routing operate against path segments.
36* @returns The resolved href string
37*/
38function useHref(to, { relative } = {}) {
39 invariant(useInRouterContext(), `useHref() may be used only in the context of a <Router> component.`);
40 let { basename, navigator } = React$1.useContext(NavigationContext);
41 let { hash, pathname, search } = useResolvedPath(to, { relative });
42 let joinedPathname = pathname;
43 if (basename !== "/") joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
44 return navigator.createHref({
45 pathname: joinedPathname,
46 search,
47 hash
48 });
49}
50/**
51* Returns `true` if this component is a descendant of a {@link Router}, useful
52* to ensure a component is used within a {@link Router}.
53*
54* @public
55* @category Hooks
56* @mode framework
57* @mode data
58* @returns Whether the component is within a {@link Router} context
59*/
60function useInRouterContext() {
61 return React$1.useContext(LocationContext) != null;
62}
63/**
64* Returns the current {@link Location}. This can be useful if you'd like to
65* perform some side effect whenever it changes.
66*
67* @example
68* import * as React from 'react'
69* import { useLocation } from 'react-router'
70*
71* function SomeComponent() {
72* let location = useLocation()
73*
74* React.useEffect(() => {
75* // Google Analytics
76* ga('send', 'pageview')
77* }, [location]);
78*
79* return (
80* // ...
81* );
82* }
83*
84* @public
85* @category Hooks
86* @returns The current {@link Location} object
87*/
88function useLocation() {
89 invariant(useInRouterContext(), `useLocation() may be used only in the context of a <Router> component.`);
90 return React$1.useContext(LocationContext).location;
91}
92/**
93* Returns the current {@link Navigation} action which describes how the router
94* came to the current {@link Location}, either by a pop, push, or replace on
95* the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History) stack.
96*
97* @public
98* @category Hooks
99* @returns The current {@link NavigationType} (`"POP"`, `"PUSH"`, or `"REPLACE"`)
100*/
101function useNavigationType() {
102 return React$1.useContext(LocationContext).navigationType;
103}
104/**
105* Returns a {@link PathMatch} object if the given pattern matches the current URL.
106* This is useful for components that need to know "active" state, e.g.
107* {@link NavLink | `<NavLink>`}.
108*
109* @public
110* @category Hooks
111* @param pattern The pattern to match against the current {@link Location}
112* @returns The path match object if the pattern matches, `null` otherwise
113*/
114function useMatch(pattern) {
115 invariant(useInRouterContext(), `useMatch() may be used only in the context of a <Router> component.`);
116 let { pathname } = useLocation();
117 return React$1.useMemo(() => matchPath(pattern, decodePath(pathname)), [pathname, pattern]);
118}
119const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when your component is first rendered.";
120/**
121* Returns a function that lets you navigate programmatically in the browser in
122* response to user interactions or effects.
123*
124* It's often better to use {@link redirect} in [`action`](../../start/framework/route-module#action)/[`loader`](../../start/framework/route-module#loader)
125* functions than this hook.
126*
127* The returned function signature is `navigate(to, options?)`/`navigate(delta)` where:
128*
129* * `to` can be a string path, a {@link To} object, or a number (delta)
130* * `options` contains options for modifying the navigation
131* * These options work in all modes (Framework, Data, and Declarative):
132* * `relative`: `"route"` or `"path"` to control relative routing logic
133* * `replace`: Replace the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History) stack
134* * `state`: Optional [`history.state`](https://developer.mozilla.org/en-US/docs/Web/API/History/state) to include with the new {@link Location}
135* * These options only work in Framework and Data modes:
136* * `flushSync`: Wrap the DOM updates in [`ReactDom.flushSync`](https://react.dev/reference/react-dom/flushSync)
137* * `preventScrollReset`: Do not scroll back to the top of the page after navigation
138* * `viewTransition`: Enable [`document.startViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition) for this navigation
139*
140* @example
141* import { useNavigate } from "react-router";
142*
143* function SomeComponent() {
144* let navigate = useNavigate();
145* return (
146* <button onClick={() => navigate(-1)}>
147* Go Back
148* </button>
149* );
150* }
151*
152* @additionalExamples
153* ### Navigate to another path
154*
155* ```tsx
156* navigate("/some/route");
157* navigate("/some/route?search=param");
158* ```
159*
160* ### Navigate with a {@link To} object
161*
162* All properties are optional.
163*
164* ```tsx
165* navigate(
166* {
167* pathname: "/some/route",
168* search: "?search=param",
169* hash: "#hash",
170* },
171* {
172* state: { some: "state" },
173* },
174* );
175* ```
176*
177* If you use `state`, that will be available on the {@link Location} object on
178* the next page. Access it with `useLocation().state` (see {@link useLocation}).
179*
180* ### Navigate back or forward in the history stack
181*
182* ```tsx
183* // back
184* // often used to close modals
185* navigate(-1);
186*
187* // forward
188* // often used in a multistep wizard workflows
189* navigate(1);
190* ```
191*
192* Be cautious with `navigate(number)`. If your application can load up to a
193* route that has a button that tries to navigate forward/back, there may not be
194* a [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
195* entry to go back or forward to, or it can go somewhere you don't expect
196* (like a different domain).
197*
198* Only use this if you're sure they will have an entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
199* stack to navigate to.
200*
201* ### Replace the current entry in the history stack
202*
203* This will remove the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
204* stack, replacing it with a new one, similar to a server side redirect.
205*
206* ```tsx
207* navigate("/some/route", { replace: true });
208* ```
209*
210* ### Prevent Scroll Reset
211*
212* [MODES: framework, data]
213*
214* <br/>
215* <br/>
216*
217* To prevent {@link ScrollRestoration | `<ScrollRestoration>`} from resetting
218* the scroll position, use the `preventScrollReset` option.
219*
220* ```tsx
221* navigate("?some-tab=1", { preventScrollReset: true });
222* ```
223*
224* For example, if you have a tab interface connected to search params in the
225* middle of a page, and you don't want it to scroll to the top when a tab is
226* clicked.
227*
228* ### Return Type Augmentation
229*
230* Internally, `useNavigate` uses a separate implementation when you are in
231* Declarative mode versus Data/Framework mode - the primary difference being
232* that the latter is able to return a stable reference that does not change
233* identity across navigations. The implementation in Data/Framework mode also
234* returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
235* that resolves when the navigation is completed. This means the return type of
236* `useNavigate` is `void | Promise<void>`. This is accurate, but can lead to
237* some red squigglies based on the union in the return value:
238*
239* - If you're using `typescript-eslint`, you may see errors from
240* [`@typescript-eslint/no-floating-promises`](https://typescript-eslint.io/rules/no-floating-promises)
241* - In Framework/Data mode, `React.use(navigate())` will show a false-positive
242* `Argument of type 'void | Promise<void>' is not assignable to parameter of
243* type 'Usable<void>'` error
244*
245* The easiest way to work around these issues is to augment the type based on the
246* router you're using:
247*
248* ```ts
249* // If using <BrowserRouter>
250* declare module "react-router" {
251* interface NavigateFunction {
252* (to: To, options?: NavigateOptions): void;
253* (delta: number): void;
254* }
255* }
256*
257* // If using <RouterProvider> or Framework mode
258* declare module "react-router" {
259* interface NavigateFunction {
260* (to: To, options?: NavigateOptions): Promise<void>;
261* (delta: number): Promise<void>;
262* }
263* }
264* ```
265*
266* @public
267* @category Hooks
268* @returns A navigate function for programmatic navigation
269*/
270function useNavigate() {
271 let { isDataRoute } = React$1.useContext(RouteContext);
272 return isDataRoute ? useNavigateStable() : useNavigateUnstable();
273}
274function useNavigateUnstable() {
275 invariant(useInRouterContext(), `useNavigate() may be used only in the context of a <Router> component.`);
276 let dataRouterContext = React$1.useContext(DataRouterContext);
277 let { basename, navigator } = React$1.useContext(NavigationContext);
278 let { matches } = React$1.useContext(RouteContext);
279 let { pathname: locationPathname } = useLocation();
280 let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
281 let activeRef = React$1.useRef(false);
282 React$1.useLayoutEffect(() => {
283 activeRef.current = true;
284 });
285 return React$1.useCallback((to, options = {}) => {
286 warning(activeRef.current, navigateEffectWarning);
287 if (!activeRef.current) return;
288 if (typeof to === "number") {
289 navigator.go(to);
290 return;
291 }
292 let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
293 if (dataRouterContext == null && basename !== "/") path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
294 (!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
295 }, [
296 basename,
297 navigator,
298 routePathnamesJson,
299 locationPathname,
300 dataRouterContext
301 ]);
302}
303const OutletContext = React$1.createContext(null);
304/**
305* Returns the parent route {@link Outlet | `<Outlet context>`}.
306*
307* Often parent routes manage state or other values you want shared with child
308* routes. You can create your own [context provider](https://react.dev/learn/passing-data-deeply-with-context)
309* if you like, but this is such a common situation that it's built-into
310* {@link Outlet | `<Outlet>`}.
311*
312* ```tsx
313* // Parent route
314* function Parent() {
315* const [count, setCount] = React.useState(0);
316* return <Outlet context={[count, setCount]} />;
317* }
318* ```
319*
320* ```tsx
321* // Child route
322* import { useOutletContext } from "react-router";
323*
324* function Child() {
325* const [count, setCount] = useOutletContext();
326* const increment = () => setCount((c) => c + 1);
327* return <button onClick={increment}>{count}</button>;
328* }
329* ```
330*
331* If you're using TypeScript, we recommend the parent component provide a
332* custom hook for accessing the context value. This makes it easier for
333* consumers to get nice typings, control consumers, and know who's consuming
334* the context value.
335*
336* Here's a more realistic example:
337*
338* ```tsx filename=src/routes/dashboard.tsx lines=[14,20]
339* import { useState } from "react";
340* import { Outlet, useOutletContext } from "react-router";
341*
342* import type { User } from "./types";
343*
344* type ContextType = { user: User | null };
345*
346* export default function Dashboard() {
347* const [user, setUser] = useState<User | null>(null);
348*
349* return (
350* <div>
351* <h1>Dashboard</h1>
352* <Outlet context={{ user } satisfies ContextType} />
353* </div>
354* );
355* }
356*
357* export function useUser() {
358* return useOutletContext<ContextType>();
359* }
360* ```
361*
362* ```tsx filename=src/routes/dashboard/messages.tsx lines=[1,4]
363* import { useUser } from "../dashboard";
364*
365* export default function DashboardMessages() {
366* const { user } = useUser();
367* return (
368* <div>
369* <h2>Messages</h2>
370* <p>Hello, {user.name}!</p>
371* </div>
372* );
373* }
374* ```
375*
376* @public
377* @category Hooks
378* @returns The context value passed to the parent {@link Outlet} component
379*/
380function useOutletContext() {
381 return React$1.useContext(OutletContext);
382}
383/**
384* Returns the element for the child route at this level of the route
385* hierarchy. Used internally by {@link Outlet | `<Outlet>`} to render child
386* routes.
387*
388* @public
389* @category Hooks
390* @param context The context to pass to the outlet
391* @returns The child route element or `null` if no child routes match
392*/
393function useOutlet(context) {
394 let outlet = React$1.useContext(RouteContext).outlet;
395 return React$1.useMemo(() => outlet && /* @__PURE__ */ React$1.createElement(OutletContext.Provider, { value: context }, outlet), [outlet, context]);
396}
397/**
398* Returns an object of key/value-pairs of the dynamic params from the current
399* URL that were matched by the routes. Child routes inherit all params from
400* their parent routes.
401*
402* Assuming a route pattern like `/posts/:postId` is matched by `/posts/123`
403* then `params.postId` will be `"123"`.
404*
405* @example
406* import { useParams } from "react-router";
407*
408* function SomeComponent() {
409* let params = useParams();
410* params.postId;
411* }
412*
413* @additionalExamples
414* ### Basic Usage
415*
416* ```tsx
417* import { useParams } from "react-router";
418*
419* // given a route like:
420* <Route path="/posts/:postId" element={<Post />} />;
421*
422* // or a data route like:
423* createBrowserRouter([
424* {
425* path: "/posts/:postId",
426* component: Post,
427* },
428* ]);
429*
430* // or in routes.ts
431* route("/posts/:postId", "routes/post.tsx");
432* ```
433*
434* Access the params in a component:
435*
436* ```tsx
437* import { useParams } from "react-router";
438*
439* export default function Post() {
440* let params = useParams();
441* return <h1>Post: {params.postId}</h1>;
442* }
443* ```
444*
445* ### Multiple Params
446*
447* Patterns can have multiple params:
448*
449* ```tsx
450* "/posts/:postId/comments/:commentId";
451* ```
452*
453* All will be available in the params object:
454*
455* ```tsx
456* import { useParams } from "react-router";
457*
458* export default function Post() {
459* let params = useParams();
460* return (
461* <h1>
462* Post: {params.postId}, Comment: {params.commentId}
463* </h1>
464* );
465* }
466* ```
467*
468* ### Catchall Params
469*
470* Catchall params are defined with `*`:
471*
472* ```tsx
473* "/files/*";
474* ```
475*
476* The matched value will be available in the params object as follows:
477*
478* ```tsx
479* import { useParams } from "react-router";
480*
481* export default function File() {
482* let params = useParams();
483* let catchall = params["*"];
484* // ...
485* }
486* ```
487*
488* You can destructure the catchall param:
489*
490* ```tsx
491* export default function File() {
492* let { "*": catchall } = useParams();
493* console.log(catchall);
494* }
495* ```
496*
497* @public
498* @category Hooks
499* @returns An object containing the dynamic route parameters
500*/
501function useParams() {
502 let { matches } = React$1.useContext(RouteContext);
503 return matches[matches.length - 1]?.params ?? {};
504}
505/**
506* Resolves the pathname of the given `to` value against the current
507* {@link Location}. Similar to {@link useHref}, but returns a
508* {@link Path} instead of a string.
509*
510* @example
511* import { useResolvedPath } from "react-router";
512*
513* function SomeComponent() {
514* // if the user is at /dashboard/profile
515* let path = useResolvedPath("../accounts");
516* path.pathname; // "/dashboard/accounts"
517* path.search; // ""
518* path.hash; // ""
519* }
520*
521* @public
522* @category Hooks
523* @param to The path to resolve
524* @param options Options
525* @param options.relative Defaults to `"route"` so routing is relative to the route tree.
526* Set to `"path"` to make relative routing operate against path segments.
527* @returns The resolved {@link Path} object with `pathname`, `search`, and `hash`
528*/
529function useResolvedPath(to, { relative } = {}) {
530 let { matches } = React$1.useContext(RouteContext);
531 let { pathname: locationPathname } = useLocation();
532 let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
533 return React$1.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [
534 to,
535 routePathnamesJson,
536 locationPathname,
537 relative
538 ]);
539}
540/**
541* Hook version of {@link Routes | `<Routes>`} that uses objects instead of
542* components. These objects have the same properties as the component props.
543* The return value of `useRoutes` is either a valid React element you can use
544* to render the route tree, or `null` if nothing matched.
545*
546* @example
547* import { useRoutes } from "react-router";
548*
549* function App() {
550* let element = useRoutes([
551* {
552* path: "/",
553* element: <Dashboard />,
554* children: [
555* {
556* path: "messages",
557* element: <DashboardMessages />,
558* },
559* { path: "tasks", element: <DashboardTasks /> },
560* ],
561* },
562* { path: "team", element: <AboutPage /> },
563* ]);
564*
565* return element;
566* }
567*
568* @public
569* @category Hooks
570* @param routes An array of {@link RouteObject}s that define the route hierarchy
571* @param locationArg An optional {@link Location} object or pathname string to
572* use instead of the current {@link Location}
573* @returns A React element to render the matched route, or `null` if no routes matched
574*/
575function useRoutes(routes, locationArg) {
576 return useRoutesImpl(routes, locationArg);
577}
578function useRoutesImpl(routes, locationArg, dataRouterOpts) {
579 invariant(useInRouterContext(), `useRoutes() may be used only in the context of a <Router> component.`);
580 let { navigator } = React$1.useContext(NavigationContext);
581 let { matches: parentMatches } = React$1.useContext(RouteContext);
582 let routeMatch = parentMatches[parentMatches.length - 1];
583 let parentParams = routeMatch ? routeMatch.params : {};
584 routeMatch && routeMatch.pathname;
585 let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
586 routeMatch && routeMatch.route;
587 let locationFromContext = useLocation();
588 let location;
589 if (locationArg) {
590 let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
591 invariant(parentPathnameBase === "/" || parsedLocationArg.pathname?.startsWith(parentPathnameBase), `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.`);
592 location = parsedLocationArg;
593 } else location = locationFromContext;
594 let pathname = location.pathname || "/";
595 let remainingPathname = pathname;
596 if (parentPathnameBase !== "/") {
597 let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
598 remainingPathname = "/" + pathname.replace(/^\//, "").split("/").slice(parentSegments.length).join("/");
599 }
600 let matches = dataRouterOpts && dataRouterOpts.state.matches.length ? dataRouterOpts.state.matches.map((m) => Object.assign(m, { route: dataRouterOpts.manifest[m.route.id] || m.route })) : matchRoutes(routes, { pathname: remainingPathname });
601 let renderedMatches = _renderMatches(matches && matches.map((match) => Object.assign({}, match, {
602 params: Object.assign({}, parentParams, match.params),
603 pathname: joinPaths([parentPathnameBase, navigator.encodeLocation ? navigator.encodeLocation(match.pathname.replace(/%/g, "%25").replace(/\?/g, "%3F").replace(/#/g, "%23")).pathname : match.pathname]),
604 pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase.replace(/%/g, "%25").replace(/\?/g, "%3F").replace(/#/g, "%23")).pathname : match.pathnameBase])
605 })), parentMatches, dataRouterOpts);
606 if (locationArg && renderedMatches) return /* @__PURE__ */ React$1.createElement(LocationContext.Provider, { value: {
607 location: {
608 pathname: "/",
609 search: "",
610 hash: "",
611 state: null,
612 key: "default",
613 mask: void 0,
614 ...location
615 },
616 navigationType: "POP"
617 } }, renderedMatches);
618 return renderedMatches;
619}
620function DefaultErrorComponent() {
621 let error = useRouteError();
622 let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
623 let stack = error instanceof Error ? error.stack : null;
624 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement("h2", null, "Unexpected Application Error!"), /* @__PURE__ */ React$1.createElement("h3", { style: { fontStyle: "italic" } }, message), stack ? /* @__PURE__ */ React$1.createElement("pre", { style: {
625 padding: "0.5rem",
626 backgroundColor: "rgba(200,200,200, 0.5)"
627 } }, stack) : null, null);
628}
629const defaultErrorElement = /* @__PURE__ */ React$1.createElement(DefaultErrorComponent, null);
630var RenderErrorBoundary = class extends React$1.Component {
631 constructor(props) {
632 super(props);
633 this.state = {
634 location: props.location,
635 revalidation: props.revalidation,
636 error: props.error
637 };
638 }
639 static contextType = RSCRouterContext;
640 static getDerivedStateFromError(error) {
641 return { error };
642 }
643 static getDerivedStateFromProps(props, state) {
644 if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") return {
645 error: props.error,
646 location: props.location,
647 revalidation: props.revalidation
648 };
649 return {
650 error: props.error !== void 0 ? props.error : state.error,
651 location: state.location,
652 revalidation: props.revalidation || state.revalidation
653 };
654 }
655 componentDidCatch(error, errorInfo) {
656 if (this.props.onError) this.props.onError(error, errorInfo);
657 else console.error("React Router caught the following error during render", error);
658 }
659 render() {
660 let error = this.state.error;
661 if (this.context && typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
662 const decoded = decodeRouteErrorResponseDigest(error.digest);
663 if (decoded) error = decoded;
664 }
665 let result = error !== void 0 ? /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React$1.createElement(RouteErrorContext.Provider, {
666 value: error,
667 children: this.props.component
668 })) : this.props.children;
669 if (this.context) return /* @__PURE__ */ React$1.createElement(RSCErrorHandler, { error }, result);
670 return result;
671 }
672};
673const errorRedirectHandledMap = /* @__PURE__ */ new WeakMap();
674function RSCErrorHandler({ children, error }) {
675 let { basename } = React$1.useContext(NavigationContext);
676 if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
677 let redirect = decodeRedirectErrorDigest(error.digest);
678 if (redirect) {
679 let existingRedirect = errorRedirectHandledMap.get(error);
680 if (existingRedirect) throw existingRedirect;
681 let parsed = parseToInfo(redirect.location, basename);
682 let target = parsed.absoluteURL || parsed.to;
683 if (hasInvalidProtocol(target)) throw new Error("Invalid redirect location");
684 if (isBrowser && !errorRedirectHandledMap.get(error)) if (parsed.isExternal || redirect.reloadDocument) window.location.href = target;
685 else {
686 const redirectPromise = Promise.resolve().then(() => window.__reactRouterDataRouter.navigate(parsed.to, { replace: redirect.replace }));
687 errorRedirectHandledMap.set(error, redirectPromise);
688 throw redirectPromise;
689 }
690 return /* @__PURE__ */ React$1.createElement("meta", {
691 httpEquiv: "refresh",
692 content: `0;url=${target}`
693 });
694 }
695 }
696 return children;
697}
698function RenderedRoute({ routeContext, match, children }) {
699 let dataRouterContext = React$1.useContext(DataRouterContext);
700 if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
701 return /* @__PURE__ */ React$1.createElement(RouteContext.Provider, { value: routeContext }, children);
702}
703function _renderMatches(matches, parentMatches = [], dataRouterOpts) {
704 let dataRouterState = dataRouterOpts?.state;
705 if (matches == null) {
706 if (!dataRouterState) return null;
707 if (dataRouterState.errors) matches = dataRouterState.matches;
708 else if (parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) matches = dataRouterState.matches;
709 else return null;
710 }
711 let renderedMatches = matches;
712 let errors = dataRouterState?.errors;
713 if (errors != null) {
714 let errorIndex = renderedMatches.findIndex((m) => m.route.id && errors?.[m.route.id] !== void 0);
715 invariant(errorIndex >= 0, `Could not find a matching route for errors on route IDs: ${Object.keys(errors).join(",")}`);
716 renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
717 }
718 let renderFallback = false;
719 let fallbackIndex = -1;
720 if (dataRouterOpts && dataRouterState) {
721 renderFallback = dataRouterState.renderFallback;
722 for (let i = 0; i < renderedMatches.length; i++) {
723 let match = renderedMatches[i];
724 if (match.route.HydrateFallback || match.route.hydrateFallbackElement) fallbackIndex = i;
725 if (match.route.id) {
726 let { loaderData, errors } = dataRouterState;
727 let needsToRunLoader = match.route.loader && !loaderData.hasOwnProperty(match.route.id) && (!errors || errors[match.route.id] === void 0);
728 if (match.route.lazy || needsToRunLoader) {
729 if (dataRouterOpts.isStatic) renderFallback = true;
730 if (fallbackIndex >= 0) renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
731 else renderedMatches = [renderedMatches[0]];
732 break;
733 }
734 }
735 }
736 }
737 let onErrorHandler = dataRouterOpts?.onError;
738 let onError = dataRouterState && onErrorHandler ? (error, errorInfo) => {
739 onErrorHandler(error, {
740 location: dataRouterState.location,
741 params: dataRouterState.matches?.[0]?.params ?? {},
742 pattern: getRoutePattern(dataRouterState.matches),
743 errorInfo
744 });
745 } : void 0;
746 return renderedMatches.reduceRight((outlet, match, index) => {
747 let error;
748 let shouldRenderHydrateFallback = false;
749 let errorElement = null;
750 let hydrateFallbackElement = null;
751 if (dataRouterState) {
752 error = errors && match.route.id ? errors[match.route.id] : void 0;
753 errorElement = match.route.errorElement || defaultErrorElement;
754 if (renderFallback) {
755 if (fallbackIndex < 0 && index === 0) {
756 warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration");
757 shouldRenderHydrateFallback = true;
758 hydrateFallbackElement = null;
759 } else if (fallbackIndex === index) {
760 shouldRenderHydrateFallback = true;
761 hydrateFallbackElement = match.route.hydrateFallbackElement || null;
762 }
763 }
764 }
765 let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
766 let getChildren = () => {
767 let children;
768 if (error) children = errorElement;
769 else if (shouldRenderHydrateFallback) children = hydrateFallbackElement;
770 else if (match.route.Component) children = /* @__PURE__ */ React$1.createElement(match.route.Component, null);
771 else if (match.route.element) children = match.route.element;
772 else children = outlet;
773 return /* @__PURE__ */ React$1.createElement(RenderedRoute, {
774 match,
775 routeContext: {
776 outlet,
777 matches,
778 isDataRoute: dataRouterState != null
779 },
780 children
781 });
782 };
783 return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /* @__PURE__ */ React$1.createElement(RenderErrorBoundary, {
784 location: dataRouterState.location,
785 revalidation: dataRouterState.revalidation,
786 component: errorElement,
787 error,
788 children: getChildren(),
789 routeContext: {
790 outlet: null,
791 matches,
792 isDataRoute: true
793 },
794 onError
795 }) : getChildren();
796 }, null);
797}
798function getDataRouterConsoleError(hookName) {
799 return `${hookName} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`;
800}
801function useDataRouterContext(hookName) {
802 let ctx = React$1.useContext(DataRouterContext);
803 invariant(ctx, getDataRouterConsoleError(hookName));
804 return ctx;
805}
806function useDataRouterState(hookName) {
807 let state = React$1.useContext(DataRouterStateContext);
808 invariant(state, getDataRouterConsoleError(hookName));
809 return state;
810}
811function useRouteContext(hookName) {
812 let route = React$1.useContext(RouteContext);
813 invariant(route, getDataRouterConsoleError(hookName));
814 return route;
815}
816function useCurrentRouteId(hookName) {
817 let route = useRouteContext(hookName);
818 let thisRoute = route.matches[route.matches.length - 1];
819 invariant(thisRoute.route.id, `${hookName} can only be used on routes that contain a unique "id"`);
820 return thisRoute.route.id;
821}
822/**
823* Returns the ID for the nearest contextual route
824*
825* @category Hooks
826* @returns The ID of the nearest contextual route
827*/
828function useRouteId() {
829 return useCurrentRouteId("useRouteId");
830}
831/**
832* Returns the current {@link Navigation}, defaulting to an "idle" navigation
833* when no navigation is in progress. You can use this to render pending UI
834* (like a global spinner) or read [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
835* from a form navigation.
836*
837* @example
838* import { useNavigation } from "react-router";
839*
840* function SomeComponent() {
841* let navigation = useNavigation();
842* navigation.state;
843* navigation.formData;
844* // etc.
845* }
846*
847* @public
848* @category Hooks
849* @mode framework
850* @mode data
851* @returns The current {@link Navigation} object
852*/
853function useNavigation() {
854 let state = useDataRouterState("useNavigation");
855 return React$1.useMemo(() => {
856 let { matches, historyAction, ...rest } = state.navigation;
857 return rest;
858 }, [state.navigation]);
859}
860/**
861* Revalidate the data on the page for reasons outside of normal data mutations
862* like [`Window` focus](https://developer.mozilla.org/en-US/docs/Web/API/Window/focus_event)
863* or polling on an interval.
864*
865* Note that page data is already revalidated automatically after actions.
866* If you find yourself using this for normal CRUD operations on your data in
867* response to user interactions, you're probably not taking advantage of the
868* other APIs like {@link useFetcher}, {@link Form}, {@link useSubmit} that do
869* this automatically.
870*
871* @example
872* import { useRevalidator } from "react-router";
873*
874* function WindowFocusRevalidator() {
875* const revalidator = useRevalidator();
876*
877* useFakeWindowFocus(() => {
878* revalidator.revalidate();
879* });
880*
881* return (
882* <div hidden={revalidator.state === "idle"}>
883* Revalidating...
884* </div>
885* );
886* }
887*
888* @public
889* @category Hooks
890* @mode framework
891* @mode data
892* @returns An object with a `revalidate` function and the current revalidation
893* `state`
894*/
895function useRevalidator() {
896 let dataRouterContext = useDataRouterContext("useRevalidator");
897 let state = useDataRouterState("useRevalidator");
898 let revalidate = React$1.useCallback(async () => {
899 await dataRouterContext.router.revalidate();
900 }, [dataRouterContext.router]);
901 return React$1.useMemo(() => ({
902 revalidate,
903 state: state.revalidation
904 }), [revalidate, state.revalidation]);
905}
906/**
907* Returns the active route matches, useful for accessing `loaderData` for
908* parent/child routes or the route [`handle`](../../start/framework/route-module#handle)
909* property
910*
911* Pairing the route `handle` with `useMatches` gets very powerful since you can put
912* whatever you want on a route handle and have access to `useMatches` anywhere.
913* Please see the [handle](../../how-to/using-handle) documentation for an example
914* of breadcrumbs via `useMatches`/`handle`.
915*
916* ```tsx
917* import { useMatches } from "react-router";
918*
919* function SomeComponent() {
920* const matches = useMatches();
921* // matches[i].id // route id
922* // matches[i].pathname // the portion of the URL the route matched
923* // matches[i].params // the parsed params from the URL
924* // matches[i].loaderData // the data from the loader
925* // matches[i].handle // the route handle with any app specific data
926* }
927* ```
928*
929* <docs-info>useMatches only works with a data router like `createBrowserRouter`,
930* since they know the full route tree up front and can provide all of the current
931* matches. Additionally, `useMatches` will not match down into any descendant route
932* trees since the router isn't aware of the descendant routes.</docs-info>
933*
934* @public
935* @category Hooks
936* @mode framework
937* @mode data
938* @returns An array of {@link UIMatch | UI matches} for the current route hierarchy
939*/
940function useMatches() {
941 let { matches, loaderData } = useDataRouterState("useMatches");
942 return React$1.useMemo(() => matches.map((m) => convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
943}
944/**
945* Returns the data from the closest route
946* [`loader`](../../start/framework/route-module#loader) or
947* [`clientLoader`](../../start/framework/route-module#clientloader).
948*
949* @example
950* import { useLoaderData } from "react-router";
951*
952* export async function loader() {
953* return await fakeDb.invoices.findAll();
954* }
955*
956* export default function Invoices() {
957* let invoices = useLoaderData<typeof loader>();
958* // ...
959* }
960*
961* @public
962* @category Hooks
963* @mode framework
964* @mode data
965* @returns The data returned from the route's [`loader`](../../start/framework/route-module#loader) or [`clientLoader`](../../start/framework/route-module#clientloader) function
966*/
967function useLoaderData() {
968 let state = useDataRouterState("useLoaderData");
969 let routeId = useCurrentRouteId("useLoaderData");
970 return state.loaderData[routeId];
971}
972/**
973* Returns the [`loader`](../../start/framework/route-module#loader) data for a
974* given route by route ID.
975*
976* Route IDs are created automatically. They are simply the path of the route file
977* relative to the app folder without the extension.
978*
979* | Route Filename | Route ID |
980* | ---------------------------- | ---------------------- |
981* | `app/root.tsx` | `"root"` |
982* | `app/routes/teams.tsx` | `"routes/teams"` |
983* | `app/whatever/teams.$id.tsx` | `"whatever/teams.$id"` |
984*
985* @example
986* import { useRouteLoaderData } from "react-router";
987*
988* function SomeComponent() {
989* const { user } = useRouteLoaderData("root");
990* }
991*
992* // You can also specify your own route ID's manually in your routes.ts file:
993* route("/", "containers/app.tsx", { id: "app" })
994* useRouteLoaderData("app");
995*
996* @public
997* @category Hooks
998* @mode framework
999* @mode data
1000* @param routeId The ID of the route to return loader data from
1001* @returns The data returned from the specified route's [`loader`](../../start/framework/route-module#loader)
1002* function, or `undefined` if not found
1003*/
1004function useRouteLoaderData(routeId) {
1005 return useDataRouterState("useRouteLoaderData").loaderData[routeId];
1006}
1007/**
1008* Returns the [`action`](../../start/framework/route-module#action) data from
1009* the most recent `POST` navigation form submission or `undefined` if there
1010* hasn't been one.
1011*
1012* @example
1013* import { Form, useActionData } from "react-router";
1014*
1015* export async function action({ request }) {
1016* const body = await request.formData();
1017* const name = body.get("visitorsName");
1018* return { message: `Hello, ${name}` };
1019* }
1020*
1021* export default function Invoices() {
1022* const data = useActionData();
1023* return (
1024* <Form method="post">
1025* <input type="text" name="visitorsName" />
1026* {data ? data.message : "Waiting..."}
1027* </Form>
1028* );
1029* }
1030*
1031* @public
1032* @category Hooks
1033* @mode framework
1034* @mode data
1035* @returns The data returned from the route's [`action`](../../start/framework/route-module#action)
1036* function, or `undefined` if no [`action`](../../start/framework/route-module#action)
1037* has been called
1038*/
1039function useActionData() {
1040 let state = useDataRouterState("useActionData");
1041 let routeId = useCurrentRouteId("useLoaderData");
1042 return state.actionData ? state.actionData[routeId] : void 0;
1043}
1044/**
1045* Accesses the error thrown during an
1046* [`action`](../../start/framework/route-module#action),
1047* [`loader`](../../start/framework/route-module#loader),
1048* or component render to be used in a route module
1049* [`ErrorBoundary`](../../start/framework/route-module#errorboundary).
1050*
1051* @example
1052* export function ErrorBoundary() {
1053* const error = useRouteError();
1054* return <div>{error.message}</div>;
1055* }
1056*
1057* @public
1058* @category Hooks
1059* @mode framework
1060* @mode data
1061* @returns The error that was thrown during route [loading](../../start/framework/route-module#loader),
1062* [`action`](../../start/framework/route-module#action) execution, or rendering
1063*/
1064function useRouteError() {
1065 let error = React$1.useContext(RouteErrorContext);
1066 let state = useDataRouterState("useRouteError");
1067 let routeId = useCurrentRouteId("useRouteError");
1068 if (error !== void 0) return error;
1069 return state.errors?.[routeId];
1070}
1071/**
1072* Returns the resolved promise value from the closest {@link Await | `<Await>`}.
1073*
1074* @example
1075* function SomeDescendant() {
1076* const value = useAsyncValue();
1077* // ...
1078* }
1079*
1080* // somewhere in your app
1081* <Await resolve={somePromise}>
1082* <SomeDescendant />
1083* </Await>;
1084*
1085* @public
1086* @category Hooks
1087* @mode framework
1088* @mode data
1089* @returns The resolved value from the nearest {@link Await} component
1090*/
1091function useAsyncValue() {
1092 return React$1.useContext(AwaitContext)?._data;
1093}
1094/**
1095* Returns the rejection value from the closest {@link Await | `<Await>`}.
1096*
1097* @example
1098* import { Await, useAsyncError } from "react-router";
1099*
1100* function ErrorElement() {
1101* const error = useAsyncError();
1102* return (
1103* <p>Uh Oh, something went wrong! {error.message}</p>
1104* );
1105* }
1106*
1107* // somewhere in your app
1108* <Await
1109* resolve={promiseThatRejects}
1110* errorElement={<ErrorElement />}
1111* />;
1112*
1113* @public
1114* @category Hooks
1115* @mode framework
1116* @mode data
1117* @returns The error that was thrown in the nearest {@link Await} component
1118*/
1119function useAsyncError() {
1120 return React$1.useContext(AwaitContext)?._error;
1121}
1122let blockerId = 0;
1123/**
1124* Allow the application to block navigations within the SPA and present the
1125* user a confirmation dialog to confirm the navigation. Mostly used to avoid
1126* using half-filled form data. This does not handle hard-reloads or
1127* cross-origin navigations.
1128*
1129* The {@link Blocker} object returned by the hook has the following properties:
1130*
1131* - **`state`**
1132* - `unblocked` - the blocker is idle and has not prevented any navigation
1133* - `blocked` - the blocker has prevented a navigation
1134* - `proceeding` - the blocker is proceeding through from a blocked navigation
1135* - **`location`**
1136* - When in a `blocked` state, this represents the {@link Location} to which
1137* we blocked a navigation. When in a `proceeding` state, this is the
1138* location being navigated to after a `blocker.proceed()` call.
1139* - **`proceed()`**
1140* - When in a `blocked` state, you may call `blocker.proceed()` to proceed to
1141* the blocked location.
1142* - **`reset()`**
1143* - When in a `blocked` state, you may call `blocker.reset()` to return the
1144* blocker to an `unblocked` state and leave the user at the current
1145* location.
1146*
1147* @example
1148* // Boolean version
1149* let blocker = useBlocker(value !== "");
1150*
1151* // Function version
1152* let blocker = useBlocker(
1153* ({ currentLocation, nextLocation, historyAction }) =>
1154* value !== "" &&
1155* currentLocation.pathname !== nextLocation.pathname
1156* );
1157*
1158* @additionalExamples
1159* ```tsx
1160* import { useCallback, useState } from "react";
1161* import { BlockerFunction, useBlocker } from "react-router";
1162*
1163* export function ImportantForm() {
1164* const [value, setValue] = useState("");
1165*
1166* const shouldBlock = useCallback<BlockerFunction>(
1167* () => value !== "",
1168* [value]
1169* );
1170* const blocker = useBlocker(shouldBlock);
1171*
1172* return (
1173* <form
1174* onSubmit={(e) => {
1175* e.preventDefault();
1176* setValue("");
1177* if (blocker.state === "blocked") {
1178* blocker.proceed();
1179* }
1180* }}
1181* >
1182* <input
1183* name="data"
1184* value={value}
1185* onChange={(e) => setValue(e.target.value)}
1186* />
1187*
1188* <button type="submit">Save</button>
1189*
1190* {blocker.state === "blocked" ? (
1191* <>
1192* <p style={{ color: "red" }}>
1193* Blocked the last navigation to
1194* </p>
1195* <button
1196* type="button"
1197* onClick={() => blocker.proceed()}
1198* >
1199* Let me through
1200* </button>
1201* <button
1202* type="button"
1203* onClick={() => blocker.reset()}
1204* >
1205* Keep me here
1206* </button>
1207* </>
1208* ) : blocker.state === "proceeding" ? (
1209* <p style={{ color: "orange" }}>
1210* Proceeding through blocked navigation
1211* </p>
1212* ) : (
1213* <p style={{ color: "green" }}>
1214* Blocker is currently unblocked
1215* </p>
1216* )}
1217* </form>
1218* );
1219* }
1220* ```
1221*
1222* @public
1223* @category Hooks
1224* @mode framework
1225* @mode data
1226* @param shouldBlock Either a boolean or a function returning a boolean which
1227* indicates whether the navigation should be blocked. The function format
1228* receives a single object parameter containing the `currentLocation`,
1229* `nextLocation`, and `historyAction` of the potential navigation.
1230* @returns A {@link Blocker} object with state and reset functionality
1231*/
1232function useBlocker(shouldBlock) {
1233 let { router, basename } = useDataRouterContext("useBlocker");
1234 let state = useDataRouterState("useBlocker");
1235 let [blockerKey, setBlockerKey] = React$1.useState("");
1236 let blockerFunction = React$1.useCallback((arg) => {
1237 if (typeof shouldBlock !== "function") return !!shouldBlock;
1238 if (basename === "/") return shouldBlock(arg);
1239 let { currentLocation, nextLocation, historyAction } = arg;
1240 return shouldBlock({
1241 currentLocation: {
1242 ...currentLocation,
1243 pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
1244 },
1245 nextLocation: {
1246 ...nextLocation,
1247 pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
1248 },
1249 historyAction
1250 });
1251 }, [basename, shouldBlock]);
1252 React$1.useEffect(() => {
1253 let key = String(++blockerId);
1254 setBlockerKey(key);
1255 return () => router.deleteBlocker(key);
1256 }, [router]);
1257 React$1.useEffect(() => {
1258 if (blockerKey !== "") router.getBlocker(blockerKey, blockerFunction);
1259 }, [
1260 router,
1261 blockerKey,
1262 blockerFunction
1263 ]);
1264 return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
1265}
1266function useNavigateStable() {
1267 let { router } = useDataRouterContext("useNavigate");
1268 let id = useCurrentRouteId("useNavigate");
1269 let activeRef = React$1.useRef(false);
1270 React$1.useLayoutEffect(() => {
1271 activeRef.current = true;
1272 });
1273 return React$1.useCallback(async (to, options = {}) => {
1274 warning(activeRef.current, navigateEffectWarning);
1275 if (!activeRef.current) return;
1276 if (typeof to === "number") await router.navigate(to);
1277 else await router.navigate(to, {
1278 fromRouteId: id,
1279 ...options
1280 });
1281 }, [router, id]);
1282}
1283const alreadyWarned = {};
1284function warningOnce(key, cond, message) {
1285 if (!cond && !alreadyWarned[key]) {
1286 alreadyWarned[key] = true;
1287 warning(false, message);
1288 }
1289}
1290function useRoute(...args) {
1291 const currentRouteId = useCurrentRouteId("useRoute");
1292 const id = args[0] ?? currentRouteId;
1293 const state = useDataRouterState("useRoute");
1294 const route = state.matches.find(({ route }) => route.id === id);
1295 if (route === void 0) return void 0;
1296 return {
1297 handle: route.route.handle,
1298 loaderData: state.loaderData[id],
1299 actionData: state.actionData?.[id]
1300 };
1301}
1302function toRouterStateMatch(match) {
1303 return {
1304 id: match.route.id,
1305 pathname: match.pathname,
1306 params: match.params,
1307 handle: match.route.handle
1308 };
1309}
1310/**
1311* A unified hook for reading router state: current (`active`) and in-flight
1312* (`pending`) locations, search params, params, matches, and navigation type.
1313*
1314* This hook consolidates the information you used to get from {@link useLocation},
1315* {@link useSearchParams}, {@link useParams}, {@link useMatches}, {@link useNavigation},
1316* and {@link useNavigationType} into a single hook.
1317*
1318*
1319* @example
1320* import { unstable_useRouterState as useRouterState } from "react-router";
1321*
1322* let { active, pending } = unstable_useRouterState();
1323*
1324* // Active is always populated with the current location
1325* active.location; // replaces `useLocation()`
1326* active.searchParams; // replaces `useSearchParams()[0]`
1327* active.params; // replaces `useParams()`
1328* active.matches; // replaces `useMatches()`
1329* active.type; // replaces `useNavigationType()`
1330*
1331* // Pending is only populated during a navigation
1332* pending.location; // replaces `useNavigation().location`
1333* pending.searchParams; // equivalent to `new URLSearchParams(useNavigation().search)`
1334* pending.params; // Not directly accessible today
1335* pending.matches; // Not directly accessible today
1336* pending.type; // Not directly accessible today
1337* pending.state; // replaces `useNavigation().state`
1338* pending.formMethod; // replaces useNavigation().formMethod
1339* pending.formAction; // replaces useNavigation().formAction
1340* pending.formEncType; // replaces useNavigation().formEncType
1341* pending.formData; // replaces useNavigation().formData
1342* pending.json; // replaces useNavigation().json
1343* pending.text; // replaces useNavigation().text
1344*
1345* @name unstable_useRouterState
1346* @public
1347* @category Hooks
1348* @mode framework
1349* @mode data
1350* @returns The current router state with `active` and `pending` variants
1351*/
1352function useRouterState() {
1353 let { location, historyAction: type, matches, navigation } = useDataRouterState("unstable_useRouterState");
1354 let active = React$1.useMemo(() => ({
1355 type,
1356 location,
1357 searchParams: new URLSearchParams(location.search),
1358 params: matches[matches.length - 1]?.params ?? {},
1359 matches: matches.map((m) => toRouterStateMatch(m))
1360 }), [
1361 location,
1362 matches,
1363 type
1364 ]);
1365 let pending = React$1.useMemo(() => {
1366 if (navigation.state === "idle") return null;
1367 let shared = {
1368 type: navigation.historyAction,
1369 location: navigation.location,
1370 searchParams: new URLSearchParams(navigation.location.search),
1371 params: navigation.matches[navigation.matches.length - 1]?.params ?? {},
1372 matches: navigation.matches.map((m) => toRouterStateMatch(m))
1373 };
1374 return navigation.state === "loading" ? {
1375 ...shared,
1376 state: "loading",
1377 formMethod: navigation.formMethod,
1378 formAction: navigation.formAction,
1379 formEncType: navigation.formEncType,
1380 formData: navigation.formData,
1381 json: navigation.json,
1382 text: navigation.text
1383 } : {
1384 ...shared,
1385 state: "submitting",
1386 formMethod: navigation.formMethod,
1387 formAction: navigation.formAction,
1388 formEncType: navigation.formEncType,
1389 formData: navigation.formData,
1390 json: navigation.json,
1391 text: navigation.text
1392 };
1393 }, [navigation]);
1394 return React$1.useMemo(() => ({
1395 active,
1396 pending
1397 }), [active, pending]);
1398}
1399//#endregion
1400export { _renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRoute, useRouteError, useRouteId, useRouteLoaderData, useRouterState, useRoutes, useRoutesImpl };