react-router
Version:
Declarative routing for React
1,383 lines (1,371 loc) • 86.9 kB
text/typescript
import './components-CjQijYga.mjs';
import * as React from 'react';
import { a_ as RouteManifest, a$ as ServerRouteModule, Y as MiddlewareEnabled, u as unstable_RouterContextProvider, X as AppLoadContext, ak as LoaderFunctionArgs, ab as ActionFunctionArgs, y as RouteModules, a4 as StaticHandlerContext, H as HydrationState, a0 as DataRouteObject, j as ClientLoaderFunction, aj as HTMLFormMethod, ah as FormEncType, a as RelativeRoutingType, aL as PageLinkDescriptor, T as To, b0 as History, a3 as GetScrollRestorationKeyFunction, e as RouterInit, F as FutureConfig$1, D as DataStrategyFunction, P as PatchRoutesOnNavigationFunction, z as NavigateOptions, a5 as Fetcher, f as RouteObject, R as Router, J as SerializeFrom, B as BlockerFunction, c as Location, b1 as CreateStaticHandlerOptions$1, a1 as StaticHandler } from './route-data-CqEmXQub.mjs';
type ServerRouteManifest = RouteManifest<Omit<ServerRoute, "children">>;
interface ServerRoute extends Route {
children: ServerRoute[];
module: ServerRouteModule;
}
type OptionalCriticalCss = CriticalCss | undefined;
/**
* The output of the compiler for the server build.
*/
interface ServerBuild {
entry: {
module: ServerEntryModule;
};
routes: ServerRouteManifest;
assets: AssetsManifest;
basename?: string;
publicPath: string;
assetsBuildDirectory: string;
future: FutureConfig;
ssr: boolean;
unstable_getCriticalCss?: (args: {
pathname: string;
}) => OptionalCriticalCss | Promise<OptionalCriticalCss>;
/**
* @deprecated This is now done via a custom header during prerendering
*/
isSpaMode: boolean;
prerender: string[];
routeDiscovery: {
mode: "lazy" | "initial";
manifestPath: string;
};
}
interface HandleDocumentRequestFunction {
(request: Request, responseStatusCode: number, responseHeaders: Headers, context: EntryContext, loadContext: MiddlewareEnabled extends true ? unstable_RouterContextProvider : AppLoadContext): Promise<Response> | Response;
}
interface HandleDataRequestFunction {
(response: Response, args: LoaderFunctionArgs | ActionFunctionArgs): Promise<Response> | Response;
}
interface HandleErrorFunction {
(error: unknown, args: LoaderFunctionArgs | ActionFunctionArgs): void;
}
/**
* A module that serves as the entry point for a Remix app during server
* rendering.
*/
interface ServerEntryModule {
default: HandleDocumentRequestFunction;
handleDataRequest?: HandleDataRequestFunction;
handleError?: HandleErrorFunction;
streamTimeout?: number;
}
type SerializedError = {
message: string;
stack?: string;
};
interface FrameworkContextObject {
manifest: AssetsManifest;
routeModules: RouteModules;
criticalCss?: CriticalCss;
serverHandoffString?: string;
future: FutureConfig;
ssr: boolean;
isSpaMode: boolean;
routeDiscovery: ServerBuild["routeDiscovery"];
serializeError?(error: Error): SerializedError;
renderMeta?: {
didRenderScripts?: boolean;
streamCache?: Record<number, Promise<void> & {
result?: {
done: boolean;
value: string;
};
error?: unknown;
}>;
};
}
interface EntryContext extends FrameworkContextObject {
staticHandlerContext: StaticHandlerContext;
serverHandoffStream?: ReadableStream<Uint8Array>;
}
interface FutureConfig {
unstable_subResourceIntegrity: boolean;
unstable_middleware: boolean;
}
type CriticalCss = string | {
rel: "stylesheet";
href: string;
};
interface AssetsManifest {
entry: {
imports: string[];
module: string;
};
routes: RouteManifest<EntryRoute>;
url: string;
version: string;
hmr?: {
timestamp?: number;
runtime: string;
};
sri?: Record<string, string> | true;
}
interface Route {
index?: boolean;
caseSensitive?: boolean;
id: string;
parentId?: string;
path?: string;
}
interface EntryRoute extends Route {
hasAction: boolean;
hasLoader: boolean;
hasClientAction: boolean;
hasClientLoader: boolean;
hasClientMiddleware: boolean;
hasErrorBoundary: boolean;
imports?: string[];
css?: string[];
module: string;
clientActionModule: string | undefined;
clientLoaderModule: string | undefined;
clientMiddlewareModule: string | undefined;
hydrateFallbackModule: string | undefined;
parentId?: string;
}
declare function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation: Set<string>, manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState, ssr: boolean, isSpaMode: boolean): DataRouteObject[];
declare function createClientRoutes(manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState | null, ssr: boolean, isSpaMode: boolean, parentId?: string, routesByParentId?: Record<string, Omit<EntryRoute, "children">[]>, needsRevalidation?: Set<string>): DataRouteObject[];
declare function shouldHydrateRouteLoader(routeId: string, clientLoader: ClientLoaderFunction | undefined, hasLoader: boolean, isSpaMode: boolean): boolean;
type ParamKeyValuePair = [string, string];
type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams;
/**
Creates a URLSearchParams object using the given initializer.
This is identical to `new URLSearchParams(init)` except it also
supports arrays as values in the object form of the initializer
instead of just strings. This is convenient when you need multiple
values for a given key, but don't want to use an array initializer.
For example, instead of:
```tsx
let searchParams = new URLSearchParams([
['sort', 'name'],
['sort', 'price']
]);
```
you can do:
```
let searchParams = createSearchParams({
sort: ['name', 'price']
});
```
@category Utils
*/
declare function createSearchParams(init?: URLSearchParamsInit): URLSearchParams;
type JsonObject = {
[Key in string]: JsonValue;
} & {
[Key in string]?: JsonValue | undefined;
};
type JsonArray = JsonValue[] | readonly JsonValue[];
type JsonPrimitive = string | number | boolean | null;
type JsonValue = JsonPrimitive | JsonObject | JsonArray;
type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | JsonValue | null;
/**
* Submit options shared by both navigations and fetchers
*/
interface SharedSubmitOptions {
/**
* The HTTP method used to submit the form. Overrides `<form method>`.
* Defaults to "GET".
*/
method?: HTMLFormMethod;
/**
* The action URL path used to submit the form. Overrides `<form action>`.
* Defaults to the path of the current route.
*/
action?: string;
/**
* The encoding used to submit the form. Overrides `<form encType>`.
* Defaults to "application/x-www-form-urlencoded".
*/
encType?: FormEncType;
/**
* Determines whether the form action is relative to the route hierarchy or
* the pathname. Use this if you want to opt out of navigating the route
* hierarchy and want to instead route based on /-delimited URL segments
*/
relative?: RelativeRoutingType;
/**
* In browser-based environments, prevent resetting scroll after this
* navigation when using the <ScrollRestoration> component
*/
preventScrollReset?: boolean;
/**
* Enable flushSync for this submission's state updates
*/
flushSync?: boolean;
}
/**
* Submit options available to fetchers
*/
interface FetcherSubmitOptions extends SharedSubmitOptions {
}
/**
* Submit options available to navigations
*/
interface SubmitOptions extends FetcherSubmitOptions {
/**
* Set `true` to replace the current entry in the browser's history stack
* instead of creating a new one (i.e. stay on "the same page"). Defaults
* to `false`.
*/
replace?: boolean;
/**
* State object to add to the history stack entry for this navigation
*/
state?: any;
/**
* Indicate a specific fetcherKey to use when using navigate=false
*/
fetcherKey?: string;
/**
* navigate=false will use a fetcher instead of a navigation
*/
navigate?: boolean;
/**
* Enable view transitions on this submission navigation
*/
viewTransition?: boolean;
}
declare const FrameworkContext: React.Context<FrameworkContextObject | undefined>;
/**
* Defines the discovery behavior of the link:
*
* - "render" - default, discover the route when the link renders
* - "none" - don't eagerly discover, only discover if the link is clicked
*/
type DiscoverBehavior = "render" | "none";
/**
* Defines the prefetching behavior of the link:
*
* - "none": Never fetched
* - "intent": Fetched when the user focuses or hovers the link
* - "render": Fetched when the link is rendered
* - "viewport": Fetched when the link is in the viewport
*/
type PrefetchBehavior = "intent" | "render" | "none" | "viewport";
/**
* Renders all of the `<link>` tags created by the route module
* [`links`](../../start/framework/route-module#links) export. You should render
* it inside the `<head>` of your document.
*
* @example
* import { Links } from "react-router";
*
* export default function Root() {
* return (
* <html>
* <head>
* <Links />
* </head>
* <body></body>
* </html>
* );
* }
*
* @public
* @category Components
* @mode framework
* @returns A collection of React elements for `<link>` tags
*/
declare function Links(): React.JSX.Element;
/**
* Renders `<link rel=prefetch|modulepreload>` tags for modules and data of
* another page to enable an instant navigation to that page.
* [`<Link prefetch>`](../../components/Link#prefetch) uses this internally, but
* you can render it to prefetch a page for any other reason.
*
* For example, you may render one of this as the user types into a search field
* to prefetch search results before they click through to their selection.
*
* @example
* import { PrefetchPageLinks } from "react-router";
*
* <PrefetchPageLinks page="/absolute/path" />
*
* @public
* @category Components
* @mode framework
* @param props Props
* @param props.page The absolute path of the page to prefetch, e.g. `/absolute/path`.
* @param props.linkProps Additional props to spread onto the
* [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link)
* tags, such as `crossOrigin`, `integrity`, `rel`, etc.
* @returns A collection of React elements for `<link>` tags
*/
declare function PrefetchPageLinks({ page, ...linkProps }: PageLinkDescriptor): React.JSX.Element | null;
/**
* Renders all the `<meta>` tags created by the route module
* [`meta`](../../start/framework/route-module#meta) exports. You should render
* it inside the `<head>` of your HTML.
*
* @example
* import { Meta } from "react-router";
*
* export default function Root() {
* return (
* <html>
* <head>
* <Meta />
* </head>
* </html>
* );
* }
*
* @public
* @category Components
* @mode framework
* @returns A collection of React elements for `<meta>` tags
*/
declare function Meta(): React.JSX.Element;
/**
* A couple common attributes:
*
* - `<Scripts crossOrigin>` for hosting your static assets on a different server than your app.
* - `<Scripts nonce>` to support a [content security policy for scripts](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) with [nonce-sources](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources) for your `<script>` tags.
*
* You cannot pass through attributes such as `async`, `defer`, `src`, `type`, `noModule` because they are managed by React Router internally.
*
* @category Types
*/
type ScriptsProps = Omit<React.HTMLProps<HTMLScriptElement>, "async" | "children" | "dangerouslySetInnerHTML" | "defer" | "src" | "type" | "noModule" | "suppressHydrationWarning"> & {
/**
* A [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
* attribute to render on [the `<script>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script)
*/
nonce?: string | undefined;
};
/**
* Renders the client runtime of your app. It should be rendered inside the
* [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/body)
* of the document.
*
* If server rendering, you can omit `<Scripts/>` and the app will work as a
* traditional web app without JavaScript, relying solely on HTML and browser
* behaviors.
*
* @example
* import { Scripts } from "react-router";
*
* export default function Root() {
* return (
* <html>
* <head />
* <body>
* <Scripts />
* </body>
* </html>
* );
* }
*
* @public
* @category Components
* @mode framework
* @param scriptProps Additional props to spread onto the
* [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script)
* tag, such as `crossOrigin`, `nonce`, etc.
* @returns A collection of React elements for `<script>` tags
*/
declare function Scripts(scriptProps: ScriptsProps): React.JSX.Element | null;
/**
* @category Data Routers
*/
interface DOMRouterOpts {
/**
* Basename path for the application.
*/
basename?: string;
/**
* Function to provide the initial `context` values for all client side navigations/fetches
*/
unstable_getContext?: RouterInit["unstable_getContext"];
/**
* Future flags to enable for the router.
*/
future?: Partial<FutureConfig$1>;
/**
* When Server-Rendering and opting-out of automatic hydration, the `hydrationData`
* option allows you to pass in hydration data from your server-render. This will
* almost always be a subset of data from the {@link StaticHandlerContext} value you
* get back from the `{@link StaticHandler} `query()` method:
*
* ```tsx
* const router = createBrowserRouter(routes, {
* hydrationData: {
* loaderData: {
* // [routeId]: serverLoaderData
* },
* // may also include `errors` and/or `actionData`
* },
* });
* ```
*
* **Partial Hydration Data**
*
* You will almost always include a complete set of `loaderData` to hydrate a
* server-rendered app. But in advanced use-cases (such as Framework Mode's
* `clientLoader`), you may want to include `loaderData` for only some routes
* that were loaded/rendered on the server. This allows you to hydrate _some_
* of the routes (such as the app layout/shell) while showing a `HydrateFallback`
* and running the loaders for other routes during hydration.
*
* A route `loader` will run during hydration in 2 scenarios:
*
* - No hydration data is provided
* - In these cases the `HydrateFallback` component will render on initial hydration
* - The `loader.hydrate` property is set to true
* - This allows you to run the loader even if you did not render a fallback
* on initial hydration (i.e., to prime a cache with hydration data)
*
* ```tsx
* const router = createBrowserRouter(
* [
* {
* id: "root",
* loader: rootLoader,
* Component: Root,
* children: [
* {
* id: "index",
* loader: indexLoader,
* HydrateFallback: IndexSkeleton,
* Component: Index,
* },
* ],
* },
* ],
* {
* hydrationData: {
* loaderData: {
* root: "ROOT DATA",
* // No index data provided
* },
* },
* }
* );
* ```
*/
hydrationData?: HydrationState;
/**
* Override the default data strategy of running loaders in parallel.
* See {@link DataStrategyFunction}.
*
* <docs-warning>This is a low-level API intended for advanced use-cases. This
* overrides React Router's internal handling of `loader`/`action` execution,
* and if done incorrectly will break your app code. Please use with caution
* and perform the appropriate testing.</docs-warning>
*
* By default, React Router is opinionated about how your data is loaded/submitted -
* and most notably, executes all of your loaders in parallel for optimal data
* fetching. While we think this is the right behavior for most use-cases, we
* realize that there is no "one size fits all" solution when it comes to data
* fetching for the wide landscape of application requirements.
*
* The `dataStrategy` option gives you full control over how your loaders and
* actions are executed and lays the foundation to build in more advanced APIs
* such as middleware, context, and caching layers. Over time, we expect that
* we'll leverage this API internally to bring more first class APIs to React
* Router, but until then (and beyond), this is your way to add more advanced
* functionality for your applications data needs.
*
* The `dataStrategy` function should return a key/value object of
* `routeId` -> {@link DataStrategyResult} and should include entries for any routes
* where a handler was executed. A `DataStrategyResult` indicates if the handler
* was successful or not based on the `DataStrategyResult.type` field. If the
* returned `DataStrategyResult["result"]` is a `Response`, React Router will
* unwrap it for you (via `res.json` or `res.text`). If you need to do custom
* decoding of a `Response` but want to preserve the status code, you can use
* the `data` utility to return your decoded data along with a `ResponseInit`.
*
* <details>
* <summary><b>Example <code>dataStrategy</code> Use Cases</b></summary>
*
* **Adding logging**
*
* In the simplest case, let's look at hooking into this API to add some logging
* for when our route loaders/actions execute:
*
* ```ts
* let router = createBrowserRouter(routes, {
* async dataStrategy({ request, matches }) {
* const matchesToLoad = matches.filter((m) => m.shouldLoad);
* const results = {};
* await Promise.all(
* matchesToLoad.map(async (match) => {
* console.log(`Processing ${match.route.id}`);
* results[match.route.id] = await match.resolve();;
* })
* );
* return results;
* },
* });
* ```
*
* **Middleware**
*
* Let's define a middleware on each route via `handle` and call middleware
* sequentially first, then call all loaders in parallel - providing any data
* made available via the middleware:
*
* ```ts
* const routes = [
* {
* id: "parent",
* path: "/parent",
* loader({ request }, context) {
* // ...
* },
* handle: {
* async middleware({ request }, context) {
* context.parent = "PARENT MIDDLEWARE";
* },
* },
* children: [
* {
* id: "child",
* path: "child",
* loader({ request }, context) {
* // ...
* },
* handle: {
* async middleware({ request }, context) {
* context.child = "CHILD MIDDLEWARE";
* },
* },
* },
* ],
* },
* ];
*
* let router = createBrowserRouter(routes, {
* async dataStrategy({ request, params, matches }) {
* // Run middleware sequentially and let them add data to `context`
* let context = {};
* for (const match of matches) {
* if (match.route.handle?.middleware) {
* await match.route.handle.middleware(
* { request, params },
* context
* );
* }
* }
*
* // Run loaders in parallel with the `context` value
* let matchesToLoad = matches.filter((m) => m.shouldLoad);
* let results = await Promise.all(
* matchesToLoad.map((match, i) =>
* match.resolve((handler) => {
* // Whatever you pass to `handler` will be passed as the 2nd parameter
* // to your loader/action
* return handler(context);
* })
* )
* );
* return results.reduce(
* (acc, result, i) =>
* Object.assign(acc, {
* [matchesToLoad[i].route.id]: result,
* }),
* {}
* );
* },
* });
* ```
*
* **Custom Handler**
*
* It's also possible you don't even want to define a loader implementation at
* the route level. Maybe you want to just determine the routes and issue a single
* GraphQL request for all of your data? You can do that by setting your
* `route.loader=true` so it qualifies as "having a loader", and then store GQL
* fragments on `route.handle`:
*
* ```ts
* const routes = [
* {
* id: "parent",
* path: "/parent",
* loader: true,
* handle: {
* gql: gql`
* fragment Parent on Whatever {
* parentField
* }
* `,
* },
* children: [
* {
* id: "child",
* path: "child",
* loader: true,
* handle: {
* gql: gql`
* fragment Child on Whatever {
* childField
* }
* `,
* },
* },
* ],
* },
* ];
*
* let router = createBrowserRouter(routes, {
* async dataStrategy({ request, params, matches }) {
* // Compose route fragments into a single GQL payload
* let gql = getFragmentsFromRouteHandles(matches);
* let data = await fetchGql(gql);
* // Parse results back out into individual route level `DataStrategyResult`'s
* // keyed by `routeId`
* let results = parseResultsFromGql(data);
* return results;
* },
* });
* ```
*</details>
*/
dataStrategy?: DataStrategyFunction;
/**
* Lazily define portions of the route tree on navigations.
* See {@link PatchRoutesOnNavigationFunction}.
*
* By default, React Router wants you to provide a full route tree up front via
* `createBrowserRouter(routes)`. This allows React Router to perform synchronous
* route matching, execute loaders, and then render route components in the most
* optimistic manner without introducing waterfalls. The tradeoff is that your
* initial JS bundle is larger by definition - which may slow down application
* start-up times as your application grows.
*
* To combat this, we introduced [`route.lazy`][route-lazy] in [v6.9.0][6-9-0]
* which let's you lazily load the route _implementation_ (`loader`, `Component`,
* etc.) while still providing the route _definition_ aspects up front (`path`,
* `index`, etc.). This is a good middle ground because React Router still knows
* about your route definitions (the lightweight part) up front and can perform
* synchronous route matching, but then delay loading any of the route implementation
* aspects (the heavier part) until the route is actually navigated to.
*
* In some cases, even this doesn't go far enough. For very large applications,
* providing all route definitions up front can be prohibitively expensive.
* Additionally, it might not even be possible to provide all route definitions
* up front in certain Micro-Frontend or Module-Federation architectures.
*
* This is where `patchRoutesOnNavigation` comes in ([RFC][fog-of-war-rfc]).
* This API is for advanced use-cases where you are unable to provide the full
* route tree up-front and need a way to lazily "discover" portions of the route
* tree at runtime. This feature is often referred to as ["Fog of War"][fog-of-war]
* because similar to how video games expand the "world" as you move around -
* the router would be expanding its routing tree as the user navigated around
* the app - but would only ever end up loading portions of the tree that the
* user visited.
*
* `patchRoutesOnNavigation` will be called anytime React Router is unable to
* match a `path`. The arguments include the `path`, any partial `matches`, and
* a `patch` function you can call to patch new routes into the tree at a
* specific location. This method is executed during the `loading` portion of
* the navigation for `GET` requests and during the `submitting` portion of the
* navigation for non-`GET` requests.
*
* <details>
* <summary><b>Example <code>patchRoutesOnNavigation</code> Use Cases</b></summary>
*
* **Patching children into an existing route**
*
* ```tsx
* const router = createBrowserRouter(
* [
* {
* id: "root",
* path: "/",
* Component: RootComponent,
* },
* ],
* {
* async patchRoutesOnNavigation({ path, patch }) {
* if (path === "/a") {
* // Load/patch the `a` route as a child of the route with id `root`
* let route = await getARoute();
* // ^ { path: 'a', Component: A }
* patch("root", [route]);
* }
* },
* }
* );
* ```
*
* In the above example, if the user clicks a link to `/a`, React Router won't
* match any routes initially and will call `patchRoutesOnNavigation` with a
* `path = "/a"` and a `matches` array containing the root route match. By calling
* `patch('root', [route])`, the new route will be added to the route tree as a
* child of the `root` route and React Router will perform matching on the updated
* routes. This time it will successfully match the `/a` path and the navigation
* will complete successfully.
*
* **Patching new root-level routes**
*
* If you need to patch a new route to the top of the tree (i.e., it doesn't
* have a parent), you can pass `null` as the `routeId`:
*
* ```tsx
* const router = createBrowserRouter(
* [
* {
* id: "root",
* path: "/",
* Component: RootComponent,
* },
* ],
* {
* async patchRoutesOnNavigation({ path, patch }) {
* if (path === "/root-sibling") {
* // Load/patch the `/root-sibling` route as a sibling of the root route
* let route = await getRootSiblingRoute();
* // ^ { path: '/root-sibling', Component: RootSibling }
* patch(null, [route]);
* }
* },
* }
* );
* ```
*
* **Patching sub-trees asynchronously**
*
* You can also perform asynchronous matching to lazily fetch entire sections
* of your application:
*
* ```jsx
* let router = createBrowserRouter(
* [
* {
* path: "/",
* Component: Home,
* },
* ],
* {
* async patchRoutesOnNavigation({ path, patch }) {
* if (path.startsWith("/dashboard")) {
* let children = await import("./dashboard");
* patch(null, children);
* }
* if (path.startsWith("/account")) {
* let children = await import("./account");
* patch(null, children);
* }
* },
* }
* );
* ```
*
* <docs-info>If in-progress execution of `patchRoutesOnNavigation` is
* interrupted by a subsequent navigation, then any remaining `patch` calls
* in the interrupted execution will not update the route tree because the
* operation was cancelled.</docs-info>
*
* **Co-locating route discovery with route definition**
*
* If you don't wish to perform your own pseudo-matching, you can leverage the
* partial `matches` array and the `handle` field on a route to keep the children
* definitions co-located:
*
* ```jsx
* let router = createBrowserRouter(
* [
* {
* path: "/",
* Component: Home,
* },
* {
* path: "/dashboard",
* children: [
* {
* // If we want to include /dashboard in the critical routes, we need to
* // also include it's index route since patchRoutesOnNavigation will not be
* // called on a navigation to `/dashboard` because it will have successfully
* // matched the `/dashboard` parent route
* index: true,
* // ...
* },
* ],
* handle: {
* lazyChildren: () => import("./dashboard"),
* },
* },
* {
* path: "/account",
* children: [
* {
* index: true,
* // ...
* },
* ],
* handle: {
* lazyChildren: () => import("./account"),
* },
* },
* ],
* {
* async patchRoutesOnNavigation({ matches, patch }) {
* let leafRoute = matches[matches.length - 1]?.route;
* if (leafRoute?.handle?.lazyChildren) {
* let children =
* await leafRoute.handle.lazyChildren();
* patch(leafRoute.id, children);
* }
* },
* }
* );
* ```
*
* **A note on routes with parameters**
*
* Because React Router uses ranked routes to find the best match for a given
* path, there is an interesting ambiguity introduced when only a partial route
* tree is known at any given point in time. If we match a fully static route
* such as `path: "/about/contact-us"` then we know we've found the right match
* since it's composed entirely of static URL segments, and thus we do not need
* to bother asking for any other potentially higher-scoring routes.
*
* However, routes with parameters (dynamic or splat) can't make this assumption
* because there might be a not-yet-discovered route tht scores higher. Consider
* a full route tree such as:
*
* ```js
* // Assume this is the full route tree for your app
* const routes = [
* {
* path: "/",
* Component: Home,
* },
* {
* id: "blog",
* path: "/blog",
* Component: BlogLayout,
* children: [
* { path: "new", Component: NewPost },
* { path: ":slug", Component: BlogPost },
* ],
* },
* ];
* ```
*
* And then assume we want to use `patchRoutesOnNavigation` to fill this in
* as the user navigates around:
*
* ```js
* // Start with only the index route
* const router = createBrowserRouter(
* [
* {
* path: "/",
* Component: Home,
* },
* ],
* {
* patchRoutesOnNavigation({ path, patch }) {
* if (path === "/blog/new") {
* patch("blog", [
* {
* path: "new",
* Component: NewPost,
* },
* ]);
* } else if (path.startsWith("/blog")) {
* patch("blog", [
* {
* path: ":slug",
* Component: BlogPost,
* },
* ]);
* }
* },
* }
* );
* ```
*
* If the user were to a blog post first (i.e., `/blog/my-post`) we would patch
* in the `:slug` route. Then if the user navigated to `/blog/new` to write a
* new post, we'd match `/blog/:slug` but it wouldn't be the _right_ match!
* We need to call `patchRoutesOnNavigation` just in case there exists a
* higher-scoring route we've not yet discovered, which in this case there is.
*
* So, anytime React Router matches a path that contains at least one param,
* it will call `patchRoutesOnNavigation` and match routes again just to
* confirm it has found the best match.
*
* If your `patchRoutesOnNavigation` implementation is expensive or making
* side-effect `fetch` calls to a backend server, you may want to consider
* tracking previously seen routes to avoid over-fetching in cases where you
* know the proper route has already been found. This can usually be as simple
* as maintaining a small cache of prior `path` values for which you've already
* patched in the right routes:
*
* ```js
* let discoveredRoutes = new Set();
*
* const router = createBrowserRouter(routes, {
* patchRoutesOnNavigation({ path, patch }) {
* if (discoveredRoutes.has(path)) {
* // We've seen this before so nothing to patch in and we can let the router
* // use the routes it already knows about
* return;
* }
*
* discoveredRoutes.add(path);
*
* // ... patch routes in accordingly
* },
* });
* ```
* </details>
*/
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
/**
* [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object
* override - defaults to the global `window` instance.
*/
window?: Window;
}
/**
* Create a new {@link DataRouter| data router} that manages the application
* path via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
* and [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState).
*
* @public
* @category Data Routers
* @mode data
* @param routes Application routes
* @param opts Options
* @param {DOMRouterOpts.basename} opts.basename n/a
* @param {DOMRouterOpts.dataStrategy} opts.dataStrategy n/a
* @param {DOMRouterOpts.future} opts.future n/a
* @param {DOMRouterOpts.unstable_getContext} opts.unstable_getContext n/a
* @param {DOMRouterOpts.hydrationData} opts.hydrationData n/a
* @param {DOMRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
* @param {DOMRouterOpts.window} opts.window n/a
* @returns An initialized {@link DataRouter| data router} to pass to {@link RouterProvider | `<RouterProvider>`}
*/
declare function createBrowserRouter(routes: RouteObject[], opts?: DOMRouterOpts): Router;
/**
* Create a new {@link DataRouter| data router} that manages the application
* path via the URL [`hash`]https://developer.mozilla.org/en-US/docs/Web/API/URL/hash).
*
* @public
* @category Data Routers
* @mode data
* @param routes Application routes
* @param opts Options
* @param {DOMRouterOpts.basename} opts.basename n/a
* @param {DOMRouterOpts.future} opts.future n/a
* @param {DOMRouterOpts.unstable_getContext} opts.unstable_getContext n/a
* @param {DOMRouterOpts.hydrationData} opts.hydrationData n/a
* @param {DOMRouterOpts.dataStrategy} opts.dataStrategy n/a
* @param {DOMRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
* @param {DOMRouterOpts.window} opts.window n/a
* @returns An initialized {@link DataRouter| data router} to pass to {@link RouterProvider | `<RouterProvider>`}
*/
declare function createHashRouter(routes: RouteObject[], opts?: DOMRouterOpts): Router;
/**
* @category Types
*/
interface BrowserRouterProps {
basename?: string;
children?: React.ReactNode;
window?: Window;
}
/**
* A declarative {@link Router | `<Router>`} using the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* API for client-side routing.
*
* @public
* @category Declarative Routers
* @mode declarative
* @param props Props
* @param props.basename Application basename
* @param props.children {@link Route | `<Route>`} components describing your route configuration
* @param props.window [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)
* object override - defaults to the global `window` instance
* @returns A declarative {@link Router | `<Router>`} using the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* API for client-side routing.
*/
declare function BrowserRouter({ basename, children, window, }: BrowserRouterProps): React.JSX.Element;
/**
* @category Types
*/
interface HashRouterProps {
basename?: string;
children?: React.ReactNode;
window?: Window;
}
/**
* A declarative {@link Router | `<Router>`} that stores the location in the
* [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash) portion
* of the URL so it is not sent to the server.
*
* @public
* @category Declarative Routers
* @mode declarative
* @param props Props
* @param props.basename Application basename
* @param props.children {@link Route | `<Route>`} components describing your route configuration
* @param props.window [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)
* object override - defaults to the global `window` instance
* @returns A declarative {@link Router | `<Router>`} using the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash)
* for client-side routing.
*/
declare function HashRouter({ basename, children, window }: HashRouterProps): React.JSX.Element;
/**
* @category Types
*/
interface HistoryRouterProps {
basename?: string;
children?: React.ReactNode;
history: History;
}
/**
* A declarative {@link Router | `<Router>`} that accepts a pre-instantiated
* `history` object.
* It's important to note that using your own `history` object is highly discouraged
* and may add two versions of the `history` library to your bundles unless you use
* the same version of the `history` library that React Router uses internally.
*
* @name unstable_HistoryRouter
* @public
* @category Declarative Routers
* @mode declarative
* @param props Props
* @param props.basename Application basename
* @param props.children {@link Route | `<Route>`} components describing your route configuration
* @param props.history A history implementation for use by the router
* @returns A declarative router using the provided history implementation for client-side routing.
*/
declare function HistoryRouter({ basename, children, history, }: HistoryRouterProps): React.JSX.Element;
declare namespace HistoryRouter {
var displayName: string;
}
/**
* @category Types
*/
interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
/**
* Defines the link discovery behavior
*
* ```tsx
* <Link /> // default ("render")
* <Link discover="render" />
* <Link discover="none" />
* ```
*
* - **render** - default, discover the route when the link renders
* - **none** - don't eagerly discover, only discover if the link is clicked
*/
discover?: DiscoverBehavior;
/**
* Defines the data and module prefetching behavior for the link.
*
* ```tsx
* <Link /> // default
* <Link prefetch="none" />
* <Link prefetch="intent" />
* <Link prefetch="render" />
* <Link prefetch="viewport" />
* ```
*
* - **none** - default, no prefetching
* - **intent** - prefetches when the user hovers or focuses the link
* - **render** - prefetches when the link renders
* - **viewport** - prefetches when the link is in the viewport, very useful for mobile
*
* Prefetching is done with HTML [`<link rel="prefetch">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
* tags. They are inserted after the link.
*
* ```tsx
* <a href="..." />
* <a href="..." />
* <link rel="prefetch" /> // might conditionally render
* ```
*
* Because of this, if you are using `nav :last-child` you will need to use
* `nav :last-of-type` so the styles don't conditionally fall off your last link
* (and any other similar selectors).
*/
prefetch?: PrefetchBehavior;
/**
* Will use document navigation instead of client side routing when the link is
* clicked: the browser will handle the transition normally (as if it were an
* [`<a href>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)).
*
* ```tsx
* <Link to="/logout" reloadDocument />
* ```
*/
reloadDocument?: boolean;
/**
* Replaces the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
* stack instead of pushing a new one onto it.
*
* ```tsx
* <Link replace />
* ```
*
* ```
* # with a history stack like this
* A -> B
*
* # normal link click pushes a new entry
* A -> B -> C
*
* # but with `replace`, B is replaced by C
* A -> C
* ```
*/
replace?: boolean;
/**
* Adds persistent client side routing state to the next location.
*
* ```tsx
* <Link to="/somewhere/else" state={{ some: "value" }} />
* ```
*
* The location state is accessed from the `location`.
*
* ```tsx
* function SomeComp() {
* const location = useLocation();
* location.state; // { some: "value" }
* }
* ```
*
* This state is inaccessible on the server as it is implemented on top of
* [`history.state`](https://developer.mozilla.org/en-US/docs/Web/API/History/state)
*/
state?: any;
/**
* Prevents the scroll position from being reset to the top of the window when
* the link is clicked and the app is using {@link ScrollRestoration}. This only
* prevents new locations resetting scroll to the top, scroll position will be
* restored for back/forward button navigation.
*
* ```tsx
* <Link to="?tab=one" preventScrollReset />
* ```
*/
preventScrollReset?: boolean;
/**
* Defines the relative path behavior for the link.
*
* ```tsx
* <Link to=".." /> // default: "route"
* <Link relative="route" />
* <Link relative="path" />
* ```
*
* Consider a route hierarchy where a parent route pattern is `"blog"` and a child
* route pattern is `"blog/:slug/edit"`.
*
* - **route** - default, resolves the link relative to the route pattern. In the
* example above, a relative link of `".."` will remove both `:slug/edit` segments
* back to `"/blog"`.
* - **path** - relative to the path so `".."` will only remove one URL segment up
* to `"/blog/:slug"`
*
* Note that index routes and layout routes do not have paths so they are not
* included in the relative path calculation.
*/
relative?: RelativeRoutingType;
/**
* Can be a string or a partial {@link Path}:
*
* ```tsx
* <Link to="/some/path" />
*
* <Link
* to={{
* pathname: "/some/path",
* search: "?query=string",
* hash: "#hash",
* }}
* />
* ```
*/
to: To;
/**
* Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
* for this navigation.
*
* ```jsx
* <Link to={to} viewTransition>
* Click me
* </Link>
* ```
*
* To apply specific styles for the transition, see {@link useViewTransitionState}
*/
viewTransition?: boolean;
}
/**
* A progressively enhanced [`<a href>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
* wrapper to enable navigation with client-side routing.
*
* @example
* import { Link } from "react-router";
*
* <Link to="/dashboard">Dashboard</Link>;
*
* <Link
* to={{
* pathname: "/some/path",
* search: "?query=string",
* hash: "#hash",
* }}
* />;
*
* @public
* @category Components
* @param {LinkProps.discover} props.discover [modes: framework] n/a
* @param {LinkProps.prefetch} props.prefetch [modes: framework] n/a
* @param {LinkProps.preventScrollReset} props.preventScrollReset [modes: framework, data] n/a
* @param {LinkProps.relative} props.relative n/a
* @param {LinkProps.reloadDocument} props.reloadDocument n/a
* @param {LinkProps.replace} props.replace n/a
* @param {LinkProps.state} props.state n/a
* @param {LinkProps.to} props.to n/a
* @param {LinkProps.viewTransition} props.viewTransition [modes: framework, data] n/a
*/
declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
/**
* The object passed to {@link NavLink} `children`, `className`, and `style` prop
* callbacks to render and style the link based on its state.
*
* ```
* // className
* <NavLink
* to="/messages"
* className={({ isActive, isPending }) =>
* isPending ? "pending" : isActive ? "active" : ""
* }
* >
* Messages
* </NavLink>
*
* // style
* <NavLink
* to="/messages"
* style={({ isActive, isPending }) => {
* return {
* fontWeight: isActive ? "bold" : "",
* color: isPending ? "red" : "black",
* }
* )}
* />
*
* // children
* <NavLink to="/tasks">
* {({ isActive, isPending }) => (
* <span className={isActive ? "active" : ""}>Tasks</span>
* )}
* </NavLink>
* ```
*
*/
type NavLinkRenderProps = {
/**
* Indicates if the link's URL matches the current {@link Location}.
*/
isActive: boolean;
/**
* Indicates if the pending {@link Location} matches the link's URL. Only
* available in Framework/Data modes.
*/
isPending: boolean;
/**
* Indicates if a view transition to the link's URL is in progress.
* See {@link useViewTransitionState}
*/
isTransitioning: boolean;
};
/**
* @category Types
*/
interface NavLinkProps extends Omit<LinkProps, "className" | "style" | "children"> {
/**
* Can be regular React children or a function that receives an object with the
* `active` and `pending` states of the link.
*
* ```tsx
* <NavLink to="/tasks">
* {({ isActive }) => (
* <span className={isActive ? "active" : ""}>Tasks</span>
* )}
* </NavLink>
* ```
*/
children?: React.ReactNode | ((props: NavLinkRenderProps) => React.ReactNode);
/**
* Changes the matching logic to make it case-sensitive:
*
* | Link | URL | isActive |
* | -------------------------------------------- | ------------- | -------- |
* | `<NavLink to="/SpOnGe-bOB" />` | `/sponge-bob` | true |
* | `<NavLink to="/SpOnGe-bOB" caseSensitive />` | `/sponge-bob` | false |
*/
caseSensitive?: boolean;
/**
* Classes are automatically applied to `NavLink` that correspond to the state.
*
* ```css
* a.active {
* color: red;
* }
* a.pending {
* color: blue;
* }
* a.transitioning {
* view-transition-name: my-transition;
* }
* ```
*
* Or you can specify a function that receives {@link NavLinkRenderProps} and
* returns the `className`:
*
* ```tsx
* <NavLink className={({ isActive, isPending }) => (
* isActive ? "my-active-class" :
* isPending ? "my-pending-class" :
* ""
* )} />
* ```
*/
className?: string | ((props: NavLinkRenderProps) => string | undefined);
/**
* Changes the matching logic for the `active` and `pending` states to only match
* to the "end" of the {@link NavLinkProps.to}. If the URL is longer, it will no
* longer be considered active.
*
* | Link | URL | isActive |
* | ----------------------------- | ------------ | -------- |
* | `<NavLink to="/tasks" />` | `/tasks` | true |
* | `<NavLink to="/tasks" />` | `/tasks/123` | true |
* | `<NavLink to="/tasks" end />` | `/tasks` | true |
* | `<NavLink to="/tasks" end />` | `/tasks/123` | false |
*
* `<NavLink to="/">` is an exceptional case because _every_ URL matches `/`.
* To avoid this matching every single route by default, it effectively ignores
* the `end` prop and only matches when you're at the root route.
*/
end?: boolean;
/**
* Styles can also be applied dynamically via a function that receives
* {@link NavLinkRenderProps} and returns the styles:
*
* ```tsx
* <NavLink to="/tasks" style={{ color: "red" }} />
* <NavLink to="/tasks" style={({ isActive, isPending }) => ({
* color:
* isActive ? "red" :
* isPending ? "blue" : "black"
* })} />
* ```
*/
style?: Re