`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)).
```tsx
@@ -174,7 +224,8 @@ Will use document navigation instead of client side routing when the link is cli
[modes: framework, data, declarative]
-Replaces the current entry in the history stack instead of pushing a new one onto it.
+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
@@ -210,13 +261,15 @@ function SomeComp() {
}
```
-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)
+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)
### style
[modes: framework, data, declarative]
-Regular React style object or a function that receives an object with the active and pending states of the link.
+Styles can also be applied dynamically via a function that receives
+[`NavLinkRenderProps`](https://api.reactrouter.com/v7/types/react_router.NavLinkRenderProps.html) and returns the styles:
```tsx
@@ -227,13 +280,11 @@ Regular React style object or a function that receives an object with the active
})} />
```
-Note that `pending` is only available with Framework and Data modes.
-
### to
[modes: framework, data, declarative]
-Can be a string or a partial [Path](https://api.reactrouter.com/v7/interfaces/react_router.Path):
+Can be a string or a partial [`Path`](https://api.reactrouter.com/v7/interfaces/react_router.Path.html):
```tsx
@@ -249,9 +300,10 @@ Can be a string or a partial [Path](https://api.reactrouter.com/v7/interfaces/re
### viewTransition
-[modes: framework, data, declarative]
+[modes: framework, data]
-Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) for this navigation.
+Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
+for this navigation.
```jsx
@@ -259,4 +311,5 @@ Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/Vie
```
-To apply specific styles for the transition, see [useViewTransitionState](../hooks/useViewTransitionState)
+To apply specific styles for the transition, see [`useViewTransitionState`](../hooks/useViewTransitionState)
+
diff --git a/docs/api/components/Navigate.md b/docs/api/components/Navigate.md
index d351c552d5..e512b36323 100644
--- a/docs/api/components/Navigate.md
+++ b/docs/api/components/Navigate.md
@@ -4,44 +4,57 @@ title: Navigate
# Navigate
+
+
[MODES: framework, data, declarative]
## Summary
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.Navigate.html)
-A component-based version of [useNavigate](../hooks/useNavigate) to use in a [`React.Component
-Class`](https://reactjs.org/docs/react-component.html) where hooks are not
-able to be used.
+A component-based version of [`useNavigate`](../hooks/useNavigate) to use in a
+[`React.Component` class](https://react.dev/reference/react/Component) where
+hooks cannot be used.
-It's recommended to avoid using this component in favor of [useNavigate](../hooks/useNavigate)
+It's recommended to avoid using this component in favor of [`useNavigate`](../hooks/useNavigate).
```tsx
```
+## Signature
+
+```tsx
+function Navigate({ to, replace, state, relative }: NavigateProps): null
+```
+
## Props
### relative
-[modes: framework, data, declarative]
-
-_No documentation_
+How to interpret relative routing in the `to` prop.
+See [`RelativeRoutingType`](https://api.reactrouter.com/v7/types/react_router.RelativeRoutingType.html).
### replace
-[modes: framework, data, declarative]
-
-_No documentation_
+Whether to replace the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
+stack
### state
-[modes: framework, data, declarative]
-
-_No documentation_
+State to pass to the new [`Location`](https://api.reactrouter.com/v7/interfaces/react_router.Location.html) to store in [`history.state`](https://developer.mozilla.org/en-US/docs/Web/API/History/state).
### to
-[modes: framework, data, declarative]
+The path to navigate to. This can be a string or a [`Path`](https://api.reactrouter.com/v7/interfaces/react_router.Path.html) object
-_No documentation_
diff --git a/docs/api/components/Outlet.md b/docs/api/components/Outlet.md
index 0d38ae8b8e..385e233435 100644
--- a/docs/api/components/Outlet.md
+++ b/docs/api/components/Outlet.md
@@ -4,13 +4,26 @@ title: Outlet
# Outlet
+
+
[MODES: framework, data, declarative]
## Summary
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.Outlet.html)
-Renders the matching child route of a parent route or nothing if no child route matches.
+Renders the matching child route of a parent route or nothing if no child
+route matches.
```tsx
import { Outlet } from "react-router";
@@ -25,16 +38,22 @@ export default function SomeParent() {
}
```
+## Signature
+
+```tsx
+function Outlet(props: OutletProps): React.ReactElement | null
+```
+
## Props
### context
-[modes: framework, data, declarative]
-
-Provides a context value to the element tree below the outlet. Use when the parent route needs to provide values to child routes.
+Provides a context value to the element tree below the outlet. Use when
+the parent route needs to provide values to child routes.
```tsx
```
-Access the context with [useOutletContext](../hooks/useOutletContext).
+Access the context with [`useOutletContext`](../hooks/useOutletContext).
+
diff --git a/docs/api/components/PrefetchPageLinks.md b/docs/api/components/PrefetchPageLinks.md
index 47bfe6afb5..69422cd6d3 100644
--- a/docs/api/components/PrefetchPageLinks.md
+++ b/docs/api/components/PrefetchPageLinks.md
@@ -4,62 +4,52 @@ title: PrefetchPageLinks
# PrefetchPageLinks
+
+
[MODES: framework]
## Summary
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.PrefetchPageLinks.html)
-Renders `` tags for modules and data of another page to enable an instant navigation to that page. `` uses this internally, but you can render it to prefetch a page for any other reason.
+Renders `` tags for modules and data of
+another page to enable an instant navigation to that page.
+[``](../../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.
```tsx
import { PrefetchPageLinks } from "react-router";
-;
+
```
-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.
-
-## Props
-
-### crossOrigin
-
-[modes: framework]
-
-How the element handles crossorigin requests
-
-### disabled
-
-[modes: framework]
+## Signature
-Whether the link is disabled
-
-### hrefLang
-
-[modes: framework]
-
-Language of the linked resource
-
-### integrity
-
-[modes: framework]
-
-Integrity metadata used in Subresource Integrity checks
-
-### media
-
-[modes: framework]
+```tsx
+function PrefetchPageLinks({ page, ...linkProps }: PageLinkDescriptor)
+```
-Applicable media: "screen", "print", "(max-width: 764px)"
+## Props
### page
-[modes: framework]
-
-The absolute path of the page to prefetch.
+The absolute path of the page to prefetch, e.g. `/absolute/path`.
-### referrerPolicy
+### linkProps
-[modes: framework]
+Additional props to spread onto the [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link)
+tags, such as `crossOrigin`, `integrity`, `rel`, etc.
-Referrer policy for fetches initiated by the element
diff --git a/docs/api/components/Route.md b/docs/api/components/Route.md
index 90c59b871c..3db1398209 100644
--- a/docs/api/components/Route.md
+++ b/docs/api/components/Route.md
@@ -4,6 +4,18 @@ title: Route
# Route
+
+
[MODES: framework, data, declarative]
## Summary
@@ -11,38 +23,121 @@ title: Route
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.Route.html)
Configures an element to render when a pattern matches the current location.
-It must be rendered within a [Routes](../components/Routes) element. Note that these routes
+It must be rendered within a [`Routes`](../components/Routes) element. Note that these routes
do not participate in data loading, actions, code splitting, or any other
route module features.
+```tsx
+// Usually used in a declarative router
+function App() {
+ return (
+
+
+ } />
+ } />
+ } />
+
+
+ );
+}
+
+// But can be used with a data router as well if you prefer the JSX notation
+const routes = createRoutesFromElements(
+ <>
+
+
+
+ >
+);
+
+const router = createBrowserRouter(routes);
+
+function App() {
+ return ;
+}
+```
+
+## Signature
+
+```tsx
+function Route(props: RouteProps): React.ReactElement | null
+```
+
## Props
+### action
+
+The route action.
+See [`action`](../../start/data/route-object#action).
+
### caseSensitive
-[modes: framework, data, declarative]
+Whether the path should be case-sensitive. Defaults to `false`.
-Whether the path should be matched in a case-sensitive manner.
+### Component
+
+The React Component to render when this route matches.
+Mutually exclusive with `element`.
### children
-[modes: framework, data, declarative]
+Child Route components
-_No documentation_
+### element
-### Component
+The React element to render when this Route matches.
+Mutually exclusive with `Component`.
-[modes: framework, data, declarative]
+### ErrorBoundary
-_No documentation_
+The React Component to render at this route if an error occurs.
+Mutually exclusive with `errorElement`.
-### element
+### errorElement
+
+The React element to render at this route if an error occurs.
+Mutually exclusive with `ErrorBoundary`.
+
+### handle
-[modes: framework, data, declarative]
+The route handle.
-_No documentation_
+### HydrateFallback
+
+The React Component to render while this router is loading data.
+Mutually exclusive with `hydrateFallbackElement`.
+
+### hydrateFallbackElement
+
+The React element to render while this router is loading data.
+Mutually exclusive with `HydrateFallback`.
+
+### id
+
+The unique identifier for this route (for use with [`DataRouter`](https://api.reactrouter.com/v7/interfaces/react_router.DataRouter.html)s)
+
+### index
+
+Whether this is an index route.
+
+### lazy
+
+A function that returns a promise that resolves to the route object.
+Used for code-splitting routes.
+See [`lazy`](../../start/data/route-object#lazy).
+
+### loader
+
+The route loader.
+See [`loader`](../../start/data/route-object#loader).
### path
-[modes: framework, data, declarative]
+The path pattern to match. If unspecified or empty, then this becomes a
+layout route.
+
+### shouldRevalidate
+
+The route shouldRevalidate function.
+See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
-The path to match against the current location.
diff --git a/docs/api/components/Routes.md b/docs/api/components/Routes.md
index 187b52cc4c..4fa2c28c9e 100644
--- a/docs/api/components/Routes.md
+++ b/docs/api/components/Routes.md
@@ -4,36 +4,55 @@ title: Routes
# Routes
+
+
[MODES: framework, data, declarative]
## Summary
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.Routes.html)
-Renders a branch of [Route](../components/Route) that best matches the current
-location. Note that these routes do not participate in data loading, actions,
-code splitting, or any other route module features.
+Renders a branch of [``s](../components/Route) that best matches the current
+location. Note that these routes do not participate in [data loading](../../start/framework/route-module#loader),
+[`action`](../../start/framework/route-module#action), code splitting, or
+any other [route module](../../start/framework/route-module) features.
```tsx
-import { Routes, Route } from "react-router"
+import { Route, Routes } from "react-router";
- } />
- } />
- } />
+ } />
+ } />
+ }>
```
+## Signature
+
+```tsx
+function Routes({
+ children,
+ location,
+}: RoutesProps): React.ReactElement | null
+```
+
## Props
### children
-[modes: framework, data, declarative]
-
-Nested [Route](../components/Route) elements
+Nested [`Route`](../components/Route) elements
### location
-[modes: framework, data, declarative]
+The [`Location`](https://api.reactrouter.com/v7/interfaces/react_router.Location.html) to match against. Defaults to the current location.
-The location to match against. Defaults to the current location.
diff --git a/docs/api/components/Scripts.md b/docs/api/components/Scripts.md
index 1e1d1830db..0c880c0e69 100644
--- a/docs/api/components/Scripts.md
+++ b/docs/api/components/Scripts.md
@@ -4,13 +4,31 @@ title: Scripts
# Scripts
+
+
[MODES: framework]
## Summary
[Reference Documentation ↗](https://api.reactrouter.com/v7/functions/react_router.Scripts.html)
-Renders the client runtime of your app. It should be rendered inside the `` of the document.
+Renders the client runtime of your app. It should be rendered inside the
+[``](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/body)
+ of the document.
+
+If server rendering, you can omit `` and the app will work as a
+traditional web app without JavaScript, relying solely on HTML and browser
+behaviors.
```tsx
import { Scripts } from "react-router";
@@ -27,17 +45,16 @@ export default function Root() {
}
```
-If server rendering, you can omit `` and the app will work as a traditional web app without JavaScript, relying solely on HTML and browser behaviors.
+## Signature
-## Props
-
-### ScriptsProps
+```tsx
+function Scripts(scriptProps: ScriptsProps): React.JSX.Element | null
+```
-[modes: framework]
+## Props
-A couple common attributes:
+### scriptProps
-- `` for hosting your static assets on a different server than your app.
-- `` 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 ``
+ ``,
);
});
@@ -452,7 +452,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/the/path", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -461,7 +461,7 @@ describe("A ", () => {
router={createStaticRouter(dataRoutes, context)}
context={context}
/>
-
+ ,
);
expect(html).toMatch("👋
");
@@ -473,10 +473,10 @@ describe("A ", () => {
},
actionData: null,
errors: null,
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -495,7 +495,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -504,10 +504,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toMatchInlineSnapshot(
- `"👋
"`
+ `"👋
"`,
);
});
@@ -518,7 +518,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/path/with%20space", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -527,10 +527,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toContain(
- '👋'
+ '👋',
);
});
@@ -543,7 +543,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -552,10 +552,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toContain(
- '👋'
+ '👋',
);
});
@@ -566,7 +566,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/path/with%20space", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -575,10 +575,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toContain(
- ''
+ '',
);
});
@@ -591,7 +591,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/path/with%20space", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -600,10 +600,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toContain(
- ''
+ '',
);
});
@@ -616,7 +616,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -625,10 +625,10 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
expect(html).toContain(
- ''
+ '',
);
});
@@ -639,7 +639,7 @@ describe("A ", () => {
loader: () => {
throw Response.json(
{ not: "found" },
- { status: 404, statusText: "Not Found" }
+ { status: 404, statusText: "Not Found" },
);
},
},
@@ -649,7 +649,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -658,7 +658,7 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
let expectedJsonString = JSON.stringify(
@@ -674,10 +674,10 @@ describe("A ", () => {
__type: "RouteErrorResponse",
},
},
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -689,7 +689,7 @@ describe("A ", () => {
loader: () => {
throw Response.json(
{ not: "found" },
- { status: 404, statusText: "Not Found" }
+ { status: 404, statusText: "Not Found" },
);
},
}),
@@ -700,7 +700,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -709,7 +709,7 @@ describe("A ", () => {
router={createStaticRouter(dataRoutes, context)}
context={context}
/>
-
+ ,
);
let expectedJsonString = JSON.stringify(
@@ -725,10 +725,10 @@ describe("A ", () => {
__type: "RouteErrorResponse",
},
},
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -746,7 +746,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -755,7 +755,7 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
// stack is stripped by default from SSR errors
@@ -769,10 +769,10 @@ describe("A ", () => {
__type: "Error",
},
},
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -792,7 +792,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -801,7 +801,7 @@ describe("A ", () => {
router={createStaticRouter(dataRoutes, context)}
context={context}
/>
-
+ ,
);
// stack is stripped by default from SSR errors
@@ -815,10 +815,10 @@ describe("A ", () => {
__type: "Error",
},
},
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -836,7 +836,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -845,7 +845,7 @@ describe("A ", () => {
router={createStaticRouter(routes, context)}
context={context}
/>
-
+ ,
);
// stack is stripped by default from SSR errors
@@ -860,10 +860,10 @@ describe("A ", () => {
__subType: "ReferenceError",
},
},
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -885,7 +885,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/the/path", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -895,7 +895,7 @@ describe("A ", () => {
context={context}
nonce="nonce-string"
/>
-
+ ,
);
expect(html).toMatch("👋
");
@@ -904,10 +904,10 @@ describe("A ", () => {
loaderData: {},
actionData: null,
errors: null,
- })
+ }),
);
expect(html).toMatch(
- ``
+ ``,
);
});
@@ -935,7 +935,7 @@ describe("A ", () => {
let context = (await query(
new Request("http://localhost/the/path", {
signal: new AbortController().signal,
- })
+ }),
)) as StaticHandlerContext;
let html = ReactDOMServer.renderToStaticMarkup(
@@ -945,7 +945,7 @@ describe("A ", () => {
context={context}
hydrate={false}
/>
-
+ ,
);
expect(html).toMatch("👋
");
expect(html).not.toMatch("" };
expect(escapeHtml(JSON.stringify(evilObj))).toBe(
- '{"evil":"\\u003cscript\\u003e\\u003c/script\\u003e"}'
+ '{"evil":"\\u003cscript\\u003e\\u003c/script\\u003e"}',
);
});
test("with angle brackets should parse back", () => {
let evilObj = { evil: "" };
expect(JSON.parse(escapeHtml(JSON.stringify(evilObj)))).toMatchObject(
- evilObj
+ evilObj,
);
});
@@ -28,28 +28,28 @@ describe("escapeHtml", () => {
test("with ampersands should parse back", () => {
let evilObj = { evil: "&" };
expect(JSON.parse(escapeHtml(JSON.stringify(evilObj)))).toMatchObject(
- evilObj
+ evilObj,
);
});
test('with "LINE SEPARATOR" and "PARAGRAPH SEPARATOR" should escape', () => {
let evilObj = { evil: "\u2028\u2029" };
expect(escapeHtml(JSON.stringify(evilObj))).toBe(
- '{"evil":"\\u2028\\u2029"}'
+ '{"evil":"\\u2028\\u2029"}',
);
});
test('with "LINE SEPARATOR" and "PARAGRAPH SEPARATOR" should parse back', () => {
let evilObj = { evil: "\u2028\u2029" };
expect(JSON.parse(escapeHtml(JSON.stringify(evilObj)))).toMatchObject(
- evilObj
+ evilObj,
);
});
test("escaped line terminators should work", () => {
expect(() => {
vm.runInNewContext(
- "(" + escapeHtml(JSON.stringify({ evil: "\u2028\u2029" })) + ")"
+ "(" + escapeHtml(JSON.stringify({ evil: "\u2028\u2029" })) + ")",
);
}).not.toThrow();
});
diff --git a/packages/react-router/__tests__/server-runtime/responses-test.ts b/packages/react-router/__tests__/server-runtime/responses-test.ts
index 44bb4ab8f4..734a751087 100644
--- a/packages/react-router/__tests__/server-runtime/responses-test.ts
+++ b/packages/react-router/__tests__/server-runtime/responses-test.ts
@@ -18,11 +18,11 @@ describe("json", () => {
"Content-Type": "application/json; charset=iso-8859-1",
"X-Remix": "is awesome",
},
- }
+ },
);
expect(response.headers.get("Content-Type")).toEqual(
- "application/json; charset=iso-8859-1"
+ "application/json; charset=iso-8859-1",
);
expect(response.headers.get("X-Remix")).toEqual("is awesome");
});
diff --git a/packages/react-router/__tests__/server-runtime/server-test.ts b/packages/react-router/__tests__/server-runtime/server-test.ts
index 5e88c84f20..2b00f6eb42 100644
--- a/packages/react-router/__tests__/server-runtime/server-test.ts
+++ b/packages/react-router/__tests__/server-runtime/server-test.ts
@@ -43,7 +43,7 @@ describe("server", () => {
handleDocumentRequest(request) {
return new Response(`${request.method}, ${request.url} COMPONENT`);
},
- }
+ },
);
describe("createRequestHandler", () => {
@@ -72,7 +72,7 @@ describe("server", () => {
let response = await handler(
new Request(`http://localhost:3000${to}`, {
method,
- })
+ }),
);
expect(response.status).toBe(200);
@@ -80,7 +80,7 @@ describe("server", () => {
expect(text).toContain(method);
expect(text).toContain(expected);
expect(spy.console).not.toHaveBeenCalled();
- }
+ },
);
it("strips body for HEAD requests", async () => {
@@ -88,7 +88,7 @@ describe("server", () => {
let response = await handler(
new Request("http://localhost:3000/", {
method: "HEAD",
- })
+ }),
);
expect(await response.text()).toBe("");
@@ -107,14 +107,14 @@ describe("server", () => {
handleDocumentRequest(request) {
return new Response(`${request.method}, ${request.url} COMPONENT`);
},
- }
+ },
);
let handler = createRequestHandler(build);
let response = await handler(
new Request("http://localhost:3000/_root.data"),
{
foo: "FOO",
- }
+ },
);
expect(await response.text()).toContain("FOO");
@@ -134,13 +134,13 @@ describe("server", () => {
handleDocumentRequest(request) {
return new Response(`${request.method}, ${request.url} COMPONENT`);
},
- }
+ },
);
let handler = createRequestHandler(build);
let response = await handler(
new Request("http://localhost:3000/_root.data"),
// @ts-expect-error In apps the expected type is handled via the Future interface
- new Map([[fooContext, "FOO"]])
+ new Map([[fooContext, "FOO"]]),
);
expect(await response.text()).toContain("FOO");
@@ -164,14 +164,14 @@ describe("server", () => {
handleDocumentRequest(request) {
return new Response(`${request.method}, ${request.url} COMPONENT`);
},
- }
+ },
);
let handler = createRequestHandler(build);
let response = await handler(
new Request("http://localhost:3000/_root.data"),
{
foo: "FOO",
- }
+ },
);
expect(response.status).toBe(500);
@@ -314,7 +314,7 @@ describe("shared server runtime", () => {
let result = await handler(request);
expect(await result.text()).toBe(
- "Unexpected Server Error\n\nError: should be logged when resource loader throws"
+ "Unexpected Server Error\n\nError: should be logged when resource loader throws",
);
});
@@ -457,7 +457,7 @@ describe("shared server runtime", () => {
let result = await handler(request);
expect(await result.text()).toBe(
- "Unexpected Server Error\n\nError: should be logged when resource loader throws"
+ "Unexpected Server Error\n\nError: should be logged when resource loader throws",
);
});
@@ -505,7 +505,7 @@ describe("shared server runtime", () => {
},
{
handleError: handleErrorSpy,
- }
+ },
);
let handler = createRequestHandler(build, ServerMode.Test);
@@ -526,15 +526,15 @@ describe("shared server runtime", () => {
`);
expect(handleErrorSpy).toHaveBeenCalledTimes(1);
expect(handleErrorSpy.mock.calls[0][0] instanceof DOMException).toBe(
- true
+ true,
);
expect(handleErrorSpy.mock.calls[0][0].name).toBe("AbortError");
expect(handleErrorSpy.mock.calls[0][0].message).toBe(
- "This operation was aborted"
+ "This operation was aborted",
);
expect(handleErrorSpy.mock.calls[0][1].request.method).toBe("GET");
expect(handleErrorSpy.mock.calls[0][1].request.url).toBe(
- "http://test.com/resource"
+ "http://test.com/resource",
);
});
});
@@ -999,7 +999,7 @@ describe("shared server runtime", () => {
},
{
handleError: handleErrorSpy,
- }
+ },
);
let handler = createRequestHandler(build, ServerMode.Test);
@@ -1016,19 +1016,19 @@ describe("shared server runtime", () => {
let error = await result.json();
expect(error.message).toBe("This operation was aborted");
expect(
- error.stack.startsWith("AbortError: This operation was aborted")
+ error.stack.startsWith("AbortError: This operation was aborted"),
).toBe(true);
expect(handleErrorSpy).toHaveBeenCalledTimes(1);
expect(handleErrorSpy.mock.calls[0][0] instanceof DOMException).toBe(
- true
+ true,
);
expect(handleErrorSpy.mock.calls[0][0].name).toBe("AbortError");
expect(handleErrorSpy.mock.calls[0][0].message).toBe(
- "This operation was aborted"
+ "This operation was aborted",
);
expect(handleErrorSpy.mock.calls[0][1].request.method).toBe("GET");
expect(handleErrorSpy.mock.calls[0][1].request.url).toBe(
- "http://test.com/?_data=routes/_index"
+ "http://test.com/?_data=routes/_index",
);
});
});
@@ -1538,7 +1538,7 @@ describe("shared server runtime", () => {
expect(context.errors).toBeTruthy();
expect(context.errors!["routes/_index"]).toBeInstanceOf(Error);
expect(context.errors!["routes/_index"].message).toBe(
- "Unexpected Server Error"
+ "Unexpected Server Error",
);
expect(context.errors!["routes/_index"].stack).toBeUndefined();
expect(context.loaderData).toEqual({
@@ -1680,7 +1680,7 @@ describe("shared server runtime", () => {
expect(context.errors).toBeTruthy();
expect(context.errors!["routes/test"]).toBeInstanceOf(Error);
expect(context.errors!["routes/test"].message).toBe(
- "Unexpected Server Error"
+ "Unexpected Server Error",
);
expect(context.errors!["routes/test"].stack).toBeUndefined();
expect(context.loaderData).toEqual({
@@ -1730,7 +1730,7 @@ describe("shared server runtime", () => {
expect(context.errors).toBeTruthy();
expect(context.errors!["routes/_index"]).toBeInstanceOf(Error);
expect(context.errors!["routes/_index"].message).toBe(
- "Unexpected Server Error"
+ "Unexpected Server Error",
);
expect(context.errors!["routes/_index"].stack).toBeUndefined();
expect(context.loaderData).toEqual({
@@ -1788,7 +1788,7 @@ describe("shared server runtime", () => {
expect(context.errors).toBeTruthy();
expect(context.errors!["routes/__layout"]).toBeInstanceOf(Error);
expect(context.errors!["routes/__layout"].message).toBe(
- "Unexpected Server Error"
+ "Unexpected Server Error",
);
expect(context.errors!["routes/__layout"].stack).toBeUndefined();
expect(context.loaderData).toEqual({
@@ -1846,7 +1846,7 @@ describe("shared server runtime", () => {
expect(context.errors).toBeTruthy();
expect(context.errors!["routes/__layout"]).toBeInstanceOf(Error);
expect(context.errors!["routes/__layout"].message).toBe(
- "Unexpected Server Error"
+ "Unexpected Server Error",
);
expect(context.errors!["routes/__layout"].stack).toBeUndefined();
expect(context.loaderData).toEqual({
@@ -1923,7 +1923,7 @@ describe("shared server runtime", () => {
let ogHandleDocumentRequest = build.entry.module.default;
build.entry.module.default = function (
_: Request,
- responseStatusCode: number
+ responseStatusCode: number,
) {
if (responseStatusCode === 200) {
throw new Response("Uh oh!", {
@@ -1972,7 +1972,7 @@ describe("shared server runtime", () => {
let result = await handler(request);
expect(result.status).toBe(500);
expect(await result.text()).toBe(
- "Unexpected Server Error\n\nError: rofl"
+ "Unexpected Server Error\n\nError: rofl",
);
expect(rootLoader.mock.calls.length).toBe(0);
expect(indexLoader.mock.calls.length).toBe(0);
@@ -2025,7 +2025,7 @@ describe("shared server runtime", () => {
expect(spy.console.mock.calls).toEqual([
[
new Error(
- "thrown from handleDocumentRequest and expected to be logged in console only once"
+ "thrown from handleDocumentRequest and expected to be logged in console only once",
),
],
[new Error("second error thrown from handleDocumentRequest")],
@@ -2055,7 +2055,7 @@ describe("shared server runtime", () => {
},
{
handleError: handleErrorSpy,
- }
+ },
);
let handler = createRequestHandler(build, ServerMode.Test);
@@ -2073,15 +2073,15 @@ describe("shared server runtime", () => {
expect(handleErrorSpy).toHaveBeenCalledTimes(1);
expect(handleErrorSpy.mock.calls[0][0] instanceof DOMException).toBe(
- true
+ true,
);
expect(handleErrorSpy.mock.calls[0][0].name).toBe("AbortError");
expect(handleErrorSpy.mock.calls[0][0].message).toBe(
- "This operation was aborted"
+ "This operation was aborted",
);
expect(handleErrorSpy.mock.calls[0][1].request.method).toBe("GET");
expect(handleErrorSpy.mock.calls[0][1].request.url).toBe(
- "http://test.com/"
+ "http://test.com/",
);
});
});
@@ -2113,7 +2113,7 @@ describe("shared server runtime", () => {
headers: responseHeaders,
});
},
- }
+ },
);
let handler = createRequestHandler(build, ServerMode.Development);
diff --git a/packages/react-router/__tests__/server-runtime/sessions-test.ts b/packages/react-router/__tests__/server-runtime/sessions-test.ts
index d45a14a657..dd8a1e15f4 100644
--- a/packages/react-router/__tests__/server-runtime/sessions-test.ts
+++ b/packages/react-router/__tests__/server-runtime/sessions-test.ts
@@ -103,7 +103,7 @@ describe("Cookie session storage", () => {
let setCookie = await commitSession(session);
session = await getSession(
// Tamper with the session cookie...
- getCookieFromSetCookie(setCookie).slice(0, -1)
+ getCookieFromSetCookie(setCookie).slice(0, -1),
);
expect(session.get("user")).toBeUndefined();
@@ -139,7 +139,7 @@ describe("Cookie session storage", () => {
let session = await getSession();
let setCookie = await destroySession(session);
expect(setCookie).toMatchInlineSnapshot(
- `"__session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"`
+ `"__session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"`,
);
spy.mockRestore();
});
@@ -155,7 +155,7 @@ describe("Cookie session storage", () => {
let session = await getSession();
let setCookie = await destroySession(session);
expect(setCookie).toMatchInlineSnapshot(
- `"__session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"`
+ `"__session=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"`,
);
spy.mockRestore();
});
@@ -173,7 +173,7 @@ describe("Cookie session storage", () => {
expect(spy.console).toHaveBeenCalledTimes(1);
expect(spy.console).toHaveBeenCalledWith(
- 'The "__session" cookie has an "expires" property set. This will cause the expires value to not be updated when the session is committed. Instead, you should set the expires value when serializing the cookie. You can use `commitSession(session, { expires })` if using a session storage object, or `cookie.serialize("value", { expires })` if you\'re using the cookie directly.'
+ 'The "__session" cookie has an "expires" property set. This will cause the expires value to not be updated when the session is committed. Instead, you should set the expires value when serializing the cookie. You can use `commitSession(session, { expires })` if using a session storage object, or `cookie.serialize("value", { expires })` if you\'re using the cookie directly.',
);
});
@@ -182,7 +182,7 @@ describe("Cookie session storage", () => {
expect(spy.console).toHaveBeenCalledTimes(1);
expect(spy.console).toHaveBeenCalledWith(
- 'The "__session" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies for more information.'
+ 'The "__session" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies for more information.',
);
});
});
diff --git a/packages/react-router/__tests__/server-runtime/utils.ts b/packages/react-router/__tests__/server-runtime/utils.ts
index 76f4ba77bb..6e4fa4dce5 100644
--- a/packages/react-router/__tests__/server-runtime/utils.ts
+++ b/packages/react-router/__tests__/server-runtime/utils.ts
@@ -30,7 +30,7 @@ export function mockServerBuild(
future?: Partial;
handleError?: HandleErrorFunction;
handleDocumentRequest?: HandleDocumentRequestFunction;
- } = {}
+ } = {},
): ServerBuild {
return {
ssr: true,
@@ -87,7 +87,7 @@ export function mockServerBuild(
new Response(null, {
status: responseStatusCode,
headers: responseHeaders,
- })
+ }),
),
handleDataRequest: jest.fn(async (response) => response),
handleError: opts.handleError,
@@ -113,7 +113,7 @@ export function mockServerBuild(
[id]: route,
};
},
- {}
+ {},
),
};
}
diff --git a/packages/react-router/__tests__/use-revalidator-test.tsx b/packages/react-router/__tests__/use-revalidator-test.tsx
index 973b62dca1..7d3d08f92f 100644
--- a/packages/react-router/__tests__/use-revalidator-test.tsx
+++ b/packages/react-router/__tests__/use-revalidator-test.tsx
@@ -32,7 +32,7 @@ describe("useRevalidator", () => {
loader={async () => `count=${++count}`}
element={}
/>
-
+ ,
),
{
initialEntries: ["/foo"],
@@ -41,7 +41,7 @@ describe("useRevalidator", () => {
"0-0": "count=1",
},
},
- }
+ },
);
let { container } = render();
@@ -157,14 +157,14 @@ describe("useRevalidator", () => {
);
}}
/>
-
- )
+ ,
+ ),
);
let { container } = render(
-
+ ,
);
fireEvent.click(screen.getByText("/child"));
@@ -214,14 +214,14 @@ describe("useRevalidator", () => {
}}
Component={() => {("Child:" + useLoaderData()) as string}
}
/>
-
- )
+ ,
+ ),
);
let { container } = render(
-
+ ,
);
fireEvent.click(screen.getByText("/child"));
@@ -312,7 +312,7 @@ describe("useRevalidator", () => {
hydrationData: {
loaderData: { root: 0 },
},
- }
+ },
);
render();
diff --git a/packages/react-router/__tests__/useHref-basename-test.tsx b/packages/react-router/__tests__/useHref-basename-test.tsx
index 0b5bde505f..866a36a658 100644
--- a/packages/react-router/__tests__/useHref-basename-test.tsx
+++ b/packages/react-router/__tests__/useHref-basename-test.tsx
@@ -16,7 +16,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -37,7 +37,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -57,7 +57,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -78,7 +78,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -100,7 +100,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -120,7 +120,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -141,7 +141,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -163,7 +163,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -183,7 +183,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -204,7 +204,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -229,7 +229,7 @@ describe("useHref under a basename", () => {
element={}
/>
-
+ ,
);
});
@@ -253,7 +253,7 @@ describe("useHref under a basename", () => {
} />
-
+ ,
);
});
@@ -281,7 +281,7 @@ describe("useHref under a basename", () => {
element={}
/>
-
+ ,
);
});
@@ -309,7 +309,7 @@ describe("useHref under a basename", () => {
element={}
/>
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useHref-test.tsx b/packages/react-router/__tests__/useHref-test.tsx
index f3e2c4c173..0aa3c23bd0 100644
--- a/packages/react-router/__tests__/useHref-test.tsx
+++ b/packages/react-router/__tests__/useHref-test.tsx
@@ -19,7 +19,7 @@ describe("useHref", () => {
element={}
/>
-
+ ,
);
});
@@ -42,7 +42,7 @@ describe("useHref", () => {
element={}
/>
-
+ ,
);
});
@@ -66,7 +66,7 @@ describe("useHref", () => {
element={}
/>
-
+ ,
);
});
@@ -88,7 +88,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
@@ -108,7 +108,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
@@ -129,7 +129,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
@@ -153,7 +153,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
@@ -175,7 +175,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
@@ -201,7 +201,7 @@ describe("useHref", () => {
/>
-
+ ,
);
});
@@ -226,7 +226,7 @@ describe("useHref", () => {
element={}
/>
-
+ ,
);
});
@@ -252,7 +252,7 @@ describe("useHref", () => {
/>
-
+ ,
);
});
@@ -272,7 +272,7 @@ describe("useHref", () => {
} />
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useLocation-test.tsx b/packages/react-router/__tests__/useLocation-test.tsx
index 121073a0d5..de87981e74 100644
--- a/packages/react-router/__tests__/useLocation-test.tsx
+++ b/packages/react-router/__tests__/useLocation-test.tsx
@@ -16,7 +16,7 @@ describe("useLocation", () => {
} />
-
+ ,
);
});
@@ -33,7 +33,7 @@ describe("useLocation", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -74,7 +74,7 @@ describe("useLocation", () => {
} />
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useMatch-test.tsx b/packages/react-router/__tests__/useMatch-test.tsx
index f51219a055..21dcbe6d53 100644
--- a/packages/react-router/__tests__/useMatch-test.tsx
+++ b/packages/react-router/__tests__/useMatch-test.tsx
@@ -19,7 +19,7 @@ describe("useMatch", () => {
Home} />
-
+ ,
);
});
@@ -51,7 +51,7 @@ describe("useMatch", () => {
Home} />
-
+ ,
);
});
@@ -83,7 +83,7 @@ describe("useMatch", () => {
Home} />
-
+ ,
);
});
@@ -118,7 +118,7 @@ describe("useMatch", () => {
} />
-
+ ,
);
});
@@ -128,7 +128,7 @@ describe("useMatch", () => {
} />
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useNavigate-test.tsx b/packages/react-router/__tests__/useNavigate-test.tsx
index 66823db747..743aed2709 100644
--- a/packages/react-router/__tests__/useNavigate-test.tsx
+++ b/packages/react-router/__tests__/useNavigate-test.tsx
@@ -38,7 +38,7 @@ describe("useNavigate", () => {
} />
About} />
-
+ ,
);
});
@@ -74,7 +74,7 @@ describe("useNavigate", () => {
} />
-
+ ,
);
});
@@ -131,7 +131,7 @@ describe("useNavigate", () => {
} />
-
+ ,
);
});
@@ -188,7 +188,7 @@ describe("useNavigate", () => {
} />
-
+ ,
);
});
@@ -264,40 +264,40 @@ describe("useNavigate", () => {
} />
-
+ ,
);
});
expect(() =>
TestRenderer.act(() => {
renderer.root.findAllByType("button")[0].props.onClick();
- })
+ }),
).toThrowErrorMatchingInlineSnapshot(
- `"Cannot include a '?' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing?search"}]. Please separate it out to the \`to.search\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`
+ `"Cannot include a '?' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing?search"}]. Please separate it out to the \`to.search\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`,
);
expect(() =>
TestRenderer.act(() => {
renderer.root.findAllByType("button")[1].props.onClick();
- })
+ }),
).toThrowErrorMatchingInlineSnapshot(
- `"Cannot include a '#' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing#hash"}]. Please separate it out to the \`to.hash\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`
+ `"Cannot include a '#' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing#hash"}]. Please separate it out to the \`to.hash\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`,
);
expect(() =>
TestRenderer.act(() => {
renderer.root.findAllByType("button")[2].props.onClick();
- })
+ }),
).toThrowErrorMatchingInlineSnapshot(
- `"Cannot include a '?' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing?search#hash"}]. Please separate it out to the \`to.search\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`
+ `"Cannot include a '?' character in a manually specified \`to.pathname\` field [{"pathname":"/about/thing?search#hash"}]. Please separate it out to the \`to.search\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`,
);
expect(() =>
TestRenderer.act(() => {
renderer.root.findAllByType("button")[3].props.onClick();
- })
+ }),
).toThrowErrorMatchingInlineSnapshot(
- `"Cannot include a '#' character in a manually specified \`to.search\` field [{"pathname":"/about/thing","search":"?search#hash"}]. Please separate it out to the \`to.hash\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`
+ `"Cannot include a '#' character in a manually specified \`to.search\` field [{"pathname":"/about/thing","search":"?search#hash"}]. Please separate it out to the \`to.hash\` field. Alternatively you may provide the full path as a string in and the router will parse it for you."`,
);
});
@@ -493,7 +493,7 @@ describe("useNavigate", () => {
} />
About} />
-
+ ,
);
});
@@ -510,7 +510,7 @@ describe("useNavigate", () => {
`);
expect(warnSpy).toHaveBeenCalledWith(
- "You should call navigate() in a React.useEffect(), not when your component is first rendered."
+ "You should call navigate() in a React.useEffect(), not when your component is first rendered.",
);
});
@@ -523,7 +523,7 @@ describe("useNavigate", () => {
} />
About} />
-
+ ,
);
});
@@ -553,7 +553,7 @@ describe("useNavigate", () => {
} />
About} />
-
+ ,
);
});
@@ -561,7 +561,7 @@ describe("useNavigate", () => {
let navigate = useNavigate();
let onChildRendered = React.useCallback(
() => navigate("/about"),
- [navigate]
+ [navigate],
);
return ;
}
@@ -610,7 +610,7 @@ describe("useNavigate", () => {
`);
expect(warnSpy).toHaveBeenCalledWith(
- "You should call navigate() in a React.useEffect(), not when your component is first rendered."
+ "You should call navigate() in a React.useEffect(), not when your component is first rendered.",
);
});
@@ -653,7 +653,7 @@ describe("useNavigate", () => {
let navigate = useNavigate();
let onChildRendered = React.useCallback(
() => navigate("/about"),
- [navigate]
+ [navigate],
);
return ;
},
@@ -714,7 +714,7 @@ describe("useNavigate", () => {
} />
} />
-
+ ,
);
});
@@ -746,7 +746,7 @@ describe("useNavigate", () => {
/>
About} />
-
+ ,
);
});
@@ -776,7 +776,7 @@ describe("useNavigate", () => {
/>
About} />
-
+ ,
);
});
@@ -803,7 +803,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -833,7 +833,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -869,7 +869,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -905,7 +905,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -954,7 +954,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -984,7 +984,7 @@ describe("useNavigate", () => {
-
+ ,
);
});
@@ -1014,7 +1014,7 @@ describe("useNavigate", () => {
element={}
/>
-
+ ,
);
});
@@ -1044,7 +1044,7 @@ describe("useNavigate", () => {
/>
-
+ ,
);
});
@@ -1074,7 +1074,7 @@ describe("useNavigate", () => {
/>
-
+ ,
);
});
@@ -1112,7 +1112,7 @@ describe("useNavigate", () => {
-
+ ,
);
});
@@ -1150,7 +1150,7 @@ describe("useNavigate", () => {
-
+ ,
);
});
@@ -1183,7 +1183,7 @@ describe("useNavigate", () => {
-
+ ,
);
});
@@ -1213,7 +1213,7 @@ describe("useNavigate", () => {
}
/>
-
+ ,
);
});
@@ -1268,7 +1268,7 @@ describe("useNavigate", () => {
About} />
-
+ ,
);
});
@@ -1381,9 +1381,9 @@ describe("useNavigate", () => {
<>
} />
About} />
- >
+ >,
),
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1414,9 +1414,9 @@ describe("useNavigate", () => {
element={}
/>
About} />
- >
+ >,
),
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1444,9 +1444,9 @@ describe("useNavigate", () => {
} />
About} />
- >
+ >,
),
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1477,9 +1477,9 @@ describe("useNavigate", () => {
/>
About} />
- >
+ >,
),
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1516,9 +1516,9 @@ describe("useNavigate", () => {
About} />
- >
+ >,
),
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1555,9 +1555,9 @@ describe("useNavigate", () => {
About} />
- >
+ >,
),
- { initialEntries: ["/home/page"] }
+ { initialEntries: ["/home/page"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1607,9 +1607,9 @@ describe("useNavigate", () => {
About} />
- >
+ >,
),
- { initialEntries: ["/home/page"] }
+ { initialEntries: ["/home/page"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1640,9 +1640,9 @@ describe("useNavigate", () => {
Destination} />
- >
+ >,
),
- { initialEntries: ["/layout/thing"] }
+ { initialEntries: ["/layout/thing"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1673,9 +1673,9 @@ describe("useNavigate", () => {
path="contacts/:id"
element={}
/>
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1706,9 +1706,9 @@ describe("useNavigate", () => {
element={}
/>
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1739,9 +1739,9 @@ describe("useNavigate", () => {
element={}
/>
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1778,9 +1778,9 @@ describe("useNavigate", () => {
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1817,9 +1817,9 @@ describe("useNavigate", () => {
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1853,9 +1853,9 @@ describe("useNavigate", () => {
Destination} />
- >
+ >,
),
- { initialEntries: ["/layout/thing"] }
+ { initialEntries: ["/layout/thing"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -1886,9 +1886,9 @@ describe("useNavigate", () => {
}
/>
- >
+ >,
),
- { initialEntries: ["/contacts/1"] }
+ { initialEntries: ["/contacts/1"] },
);
function Contacts() {
@@ -1951,7 +1951,7 @@ describe("useNavigate", () => {
],
},
],
- { initialEntries: ["/home"] }
+ { initialEntries: ["/home"] },
);
let renderer: TestRenderer.ReactTestRenderer;
@@ -2071,7 +2071,7 @@ describe("useNavigate", () => {
} />
Path} />
-
+ ,
);
});
@@ -2115,7 +2115,7 @@ describe("useNavigate", () => {
/>
Path} />
-
+ ,
);
});
@@ -2154,7 +2154,7 @@ describe("useNavigate", () => {
},
{ path: "/path", Component: () => Path
},
],
- { basename: "/base", initialEntries: ["/base"] }
+ { basename: "/base", initialEntries: ["/base"] },
);
function Home() {
@@ -2201,7 +2201,7 @@ describe("useNavigate", () => {
},
{ path: "/path", Component: () => Path
},
],
- { basename: "/base", initialEntries: ["/base"] }
+ { basename: "/base", initialEntries: ["/base"] },
);
function Home() {
diff --git a/packages/react-router/__tests__/useOutlet-test.tsx b/packages/react-router/__tests__/useOutlet-test.tsx
index f283bd4874..32dc725d96 100644
--- a/packages/react-router/__tests__/useOutlet-test.tsx
+++ b/packages/react-router/__tests__/useOutlet-test.tsx
@@ -22,7 +22,7 @@ describe("useOutlet", () => {
} />
-
+ ,
);
});
@@ -42,7 +42,7 @@ describe("useOutlet", () => {
} />
-
+ ,
);
});
@@ -66,7 +66,7 @@ describe("useOutlet", () => {
} />
-
+ ,
);
});
@@ -93,7 +93,7 @@ describe("useOutlet", () => {
Profile} />
-
+ ,
);
});
@@ -119,7 +119,7 @@ describe("useOutlet", () => {
index} />
-
+ ,
);
});
@@ -145,7 +145,7 @@ describe("useOutlet", () => {
index} />
-
+ ,
);
});
@@ -183,7 +183,7 @@ describe("useOutlet", () => {
} />
-
+ ,
);
});
@@ -235,7 +235,7 @@ describe("useOutlet", () => {
} />
-
+ ,
);
});
@@ -286,7 +286,7 @@ describe("useOutlet", () => {
-
+ ,
);
});
@@ -328,7 +328,7 @@ describe("useOutlet", () => {
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useParams-test.tsx b/packages/react-router/__tests__/useParams-test.tsx
index 4b34daf16a..5413cee245 100644
--- a/packages/react-router/__tests__/useParams-test.tsx
+++ b/packages/react-router/__tests__/useParams-test.tsx
@@ -14,7 +14,7 @@ describe("useParams", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -35,7 +35,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -56,7 +56,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -89,7 +89,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -116,7 +116,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -137,7 +137,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -171,7 +171,7 @@ describe("useParams", () => {
} />
-
+ ,
);
});
@@ -182,7 +182,7 @@ describe("useParams", () => {
`);
expect(consoleWarn).toHaveBeenCalledWith(
- expect.stringMatching("malformed URL segment")
+ expect.stringMatching("malformed URL segment"),
);
});
});
@@ -198,7 +198,7 @@ describe("useParams", () => {
-
+ ,
);
});
diff --git a/packages/react-router/__tests__/useResolvedPath-test.tsx b/packages/react-router/__tests__/useResolvedPath-test.tsx
index 7f183b4f7a..785694708e 100644
--- a/packages/react-router/__tests__/useResolvedPath-test.tsx
+++ b/packages/react-router/__tests__/useResolvedPath-test.tsx
@@ -26,7 +26,7 @@ describe("useResolvedPath", () => {
element={}
/>
-
+ ,
);
});
@@ -56,7 +56,7 @@ describe("useResolvedPath", () => {
}
/>
-
+ ,
);
});
@@ -79,7 +79,7 @@ describe("useResolvedPath", () => {
element={}
/>
-
+ ,
);
});
@@ -102,7 +102,7 @@ describe("useResolvedPath", () => {
} />
-
+ ,
);
});
@@ -123,7 +123,7 @@ describe("useResolvedPath", () => {
} />
-
+ ,
);
});
@@ -149,7 +149,7 @@ describe("useResolvedPath", () => {
}
/>
-
+ ,
);
});
@@ -175,7 +175,7 @@ describe("useResolvedPath", () => {
}
/>
-
+ ,
);
});
@@ -198,7 +198,7 @@ describe("useResolvedPath", () => {
} />
-
+ ,
);
});
@@ -219,7 +219,7 @@ describe("useResolvedPath", () => {
} />
-
+ ,
);
});
@@ -381,7 +381,7 @@ describe("useResolvedPath", () => {
-
+ ,
);
let html = getHtml(container);
html = html ? html.replace(/</g, "<").replace(/>/g, ">") : html;
diff --git a/packages/react-router/__tests__/useRoutes-test.tsx b/packages/react-router/__tests__/useRoutes-test.tsx
index 91de38a632..b433e986b9 100644
--- a/packages/react-router/__tests__/useRoutes-test.tsx
+++ b/packages/react-router/__tests__/useRoutes-test.tsx
@@ -15,7 +15,7 @@ describe("useRoutes", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -41,7 +41,7 @@ describe("useRoutes", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -64,7 +64,7 @@ describe("useRoutes", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -90,7 +90,7 @@ describe("useRoutes", () => {
renderer = TestRenderer.create(
-
+ ,
);
});
@@ -124,7 +124,7 @@ describe("useRoutes", () => {
routes={routes}
location={{ pathname: "/three", search: "", hash: "" }}
/>
-
+ ,
);
});
@@ -159,15 +159,15 @@ describe("useRoutes", () => {
TestRenderer.create(
-
+ ,
);
});
expect(consoleWarn).toHaveBeenCalledTimes(1);
expect(consoleWarn).toHaveBeenCalledWith(
expect.stringContaining(
- `Matched leaf route at location "/layout" does not have an element`
- )
+ `Matched leaf route at location "/layout" does not have an element`,
+ ),
);
});
});
diff --git a/packages/react-router/__tests__/utils/MemoryNavigate.tsx b/packages/react-router/__tests__/utils/MemoryNavigate.tsx
index 146e059011..a1c0a31d30 100644
--- a/packages/react-router/__tests__/utils/MemoryNavigate.tsx
+++ b/packages/react-router/__tests__/utils/MemoryNavigate.tsx
@@ -25,7 +25,7 @@ export default function MemoryNavigate({
dataRouterContext?.router.navigate(to);
}
},
- [dataRouterContext, to, formMethod, formData]
+ [dataRouterContext, to, formMethod, formData],
);
// Only prepend the basename to the rendered href, send the non-prefixed `to`
diff --git a/packages/react-router/__tests__/utils/framework.ts b/packages/react-router/__tests__/utils/framework.ts
index 824fc3a761..72762d49d7 100644
--- a/packages/react-router/__tests__/utils/framework.ts
+++ b/packages/react-router/__tests__/utils/framework.ts
@@ -4,7 +4,7 @@ import type {
} from "../../lib/dom/ssr/entry";
export function mockFrameworkContext(
- overrides?: Partial
+ overrides?: Partial,
): FrameworkContextObject {
return {
routeModules: { root: { default: () => null } },
@@ -44,7 +44,7 @@ export function mockFrameworkContext(
}
export function mockEntryContext(
- overrides?: Partial
+ overrides?: Partial,
): EntryContext {
return {
...mockFrameworkContext(overrides),
diff --git a/packages/react-router/__tests__/utils/renderStrict.tsx b/packages/react-router/__tests__/utils/renderStrict.tsx
index 3ce64e06c4..a9f4d19483 100644
--- a/packages/react-router/__tests__/utils/renderStrict.tsx
+++ b/packages/react-router/__tests__/utils/renderStrict.tsx
@@ -13,7 +13,7 @@ function renderStrict(
element:
| React.FunctionComponentElement
| React.FunctionComponentElement[],
- node: ReactDOM.Container
+ node: ReactDOM.Container,
): void {
ReactDOM.render({element}, node);
}
diff --git a/packages/react-router/__tests__/vendor/turbo-stream-test.ts b/packages/react-router/__tests__/vendor/turbo-stream-test.ts
index 54332b1703..8c9d615e55 100644
--- a/packages/react-router/__tests__/vendor/turbo-stream-test.ts
+++ b/packages/react-router/__tests__/vendor/turbo-stream-test.ts
@@ -244,7 +244,7 @@ test("should encode and decode object and dedupe object key, value, and promise
write(chunk) {
encoded += chunk;
},
- })
+ }),
);
expect(Array.from(encoded.matchAll(/"foo"/g))).toHaveLength(1);
@@ -288,7 +288,7 @@ test("should encode and decode rejected promise", async () => {
const decoded = await decode(encode(input));
expect(decoded.value).toBeInstanceOf(Promise);
await expect(decoded.value).rejects.toEqual(
- await input.catch((reason) => reason)
+ await input.catch((reason) => reason),
);
await decoded.done;
});
@@ -308,7 +308,7 @@ test("should encode and decode object with rejected promise", async () => {
const value = decoded.value as typeof input;
expect(value.foo).toBeInstanceOf(Promise);
await expect(value.foo).rejects.toEqual(
- await input.foo.catch((reason) => reason)
+ await input.foo.catch((reason) => reason),
);
return decoded.done;
});
@@ -352,7 +352,7 @@ test("should encode and decode custom type", async () => {
}),
{
plugins: [decoder],
- }
+ },
);
const value = decoded.value as Custom;
expect(value).toBeInstanceOf(Custom);
@@ -393,7 +393,7 @@ test("should encode and decode custom type when nested alongside Promise", async
}
},
],
- }
+ },
)) as unknown as {
value: {
number: number;
@@ -431,7 +431,7 @@ test("should allow plugins to encode and decode functions", async () => {
}
},
],
- }
+ },
);
expect(decoded.value).toBeInstanceOf(Function);
expect((decoded.value as typeof input)()).toBe("foo");
@@ -460,7 +460,7 @@ test("should allow postPlugins to handle values that would otherwise throw", asy
}
},
],
- }
+ },
);
expect(decoded.value).toEqual({ func: undefined, class: undefined });
await decoded.done;
@@ -471,7 +471,7 @@ test("should propagate abort reason to deferred promises for sync resolved promi
const reason = new Error("reason");
abortController.abort(reason);
const decoded = await decode(
- encode(Promise.resolve("foo"), { signal: abortController.signal })
+ encode(Promise.resolve("foo"), { signal: abortController.signal }),
);
await expect(decoded.value).rejects.toEqual(reason);
});
@@ -481,7 +481,7 @@ test("should propagate abort reason to deferred promises for async resolved prom
const deferred = new Deferred();
const reason = new Error("reason");
const decoded = await decode(
- encode(deferred.promise, { signal: abortController.signal })
+ encode(deferred.promise, { signal: abortController.signal }),
);
abortController.abort(reason);
await expect(decoded.value).rejects.toEqual(reason);
@@ -511,7 +511,7 @@ test("should encode and decode objects with multiple promises resolving to the s
write(chunk) {
encoded += chunk;
},
- })
+ }),
);
expect(Array.from(encoded.matchAll(/"baz"/g))).toHaveLength(1);
});
@@ -542,7 +542,7 @@ test("should encode and decode objects with reused values", async () => {
write(chunk) {
encoded += chunk;
},
- })
+ }),
);
expect(Array.from(encoded.matchAll(/"baz"/g))).toHaveLength(1);
await decoded.done;
@@ -573,7 +573,7 @@ test("should encode and decode objects with multiple promises rejecting to the s
write(chunk) {
encoded += chunk;
},
- })
+ }),
);
expect(Array.from(encoded.matchAll(/"baz"/g))).toHaveLength(1);
});
diff --git a/packages/react-router/index.ts b/packages/react-router/index.ts
index 6610e517f5..5e96c5f30d 100644
--- a/packages/react-router/index.ts
+++ b/packages/react-router/index.ts
@@ -204,7 +204,11 @@ export {
Scripts,
PrefetchPageLinks,
} from "./lib/dom/ssr/components";
-export type { ScriptsProps } from "./lib/dom/ssr/components";
+export type {
+ ScriptsProps,
+ PrefetchBehavior,
+ DiscoverBehavior,
+} from "./lib/dom/ssr/components";
export type { EntryContext } from "./lib/dom/ssr/entry";
export type {
ClientActionFunction,
@@ -286,12 +290,16 @@ export { href } from "./lib/href";
export type {
BrowserCreateFromReadableStreamFunction as unstable_BrowserCreateFromReadableStreamFunction,
EncodeReplyFunction as unstable_EncodeReplyFunction,
+ RSCHydratedRouterProps as unstable_RSCHydratedRouterProps,
} from "./lib/rsc/browser";
export {
createCallServer as unstable_createCallServer,
RSCHydratedRouter as unstable_RSCHydratedRouter,
} from "./lib/rsc/browser";
-export type { SSRCreateFromReadableStreamFunction as unstable_SSRCreateFromReadableStreamFunction } from "./lib/rsc/server.ssr";
+export type {
+ SSRCreateFromReadableStreamFunction as unstable_SSRCreateFromReadableStreamFunction,
+ RSCStaticRouterProps as unstable_RSCStaticRouterProps,
+} from "./lib/rsc/server.ssr";
export {
routeRSCServerRequest as unstable_routeRSCServerRequest,
RSCStaticRouter as unstable_RSCStaticRouter,
diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx
index a422823662..d0c814b22a 100644
--- a/packages/react-router/lib/components.tsx
+++ b/packages/react-router/lib/components.tsx
@@ -69,9 +69,6 @@ import {
import type { ViewTransition } from "./dom/global";
import { warnOnce } from "./server-runtime/warnings";
-/**
- * @private
- */
export function mapRouteProperties(route: RouteObject) {
let updates: Partial & { hasErrorBoundary: boolean } = {
// Note: this check also occurs in createRoutesFromChildren so update
@@ -88,7 +85,7 @@ export function mapRouteProperties(route: RouteObject) {
warning(
false,
"You should not include both `Component` and `element` on your route - " +
- "`Component` will be used."
+ "`Component` will be used.",
);
}
}
@@ -104,7 +101,7 @@ export function mapRouteProperties(route: RouteObject) {
warning(
false,
"You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - " +
- "`HydrateFallback` will be used."
+ "`HydrateFallback` will be used.",
);
}
}
@@ -120,7 +117,7 @@ export function mapRouteProperties(route: RouteObject) {
warning(
false,
"You should not include both `ErrorBoundary` and `errorElement` on your route - " +
- "`ErrorBoundary` will be used."
+ "`ErrorBoundary` will be used.",
);
}
}
@@ -138,13 +135,17 @@ export const hydrationRouteProperties: (keyof RouteObject)[] = [
"hydrateFallbackElement",
];
+/**
+ * @category Data Routers
+ */
export interface MemoryRouterOpts {
/**
* Basename path for the application.
*/
basename?: string;
/**
- * Function to provide the initial context values for all client side navigations/fetches
+ * Function to provide the initial context values for all client side
+ * navigations/fetches
*/
unstable_getContext?: RouterInit["unstable_getContext"];
/**
@@ -157,11 +158,11 @@ export interface MemoryRouterOpts {
*/
hydrationData?: HydrationState;
/**
- * Initial entires in the in-memory history stack
+ * Initial entries in the in-memory history stack
*/
initialEntries?: InitialEntry[];
/**
- * Index of `initialEntries` the application should initialize to
+ * Index of {@link initialEntries} the application should initialize to
*/
initialIndex?: number;
/**
@@ -176,20 +177,28 @@ export interface MemoryRouterOpts {
}
/**
- * Create a new data router that manages the application path using an in-memory
- * history stack. Useful for non-browser environments without a DOM API.
+ * Create a new {@link DataRouter} that manages the application path using an
+ * in-memory [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
+ * stack. Useful for non-browser environments without a DOM API.
*
+ * @public
* @category Data Routers
+ * @mode data
+ * @param routes Application routes
+ * @param opts Options
+ * @param {MemoryRouterOpts.basename} opts.basename n/a
+ * @param {MemoryRouterOpts.dataStrategy} opts.dataStrategy n/a
+ * @param {MemoryRouterOpts.future} opts.future n/a
+ * @param {MemoryRouterOpts.unstable_getContext} opts.unstable_getContext n/a
+ * @param {MemoryRouterOpts.hydrationData} opts.hydrationData n/a
+ * @param {MemoryRouterOpts.initialEntries} opts.initialEntries n/a
+ * @param {MemoryRouterOpts.initialIndex} opts.initialIndex n/a
+ * @param {MemoryRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
+ * @returns An initialized {@link DataRouter} to pass to {@link RouterProvider | ``}
*/
export function createMemoryRouter(
- /**
- * Application routes
- */
routes: RouteObject[],
- /**
- * Router options
- */
- opts?: MemoryRouterOpts
+ opts?: MemoryRouterOpts,
): DataRouter {
return createRouter({
basename: opts?.basename,
@@ -233,14 +242,47 @@ class Deferred {
}
}
-// Copied from react-dom types
+/**
+ * @category Types
+ */
export interface RouterProviderProps {
+ /**
+ * The {@link DataRouter} instance to use for navigation and data fetching.
+ */
router: DataRouter;
+ /**
+ * The [`ReactDOM.flushSync`](https://react.dev/reference/react-dom/flushSync)
+ * implementation to use for flushing updates.
+ *
+ * You usually don't have to worry about this:
+ * - The `RouterProvider` exported from `react-router/dom` handles this internally for you
+ * - If you are rendering in a non-DOM environment, you can import
+ * `RouterProvider` from `react-router` and ignore this prop
+ */
flushSync?: (fn: () => unknown) => undefined;
}
/**
- * Given a Remix Router instance, render the appropriate UI
+ * Render the UI for the given {@link DataRouter}. This component should
+ * typically be at the top of an app's element tree.
+ *
+ * @example
+ * import { createBrowserRouter } from "react-router";
+ * import { RouterProvider } from "react-router/dom";
+ * import { createRoot } from "react-dom/client";
+ *
+ * const router = createBrowserRouter(routes);
+ * createRoot(document.getElementById("root")).render(
+ *
+ * );
+ *
+ * @public
+ * @category Data Routers
+ * @mode data
+ * @param props Props
+ * @param {RouterProviderProps.flushSync} props.flushSync n/a
+ * @param {RouterProviderProps.router} props.router n/a
+ * @returns React element for the rendered router
*/
export function RouterProvider({
router,
@@ -263,7 +305,7 @@ export function RouterProvider({
let setState = React.useCallback(
(
newState: RouterState,
- { deletedFetchers, flushSync, viewTransitionOpts }
+ { deletedFetchers, flushSync, viewTransitionOpts },
) => {
newState.fetchers.forEach((fetcher, key) => {
if (fetcher.data !== undefined) {
@@ -279,7 +321,7 @@ export function RouterProvider({
"so `ReactDOM.flushSync()` is unavailable. Please update your app " +
'to `import { RouterProvider } from "react-router/dom"` and ensure ' +
"you have `react-dom` installed as a dependency to use the " +
- "`flushSync` option."
+ "`flushSync` option.",
);
let isViewTransitionAvailable =
@@ -291,7 +333,7 @@ export function RouterProvider({
viewTransitionOpts == null || isViewTransitionAvailable,
"You provided the `viewTransition` option to a router update, " +
"but you do not appear to be running in a DOM environment as " +
- "`window.startViewTransition` is not available."
+ "`window.startViewTransition` is not available.",
);
// If this isn't a view transition or it's not available in this browser,
@@ -363,7 +405,7 @@ export function RouterProvider({
});
}
},
- [router.window, reactDomFlushSyncImpl, transition, renderDfd]
+ [router.window, reactDomFlushSyncImpl, transition, renderDfd],
);
// Need to use a layout effect here so we are subscribed early enough to
@@ -454,7 +496,7 @@ export function RouterProvider({
static: false,
basename,
}),
- [router, navigator, basename]
+ [router, navigator, basename],
);
// The fragment and {null} here are important! We need them to keep React 18's
@@ -509,16 +551,36 @@ function DataRoutes({
* @category Types
*/
export interface MemoryRouterProps {
+ /**
+ * Application basename
+ */
basename?: string;
+ /**
+ * Nested {@link Route} elements describing the route tree
+ */
children?: React.ReactNode;
+ /**
+ * Initial entries in the in-memory history stack
+ */
initialEntries?: InitialEntry[];
+ /**
+ * Index of {@link initialEntries} the application should initialize to
+ */
initialIndex?: number;
}
/**
- * A `` that stores all entries in memory.
+ * A declarative {@link Router | ``} that stores all entries in memory.
*
- * @category Component Routers
+ * @public
+ * @category Declarative Routers
+ * @mode declarative
+ * @param props Props
+ * @param {MemoryRouterProps.basename} props.basename n/a
+ * @param {MemoryRouterProps.children} props.children n/a
+ * @param {MemoryRouterProps.initialEntries} props.initialEntries n/a
+ * @param {MemoryRouterProps.initialIndex} props.initialIndex n/a
+ * @returns A declarative in memory router for client side routing.
*/
export function MemoryRouter({
basename,
@@ -544,7 +606,7 @@ export function MemoryRouter({
(newState: { action: NavigationType; location: Location }) => {
React.startTransition(() => setStateImpl(newState));
},
- [setStateImpl]
+ [setStateImpl],
);
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
@@ -564,20 +626,45 @@ export function MemoryRouter({
* @category Types
*/
export interface NavigateProps {
+ /**
+ * The path to navigate to. This can be a string or a {@link Path} object
+ */
to: To;
+ /**
+ * Whether to replace the current entry in the [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
+ * stack
+ */
replace?: boolean;
+ /**
+ * State to pass to the new {@link Location} to store in [`history.state`](https://developer.mozilla.org/en-US/docs/Web/API/History/state).
+ */
state?: any;
+ /**
+ * How to interpret relative routing in the {@link to} prop.
+ * See {@link RelativeRoutingType}.
+ */
relative?: RelativeRoutingType;
}
/**
- * A component-based version of {@link useNavigate} to use in a [`React.Component
- * Class`](https://reactjs.org/docs/react-component.html) where hooks are not
- * able to be used.
+ * A component-based version of {@link useNavigate} to use in a
+ * [`React.Component` class](https://react.dev/reference/react/Component) where
+ * hooks cannot be used.
+ *
+ * It's recommended to avoid using this component in favor of {@link useNavigate}.
*
- * It's recommended to avoid using this component in favor of {@link useNavigate}
+ * @example
+ *
*
+ * @public
* @category Components
+ * @param props Props
+ * @param {NavigateProps.relative} props.relative n/a
+ * @param {NavigateProps.replace} props.replace n/a
+ * @param {NavigateProps.state} props.state n/a
+ * @param {NavigateProps.to} props.to n/a
+ * @returns {void}
+ *
*/
export function Navigate({
to,
@@ -589,7 +676,7 @@ export function Navigate({
useInRouterContext(),
// TODO: This error is probably because they somehow have 2 versions of
// the router loaded. We can help them understand how to avoid that.
- ` may be used only in the context of a component.`
+ ` may be used only in the context of a component.`,
);
let { static: isStatic } = React.useContext(NavigationContext);
@@ -598,7 +685,7 @@ export function Navigate({
!isStatic,
` must not be used on the initial render in a . ` +
`This is a no-op, but you should modify your code so the is ` +
- `only ever rendered in response to some user interaction or state change.`
+ `only ever rendered in response to some user interaction or state change.`,
);
let { matches } = React.useContext(RouteContext);
@@ -611,7 +698,7 @@ export function Navigate({
to,
getResolveToMatches(matches),
locationPathname,
- relative === "path"
+ relative === "path",
);
let jsonPath = JSON.stringify(path);
@@ -627,34 +714,39 @@ export function Navigate({
*/
export interface OutletProps {
/**
- Provides a context value to the element tree below the outlet. Use when the parent route needs to provide values to child routes.
-
- ```tsx
-
- ```
-
- Access the context with {@link useOutletContext}.
+ * Provides a context value to the element tree below the outlet. Use when
+ * the parent route needs to provide values to child routes.
+ *
+ * ```tsx
+ *
+ * ```
+ *
+ * Access the context with {@link useOutletContext}.
*/
context?: unknown;
}
/**
- Renders the matching child route of a parent route or nothing if no child route matches.
-
- ```tsx
- import { Outlet } from "react-router"
-
- export default function SomeParent() {
- return (
-
-
Parent Content
-
-
- );
- }
- ```
-
- @category Components
+ * Renders the matching child route of a parent route or nothing if no child
+ * route matches.
+ *
+ * @example
+ * import { Outlet } from "react-router";
+ *
+ * export default function SomeParent() {
+ * return (
+ *
+ *
Parent Content
+ *
+ *
+ * );
+ * }
+ *
+ * @public
+ * @category Components
+ * @param props Props
+ * @param {OutletProps.context} props.context n/a
+ * @returns React element for the rendered outlet or `null` if no child route matches.
*/
export function Outlet(props: OutletProps): React.ReactElement | null {
return useOutlet(props.context);
@@ -664,22 +756,82 @@ export function Outlet(props: OutletProps): React.ReactElement | null {
* @category Types
*/
export interface PathRouteProps {
+ /**
+ * Whether the path should be case-sensitive. Defaults to `false`.
+ */
caseSensitive?: NonIndexRouteObject["caseSensitive"];
+ /**
+ * The path pattern to match. If unspecified or empty, then this becomes a
+ * layout route.
+ */
path?: NonIndexRouteObject["path"];
+ /**
+ * The unique identifier for this route (for use with {@link DataRouter}s)
+ */
id?: NonIndexRouteObject["id"];
+ /**
+ * A function that returns a promise that resolves to the route object.
+ * Used for code-splitting routes.
+ * See [`lazy`](../../start/data/route-object#lazy).
+ */
lazy?: LazyRouteFunction;
+ /**
+ * The route loader.
+ * See [`loader`](../../start/data/route-object#loader).
+ */
loader?: NonIndexRouteObject["loader"];
+ /**
+ * The route action.
+ * See [`action`](../../start/data/route-object#action).
+ */
action?: NonIndexRouteObject["action"];
hasErrorBoundary?: NonIndexRouteObject["hasErrorBoundary"];
+ /**
+ * The route shouldRevalidate function.
+ * See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
+ */
shouldRevalidate?: NonIndexRouteObject["shouldRevalidate"];
+ /**
+ * The route handle.
+ */
handle?: NonIndexRouteObject["handle"];
+ /**
+ * Whether this is an index route.
+ */
index?: false;
+ /**
+ * Child Route components
+ */
children?: React.ReactNode;
+ /**
+ * The React element to render when this Route matches.
+ * Mutually exclusive with {@link Component}.
+ */
element?: React.ReactNode | null;
+ /**
+ * The React element to render while this router is loading data.
+ * Mutually exclusive with {@link HydrateFallback}.
+ */
hydrateFallbackElement?: React.ReactNode | null;
+ /**
+ * The React element to render at this route if an error occurs.
+ * Mutually exclusive with {@link ErrorBoundary}.
+ */
errorElement?: React.ReactNode | null;
+ /**
+ * The React Component to render when this route matches.
+ * Mutually exclusive with {@link element}.
+ */
Component?: React.ComponentType | null;
+ /**
+ * The React Component to render while this router is loading data.
+ * Mutually exclusive with {@link hydrateFallbackElement}.
+ */
HydrateFallback?: React.ComponentType | null;
+ /**
+ * The React Component to render at this route if an error occurs.
+ * Mutually exclusive with {@link errorElement}.
+ */
ErrorBoundary?: React.ComponentType | null;
}
@@ -692,22 +844,82 @@ export interface LayoutRouteProps extends PathRouteProps {}
* @category Types
*/
export interface IndexRouteProps {
+ /**
+ * Whether the path should be case-sensitive. Defaults to `false`.
+ */
caseSensitive?: IndexRouteObject["caseSensitive"];
+ /**
+ * The path pattern to match. If unspecified or empty, then this becomes a
+ * layout route.
+ */
path?: IndexRouteObject["path"];
+ /**
+ * The unique identifier for this route (for use with {@link DataRouter}s)
+ */
id?: IndexRouteObject["id"];
+ /**
+ * A function that returns a promise that resolves to the route object.
+ * Used for code-splitting routes.
+ * See [`lazy`](../../start/data/route-object#lazy).
+ */
lazy?: LazyRouteFunction;
+ /**
+ * The route loader.
+ * See [`loader`](../../start/data/route-object#loader).
+ */
loader?: IndexRouteObject["loader"];
+ /**
+ * The route action.
+ * See [`action`](../../start/data/route-object#action).
+ */
action?: IndexRouteObject["action"];
hasErrorBoundary?: IndexRouteObject["hasErrorBoundary"];
+ /**
+ * The route shouldRevalidate function.
+ * See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
+ */
shouldRevalidate?: IndexRouteObject["shouldRevalidate"];
+ /**
+ * The route handle.
+ */
handle?: IndexRouteObject["handle"];
+ /**
+ * Whether this is an index route.
+ */
index: true;
+ /**
+ * Child Route components
+ */
children?: undefined;
+ /**
+ * The React element to render when this Route matches.
+ * Mutually exclusive with {@link Component}.
+ */
element?: React.ReactNode | null;
+ /**
+ * The React element to render while this router is loading data.
+ * Mutually exclusive with {@link HydrateFallback}.
+ */
hydrateFallbackElement?: React.ReactNode | null;
+ /**
+ * The React element to render at this route if an error occurs.
+ * Mutually exclusive with {@link ErrorBoundary}.
+ */
errorElement?: React.ReactNode | null;
+ /**
+ * The React Component to render when this route matches.
+ * Mutually exclusive with {@link element}.
+ */
Component?: React.ComponentType | null;
+ /**
+ * The React Component to render while this router is loading data.
+ * Mutually exclusive with {@link hydrateFallbackElement}.
+ */
HydrateFallback?: React.ComponentType | null;
+ /**
+ * The React Component to render at this route if an error occurs.
+ * Mutually exclusive with {@link errorElement}.
+ */
ErrorBoundary?: React.ComponentType | null;
}
@@ -719,13 +931,61 @@ export type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps;
* do not participate in data loading, actions, code splitting, or any other
* route module features.
*
+ * @example
+ * // Usually used in a declarative router
+ * function App() {
+ * return (
+ *
+ *
+ * } />
+ * } />
+ * } />
+ *
+ *
+ * );
+ * }
+ *
+ * // But can be used with a data router as well if you prefer the JSX notation
+ * const routes = createRoutesFromElements(
+ * <>
+ *
+ *
+ *
+ * >
+ * );
+ *
+ * const router = createBrowserRouter(routes);
+ *
+ * function App() {
+ * return ;
+ * }
+ *
+ * @public
* @category Components
+ * @param props Props
+ * @param {PathRouteProps.action} props.action n/a
+ * @param {PathRouteProps.caseSensitive} props.caseSensitive n/a
+ * @param {PathRouteProps.Component} props.Component n/a
+ * @param {PathRouteProps.children} props.children n/a
+ * @param {PathRouteProps.element} props.element n/a
+ * @param {PathRouteProps.ErrorBoundary} props.ErrorBoundary n/a
+ * @param {PathRouteProps.errorElement} props.errorElement n/a
+ * @param {PathRouteProps.handle} props.handle n/a
+ * @param {PathRouteProps.HydrateFallback} props.HydrateFallback n/a
+ * @param {PathRouteProps.hydrateFallbackElement} props.hydrateFallbackElement n/a
+ * @param {PathRouteProps.id} props.id n/a
+ * @param {PathRouteProps.index} props.index n/a
+ * @param {PathRouteProps.lazy} props.lazy n/a
+ * @param {PathRouteProps.loader} props.loader n/a
+ * @param {PathRouteProps.path} props.path n/a
+ * @param {PathRouteProps.shouldRevalidate} props.shouldRevalidate n/a
+ * @returns {void}
*/
-export function Route(_props: RouteProps): React.ReactElement | null {
+export function Route(props: RouteProps): React.ReactElement | null {
invariant(
false,
`A is only ever to be used as the child of element, ` +
- `never rendered directly. Please wrap your in a .`
+ `never rendered directly. Please wrap your in a .`,
);
}
@@ -733,11 +993,33 @@ export function Route(_props: RouteProps): React.ReactElement | null {
* @category Types
*/
export interface RouterProps {
+ /**
+ * The base path for the application. This is prepended to all locations
+ */
basename?: string;
+ /**
+ * Nested {@link Route} elements describing the route tree
+ */
children?: React.ReactNode;
+ /**
+ * The location to match against. Defaults to the current location.
+ * This can be a string or a {@link Location} object.
+ */
location: Partial | string;
+ /**
+ * The type of navigation that triggered this location change.
+ * Defaults to {@link NavigationType.Pop}.
+ */
navigationType?: NavigationType;
+ /**
+ * The navigator to use for navigation. This is usually a history object
+ * or a custom navigator that implements the {@link Navigator} interface.
+ */
navigator: Navigator;
+ /**
+ * Whether this router is static or not (used for SSR). If `true`, the router
+ * will not be reactive to location changes.
+ */
static?: boolean;
}
@@ -745,10 +1027,21 @@ export interface RouterProps {
* Provides location context for the rest of the app.
*
* Note: You usually won't render a `` directly. Instead, you'll render a
- * router that is more specific to your environment such as a ``
- * in web browsers or a `` for server rendering.
+ * router that is more specific to your environment such as a {@link BrowserRouter}
+ * in web browsers or a {@link ServerRouter} for server rendering.
*
- * @category Components
+ * @public
+ * @category Declarative Routers
+ * @mode declarative
+ * @param props Props
+ * @param {RouterProps.basename} props.basename n/a
+ * @param {RouterProps.children} props.children n/a
+ * @param {RouterProps.location} props.location n/a
+ * @param {RouterProps.navigationType} props.navigationType n/a
+ * @param {RouterProps.navigator} props.navigator n/a
+ * @param {RouterProps.static} props.static n/a
+ * @returns React element for the rendered router or `null` if the location does
+ * not match the {@link props.basename}
*/
export function Router({
basename: basenameProp = "/",
@@ -761,7 +1054,7 @@ export function Router({
invariant(
!useInRouterContext(),
`You cannot render a inside another .` +
- ` You should never have more than one in your app.`
+ ` You should never have more than one in your app.`,
);
// Preserve trailing slashes on basename, so we can let the user control
@@ -774,7 +1067,7 @@ export function Router({
static: staticProp,
future: {},
}),
- [basename, navigator, staticProp]
+ [basename, navigator, staticProp],
);
if (typeof locationProp === "string") {
@@ -812,7 +1105,7 @@ export function Router({
locationContext != null,
` is not able to match the URL ` +
`"${pathname}${search}${hash}" because it does not start with the ` +
- `basename, so the won't render anything.`
+ `basename, so the won't render anything.`,
);
if (locationContext == null) {
@@ -834,29 +1127,33 @@ export interface RoutesProps {
* Nested {@link Route} elements
*/
children?: React.ReactNode;
-
/**
- * The location to match against. Defaults to the current location.
+ * The {@link Location} to match against. Defaults to the current location.
*/
location?: Partial | string;
}
/**
- Renders a branch of {@link Route | ``} that best matches the current
- location. Note that these routes do not participate in data loading, actions,
- code splitting, or any other route module features.
-
- ```tsx
- import { Routes, Route } from "react-router"
-
-
- } />
- } />
- }>
-
- ```
-
- @category Components
+ * Renders a branch of {@link Route | ``s} that best matches the current
+ * location. Note that these routes do not participate in [data loading](../../start/framework/route-module#loader),
+ * [`action`](../../start/framework/route-module#action), code splitting, or
+ * any other [route module](../../start/framework/route-module) features.
+ *
+ * @example
+ * import { Route, Routes } from "react-router";
+ *
+ *
+ * } />
+ * } />
+ * }>
+ *
+ *
+ * @public
+ * @category Components
+ * @param props Props
+ * @param {RoutesProps.children} props.children n/a
+ * @param {RoutesProps.location} props.location n/a
+ * @returns React element for the rendered routes or `null` if no route matches
*/
export function Routes({
children,
@@ -874,147 +1171,156 @@ export interface AwaitResolveRenderFunction {
*/
export interface AwaitProps {
/**
- When using a function, the resolved value is provided as the parameter.
-
- ```tsx [2]
-
- {(resolvedReviews) => }
-
- ```
-
- When using React elements, {@link useAsyncValue} will provide the
- resolved value:
-
- ```tsx [2]
-
-
-
-
- function Reviews() {
- const resolvedReviews = useAsyncValue()
- return ...
- }
- ```
- */
+ * When using a function, the resolved value is provided as the parameter.
+ *
+ * ```tsx [2]
+ *
+ * {(resolvedReviews) => }
+ *
+ * ```
+ *
+ * When using React elements, {@link useAsyncValue} will provide the
+ * resolved value:
+ *
+ * ```tsx [2]
+ *
+ *
+ *
+ *
+ * function Reviews() {
+ * const resolvedReviews = useAsyncValue();
+ * return ...
;
+ * }
+ * ```
+ */
children: React.ReactNode | AwaitResolveRenderFunction;
/**
- The error element renders instead of the children when the promise rejects.
-
- ```tsx
- Oops}
- resolve={reviewsPromise}
- >
-
-
- ```
-
- To provide a more contextual error, you can use the {@link useAsyncError} in a
- child component
-
- ```tsx
- }
- resolve={reviewsPromise}
- >
-
-
-
- function ReviewsError() {
- const error = useAsyncError()
- return Error loading reviews: {error.message}
- }
- ```
-
- If you do not provide an errorElement, the rejected value will bubble up to
- the nearest route-level {@link NonIndexRouteObject#ErrorBoundary | ErrorBoundary} and be accessible
- via {@link useRouteError} hook.
- */
+ * The error element renders instead of the `children` when the [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
+ * rejects.
+ *
+ * ```tsx
+ * Oops}
+ * resolve={reviewsPromise}
+ * >
+ *
+ *
+ * ```
+ *
+ * To provide a more contextual error, you can use the {@link useAsyncError} in a
+ * child component
+ *
+ * ```tsx
+ * }
+ * resolve={reviewsPromise}
+ * >
+ *
+ *
+ *
+ * function ReviewsError() {
+ * const error = useAsyncError();
+ * return Error loading reviews: {error.message}
;
+ * }
+ * ```
+ *
+ * If you do not provide an `errorElement`, the rejected value will bubble up
+ * to the nearest route-level [`ErrorBoundary`](../../start/framework/route-module#errorboundary)
+ * and be accessible via the {@link useRouteError} hook.
+ */
errorElement?: React.ReactNode;
/**
- Takes a promise returned from a {@link LoaderFunction | loader} value to be resolved and rendered.
-
- ```jsx
- import { useLoaderData, Await } from "react-router"
-
- export async function loader() {
- let reviews = getReviews() // not awaited
- let book = await getBook()
- return {
- book,
- reviews, // this is a promise
- }
- }
-
- export default function Book() {
- const {
- book,
- reviews, // this is the same promise
- } = useLoaderData()
-
- return (
-
-
{book.title}
-
{book.description}
-
}>
-
-
-
-
-
- );
- }
- ```
+ * Takes a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
+ * returned from a [`loader`](../../start/framework/route-module#loader) to be
+ * resolved and rendered.
+ *
+ * ```tsx
+ * import { Await, useLoaderData } from "react-router";
+ *
+ * export async function loader() {
+ * let reviews = getReviews(); // not awaited
+ * let book = await getBook();
+ * return {
+ * book,
+ * reviews, // this is a promise
+ * };
+ * }
+ *
+ * export default function Book() {
+ * const {
+ * book,
+ * reviews, // this is the same promise
+ * } = useLoaderData();
+ *
+ * return (
+ *
+ *
{book.title}
+ *
{book.description}
+ *
}>
+ *
+ *
+ *
+ *
+ *
+ * );
+ * }
+ * ```
*/
resolve: Resolve;
}
/**
-Used to render promise values with automatic error handling.
-
-```tsx
-import { Await, useLoaderData } from "react-router";
-
-export function loader() {
- // not awaited
- const reviews = getReviews()
- // awaited (blocks the transition)
- const book = await fetch("https://redirect.github.com/api/book").then((res) => res.json())
- return { book, reviews }
-}
-
-function Book() {
- const { book, reviews } = useLoaderData();
- return (
-
-
{book.title}
-
{book.description}
-
}>
-
Could not load reviews 😬
- }
- children={(resolvedReviews) => (
-
- )}
- />
-
-
- );
-}
-```
-
-**Note:** `` expects to be rendered inside of a ``
-
-@category Components
-
-*/
+ * Used to render promise values with automatic error handling.
+ *
+ * **Note:** `` expects to be rendered inside a [``](https://react.dev/reference/react/Suspense)
+ *
+ * @example
+ * import { Await, useLoaderData } from "react-router";
+ *
+ * export async function loader() {
+ * // not awaited
+ * const reviews = getReviews();
+ * // awaited (blocks the transition)
+ * const book = await fetch("https://redirect.github.com/api/book").then((res) => res.json());
+ * return { book, reviews };
+ * }
+ *
+ * function Book() {
+ * const { book, reviews } = useLoaderData();
+ * return (
+ *
+ *
{book.title}
+ *
{book.description}
+ *
}>
+ *
Could not load reviews 😬
+ * }
+ * children={(resolvedReviews) => (
+ *
+ * )}
+ * />
+ *
+ *
+ * );
+ * }
+ *
+ * @public
+ * @category Components
+ * @mode framework
+ * @mode data
+ * @param props Props
+ * @param {AwaitProps.children} props.children n/a
+ * @param {AwaitProps.errorElement} props.errorElement n/a
+ * @param {AwaitProps.resolve} props.resolve n/a
+ * @returns React element for the rendered awaited value
+ */
export function Await({
children,
errorElement,
@@ -1059,7 +1365,7 @@ class AwaitErrorBoundary extends React.Component<
console.error(
" caught the following error during render",
error,
- errorInfo
+ errorInfo,
);
}
@@ -1089,8 +1395,8 @@ class AwaitErrorBoundary extends React.Component<
"_error" in promise
? AwaitRenderStatus.error
: "_data" in promise
- ? AwaitRenderStatus.success
- : AwaitRenderStatus.pending;
+ ? AwaitRenderStatus.success
+ : AwaitRenderStatus.pending;
} else {
// Raw (untracked) promise - track it
status = AwaitRenderStatus.pending;
@@ -1099,7 +1405,7 @@ class AwaitErrorBoundary extends React.Component<
(data: any) =>
Object.defineProperty(resolve, "_data", { get: () => data }),
(error: any) =>
- Object.defineProperty(resolve, "_error", { get: () => error })
+ Object.defineProperty(resolve, "_error", { get: () => error }),
);
}
@@ -1123,10 +1429,7 @@ class AwaitErrorBoundary extends React.Component<
}
}
-/**
- * @private
- * Indirection to leverage useAsyncValue for a render-prop API on ``
- */
+// Indirection to leverage useAsyncValue for a render-prop API on ``
function ResolveAwait({
children,
}: {
@@ -1147,10 +1450,14 @@ function ResolveAwait({
* `` to create a route config from its children.
*
* @category Utils
+ * @mode data
+ * @param children The React children to convert into a route config
+ * @param parentPath The path of the parent route, used to generate unique IDs.
+ * @returns An array of {@link RouteObject}s that can be used with a {@link DataRouter}
*/
export function createRoutesFromChildren(
children: React.ReactNode,
- parentPath: number[] = []
+ parentPath: number[] = [],
): RouteObject[] {
let routes: RouteObject[] = [];
@@ -1167,7 +1474,7 @@ export function createRoutesFromChildren(
// Transparently support React.Fragment and its children.
routes.push.apply(
routes,
- createRoutesFromChildren(element.props.children, treePath)
+ createRoutesFromChildren(element.props.children, treePath),
);
return;
}
@@ -1176,12 +1483,12 @@ export function createRoutesFromChildren(
element.type === Route,
`[${
typeof element.type === "string" ? element.type : element.type.name
- }] is not a component. All component children of must be a or `
+ }] is not a component. All component children of must be a or `,
);
invariant(
!element.props.index || !element.props.children,
- "An index route cannot have child routes."
+ "An index route cannot have child routes.",
);
let route: RouteObject = {
@@ -1209,7 +1516,7 @@ export function createRoutesFromChildren(
if (element.props.children) {
route.children = createRoutesFromChildren(
element.props.children,
- treePath
+ treePath,
);
}
@@ -1220,17 +1527,45 @@ export function createRoutesFromChildren(
}
/**
- * Create route objects from JSX elements instead of arrays of objects
+ * Create route objects from JSX elements instead of arrays of objects.
+ *
+ * @example
+ * const routes = createRoutesFromElements(
+ * <>
+ *
+ *
+ *
+ * >
+ * );
+ *
+ * const router = createBrowserRouter(routes);
+ *
+ * function App() {
+ * return ;
+ * }
+ *
+ * @name createRoutesFromElements
+ * @public
+ * @category Utils
+ * @mode data
+ * @param children The React children to convert into a route config
+ * @param parentPath The path of the parent route, used to generate unique IDs.
+ * This is used for internal recursion and is not intended to be used by the
+ * application developer.
+ * @returns An array of {@link RouteObject}s that can be used with a {@link DataRouter}
*/
-export let createRoutesFromElements = createRoutesFromChildren;
+export const createRoutesFromElements = createRoutesFromChildren;
/**
- * Renders the result of `matchRoutes()` into a React element.
+ * Renders the result of {@link matchRoutes} into a React element.
*
+ * @public
* @category Utils
+ * @param matches The array of {@link RouteMatch | route matches} to render
+ * @returns A React element that renders the matched routes or `null` if no matches
*/
export function renderMatches(
- matches: RouteMatch[] | null
+ matches: RouteMatch[] | null,
): React.ReactElement | null {
return _renderMatches(matches);
}
diff --git a/packages/react-router/lib/context.ts b/packages/react-router/lib/context.ts
index 9ff5c96891..21b9c380a4 100644
--- a/packages/react-router/lib/context.ts
+++ b/packages/react-router/lib/context.ts
@@ -73,7 +73,7 @@ export type DataRouteObject = RouteObject & {
export interface RouteMatch<
ParamKey extends string = string,
- RouteObjectType extends RouteObject = RouteObject
+ RouteObjectType extends RouteObject = RouteObject,
> extends AgnosticRouteMatch {}
export interface DataRouteMatch extends RouteMatch {}
@@ -128,7 +128,7 @@ ViewTransitionContext.displayName = "ViewTransition";
export type FetchersContextObject = Map;
export const FetchersContext = React.createContext(
- new Map()
+ new Map(),
);
FetchersContext.displayName = "Fetchers";
@@ -178,7 +178,7 @@ interface NavigationContextObject {
}
export const NavigationContext = React.createContext(
- null!
+ null!,
);
NavigationContext.displayName = "Navigation";
@@ -188,7 +188,7 @@ interface LocationContextObject {
}
export const LocationContext = React.createContext(
- null!
+ null!,
);
LocationContext.displayName = "Location";
diff --git a/packages/react-router/lib/dom-export/hydrated-router.tsx b/packages/react-router/lib/dom-export/hydrated-router.tsx
index 949af934b2..10215fab4a 100644
--- a/packages/react-router/lib/dom-export/hydrated-router.tsx
+++ b/packages/react-router/lib/dom-export/hydrated-router.tsx
@@ -56,7 +56,7 @@ function initSsrInfo(): void {
if (importMap?.textContent) {
try {
window.__reactRouterManifest.sri = JSON.parse(
- importMap.textContent
+ importMap.textContent,
).integrity;
} catch (err) {
console.error("Failed to parse import map", err);
@@ -85,7 +85,7 @@ function createHydratedRouter({
if (!ssrInfo) {
throw new Error(
"You must be using the SSR features of React Router in order to skip " +
- "passing a `router` prop to ``"
+ "passing a `router` prop to ``",
);
}
@@ -122,7 +122,7 @@ function createHydratedRouter({
ssrInfo.routeModules,
ssrInfo.context.state,
ssrInfo.context.ssr,
- ssrInfo.context.isSpaMode
+ ssrInfo.context.isSpaMode,
);
let hydrationData: HydrationState | undefined = undefined;
@@ -152,7 +152,7 @@ function createHydratedRouter({
}),
window.location,
window.__reactRouterContext?.basename,
- ssrInfo.context.isSpaMode
+ ssrInfo.context.isSpaMode,
);
if (hydrationData && hydrationData.errors) {
@@ -180,7 +180,7 @@ function createHydratedRouter({
ssrInfo.manifest,
ssrInfo.routeModules,
ssrInfo.context.ssr,
- ssrInfo.context.basename
+ ssrInfo.context.basename,
),
patchRoutesOnNavigation: getPatchRoutesOnNavigationFunction(
ssrInfo.manifest,
@@ -188,7 +188,7 @@ function createHydratedRouter({
ssrInfo.context.ssr,
ssrInfo.context.routeDiscovery,
ssrInfo.context.isSpaMode,
- ssrInfo.context.basename
+ ssrInfo.context.basename,
),
});
ssrInfo.router = router;
@@ -218,10 +218,17 @@ interface HydratedRouterProps {
}
/**
- * Framework-mode router component to be used in `entry.client.tsx` to hydrate a
- * router from a `ServerRouter`
+ * Framework-mode router component to be used to to hydrate a router from a
+ * `ServerRouter`. See [`entry.client.tsx`](../api/framework-conventions/entry.client.tsx).
*
- * @category Component Routers
+ * @public
+ * @category Framework Routers
+ * @mode framework
+ * @param props Props
+ * @param props.unstable_getContext Context object to passed through to
+ * {@link createBrowserRouter} and made available to `clientLoader`/`clientAction`
+ * functions
+ * @returns A React element that represents the hydrated application.
*/
export function HydratedRouter(props: HydratedRouterProps) {
if (!router) {
@@ -236,7 +243,7 @@ export function HydratedRouter(props: HydratedRouterProps) {
let [criticalCss, setCriticalCss] = React.useState(
process.env.NODE_ENV === "development"
? ssrInfo?.context.criticalCss
- : undefined
+ : undefined,
);
React.useEffect(() => {
if (process.env.NODE_ENV === "development") {
@@ -289,7 +296,7 @@ export function HydratedRouter(props: HydratedRouterProps) {
ssrInfo.routeModules,
ssrInfo.context.ssr,
ssrInfo.context.routeDiscovery,
- ssrInfo.context.isSpaMode
+ ssrInfo.context.isSpaMode,
);
// We need to include a wrapper RemixErrorBoundary here in case the root error
diff --git a/packages/react-router/lib/dom/dom.ts b/packages/react-router/lib/dom/dom.ts
index 24ec0a6945..82404939fb 100644
--- a/packages/react-router/lib/dom/dom.ts
+++ b/packages/react-router/lib/dom/dom.ts
@@ -33,7 +33,7 @@ function isModifiedEvent(event: LimitedMouseEvent) {
export function shouldProcessLinkClick(
event: LimitedMouseEvent,
- target?: string
+ target?: string,
) {
return (
event.button === 0 && // Ignore everything but left clicks
@@ -77,7 +77,7 @@ export type URLSearchParamsInit =
@category Utils
*/
export function createSearchParams(
- init: URLSearchParamsInit = ""
+ init: URLSearchParamsInit = "",
): URLSearchParams {
return new URLSearchParams(
typeof init === "string" ||
@@ -87,15 +87,15 @@ export function createSearchParams(
: Object.keys(init).reduce((memo, key) => {
let value = init[key];
return memo.concat(
- Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]
+ Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]],
);
- }, [] as ParamKeyValuePair[])
+ }, [] as ParamKeyValuePair[]),
);
}
export function getSearchParamsForLocation(
locationSearch: string,
- defaultSearchParams: URLSearchParams | null
+ defaultSearchParams: URLSearchParams | null,
) {
let searchParams = createSearchParams(locationSearch);
@@ -143,7 +143,7 @@ function isFormDataSubmitterSupported() {
new FormData(
document.createElement("form"),
// @ts-expect-error if FormData supports the submitter parameter, this will throw
- 0
+ 0,
);
_formDataSupportsSubmitter = false;
} catch (e) {
@@ -242,7 +242,7 @@ function getFormEncType(encType: string | null) {
warning(
false,
`"${encType}" is not a valid \`encType\` for \`