landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
This commit is contained in:
+880
@@ -0,0 +1,880 @@
|
||||
# `react-router`
|
||||
|
||||
## v6.30.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- [`@remix-run/router@1.23.3`](https://github.com/remix-run/react-router/releases/tag/@remix-run/router@1.23.3)
|
||||
|
||||
## 6.30.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.23.2`
|
||||
|
||||
## 6.30.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.23.1`
|
||||
|
||||
## 6.30.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Partially revert optimization added in `6.29.0` to reduce calls to `matchRoutes` because it surfaced other issues ([#13623](https://github.com/remix-run/react-router/pull/13623))
|
||||
- Stop logging invalid warning when `v7_relativeSplatPath` is set to false ([#13502](https://github.com/remix-run/react-router/pull/13502))
|
||||
|
||||
## 6.30.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add `fetcherKey` as a parameter to `patchRoutesOnNavigation` ([#13109](https://github.com/remix-run/react-router/pull/13109))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.23.0`
|
||||
|
||||
## 6.29.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Provide the request `signal` as a parameter to `patchRoutesOnNavigation` ([#12900](https://github.com/remix-run/react-router/pull/12900))
|
||||
|
||||
- This can be used to abort any manifest fetches if the in-flight navigation/fetcher is aborted
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Do not log v7 deprecation warnings in production builds ([#12794](https://github.com/remix-run/react-router/pull/12794))
|
||||
- Limit matchRoutes optimization to client side routers ([#12881](https://github.com/remix-run/react-router/pull/12881))
|
||||
- Optimize route matching by skipping redundant `matchRoutes` calls when possible ([#12169](https://github.com/remix-run/react-router/pull/12169))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.22.0`
|
||||
|
||||
## 6.28.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.21.1`
|
||||
|
||||
## 6.28.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow users to opt out of deprecation warnings by setting flags to false ([#12441](https://github.com/remix-run/react-router/pull/12441))
|
||||
|
||||
## 6.28.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Log deprecation warnings for v7 flags ([#11750](https://github.com/remix-run/react-router/pull/11750))
|
||||
- Add deprecation warnings to `json`/`defer` in favor of returning raw objects
|
||||
- These methods will be removed in React Router v7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Update JSDoc URLs for new website structure (add /v6/ segment) ([#12141](https://github.com/remix-run/react-router/pull/12141))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.21.0`
|
||||
|
||||
## 6.27.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Stabilize `unstable_patchRoutesOnNavigation` ([#11973](https://github.com/remix-run/react-router/pull/11973))
|
||||
- Add new `PatchRoutesOnNavigationFunctionArgs` type for convenience ([#11967](https://github.com/remix-run/react-router/pull/11967))
|
||||
- Stabilize `unstable_dataStrategy` ([#11974](https://github.com/remix-run/react-router/pull/11974))
|
||||
- Stabilize the `unstable_flushSync` option for navigations and fetchers ([#11989](https://github.com/remix-run/react-router/pull/11989))
|
||||
- Stabilize the `unstable_viewTransition` option for navigations and the corresponding `unstable_useViewTransitionState` hook ([#11989](https://github.com/remix-run/react-router/pull/11989))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix bug when submitting to the current contextual route (parent route with an index child) when an `?index` param already exists from a prior submission ([#12003](https://github.com/remix-run/react-router/pull/12003))
|
||||
|
||||
- Fix `useFormAction` bug - when removing `?index` param it would not keep other non-Remix `index` params ([#12003](https://github.com/remix-run/react-router/pull/12003))
|
||||
|
||||
- Fix types for `RouteObject` within `PatchRoutesOnNavigationFunction`'s `patch` method so it doesn't expect agnostic route objects passed to `patch` ([#11967](https://github.com/remix-run/react-router/pull/11967))
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.20.0`
|
||||
|
||||
## 6.26.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.19.2`
|
||||
|
||||
## 6.26.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Rename `unstable_patchRoutesOnMiss` to `unstable_patchRoutesOnNavigation` to match new behavior ([#11888](https://github.com/remix-run/react-router/pull/11888))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.19.1`
|
||||
|
||||
## 6.26.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add a new `replace(url, init?)` alternative to `redirect(url, init?)` that performs a `history.replaceState` instead of a `history.pushState` on client-side navigation redirects ([#11811](https://github.com/remix-run/react-router/pull/11811))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix initial hydration behavior when using `future.v7_partialHydration` along with `unstable_patchRoutesOnMiss` ([#11838](https://github.com/remix-run/react-router/pull/11838))
|
||||
- During initial hydration, `router.state.matches` will now include any partial matches so that we can render ancestor `HydrateFallback` components
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.19.0`
|
||||
|
||||
## 6.25.1
|
||||
|
||||
No significant changes to this package were made in this release. [See the repo `CHANGELOG.md`](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md) for an overview of all changes in v6.25.1.
|
||||
|
||||
## 6.25.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Stabilize `future.unstable_skipActionErrorRevalidation` as `future.v7_skipActionErrorRevalidation` ([#11769](https://github.com/remix-run/react-router/pull/11769))
|
||||
- When this flag is enabled, actions will not automatically trigger a revalidation if they return/throw a `Response` with a `4xx`/`5xx` status code
|
||||
- You may still opt-into revalidation via `shouldRevalidate`
|
||||
- This also changes `shouldRevalidate`'s `unstable_actionStatus` parameter to `actionStatus`
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix regression and properly decode paths inside `useMatch` so matches/params reflect decoded params ([#11789](https://github.com/remix-run/react-router/pull/11789))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.18.0`
|
||||
|
||||
## 6.24.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- When using `future.v7_relativeSplatPath`, properly resolve relative paths in splat routes that are children of pathless routes ([#11633](https://github.com/remix-run/react-router/pull/11633))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.17.1`
|
||||
|
||||
## 6.24.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add support for Lazy Route Discovery (a.k.a. Fog of War) ([#11626](https://github.com/remix-run/react-router/pull/11626))
|
||||
- RFC: <https://github.com/remix-run/react-router/discussions/11113>
|
||||
- `unstable_patchRoutesOnMiss` docs: <https://reactrouter.com/v6/routers/create-browser-router>
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.17.0`
|
||||
|
||||
## 6.23.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- allow undefined to be resolved with `<Await>` ([#11513](https://github.com/remix-run/react-router/pull/11513))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.16.1`
|
||||
|
||||
## 6.23.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add a new `unstable_dataStrategy` configuration option ([#11098](https://github.com/remix-run/react-router/pull/11098))
|
||||
- This option allows Data Router applications to take control over the approach for executing route loaders and actions
|
||||
- The default implementation is today's behavior, to fetch all loaders in parallel, but this option allows users to implement more advanced data flows including Remix single-fetch, middleware/context APIs, automatic loader caching, and more
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.16.0`
|
||||
|
||||
## 6.22.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.15.3`
|
||||
|
||||
## 6.22.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.15.2`
|
||||
|
||||
## 6.22.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix encoding/decoding issues with pre-encoded dynamic parameter values ([#11199](https://github.com/remix-run/react-router/pull/11199))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.15.1`
|
||||
|
||||
## 6.22.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.15.0`
|
||||
|
||||
## 6.21.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Remove leftover `unstable_` prefix from `Blocker`/`BlockerFunction` types ([#11187](https://github.com/remix-run/react-router/pull/11187))
|
||||
|
||||
## 6.21.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.14.2`
|
||||
|
||||
## 6.21.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix bug with `route.lazy` not working correctly on initial SPA load when `v7_partialHydration` is specified ([#11121](https://github.com/remix-run/react-router/pull/11121))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.14.1`
|
||||
|
||||
## 6.21.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add a new `future.v7_relativeSplatPath` flag to implement a breaking bug fix to relative routing when inside a splat route. ([#11087](https://github.com/remix-run/react-router/pull/11087))
|
||||
|
||||
This fix was originally added in [#10983](https://github.com/remix-run/react-router/issues/10983) and was later reverted in [#11078](https://github.com/remix-run/react-router/pull/11078) because it was determined that a large number of existing applications were relying on the buggy behavior (see [#11052](https://github.com/remix-run/react-router/issues/11052))
|
||||
|
||||
**The Bug**
|
||||
The buggy behavior is that without this flag, the default behavior when resolving relative paths is to _ignore_ any splat (`*`) portion of the current route path.
|
||||
|
||||
**The Background**
|
||||
This decision was originally made thinking that it would make the concept of nested different sections of your apps in `<Routes>` easier if relative routing would _replace_ the current splat:
|
||||
|
||||
```jsx
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="dashboard/*" element={<Dashboard />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
```
|
||||
|
||||
Any paths like `/dashboard`, `/dashboard/team`, `/dashboard/projects` will match the `Dashboard` route. The dashboard component itself can then render nested `<Routes>`:
|
||||
|
||||
```jsx
|
||||
function Dashboard() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Dashboard</h2>
|
||||
<nav>
|
||||
<Link to="/">Dashboard Home</Link>
|
||||
<Link to="team">Team</Link>
|
||||
<Link to="projects">Projects</Link>
|
||||
</nav>
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<DashboardHome />} />
|
||||
<Route path="team" element={<DashboardTeam />} />
|
||||
<Route path="projects" element={<DashboardProjects />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Now, all links and route paths are relative to the router above them. This makes code splitting and compartmentalizing your app really easy. You could render the `Dashboard` as its own independent app, or embed it into your large app without making any changes to it.
|
||||
|
||||
**The Problem**
|
||||
|
||||
The problem is that this concept of ignoring part of a path breaks a lot of other assumptions in React Router - namely that `"."` always means the current location pathname for that route. When we ignore the splat portion, we start getting invalid paths when using `"."`:
|
||||
|
||||
```jsx
|
||||
// If we are on URL /dashboard/team, and we want to link to /dashboard/team:
|
||||
function DashboardTeam() {
|
||||
// ❌ This is broken and results in <a href="/dashboard">
|
||||
return <Link to=".">A broken link to the Current URL</Link>;
|
||||
|
||||
// ✅ This is fixed but super unintuitive since we're already at /dashboard/team!
|
||||
return <Link to="./team">A broken link to the Current URL</Link>;
|
||||
}
|
||||
```
|
||||
|
||||
We've also introduced an issue that we can no longer move our `DashboardTeam` component around our route hierarchy easily - since it behaves differently if we're underneath a non-splat route, such as `/dashboard/:widget`. Now, our `"."` links will, properly point to ourself _inclusive of the dynamic param value_ so behavior will break from it's corresponding usage in a `/dashboard/*` route.
|
||||
|
||||
Even worse, consider a nested splat route configuration:
|
||||
|
||||
```jsx
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="dashboard">
|
||||
<Route path="*" element={<Dashboard />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
```
|
||||
|
||||
Now, a `<Link to=".">` and a `<Link to="..">` inside the `Dashboard` component go to the same place! That is definitely not correct!
|
||||
|
||||
Another common issue arose in Data Routers (and Remix) where any `<Form>` should post to it's own route `action` if you the user doesn't specify a form action:
|
||||
|
||||
```jsx
|
||||
let router = createBrowserRouter({
|
||||
path: "/dashboard",
|
||||
children: [
|
||||
{
|
||||
path: "*",
|
||||
action: dashboardAction,
|
||||
Component() {
|
||||
// ❌ This form is broken! It throws a 405 error when it submits because
|
||||
// it tries to submit to /dashboard (without the splat value) and the parent
|
||||
// `/dashboard` route doesn't have an action
|
||||
return <Form method="post">...</Form>;
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
This is just a compounded issue from the above because the default location for a `Form` to submit to is itself (`"."`) - and if we ignore the splat portion, that now resolves to the parent route.
|
||||
|
||||
**The Solution**
|
||||
If you are leveraging this behavior, it's recommended to enable the future flag, move your splat to it's own route, and leverage `../` for any links to "sibling" pages:
|
||||
|
||||
```jsx
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="dashboard">
|
||||
<Route index path="*" element={<Dashboard />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
|
||||
function Dashboard() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Dashboard</h2>
|
||||
<nav>
|
||||
<Link to="..">Dashboard Home</Link>
|
||||
<Link to="../team">Team</Link>
|
||||
<Link to="../projects">Projects</Link>
|
||||
</nav>
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<DashboardHome />} />
|
||||
<Route path="team" element={<DashboardTeam />} />
|
||||
<Route path="projects" element={<DashboardProjects />} />
|
||||
</Router>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
This way, `.` means "the full current pathname for my route" in all cases (including static, dynamic, and splat routes) and `..` always means "my parents pathname".
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Properly handle falsy error values in ErrorBoundary's ([#11071](https://github.com/remix-run/react-router/pull/11071))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.14.0`
|
||||
|
||||
## 6.20.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Revert the `useResolvedPath` fix for splat routes due to a large number of applications that were relying on the buggy behavior (see <https://github.com/remix-run/react-router/issues/11052#issuecomment-1836589329>). We plan to re-introduce this fix behind a future flag in the next minor version. ([#11078](https://github.com/remix-run/react-router/pull/11078))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.13.1`
|
||||
|
||||
## 6.20.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Export the `PathParam` type from the public API ([#10719](https://github.com/remix-run/react-router/pull/10719))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix bug with `resolveTo` in splat routes ([#11045](https://github.com/remix-run/react-router/pull/11045))
|
||||
- This is a follow up to [#10983](https://github.com/remix-run/react-router/pull/10983) to handle the few other code paths using `getPathContributingMatches`
|
||||
- This removes the `UNSAFE_getPathContributingMatches` export from `@remix-run/router` since we no longer need this in the `react-router`/`react-router-dom` layers
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.13.0`
|
||||
|
||||
## 6.19.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add `unstable_flushSync` option to `useNavigate`/`useSumbit`/`fetcher.load`/`fetcher.submit` to opt-out of `React.startTransition` and into `ReactDOM.flushSync` for state updates ([#11005](https://github.com/remix-run/react-router/pull/11005))
|
||||
- Remove the `unstable_` prefix from the [`useBlocker`](https://reactrouter.com/v6/hooks/use-blocker) hook as it's been in use for enough time that we are confident in the API. We do not plan to remove the prefix from `unstable_usePrompt` due to differences in how browsers handle `window.confirm` that prevent React Router from guaranteeing consistent/correct behavior. ([#10991](https://github.com/remix-run/react-router/pull/10991))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `useActionData` so it returns proper contextual action data and not _any_ action data in the tree ([#11023](https://github.com/remix-run/react-router/pull/11023))
|
||||
|
||||
- Fix bug in `useResolvedPath` that would cause `useResolvedPath(".")` in a splat route to lose the splat portion of the URL path. ([#10983](https://github.com/remix-run/react-router/pull/10983))
|
||||
|
||||
- ⚠️ This fixes a quite long-standing bug specifically for `"."` paths inside a splat route which incorrectly dropped the splat portion of the URL. If you are relative routing via `"."` inside a splat route in your application you should double check that your logic is not relying on this buggy behavior and update accordingly.
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.12.0`
|
||||
|
||||
## 6.18.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix the `future` prop on `BrowserRouter`, `HashRouter` and `MemoryRouter` so that it accepts a `Partial<FutureConfig>` instead of requiring all flags to be included. ([#10962](https://github.com/remix-run/react-router/pull/10962))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.11.0`
|
||||
|
||||
## 6.17.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `RouterProvider` `future` prop type to be a `Partial<FutureConfig>` so that not all flags must be specified ([#10900](https://github.com/remix-run/react-router/pull/10900))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.10.0`
|
||||
|
||||
## 6.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- In order to move towards stricter TypeScript support in the future, we're aiming to replace current usages of `any` with `unknown` on exposed typings for user-provided data. To do this in Remix v2 without introducing breaking changes in React Router v6, we have added generics to a number of shared types. These continue to default to `any` in React Router and are overridden with `unknown` in Remix. In React Router v7 we plan to move these to `unknown` as a breaking change. ([#10843](https://github.com/remix-run/react-router/pull/10843))
|
||||
- `Location` now accepts a generic for the `location.state` value
|
||||
- `ActionFunctionArgs`/`ActionFunction`/`LoaderFunctionArgs`/`LoaderFunction` now accept a generic for the `context` parameter (only used in SSR usages via `createStaticHandler`)
|
||||
- The return type of `useMatches` (now exported as `UIMatch`) accepts generics for `match.data` and `match.handle` - both of which were already set to `unknown`
|
||||
- Move the `@private` class export `ErrorResponse` to an `UNSAFE_ErrorResponseImpl` export since it is an implementation detail and there should be no construction of `ErrorResponse` instances in userland. This frees us up to export a `type ErrorResponse` which correlates to an instance of the class via `InstanceType`. Userland code should only ever be using `ErrorResponse` as a type and should be type-narrowing via `isRouteErrorResponse`. ([#10811](https://github.com/remix-run/react-router/pull/10811))
|
||||
- Export `ShouldRevalidateFunctionArgs` interface ([#10797](https://github.com/remix-run/react-router/pull/10797))
|
||||
- Removed private/internal APIs only required for the Remix v1 backwards compatibility layer and no longer needed in Remix v2 (`_isFetchActionRedirect`, `_hasFetcherDoneAnything`) ([#10715](https://github.com/remix-run/react-router/pull/10715))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.9.0`
|
||||
|
||||
## 6.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add's a new `redirectDocument()` function which allows users to specify that a redirect from a `loader`/`action` should trigger a document reload (via `window.location`) instead of attempting to navigate to the redirected location via React Router ([#10705](https://github.com/remix-run/react-router/pull/10705))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Ensure `useRevalidator` is referentially stable across re-renders if revalidations are not actively occurring ([#10707](https://github.com/remix-run/react-router/pull/10707))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.8.0`
|
||||
|
||||
## 6.14.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.7.2`
|
||||
|
||||
## 6.14.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix loop in `unstable_useBlocker` when used with an unstable blocker function ([#10652](https://github.com/remix-run/react-router/pull/10652))
|
||||
- Fix issues with reused blockers on subsequent navigations ([#10656](https://github.com/remix-run/react-router/pull/10656))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.7.1`
|
||||
|
||||
## 6.14.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Strip `basename` from locations provided to `unstable_useBlocker` functions to match `useLocation` ([#10573](https://github.com/remix-run/react-router/pull/10573))
|
||||
- Fix `generatePath` when passed a numeric `0` value parameter ([#10612](https://github.com/remix-run/react-router/pull/10612))
|
||||
- Fix `unstable_useBlocker` key issues in `StrictMode` ([#10573](https://github.com/remix-run/react-router/pull/10573))
|
||||
- Fix `tsc --skipLibCheck:false` issues on React 17 ([#10622](https://github.com/remix-run/react-router/pull/10622))
|
||||
- Upgrade `typescript` to 5.1 ([#10581](https://github.com/remix-run/react-router/pull/10581))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.7.0`
|
||||
|
||||
## 6.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Move [`React.startTransition`](https://react.dev/reference/react/startTransition) usage behind a [future flag](https://reactrouter.com/v6/guides/api-development-strategy) to avoid issues with existing incompatible `Suspense` usages. We recommend folks adopting this flag to be better compatible with React concurrent mode, but if you run into issues you can continue without the use of `startTransition` until v7. Issues usually boils down to creating net-new promises during the render cycle, so if you run into issues you should either lift your promise creation out of the render cycle or put it behind a `useMemo`. ([#10596](https://github.com/remix-run/react-router/pull/10596))
|
||||
|
||||
Existing behavior will no longer include `React.startTransition`:
|
||||
|
||||
```jsx
|
||||
<BrowserRouter>
|
||||
<Routes>{/*...*/}</Routes>
|
||||
</BrowserRouter>
|
||||
|
||||
<RouterProvider router={router} />
|
||||
```
|
||||
|
||||
If you wish to enable `React.startTransition`, pass the future flag to your component:
|
||||
|
||||
```jsx
|
||||
<BrowserRouter future={{ v7_startTransition: true }}>
|
||||
<Routes>{/*...*/}</Routes>
|
||||
</BrowserRouter>
|
||||
|
||||
<RouterProvider router={router} future={{ v7_startTransition: true }}/>
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Work around webpack/terser `React.startTransition` minification bug in production mode ([#10588](https://github.com/remix-run/react-router/pull/10588))
|
||||
|
||||
## 6.12.1
|
||||
|
||||
> \[!WARNING]
|
||||
> Please use version `6.13.0` or later instead of `6.12.1`. This version suffers from a `webpack`/`terser` minification issue resulting in invalid minified code in your resulting production bundles which can cause issues in your application. See [#10579](https://github.com/remix-run/react-router/issues/10579) for more details.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Adjust feature detection of `React.startTransition` to fix webpack + react 17 compilation error ([#10569](https://github.com/remix-run/react-router/pull/10569))
|
||||
|
||||
## 6.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Wrap internal router state updates with `React.startTransition` if it exists ([#10438](https://github.com/remix-run/react-router/pull/10438))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.6.3`
|
||||
|
||||
## 6.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `basename` duplication in descendant `<Routes>` inside a `<RouterProvider>` ([#10492](https://github.com/remix-run/react-router/pull/10492))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.6.2`
|
||||
|
||||
## 6.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix usage of `Component` API within descendant `<Routes>` ([#10434](https://github.com/remix-run/react-router/pull/10434))
|
||||
- Fix bug when calling `useNavigate` from `<Routes>` inside a `<RouterProvider>` ([#10432](https://github.com/remix-run/react-router/pull/10432))
|
||||
- Fix usage of `<Navigate>` in strict mode when using a data router ([#10435](https://github.com/remix-run/react-router/pull/10435))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.6.1`
|
||||
|
||||
## 6.11.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Log loader/action errors to the console in dev for easier stack trace evaluation ([#10286](https://github.com/remix-run/react-router/pull/10286))
|
||||
- Fix bug preventing rendering of descendant `<Routes>` when `RouterProvider` errors existed ([#10374](https://github.com/remix-run/react-router/pull/10374))
|
||||
- Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287))
|
||||
- Fix detection of `useNavigate` in the render cycle by setting the `activeRef` in a layout effect, allowing the `navigate` function to be passed to child components and called in a `useEffect` there. ([#10394](https://github.com/remix-run/react-router/pull/10394))
|
||||
- Switched from `useSyncExternalStore` to `useState` for internal `@remix-run/router` router state syncing in `<RouterProvider>`. We found some [subtle bugs](https://codesandbox.io/s/use-sync-external-store-loop-9g7b81) where router state updates got propagated _before_ other normal `useState` updates, which could lead to footguns in `useEffect` calls. ([#10377](https://github.com/remix-run/react-router/pull/10377), [#10409](https://github.com/remix-run/react-router/pull/10409))
|
||||
- Allow `useRevalidator()` to resolve a loader-driven error boundary scenario ([#10369](https://github.com/remix-run/react-router/pull/10369))
|
||||
- Avoid unnecessary unsubscribe/resubscribes on router state changes ([#10409](https://github.com/remix-run/react-router/pull/10409))
|
||||
- When using a `RouterProvider`, `useNavigate`/`useSubmit`/`fetcher.submit` are now stable across location changes, since we can handle relative routing via the `@remix-run/router` instance and get rid of our dependence on `useLocation()`. When using `BrowserRouter`, these hooks remain unstable across location changes because they still rely on `useLocation()`. ([#10336](https://github.com/remix-run/react-router/pull/10336))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.6.0`
|
||||
|
||||
## 6.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Added support for [**Future Flags**](https://reactrouter.com/v6/guides/api-development-strategy) in React Router. The first flag being introduced is `future.v7_normalizeFormMethod` which will normalize the exposed `useNavigation()/useFetcher()` `formMethod` fields as uppercase HTTP methods to align with the `fetch()` behavior. ([#10207](https://github.com/remix-run/react-router/pull/10207))
|
||||
|
||||
- When `future.v7_normalizeFormMethod === false` (default v6 behavior),
|
||||
- `useNavigation().formMethod` is lowercase
|
||||
- `useFetcher().formMethod` is lowercase
|
||||
- When `future.v7_normalizeFormMethod === true`:
|
||||
- `useNavigation().formMethod` is uppercase
|
||||
- `useFetcher().formMethod` is uppercase
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix route ID generation when using Fragments in `createRoutesFromElements` ([#10193](https://github.com/remix-run/react-router/pull/10193))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.5.0`
|
||||
|
||||
## 6.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- React Router now supports an alternative way to define your route `element` and `errorElement` fields as React Components instead of React Elements. You can instead pass a React Component to the new `Component` and `ErrorBoundary` fields if you choose. There is no functional difference between the two, so use whichever approach you prefer 😀. You shouldn't be defining both, but if you do `Component`/`ErrorBoundary` will "win". ([#10045](https://github.com/remix-run/react-router/pull/10045))
|
||||
|
||||
**Example JSON Syntax**
|
||||
|
||||
```jsx
|
||||
// Both of these work the same:
|
||||
const elementRoutes = [{
|
||||
path: '/',
|
||||
element: <Home />,
|
||||
errorElement: <HomeError />,
|
||||
}]
|
||||
|
||||
const componentRoutes = [{
|
||||
path: '/',
|
||||
Component: Home,
|
||||
ErrorBoundary: HomeError,
|
||||
}]
|
||||
|
||||
function Home() { ... }
|
||||
function HomeError() { ... }
|
||||
```
|
||||
|
||||
**Example JSX Syntax**
|
||||
|
||||
```jsx
|
||||
// Both of these work the same:
|
||||
const elementRoutes = createRoutesFromElements(
|
||||
<Route path='/' element={<Home />} errorElement={<HomeError /> } />
|
||||
);
|
||||
|
||||
const componentRoutes = createRoutesFromElements(
|
||||
<Route path='/' Component={Home} ErrorBoundary={HomeError} />
|
||||
);
|
||||
|
||||
function Home() { ... }
|
||||
function HomeError() { ... }
|
||||
```
|
||||
|
||||
- **Introducing Lazy Route Modules!** ([#10045](https://github.com/remix-run/react-router/pull/10045))
|
||||
|
||||
In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new `lazy()` route property. This is an async function that resolves the non-route-matching portions of your route definition (`loader`, `action`, `element`/`Component`, `errorElement`/`ErrorBoundary`, `shouldRevalidate`, `handle`).
|
||||
|
||||
Lazy routes are resolved on initial load and during the `loading` or `submitting` phase of a navigation or fetcher call. You cannot lazily define route-matching properties (`path`, `index`, `children`) since we only execute your lazy route functions after we've matched known routes.
|
||||
|
||||
Your `lazy` functions will typically return the result of a dynamic import.
|
||||
|
||||
```jsx
|
||||
// In this example, we assume most folks land on the homepage so we include that
|
||||
// in our critical-path bundle, but then we lazily load modules for /a and /b so
|
||||
// they don't load until the user navigates to those routes
|
||||
let routes = createRoutesFromElements(
|
||||
<Route path="/" element={<Layout />}>
|
||||
<Route index element={<Home />} />
|
||||
<Route path="a" lazy={() => import("./a")} />
|
||||
<Route path="b" lazy={() => import("./b")} />
|
||||
</Route>
|
||||
);
|
||||
```
|
||||
|
||||
Then in your lazy route modules, export the properties you want defined for the route:
|
||||
|
||||
```jsx
|
||||
export async function loader({ request }) {
|
||||
let data = await fetchData(request);
|
||||
return json(data);
|
||||
}
|
||||
|
||||
// Export a `Component` directly instead of needing to create a React Element from it
|
||||
export function Component() {
|
||||
let data = useLoaderData();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>You made it!</h1>
|
||||
<p>{data}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Export an `ErrorBoundary` directly instead of needing to create a React Element from it
|
||||
export function ErrorBoundary() {
|
||||
let error = useRouteError();
|
||||
return isRouteErrorResponse(error) ? (
|
||||
<h1>
|
||||
{error.status} {error.statusText}
|
||||
</h1>
|
||||
) : (
|
||||
<h1>{error.message || error}</h1>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
An example of this in action can be found in the [`examples/lazy-loading-router-provider`](https://github.com/remix-run/react-router/tree/main/examples/lazy-loading-router-provider) directory of the repository.
|
||||
|
||||
🙌 Huge thanks to @rossipedia for the [Initial Proposal](https://github.com/remix-run/react-router/discussions/9826) and [POC Implementation](https://github.com/remix-run/react-router/pull/9830).
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.4.0`
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `generatePath` incorrectly applying parameters in some cases ([#10078](https://github.com/remix-run/react-router/pull/10078))
|
||||
- Improve memoization for context providers to avoid unnecessary re-renders ([#9983](https://github.com/remix-run/react-router/pull/9983))
|
||||
|
||||
## 6.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.3.3`
|
||||
|
||||
## 6.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Remove inaccurate console warning for POP navigations and update active blocker logic ([#10030](https://github.com/remix-run/react-router/pull/10030))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.3.2`
|
||||
|
||||
## 6.8.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.3.1`
|
||||
|
||||
## 6.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add `unstable_useBlocker` hook for blocking navigations within the app's location origin ([#9709](https://github.com/remix-run/react-router/pull/9709))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `generatePath` when optional params are present ([#9764](https://github.com/remix-run/react-router/pull/9764))
|
||||
- Update `<Await>` to accept `ReactNode` as children function return result ([#9896](https://github.com/remix-run/react-router/pull/9896))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.3.0`
|
||||
|
||||
## 6.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Ensure `useId` consistency during SSR ([#9805](https://github.com/remix-run/react-router/pull/9805))
|
||||
|
||||
## 6.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.2.1`
|
||||
|
||||
## 6.6.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Prevent `useLoaderData` usage in `errorElement` ([#9735](https://github.com/remix-run/react-router/pull/9735))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.2.0`
|
||||
|
||||
## 6.5.0
|
||||
|
||||
This release introduces support for [Optional Route Segments](https://github.com/remix-run/react-router/issues/9546). Now, adding a `?` to the end of any path segment will make that entire segment optional. This works for both static segments and dynamic parameters.
|
||||
|
||||
**Optional Params Examples**
|
||||
|
||||
- `<Route path=":lang?/about>` will match:
|
||||
- `/:lang/about`
|
||||
- `/about`
|
||||
- `<Route path="/multistep/:widget1?/widget2?/widget3?">` will match:
|
||||
- `/multistep`
|
||||
- `/multistep/:widget1`
|
||||
- `/multistep/:widget1/:widget2`
|
||||
- `/multistep/:widget1/:widget2/:widget3`
|
||||
|
||||
**Optional Static Segment Example**
|
||||
|
||||
- `<Route path="/home?">` will match:
|
||||
- `/`
|
||||
- `/home`
|
||||
- `<Route path="/fr?/about">` will match:
|
||||
- `/about`
|
||||
- `/fr/about`
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Allows optional routes and optional static segments ([#9650](https://github.com/remix-run/react-router/pull/9650))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Stop incorrectly matching on partial named parameters, i.e. `<Route path="prefix-:param">`, to align with how splat parameters work. If you were previously relying on this behavior then it's recommended to extract the static portion of the path at the `useParams` call site: ([#9506](https://github.com/remix-run/react-router/pull/9506))
|
||||
|
||||
```jsx
|
||||
// Old behavior at URL /prefix-123
|
||||
<Route path="prefix-:id" element={<Comp /> }>
|
||||
|
||||
function Comp() {
|
||||
let params = useParams(); // { id: '123' }
|
||||
let id = params.id; // "123"
|
||||
...
|
||||
}
|
||||
|
||||
// New behavior at URL /prefix-123
|
||||
<Route path=":id" element={<Comp /> }>
|
||||
|
||||
function Comp() {
|
||||
let params = useParams(); // { id: 'prefix-123' }
|
||||
let id = params.id.replace(/^prefix-/, ''); // "123"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.1.0`
|
||||
|
||||
## 6.4.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.0.5`
|
||||
|
||||
## 6.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.0.4`
|
||||
|
||||
## 6.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- `useRoutes` should be able to return `null` when passing `locationArg` ([#9485](https://github.com/remix-run/react-router/pull/9485))
|
||||
- fix `initialEntries` type in `createMemoryRouter` ([#9498](https://github.com/remix-run/react-router/pull/9498))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.0.3`
|
||||
|
||||
## 6.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `IndexRouteObject` and `NonIndexRouteObject` types to make `hasErrorElement` optional ([#9394](https://github.com/remix-run/react-router/pull/9394))
|
||||
- Enhance console error messages for invalid usage of data router hooks ([#9311](https://github.com/remix-run/react-router/pull/9311))
|
||||
- If an index route has children, it will result in a runtime error. We have strengthened our `RouteObject`/`RouteProps` types to surface the error in TypeScript. ([#9366](https://github.com/remix-run/react-router/pull/9366))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.0.2`
|
||||
|
||||
## 6.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Preserve state from `initialEntries` ([#9288](https://github.com/remix-run/react-router/pull/9288))
|
||||
- Updated dependencies:
|
||||
- `@remix-run/router@1.0.1`
|
||||
|
||||
## 6.4.0
|
||||
|
||||
Whoa this is a big one! `6.4.0` brings all the data loading and mutation APIs over from Remix. Here's a quick high level overview, but it's recommended you go check out the [docs](https://reactrouter.com), especially the [feature overview](https://reactrouter.com/en/6.4.0/start/overview) and the [tutorial](https://reactrouter.com/en/6.4.0/start/tutorial).
|
||||
|
||||
**New APIs**
|
||||
|
||||
- Create your router with `createMemoryRouter`
|
||||
- Render your router with `<RouterProvider>`
|
||||
- Load data with a Route `loader` and mutate with a Route `action`
|
||||
- Handle errors with Route `errorElement`
|
||||
- Defer non-critical data with `defer` and `Await`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Path resolution is now trailing slash agnostic (#8861)
|
||||
- `useLocation` returns the scoped location inside a `<Routes location>` component (#9094)
|
||||
|
||||
**Updated Dependencies**
|
||||
|
||||
- `@remix-run/router@1.0.0`
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) React Training LLC 2015-2019
|
||||
Copyright (c) Remix Software Inc. 2020-2021
|
||||
Copyright (c) Shopify Inc. 2022-2023
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# React Router
|
||||
|
||||
The `react-router` package is the heart of [React Router](https://github.com/remix-run/react-router) and provides all
|
||||
the core functionality for both
|
||||
[`react-router-dom`](https://github.com/remix-run/react-router/tree/main/packages/react-router-dom)
|
||||
and
|
||||
[`react-router-native`](https://github.com/remix-run/react-router/tree/main/packages/react-router-native).
|
||||
|
||||
If you're using React Router, you should never `import` anything directly from
|
||||
the `react-router` package, but you should have everything you need in either
|
||||
`react-router-dom` or `react-router-native`. Both of those packages re-export
|
||||
everything from `react-router`.
|
||||
|
||||
If you'd like to extend React Router and you know what you're doing, you should
|
||||
add `react-router` **as a peer dependency, not a regular dependency** in your
|
||||
package.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import type { ActionFunction, ActionFunctionArgs, AgnosticPatchRoutesOnNavigationFunction, AgnosticPatchRoutesOnNavigationFunctionArgs, Blocker, BlockerFunction, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyMatch, DataStrategyResult, ErrorResponse, Fetcher, HydrationState, InitialEntry, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, Navigation, ParamParseKey, Params, Path, PathMatch, PathParam, PathPattern, RedirectFunction, RelativeRoutingType, Router as RemixRouter, FutureConfig as RouterFutureConfig, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch } from "@remix-run/router";
|
||||
import { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, resolvePath } from "@remix-run/router";
|
||||
import type { AwaitProps, FutureConfig, IndexRouteProps, LayoutRouteProps, MemoryRouterProps, NavigateProps, OutletProps, PathRouteProps, RouteProps, RouterProps, RouterProviderProps, RoutesProps } from "./lib/components";
|
||||
import { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, createRoutesFromChildren, renderMatches } from "./lib/components";
|
||||
import type { DataRouteMatch, DataRouteObject, IndexRouteObject, NavigateOptions, Navigator, NonIndexRouteObject, RouteMatch, RouteObject } from "./lib/context";
|
||||
import { DataRouterContext, DataRouterStateContext, LocationContext, NavigationContext, RouteContext } from "./lib/context";
|
||||
import type { NavigateFunction } from "./lib/hooks";
|
||||
import { useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteId, useRouteLoaderData, useRoutes, useRoutesImpl } from "./lib/hooks";
|
||||
import { logV6DeprecationWarnings } from "./lib/deprecations";
|
||||
type Hash = string;
|
||||
type Pathname = string;
|
||||
type Search = string;
|
||||
export type { ActionFunction, ActionFunctionArgs, AwaitProps, DataRouteMatch, DataRouteObject, DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyMatch, DataStrategyResult, ErrorResponse, Fetcher, FutureConfig, Hash, IndexRouteObject, IndexRouteProps, JsonFunction, LayoutRouteProps, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigation, Navigator, NonIndexRouteObject, OutletProps, ParamParseKey, Params, Path, PathMatch, PathParam, PathPattern, PathRouteProps, Pathname, RedirectFunction, RelativeRoutingType, RouteMatch, RouteObject, RouteProps, RouterProps, RouterProviderProps, RoutesProps, Search, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch, Blocker, BlockerFunction, };
|
||||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, createPath, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, renderMatches, resolvePath, useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, };
|
||||
export type PatchRoutesOnNavigationFunctionArgs = AgnosticPatchRoutesOnNavigationFunctionArgs<RouteObject, RouteMatch>;
|
||||
export type PatchRoutesOnNavigationFunction = AgnosticPatchRoutesOnNavigationFunction<RouteObject, RouteMatch>;
|
||||
declare function mapRouteProperties(route: RouteObject): Partial<RouteObject> & {
|
||||
hasErrorBoundary: boolean;
|
||||
};
|
||||
export declare function createMemoryRouter(routes: RouteObject[], opts?: {
|
||||
basename?: string;
|
||||
future?: Partial<Omit<RouterFutureConfig, "v7_prependBasename">>;
|
||||
hydrationData?: HydrationState;
|
||||
initialEntries?: InitialEntry[];
|
||||
initialIndex?: number;
|
||||
dataStrategy?: DataStrategyFunction;
|
||||
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
|
||||
}): RemixRouter;
|
||||
/** @internal */
|
||||
export { DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, mapRouteProperties as UNSAFE_mapRouteProperties, useRouteId as UNSAFE_useRouteId, useRoutesImpl as UNSAFE_useRoutesImpl, logV6DeprecationWarnings as UNSAFE_logV6DeprecationWarnings, };
|
||||
+1496
@@ -0,0 +1,1496 @@
|
||||
/**
|
||||
* React Router v6.30.4
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_decodePath, UNSAFE_getResolveToMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router';
|
||||
export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, resolvePath } from '@remix-run/router';
|
||||
|
||||
function _extends() {
|
||||
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
||||
for (var e = 1; e < arguments.length; e++) {
|
||||
var t = arguments[e];
|
||||
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
||||
}
|
||||
return n;
|
||||
}, _extends.apply(null, arguments);
|
||||
}
|
||||
|
||||
// Create react-specific types from the agnostic types in @remix-run/router to
|
||||
// export from react-router
|
||||
|
||||
const DataRouterContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
DataRouterContext.displayName = "DataRouter";
|
||||
}
|
||||
const DataRouterStateContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
DataRouterStateContext.displayName = "DataRouterState";
|
||||
}
|
||||
const AwaitContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
AwaitContext.displayName = "Await";
|
||||
}
|
||||
|
||||
/**
|
||||
* A Navigator is a "location changer"; it's how you get to different locations.
|
||||
*
|
||||
* Every history instance conforms to the Navigator interface, but the
|
||||
* distinction is useful primarily when it comes to the low-level `<Router>` API
|
||||
* where both the location and a navigator must be provided separately in order
|
||||
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
||||
* and/or location were to be read directly from the history instance.
|
||||
*/
|
||||
|
||||
const NavigationContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
NavigationContext.displayName = "Navigation";
|
||||
}
|
||||
const LocationContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
LocationContext.displayName = "Location";
|
||||
}
|
||||
const RouteContext = /*#__PURE__*/React.createContext({
|
||||
outlet: null,
|
||||
matches: [],
|
||||
isDataRoute: false
|
||||
});
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
RouteContext.displayName = "Route";
|
||||
}
|
||||
const RouteErrorContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
RouteErrorContext.displayName = "RouteError";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full href for the given "to" value. This is useful for building
|
||||
* custom links that are also accessible and preserve right-click behavior.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-href
|
||||
*/
|
||||
function useHref(to, _temp) {
|
||||
let {
|
||||
relative
|
||||
} = _temp === void 0 ? {} : _temp;
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useHref() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
let {
|
||||
basename,
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
hash,
|
||||
pathname,
|
||||
search
|
||||
} = useResolvedPath(to, {
|
||||
relative
|
||||
});
|
||||
let joinedPathname = pathname;
|
||||
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to creating the href. If this is a root navigation, then just use the raw
|
||||
// basename which allows the basename to have full control over the presence
|
||||
// of a trailing slash on root links
|
||||
if (basename !== "/") {
|
||||
joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
|
||||
}
|
||||
return navigator.createHref({
|
||||
pathname: joinedPathname,
|
||||
search,
|
||||
hash
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this component is a descendant of a `<Router>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-in-router-context
|
||||
*/
|
||||
function useInRouterContext() {
|
||||
return React.useContext(LocationContext) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current location object, which represents the current URL in web
|
||||
* browsers.
|
||||
*
|
||||
* Note: If you're using this it may mean you're doing some of your own
|
||||
* "routing" in your app, and we'd like to know what your use case is. We may
|
||||
* be able to provide something higher-level to better suit your needs.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-location
|
||||
*/
|
||||
function useLocation() {
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useLocation() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
return React.useContext(LocationContext).location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current navigation action which describes how the router came to
|
||||
* the current location, either by a pop, push, or replace on the history stack.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigation-type
|
||||
*/
|
||||
function useNavigationType() {
|
||||
return React.useContext(LocationContext).navigationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PathMatch object if the given pattern matches the current URL.
|
||||
* This is useful for components that need to know "active" state, e.g.
|
||||
* `<NavLink>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-match
|
||||
*/
|
||||
function useMatch(pattern) {
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useMatch() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
let {
|
||||
pathname
|
||||
} = useLocation();
|
||||
return React.useMemo(() => matchPath(pattern, UNSAFE_decodePath(pathname)), [pathname, pattern]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for the navigate() function returned from useNavigate().
|
||||
*/
|
||||
|
||||
const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered.";
|
||||
|
||||
// Mute warnings for calls to useNavigate in SSR environments
|
||||
function useIsomorphicLayoutEffect(cb) {
|
||||
let isStatic = React.useContext(NavigationContext).static;
|
||||
if (!isStatic) {
|
||||
// We should be able to get rid of this once react 18.3 is released
|
||||
// See: https://github.com/facebook/react/pull/26395
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
React.useLayoutEffect(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an imperative method for changing the location. Used by `<Link>`s, but
|
||||
* may also be used by other elements to change the location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigate
|
||||
*/
|
||||
function useNavigate() {
|
||||
let {
|
||||
isDataRoute
|
||||
} = React.useContext(RouteContext);
|
||||
// Conditional usage is OK here because the usage of a data router is static
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
return isDataRoute ? useNavigateStable() : useNavigateUnstable();
|
||||
}
|
||||
function useNavigateUnstable() {
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useNavigate() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
let dataRouterContext = React.useContext(DataRouterContext);
|
||||
let {
|
||||
basename,
|
||||
future,
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
let activeRef = React.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React.useCallback(function (to, options) {
|
||||
if (options === void 0) {
|
||||
options = {};
|
||||
}
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0;
|
||||
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our history listener yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
navigator.go(to);
|
||||
return;
|
||||
}
|
||||
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
|
||||
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to handing off to history (but only if we're not in a data router,
|
||||
// otherwise it'll prepend the basename inside of the router).
|
||||
// If this is a root navigation, then we navigate to the raw basename
|
||||
// which allows the basename to have full control over the presence of a
|
||||
// trailing slash on root links
|
||||
if (dataRouterContext == null && basename !== "/") {
|
||||
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
||||
}
|
||||
(!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
|
||||
}, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]);
|
||||
return navigate;
|
||||
}
|
||||
const OutletContext = /*#__PURE__*/React.createContext(null);
|
||||
|
||||
/**
|
||||
* Returns the context (if provided) for the child route at this level of the route
|
||||
* hierarchy.
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet-context
|
||||
*/
|
||||
function useOutletContext() {
|
||||
return React.useContext(OutletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element for the child route at this level of the route
|
||||
* hierarchy. Used internally by `<Outlet>` to render child routes.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet
|
||||
*/
|
||||
function useOutlet(context) {
|
||||
let outlet = React.useContext(RouteContext).outlet;
|
||||
if (outlet) {
|
||||
return /*#__PURE__*/React.createElement(OutletContext.Provider, {
|
||||
value: context
|
||||
}, outlet);
|
||||
}
|
||||
return outlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object of key/value pairs of the dynamic params from the current
|
||||
* URL that were matched by the route path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-params
|
||||
*/
|
||||
function useParams() {
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let routeMatch = matches[matches.length - 1];
|
||||
return routeMatch ? routeMatch.params : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the pathname of the given `to` value against the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-resolved-path
|
||||
*/
|
||||
function useResolvedPath(to, _temp2) {
|
||||
let {
|
||||
relative
|
||||
} = _temp2 === void 0 ? {} : _temp2;
|
||||
let {
|
||||
future
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element of the route that matched the current location, prepared
|
||||
* with the correct context to render the remainder of the route tree. Route
|
||||
* elements in the tree must render an `<Outlet>` to render their child route's
|
||||
* element.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-routes
|
||||
*/
|
||||
function useRoutes(routes, locationArg) {
|
||||
return useRoutesImpl(routes, locationArg);
|
||||
}
|
||||
|
||||
// Internal implementation with accept optional param for RouterProvider usage
|
||||
function useRoutesImpl(routes, locationArg, dataRouterState, future) {
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useRoutes() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
let {
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches: parentMatches
|
||||
} = React.useContext(RouteContext);
|
||||
let routeMatch = parentMatches[parentMatches.length - 1];
|
||||
let parentParams = routeMatch ? routeMatch.params : {};
|
||||
let parentPathname = routeMatch ? routeMatch.pathname : "/";
|
||||
let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
||||
let parentRoute = routeMatch && routeMatch.route;
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// You won't get a warning about 2 different <Routes> under a <Route>
|
||||
// without a trailing *, but this is a best-effort warning anyway since we
|
||||
// cannot even give the warning unless they land at the parent route.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// <Routes>
|
||||
// {/* This route path MUST end with /* because otherwise
|
||||
// it will never match /blog/post/123 */}
|
||||
// <Route path="blog" element={<Blog />} />
|
||||
// <Route path="blog/feed" element={<BlogFeed />} />
|
||||
// </Routes>
|
||||
//
|
||||
// function Blog() {
|
||||
// return (
|
||||
// <Routes>
|
||||
// <Route path="post/:id" element={<Post />} />
|
||||
// </Routes>
|
||||
// );
|
||||
// }
|
||||
let parentPath = parentRoute && parentRoute.path || "";
|
||||
warningOnce(parentPathname, !parentRoute || parentPath.endsWith("*"), "You rendered descendant <Routes> (or called `useRoutes()`) at " + ("\"" + parentPathname + "\" (under <Route path=\"" + parentPath + "\">) but the ") + "parent route path has no trailing \"*\". This means if you navigate " + "deeper, the parent won't match anymore and therefore the child " + "routes will never render.\n\n" + ("Please change the parent <Route path=\"" + parentPath + "\"> to <Route ") + ("path=\"" + (parentPath === "/" ? "*" : parentPath + "/*") + "\">."));
|
||||
}
|
||||
let locationFromContext = useLocation();
|
||||
let location;
|
||||
if (locationArg) {
|
||||
var _parsedLocationArg$pa;
|
||||
let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
||||
!(parentPathnameBase === "/" || ((_parsedLocationArg$pa = parsedLocationArg.pathname) == null ? void 0 : _parsedLocationArg$pa.startsWith(parentPathnameBase))) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "When overriding the location using `<Routes location>` or `useRoutes(routes, location)`, " + "the location pathname must begin with the portion of the URL pathname that was " + ("matched by all parent routes. The current pathname base is \"" + parentPathnameBase + "\" ") + ("but pathname \"" + parsedLocationArg.pathname + "\" was given in the `location` prop.")) : UNSAFE_invariant(false) : void 0;
|
||||
location = parsedLocationArg;
|
||||
} else {
|
||||
location = locationFromContext;
|
||||
}
|
||||
let pathname = location.pathname || "/";
|
||||
let remainingPathname = pathname;
|
||||
if (parentPathnameBase !== "/") {
|
||||
// Determine the remaining pathname by removing the # of URL segments the
|
||||
// parentPathnameBase has, instead of removing based on character count.
|
||||
// This is because we can't guarantee that incoming/outgoing encodings/
|
||||
// decodings will match exactly.
|
||||
// We decode paths before matching on a per-segment basis with
|
||||
// decodeURIComponent(), but we re-encode pathnames via `new URL()` so they
|
||||
// match what `window.location.pathname` would reflect. Those don't 100%
|
||||
// align when it comes to encoded URI characters such as % and &.
|
||||
//
|
||||
// So we may end up with:
|
||||
// pathname: "/descendant/a%25b/match"
|
||||
// parentPathnameBase: "/descendant/a%b"
|
||||
//
|
||||
// And the direct substring removal approach won't work :/
|
||||
let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
|
||||
let segments = pathname.replace(/^\//, "").split("/");
|
||||
remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
|
||||
}
|
||||
let matches = matchRoutes(routes, {
|
||||
pathname: remainingPathname
|
||||
});
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(parentRoute || matches != null, "No routes matched location \"" + location.pathname + location.search + location.hash + "\" ") : void 0;
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(matches == null || matches[matches.length - 1].route.element !== undefined || matches[matches.length - 1].route.Component !== undefined || matches[matches.length - 1].route.lazy !== undefined, "Matched leaf route at location \"" + location.pathname + location.search + location.hash + "\" " + "does not have an element or Component. This means it will render an <Outlet /> with a " + "null value by default resulting in an \"empty\" page.") : void 0;
|
||||
}
|
||||
let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
||||
params: Object.assign({}, parentParams, match.params),
|
||||
pathname: joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathname).pathname : match.pathname]),
|
||||
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
|
||||
})), parentMatches, dataRouterState, future);
|
||||
|
||||
// When a user passes in a `locationArg`, the associated routes need to
|
||||
// be wrapped in a new `LocationContext.Provider` in order for `useLocation`
|
||||
// to use the scoped location instead of the global location.
|
||||
if (locationArg && renderedMatches) {
|
||||
return /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
||||
value: {
|
||||
location: _extends({
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
state: null,
|
||||
key: "default"
|
||||
}, location),
|
||||
navigationType: Action.Pop
|
||||
}
|
||||
}, renderedMatches);
|
||||
}
|
||||
return renderedMatches;
|
||||
}
|
||||
function DefaultErrorComponent() {
|
||||
let error = useRouteError();
|
||||
let message = isRouteErrorResponse(error) ? error.status + " " + error.statusText : error instanceof Error ? error.message : JSON.stringify(error);
|
||||
let stack = error instanceof Error ? error.stack : null;
|
||||
let lightgrey = "rgba(200,200,200, 0.5)";
|
||||
let preStyles = {
|
||||
padding: "0.5rem",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let codeStyles = {
|
||||
padding: "2px 4px",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let devInfo = null;
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
console.error("Error handled by React Router default ErrorBoundary:", error);
|
||||
devInfo = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", null, "\uD83D\uDCBF Hey developer \uD83D\uDC4B"), /*#__PURE__*/React.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own ", /*#__PURE__*/React.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "ErrorBoundary"), " or", " ", /*#__PURE__*/React.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "errorElement"), " prop on your route."));
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h2", null, "Unexpected Application Error!"), /*#__PURE__*/React.createElement("h3", {
|
||||
style: {
|
||||
fontStyle: "italic"
|
||||
}
|
||||
}, message), stack ? /*#__PURE__*/React.createElement("pre", {
|
||||
style: preStyles
|
||||
}, stack) : null, devInfo);
|
||||
}
|
||||
const defaultErrorElement = /*#__PURE__*/React.createElement(DefaultErrorComponent, null);
|
||||
class RenderErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
location: props.location,
|
||||
revalidation: props.revalidation,
|
||||
error: props.error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error: error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
// When we get into an error state, the user will likely click "back" to the
|
||||
// previous page that didn't have an error. Because this wraps the entire
|
||||
// application, that will have no effect--the error page continues to display.
|
||||
// This gives us a mechanism to recover from the error when the location changes.
|
||||
//
|
||||
// Whether we're in an error state or not, we update the location in state
|
||||
// so that when we are in an error state, it gets reset when a new location
|
||||
// comes in and the user recovers from the error.
|
||||
if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
|
||||
return {
|
||||
error: props.error,
|
||||
location: props.location,
|
||||
revalidation: props.revalidation
|
||||
};
|
||||
}
|
||||
|
||||
// If we're not changing locations, preserve the location but still surface
|
||||
// any new errors that may come through. We retain the existing error, we do
|
||||
// this because the error provided from the app state may be cleared without
|
||||
// the location changing.
|
||||
return {
|
||||
error: props.error !== undefined ? props.error : state.error,
|
||||
location: state.location,
|
||||
revalidation: props.revalidation || state.revalidation
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("React Router caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
return this.state.error !== undefined ? /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
||||
value: this.props.routeContext
|
||||
}, /*#__PURE__*/React.createElement(RouteErrorContext.Provider, {
|
||||
value: this.state.error,
|
||||
children: this.props.component
|
||||
})) : this.props.children;
|
||||
}
|
||||
}
|
||||
function RenderedRoute(_ref) {
|
||||
let {
|
||||
routeContext,
|
||||
match,
|
||||
children
|
||||
} = _ref;
|
||||
let dataRouterContext = React.useContext(DataRouterContext);
|
||||
|
||||
// Track how deep we got in our render pass to emulate SSR componentDidCatch
|
||||
// in a DataStaticRouter
|
||||
if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
|
||||
dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
||||
value: routeContext
|
||||
}, children);
|
||||
}
|
||||
function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
||||
var _dataRouterState;
|
||||
if (parentMatches === void 0) {
|
||||
parentMatches = [];
|
||||
}
|
||||
if (dataRouterState === void 0) {
|
||||
dataRouterState = null;
|
||||
}
|
||||
if (future === void 0) {
|
||||
future = null;
|
||||
}
|
||||
if (matches == null) {
|
||||
var _future;
|
||||
if (!dataRouterState) {
|
||||
return null;
|
||||
}
|
||||
if (dataRouterState.errors) {
|
||||
// Don't bail if we have data router errors so we can render them in the
|
||||
// boundary. Use the pre-matched (or shimmed) matches
|
||||
matches = dataRouterState.matches;
|
||||
} else if ((_future = future) != null && _future.v7_partialHydration && parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
|
||||
// Don't bail if we're initializing with partial hydration and we have
|
||||
// router matches. That means we're actively running `patchRoutesOnNavigation`
|
||||
// so we should render down the partial matches to the appropriate
|
||||
// `HydrateFallback`. We only do this if `parentMatches` is empty so it
|
||||
// only impacts the root matches for `RouterProvider` and no descendant
|
||||
// `<Routes>`
|
||||
matches = dataRouterState.matches;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let renderedMatches = matches;
|
||||
|
||||
// If we have data errors, trim matches to the highest error boundary
|
||||
let errors = (_dataRouterState = dataRouterState) == null ? void 0 : _dataRouterState.errors;
|
||||
if (errors != null) {
|
||||
let errorIndex = renderedMatches.findIndex(m => m.route.id && (errors == null ? void 0 : errors[m.route.id]) !== undefined);
|
||||
!(errorIndex >= 0) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "Could not find a matching route for errors on route IDs: " + Object.keys(errors).join(",")) : UNSAFE_invariant(false) : void 0;
|
||||
renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
|
||||
}
|
||||
|
||||
// If we're in a partial hydration mode, detect if we need to render down to
|
||||
// a given HydrateFallback while we load the rest of the hydration data
|
||||
let renderFallback = false;
|
||||
let fallbackIndex = -1;
|
||||
if (dataRouterState && future && future.v7_partialHydration) {
|
||||
for (let i = 0; i < renderedMatches.length; i++) {
|
||||
let match = renderedMatches[i];
|
||||
// Track the deepest fallback up until the first route without data
|
||||
if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
|
||||
fallbackIndex = i;
|
||||
}
|
||||
if (match.route.id) {
|
||||
let {
|
||||
loaderData,
|
||||
errors
|
||||
} = dataRouterState;
|
||||
let needsToRunLoader = match.route.loader && loaderData[match.route.id] === undefined && (!errors || errors[match.route.id] === undefined);
|
||||
if (match.route.lazy || needsToRunLoader) {
|
||||
// We found the first route that's not ready to render (waiting on
|
||||
// lazy, or has a loader that hasn't run yet). Flag that we need to
|
||||
// render a fallback and render up until the appropriate fallback
|
||||
renderFallback = true;
|
||||
if (fallbackIndex >= 0) {
|
||||
renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
|
||||
} else {
|
||||
renderedMatches = [renderedMatches[0]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderedMatches.reduceRight((outlet, match, index) => {
|
||||
// Only data routers handle errors/fallbacks
|
||||
let error;
|
||||
let shouldRenderHydrateFallback = false;
|
||||
let errorElement = null;
|
||||
let hydrateFallbackElement = null;
|
||||
if (dataRouterState) {
|
||||
error = errors && match.route.id ? errors[match.route.id] : undefined;
|
||||
errorElement = match.route.errorElement || defaultErrorElement;
|
||||
if (renderFallback) {
|
||||
if (fallbackIndex < 0 && index === 0) {
|
||||
warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration");
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = null;
|
||||
} else if (fallbackIndex === index) {
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = match.route.hydrateFallbackElement || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
|
||||
let getChildren = () => {
|
||||
let children;
|
||||
if (error) {
|
||||
children = errorElement;
|
||||
} else if (shouldRenderHydrateFallback) {
|
||||
children = hydrateFallbackElement;
|
||||
} else if (match.route.Component) {
|
||||
// Note: This is a de-optimized path since React won't re-use the
|
||||
// ReactElement since it's identity changes with each new
|
||||
// React.createElement call. We keep this so folks can use
|
||||
// `<Route Component={...}>` in `<Routes>` but generally `Component`
|
||||
// usage is only advised in `RouterProvider` when we can convert it to
|
||||
// `element` ahead of time.
|
||||
children = /*#__PURE__*/React.createElement(match.route.Component, null);
|
||||
} else if (match.route.element) {
|
||||
children = match.route.element;
|
||||
} else {
|
||||
children = outlet;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(RenderedRoute, {
|
||||
match: match,
|
||||
routeContext: {
|
||||
outlet,
|
||||
matches,
|
||||
isDataRoute: dataRouterState != null
|
||||
},
|
||||
children: children
|
||||
});
|
||||
};
|
||||
// Only wrap in an error boundary within data router usages when we have an
|
||||
// ErrorBoundary/errorElement on this route. Otherwise let it bubble up to
|
||||
// an ancestor ErrorBoundary/errorElement
|
||||
return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /*#__PURE__*/React.createElement(RenderErrorBoundary, {
|
||||
location: dataRouterState.location,
|
||||
revalidation: dataRouterState.revalidation,
|
||||
component: errorElement,
|
||||
error: error,
|
||||
children: getChildren(),
|
||||
routeContext: {
|
||||
outlet: null,
|
||||
matches,
|
||||
isDataRoute: true
|
||||
}
|
||||
}) : getChildren();
|
||||
}, null);
|
||||
}
|
||||
var DataRouterHook = /*#__PURE__*/function (DataRouterHook) {
|
||||
DataRouterHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterHook["UseNavigateStable"] = "useNavigate";
|
||||
return DataRouterHook;
|
||||
}(DataRouterHook || {});
|
||||
var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) {
|
||||
DataRouterStateHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterStateHook["UseLoaderData"] = "useLoaderData";
|
||||
DataRouterStateHook["UseActionData"] = "useActionData";
|
||||
DataRouterStateHook["UseRouteError"] = "useRouteError";
|
||||
DataRouterStateHook["UseNavigation"] = "useNavigation";
|
||||
DataRouterStateHook["UseRouteLoaderData"] = "useRouteLoaderData";
|
||||
DataRouterStateHook["UseMatches"] = "useMatches";
|
||||
DataRouterStateHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterStateHook["UseNavigateStable"] = "useNavigate";
|
||||
DataRouterStateHook["UseRouteId"] = "useRouteId";
|
||||
return DataRouterStateHook;
|
||||
}(DataRouterStateHook || {});
|
||||
function getDataRouterConsoleError(hookName) {
|
||||
return hookName + " must be used within a data router. See https://reactrouter.com/v6/routers/picking-a-router.";
|
||||
}
|
||||
function useDataRouterContext(hookName) {
|
||||
let ctx = React.useContext(DataRouterContext);
|
||||
!ctx ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0;
|
||||
return ctx;
|
||||
}
|
||||
function useDataRouterState(hookName) {
|
||||
let state = React.useContext(DataRouterStateContext);
|
||||
!state ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0;
|
||||
return state;
|
||||
}
|
||||
function useRouteContext(hookName) {
|
||||
let route = React.useContext(RouteContext);
|
||||
!route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0;
|
||||
return route;
|
||||
}
|
||||
|
||||
// Internal version with hookName-aware debugging
|
||||
function useCurrentRouteId(hookName) {
|
||||
let route = useRouteContext(hookName);
|
||||
let thisRoute = route.matches[route.matches.length - 1];
|
||||
!thisRoute.route.id ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, hookName + " can only be used on routes that contain a unique \"id\"") : UNSAFE_invariant(false) : void 0;
|
||||
return thisRoute.route.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID for the nearest contextual route
|
||||
*/
|
||||
function useRouteId() {
|
||||
return useCurrentRouteId(DataRouterStateHook.UseRouteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current navigation, defaulting to an "idle" navigation when
|
||||
* no navigation is in progress
|
||||
*/
|
||||
function useNavigation() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseNavigation);
|
||||
return state.navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a revalidate function for manually triggering revalidation, as well
|
||||
* as the current state of any manual revalidations
|
||||
*/
|
||||
function useRevalidator() {
|
||||
let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRevalidator);
|
||||
return React.useMemo(() => ({
|
||||
revalidate: dataRouterContext.router.revalidate,
|
||||
state: state.revalidation
|
||||
}), [dataRouterContext.router.revalidate, state.revalidation]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active route matches, useful for accessing loaderData for
|
||||
* parent/child routes or the route "handle" property
|
||||
*/
|
||||
function useMatches() {
|
||||
let {
|
||||
matches,
|
||||
loaderData
|
||||
} = useDataRouterState(DataRouterStateHook.UseMatches);
|
||||
return React.useMemo(() => matches.map(m => UNSAFE_convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loader data for the nearest ancestor Route loader
|
||||
*/
|
||||
function useLoaderData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseLoaderData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
if (state.errors && state.errors[routeId] != null) {
|
||||
console.error("You cannot `useLoaderData` in an errorElement (routeId: " + routeId + ")");
|
||||
return undefined;
|
||||
}
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loaderData for the given routeId
|
||||
*/
|
||||
function useRouteLoaderData(routeId) {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action data for the nearest ancestor Route action
|
||||
*/
|
||||
function useActionData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseActionData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
return state.actionData ? state.actionData[routeId] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nearest ancestor Route error, which could be a loader/action
|
||||
* error or a render error. This is intended to be called from your
|
||||
* ErrorBoundary/errorElement to display a proper error message.
|
||||
*/
|
||||
function useRouteError() {
|
||||
var _state$errors;
|
||||
let error = React.useContext(RouteErrorContext);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteError);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);
|
||||
|
||||
// If this was a render error, we put it in a RouteError context inside
|
||||
// of RenderErrorBoundary
|
||||
if (error !== undefined) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// Otherwise look for errors from our data router state
|
||||
return (_state$errors = state.errors) == null ? void 0 : _state$errors[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the happy-path data from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncValue() {
|
||||
let value = React.useContext(AwaitContext);
|
||||
return value == null ? void 0 : value._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncError() {
|
||||
let value = React.useContext(AwaitContext);
|
||||
return value == null ? void 0 : value._error;
|
||||
}
|
||||
let blockerId = 0;
|
||||
|
||||
/**
|
||||
* Allow the application to block navigations within the SPA and present the
|
||||
* user a confirmation dialog to confirm the navigation. Mostly used to avoid
|
||||
* using half-filled form data. This does not handle hard-reloads or
|
||||
* cross-origin navigations.
|
||||
*/
|
||||
function useBlocker(shouldBlock) {
|
||||
let {
|
||||
router,
|
||||
basename
|
||||
} = useDataRouterContext(DataRouterHook.UseBlocker);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseBlocker);
|
||||
let [blockerKey, setBlockerKey] = React.useState("");
|
||||
let blockerFunction = React.useCallback(arg => {
|
||||
if (typeof shouldBlock !== "function") {
|
||||
return !!shouldBlock;
|
||||
}
|
||||
if (basename === "/") {
|
||||
return shouldBlock(arg);
|
||||
}
|
||||
|
||||
// If they provided us a function and we've got an active basename, strip
|
||||
// it from the locations we expose to the user to match the behavior of
|
||||
// useLocation
|
||||
let {
|
||||
currentLocation,
|
||||
nextLocation,
|
||||
historyAction
|
||||
} = arg;
|
||||
return shouldBlock({
|
||||
currentLocation: _extends({}, currentLocation, {
|
||||
pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
|
||||
}),
|
||||
nextLocation: _extends({}, nextLocation, {
|
||||
pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
|
||||
}),
|
||||
historyAction
|
||||
});
|
||||
}, [basename, shouldBlock]);
|
||||
|
||||
// This effect is in charge of blocker key assignment and deletion (which is
|
||||
// tightly coupled to the key)
|
||||
React.useEffect(() => {
|
||||
let key = String(++blockerId);
|
||||
setBlockerKey(key);
|
||||
return () => router.deleteBlocker(key);
|
||||
}, [router]);
|
||||
|
||||
// This effect handles assigning the blockerFunction. This is to handle
|
||||
// unstable blocker function identities, and happens only after the prior
|
||||
// effect so we don't get an orphaned blockerFunction in the router with a
|
||||
// key of "". Until then we just have the IDLE_BLOCKER.
|
||||
React.useEffect(() => {
|
||||
if (blockerKey !== "") {
|
||||
router.getBlocker(blockerKey, blockerFunction);
|
||||
}
|
||||
}, [router, blockerKey, blockerFunction]);
|
||||
|
||||
// Prefer the blocker from `state` not `router.state` since DataRouterContext
|
||||
// is memoized so this ensures we update on blocker state updates
|
||||
return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable version of useNavigate that is used when we are in the context of
|
||||
* a RouterProvider.
|
||||
*/
|
||||
function useNavigateStable() {
|
||||
let {
|
||||
router
|
||||
} = useDataRouterContext(DataRouterHook.UseNavigateStable);
|
||||
let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
|
||||
let activeRef = React.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React.useCallback(function (to, options) {
|
||||
if (options === void 0) {
|
||||
options = {};
|
||||
}
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0;
|
||||
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our router subscriber yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
router.navigate(to);
|
||||
} else {
|
||||
router.navigate(to, _extends({
|
||||
fromRouteId: id
|
||||
}, options));
|
||||
}
|
||||
}, [router, id]);
|
||||
return navigate;
|
||||
}
|
||||
const alreadyWarned$1 = {};
|
||||
function warningOnce(key, cond, message) {
|
||||
if (!cond && !alreadyWarned$1[key]) {
|
||||
alreadyWarned$1[key] = true;
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, message) : void 0;
|
||||
}
|
||||
}
|
||||
|
||||
const alreadyWarned = {};
|
||||
function warnOnce(key, message) {
|
||||
if (process.env.NODE_ENV !== "production" && !alreadyWarned[message]) {
|
||||
alreadyWarned[message] = true;
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
const logDeprecation = (flag, msg, link) => warnOnce(flag, "\u26A0\uFE0F React Router Future Flag Warning: " + msg + ". " + ("You can use the `" + flag + "` future flag to opt-in early. ") + ("For more information, see " + link + "."));
|
||||
function logV6DeprecationWarnings(renderFuture, routerFuture) {
|
||||
if ((renderFuture == null ? void 0 : renderFuture.v7_startTransition) === undefined) {
|
||||
logDeprecation("v7_startTransition", "React Router will begin wrapping state updates in `React.startTransition` in v7", "https://reactrouter.com/v6/upgrading/future#v7_starttransition");
|
||||
}
|
||||
if ((renderFuture == null ? void 0 : renderFuture.v7_relativeSplatPath) === undefined && (!routerFuture || routerFuture.v7_relativeSplatPath === undefined)) {
|
||||
logDeprecation("v7_relativeSplatPath", "Relative route resolution within Splat routes is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_relativesplatpath");
|
||||
}
|
||||
if (routerFuture) {
|
||||
if (routerFuture.v7_fetcherPersist === undefined) {
|
||||
logDeprecation("v7_fetcherPersist", "The persistence behavior of fetchers is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_fetcherpersist");
|
||||
}
|
||||
if (routerFuture.v7_normalizeFormMethod === undefined) {
|
||||
logDeprecation("v7_normalizeFormMethod", "Casing of `formMethod` fields is being normalized to uppercase in v7", "https://reactrouter.com/v6/upgrading/future#v7_normalizeformmethod");
|
||||
}
|
||||
if (routerFuture.v7_partialHydration === undefined) {
|
||||
logDeprecation("v7_partialHydration", "`RouterProvider` hydration behavior is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_partialhydration");
|
||||
}
|
||||
if (routerFuture.v7_skipActionErrorRevalidation === undefined) {
|
||||
logDeprecation("v7_skipActionErrorRevalidation", "The revalidation behavior after 4xx/5xx `action` responses is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_skipactionerrorrevalidation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Webpack + React 17 fails to compile on any of the following because webpack
|
||||
complains that `startTransition` doesn't exist in `React`:
|
||||
* import { startTransition } from "react"
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React.startTransition(() => setState()) : setState()
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React["startTransition"](() => setState()) : setState()
|
||||
|
||||
Moving it to a constant such as the following solves the Webpack/React 17 issue:
|
||||
* import * as React from from "react";
|
||||
const START_TRANSITION = "startTransition";
|
||||
START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()
|
||||
|
||||
However, that introduces webpack/terser minification issues in production builds
|
||||
in React 18 where minification/obfuscation ends up removing the call of
|
||||
React.startTransition entirely from the first half of the ternary. Grabbing
|
||||
this exported reference once up front resolves that issue.
|
||||
|
||||
See https://github.com/remix-run/react-router/issues/10579
|
||||
*/
|
||||
const START_TRANSITION = "startTransition";
|
||||
const startTransitionImpl = React[START_TRANSITION];
|
||||
|
||||
/**
|
||||
* Given a Remix Router instance, render the appropriate UI
|
||||
*/
|
||||
function RouterProvider(_ref) {
|
||||
let {
|
||||
fallbackElement,
|
||||
router,
|
||||
future
|
||||
} = _ref;
|
||||
let [state, setStateImpl] = React.useState(router.state);
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React.useCallback(newState => {
|
||||
if (v7_startTransition && startTransitionImpl) {
|
||||
startTransitionImpl(() => setStateImpl(newState));
|
||||
} else {
|
||||
setStateImpl(newState);
|
||||
}
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
|
||||
// Need to use a layout effect here so we are subscribed early enough to
|
||||
// pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
|
||||
React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
|
||||
React.useEffect(() => {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(fallbackElement == null || !router.future.v7_partialHydration, "`<RouterProvider fallbackElement>` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead") : void 0;
|
||||
// Only log this once on initial mount
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
let navigator = React.useMemo(() => {
|
||||
return {
|
||||
createHref: router.createHref,
|
||||
encodeLocation: router.encodeLocation,
|
||||
go: n => router.navigate(n),
|
||||
push: (to, state, opts) => router.navigate(to, {
|
||||
state,
|
||||
preventScrollReset: opts == null ? void 0 : opts.preventScrollReset
|
||||
}),
|
||||
replace: (to, state, opts) => router.navigate(to, {
|
||||
replace: true,
|
||||
state,
|
||||
preventScrollReset: opts == null ? void 0 : opts.preventScrollReset
|
||||
})
|
||||
};
|
||||
}, [router]);
|
||||
let basename = router.basename || "/";
|
||||
let dataRouterContext = React.useMemo(() => ({
|
||||
router,
|
||||
navigator,
|
||||
static: false,
|
||||
basename
|
||||
}), [router, navigator, basename]);
|
||||
React.useEffect(() => logV6DeprecationWarnings(future, router.future), [router, future]);
|
||||
|
||||
// The fragment and {null} here are important! We need them to keep React 18's
|
||||
// useId happy when we are server-rendering since we may have a <script> here
|
||||
// containing the hydrated server-side staticContext (from StaticRouterProvider).
|
||||
// useId relies on the component tree structure to generate deterministic id's
|
||||
// so we need to ensure it remains the same on the client even though
|
||||
// we don't need the <script> tag
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DataRouterContext.Provider, {
|
||||
value: dataRouterContext
|
||||
}, /*#__PURE__*/React.createElement(DataRouterStateContext.Provider, {
|
||||
value: state
|
||||
}, /*#__PURE__*/React.createElement(Router, {
|
||||
basename: basename,
|
||||
location: state.location,
|
||||
navigationType: state.historyAction,
|
||||
navigator: navigator,
|
||||
future: {
|
||||
v7_relativeSplatPath: router.future.v7_relativeSplatPath
|
||||
}
|
||||
}, state.initialized || router.future.v7_partialHydration ? /*#__PURE__*/React.createElement(DataRoutes, {
|
||||
routes: router.routes,
|
||||
future: router.future,
|
||||
state: state
|
||||
}) : fallbackElement))), null);
|
||||
}
|
||||
function DataRoutes(_ref2) {
|
||||
let {
|
||||
routes,
|
||||
future,
|
||||
state
|
||||
} = _ref2;
|
||||
return useRoutesImpl(routes, undefined, state, future);
|
||||
}
|
||||
/**
|
||||
* A `<Router>` that stores all entries in memory.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/memory-router
|
||||
*/
|
||||
function MemoryRouter(_ref3) {
|
||||
let {
|
||||
basename,
|
||||
children,
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
future
|
||||
} = _ref3;
|
||||
let historyRef = React.useRef();
|
||||
if (historyRef.current == null) {
|
||||
historyRef.current = createMemoryHistory({
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
v5Compat: true
|
||||
});
|
||||
}
|
||||
let history = historyRef.current;
|
||||
let [state, setStateImpl] = React.useState({
|
||||
action: history.action,
|
||||
location: history.location
|
||||
});
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React.useCallback(newState => {
|
||||
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
||||
React.useEffect(() => logV6DeprecationWarnings(future), [future]);
|
||||
return /*#__PURE__*/React.createElement(Router, {
|
||||
basename: basename,
|
||||
children: children,
|
||||
location: state.location,
|
||||
navigationType: state.action,
|
||||
navigator: history,
|
||||
future: future
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Changes the current location.
|
||||
*
|
||||
* Note: This API is mostly useful in React.Component subclasses that are not
|
||||
* able to use hooks. In functional components, we recommend you use the
|
||||
* `useNavigate` hook instead.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/navigate
|
||||
*/
|
||||
function Navigate(_ref4) {
|
||||
let {
|
||||
to,
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
} = _ref4;
|
||||
!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of
|
||||
// the router loaded. We can help them understand how to avoid that.
|
||||
"<Navigate> may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
|
||||
let {
|
||||
future,
|
||||
static: isStatic
|
||||
} = React.useContext(NavigationContext);
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(!isStatic, "<Navigate> must not be used on the initial render in a <StaticRouter>. " + "This is a no-op, but you should modify your code so the <Navigate> is " + "only ever rendered in response to some user interaction or state change.") : void 0;
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let navigate = useNavigate();
|
||||
|
||||
// Resolve the path outside of the effect so that when effects run twice in
|
||||
// StrictMode they navigate to the same place
|
||||
let path = resolveTo(to, UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath), locationPathname, relative === "path");
|
||||
let jsonPath = JSON.stringify(path);
|
||||
React.useEffect(() => navigate(JSON.parse(jsonPath), {
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
}), [navigate, jsonPath, relative, replace, state]);
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Renders the child route's element, if there is one.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/outlet
|
||||
*/
|
||||
function Outlet(props) {
|
||||
return useOutlet(props.context);
|
||||
}
|
||||
/**
|
||||
* Declares an element that should be rendered at a certain URL path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/route
|
||||
*/
|
||||
function Route(_props) {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "A <Route> is only ever to be used as the child of <Routes> element, " + "never rendered directly. Please wrap your <Route> in a <Routes>.") : UNSAFE_invariant(false) ;
|
||||
}
|
||||
/**
|
||||
* Provides location context for the rest of the app.
|
||||
*
|
||||
* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
|
||||
* router that is more specific to your environment such as a `<BrowserRouter>`
|
||||
* in web browsers or a `<StaticRouter>` for server rendering.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/router
|
||||
*/
|
||||
function Router(_ref5) {
|
||||
let {
|
||||
basename: basenameProp = "/",
|
||||
children = null,
|
||||
location: locationProp,
|
||||
navigationType = Action.Pop,
|
||||
navigator,
|
||||
static: staticProp = false,
|
||||
future
|
||||
} = _ref5;
|
||||
!!useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "You cannot render a <Router> inside another <Router>." + " You should never have more than one in your app.") : UNSAFE_invariant(false) : void 0;
|
||||
|
||||
// Preserve trailing slashes on basename, so we can let the user control
|
||||
// the enforcement of trailing slashes throughout the app
|
||||
let basename = basenameProp.replace(/^\/*/, "/");
|
||||
let navigationContext = React.useMemo(() => ({
|
||||
basename,
|
||||
navigator,
|
||||
static: staticProp,
|
||||
future: _extends({
|
||||
v7_relativeSplatPath: false
|
||||
}, future)
|
||||
}), [basename, future, navigator, staticProp]);
|
||||
if (typeof locationProp === "string") {
|
||||
locationProp = parsePath(locationProp);
|
||||
}
|
||||
let {
|
||||
pathname = "/",
|
||||
search = "",
|
||||
hash = "",
|
||||
state = null,
|
||||
key = "default"
|
||||
} = locationProp;
|
||||
let locationContext = React.useMemo(() => {
|
||||
let trailingPathname = stripBasename(pathname, basename);
|
||||
if (trailingPathname == null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
location: {
|
||||
pathname: trailingPathname,
|
||||
search,
|
||||
hash,
|
||||
state,
|
||||
key
|
||||
},
|
||||
navigationType
|
||||
};
|
||||
}, [basename, pathname, search, hash, state, key, navigationType]);
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(locationContext != null, "<Router basename=\"" + basename + "\"> is not able to match the URL " + ("\"" + pathname + search + hash + "\" because it does not start with the ") + "basename, so the <Router> won't render anything.") : void 0;
|
||||
if (locationContext == null) {
|
||||
return null;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(NavigationContext.Provider, {
|
||||
value: navigationContext
|
||||
}, /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
||||
children: children,
|
||||
value: locationContext
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* A container for a nested tree of `<Route>` elements that renders the branch
|
||||
* that best matches the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/routes
|
||||
*/
|
||||
function Routes(_ref6) {
|
||||
let {
|
||||
children,
|
||||
location
|
||||
} = _ref6;
|
||||
return useRoutes(createRoutesFromChildren(children), location);
|
||||
}
|
||||
/**
|
||||
* Component to use for rendering lazily loaded data from returning defer()
|
||||
* in a loader function
|
||||
*/
|
||||
function Await(_ref7) {
|
||||
let {
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
} = _ref7;
|
||||
return /*#__PURE__*/React.createElement(AwaitErrorBoundary, {
|
||||
resolve: resolve,
|
||||
errorElement: errorElement
|
||||
}, /*#__PURE__*/React.createElement(ResolveAwait, null, children));
|
||||
}
|
||||
var AwaitRenderStatus = /*#__PURE__*/function (AwaitRenderStatus) {
|
||||
AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
|
||||
AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
|
||||
AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
|
||||
return AwaitRenderStatus;
|
||||
}(AwaitRenderStatus || {});
|
||||
const neverSettledPromise = new Promise(() => {});
|
||||
class AwaitErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: null
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("<Await> caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
} = this.props;
|
||||
let promise = null;
|
||||
let status = AwaitRenderStatus.pending;
|
||||
if (!(resolve instanceof Promise)) {
|
||||
// Didn't get a promise - provide as a resolved promise
|
||||
status = AwaitRenderStatus.success;
|
||||
promise = Promise.resolve();
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_data", {
|
||||
get: () => resolve
|
||||
});
|
||||
} else if (this.state.error) {
|
||||
// Caught a render error, provide it as a rejected promise
|
||||
status = AwaitRenderStatus.error;
|
||||
let renderError = this.state.error;
|
||||
promise = Promise.reject().catch(() => {}); // Avoid unhandled rejection warnings
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_error", {
|
||||
get: () => renderError
|
||||
});
|
||||
} else if (resolve._tracked) {
|
||||
// Already tracked promise - check contents
|
||||
promise = resolve;
|
||||
status = "_error" in promise ? AwaitRenderStatus.error : "_data" in promise ? AwaitRenderStatus.success : AwaitRenderStatus.pending;
|
||||
} else {
|
||||
// Raw (untracked) promise - track it
|
||||
status = AwaitRenderStatus.pending;
|
||||
Object.defineProperty(resolve, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
promise = resolve.then(data => Object.defineProperty(resolve, "_data", {
|
||||
get: () => data
|
||||
}), error => Object.defineProperty(resolve, "_error", {
|
||||
get: () => error
|
||||
}));
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && promise._error instanceof AbortedDeferredError) {
|
||||
// Freeze the UI by throwing a never resolved promise
|
||||
throw neverSettledPromise;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && !errorElement) {
|
||||
// No errorElement, throw to the nearest route-level error boundary
|
||||
throw promise._error;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error) {
|
||||
// Render via our errorElement
|
||||
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: errorElement
|
||||
});
|
||||
}
|
||||
if (status === AwaitRenderStatus.success) {
|
||||
// Render children with resolved value
|
||||
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
// Throw to the suspense boundary
|
||||
throw promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Indirection to leverage useAsyncValue for a render-prop API on `<Await>`
|
||||
*/
|
||||
function ResolveAwait(_ref8) {
|
||||
let {
|
||||
children
|
||||
} = _ref8;
|
||||
let data = useAsyncValue();
|
||||
let toRender = typeof children === "function" ? children(data) : children;
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, toRender);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTILS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Creates a route config from a React "children" object, which is usually
|
||||
* either a `<Route>` element or an array of them. Used internally by
|
||||
* `<Routes>` to create a route config from its children.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/utils/create-routes-from-children
|
||||
*/
|
||||
function createRoutesFromChildren(children, parentPath) {
|
||||
if (parentPath === void 0) {
|
||||
parentPath = [];
|
||||
}
|
||||
let routes = [];
|
||||
React.Children.forEach(children, (element, index) => {
|
||||
if (! /*#__PURE__*/React.isValidElement(element)) {
|
||||
// Ignore non-elements. This allows people to more easily inline
|
||||
// conditionals in their route config.
|
||||
return;
|
||||
}
|
||||
let treePath = [...parentPath, index];
|
||||
if (element.type === React.Fragment) {
|
||||
// Transparently support React.Fragment and its children.
|
||||
routes.push.apply(routes, createRoutesFromChildren(element.props.children, treePath));
|
||||
return;
|
||||
}
|
||||
!(element.type === Route) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "[" + (typeof element.type === "string" ? element.type : element.type.name) + "] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>") : UNSAFE_invariant(false) : void 0;
|
||||
!(!element.props.index || !element.props.children) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "An index route cannot have child routes.") : UNSAFE_invariant(false) : void 0;
|
||||
let route = {
|
||||
id: element.props.id || treePath.join("-"),
|
||||
caseSensitive: element.props.caseSensitive,
|
||||
element: element.props.element,
|
||||
Component: element.props.Component,
|
||||
index: element.props.index,
|
||||
path: element.props.path,
|
||||
loader: element.props.loader,
|
||||
action: element.props.action,
|
||||
errorElement: element.props.errorElement,
|
||||
ErrorBoundary: element.props.ErrorBoundary,
|
||||
hasErrorBoundary: element.props.ErrorBoundary != null || element.props.errorElement != null,
|
||||
shouldRevalidate: element.props.shouldRevalidate,
|
||||
handle: element.props.handle,
|
||||
lazy: element.props.lazy
|
||||
};
|
||||
if (element.props.children) {
|
||||
route.children = createRoutesFromChildren(element.props.children, treePath);
|
||||
}
|
||||
routes.push(route);
|
||||
});
|
||||
return routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the result of `matchRoutes()` into a React element.
|
||||
*/
|
||||
function renderMatches(matches) {
|
||||
return _renderMatches(matches);
|
||||
}
|
||||
|
||||
function mapRouteProperties(route) {
|
||||
let updates = {
|
||||
// Note: this check also occurs in createRoutesFromChildren so update
|
||||
// there if you change this -- please and thank you!
|
||||
hasErrorBoundary: route.ErrorBoundary != null || route.errorElement != null
|
||||
};
|
||||
if (route.Component) {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (route.element) {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "You should not include both `Component` and `element` on your route - " + "`Component` will be used.") : void 0;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
element: /*#__PURE__*/React.createElement(route.Component),
|
||||
Component: undefined
|
||||
});
|
||||
}
|
||||
if (route.HydrateFallback) {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (route.hydrateFallbackElement) {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - " + "`HydrateFallback` will be used.") : void 0;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
hydrateFallbackElement: /*#__PURE__*/React.createElement(route.HydrateFallback),
|
||||
HydrateFallback: undefined
|
||||
});
|
||||
}
|
||||
if (route.ErrorBoundary) {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (route.errorElement) {
|
||||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "You should not include both `ErrorBoundary` and `errorElement` on your route - " + "`ErrorBoundary` will be used.") : void 0;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
errorElement: /*#__PURE__*/React.createElement(route.ErrorBoundary),
|
||||
ErrorBoundary: undefined
|
||||
});
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
function createMemoryRouter(routes, opts) {
|
||||
return createRouter({
|
||||
basename: opts == null ? void 0 : opts.basename,
|
||||
future: _extends({}, opts == null ? void 0 : opts.future, {
|
||||
v7_prependBasename: true
|
||||
}),
|
||||
history: createMemoryHistory({
|
||||
initialEntries: opts == null ? void 0 : opts.initialEntries,
|
||||
initialIndex: opts == null ? void 0 : opts.initialIndex
|
||||
}),
|
||||
hydrationData: opts == null ? void 0 : opts.hydrationData,
|
||||
routes,
|
||||
mapRouteProperties,
|
||||
dataStrategy: opts == null ? void 0 : opts.dataStrategy,
|
||||
patchRoutesOnNavigation: opts == null ? void 0 : opts.patchRoutesOnNavigation
|
||||
}).initialize();
|
||||
}
|
||||
|
||||
export { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, logV6DeprecationWarnings as UNSAFE_logV6DeprecationWarnings, mapRouteProperties as UNSAFE_mapRouteProperties, useRouteId as UNSAFE_useRouteId, useRoutesImpl as UNSAFE_useRoutesImpl, createMemoryRouter, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes };
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+157
@@ -0,0 +1,157 @@
|
||||
import type { InitialEntry, LazyRouteFunction, Location, RelativeRoutingType, Router as RemixRouter, To, TrackedPromise } from "@remix-run/router";
|
||||
import { Action as NavigationType } from "@remix-run/router";
|
||||
import * as React from "react";
|
||||
import type { IndexRouteObject, Navigator, NonIndexRouteObject, RouteMatch, RouteObject } from "./context";
|
||||
export interface FutureConfig {
|
||||
v7_relativeSplatPath: boolean;
|
||||
v7_startTransition: boolean;
|
||||
}
|
||||
export interface RouterProviderProps {
|
||||
fallbackElement?: React.ReactNode;
|
||||
router: RemixRouter;
|
||||
future?: Partial<Pick<FutureConfig, "v7_startTransition">>;
|
||||
}
|
||||
/**
|
||||
* Given a Remix Router instance, render the appropriate UI
|
||||
*/
|
||||
export declare function RouterProvider({ fallbackElement, router, future, }: RouterProviderProps): React.ReactElement;
|
||||
export interface MemoryRouterProps {
|
||||
basename?: string;
|
||||
children?: React.ReactNode;
|
||||
initialEntries?: InitialEntry[];
|
||||
initialIndex?: number;
|
||||
future?: Partial<FutureConfig>;
|
||||
}
|
||||
/**
|
||||
* A `<Router>` that stores all entries in memory.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/memory-router
|
||||
*/
|
||||
export declare function MemoryRouter({ basename, children, initialEntries, initialIndex, future, }: MemoryRouterProps): React.ReactElement;
|
||||
export interface NavigateProps {
|
||||
to: To;
|
||||
replace?: boolean;
|
||||
state?: any;
|
||||
relative?: RelativeRoutingType;
|
||||
}
|
||||
/**
|
||||
* Changes the current location.
|
||||
*
|
||||
* Note: This API is mostly useful in React.Component subclasses that are not
|
||||
* able to use hooks. In functional components, we recommend you use the
|
||||
* `useNavigate` hook instead.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/navigate
|
||||
*/
|
||||
export declare function Navigate({ to, replace, state, relative, }: NavigateProps): null;
|
||||
export interface OutletProps {
|
||||
context?: unknown;
|
||||
}
|
||||
/**
|
||||
* Renders the child route's element, if there is one.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/outlet
|
||||
*/
|
||||
export declare function Outlet(props: OutletProps): React.ReactElement | null;
|
||||
export interface PathRouteProps {
|
||||
caseSensitive?: NonIndexRouteObject["caseSensitive"];
|
||||
path?: NonIndexRouteObject["path"];
|
||||
id?: NonIndexRouteObject["id"];
|
||||
lazy?: LazyRouteFunction<NonIndexRouteObject>;
|
||||
loader?: NonIndexRouteObject["loader"];
|
||||
action?: NonIndexRouteObject["action"];
|
||||
hasErrorBoundary?: NonIndexRouteObject["hasErrorBoundary"];
|
||||
shouldRevalidate?: NonIndexRouteObject["shouldRevalidate"];
|
||||
handle?: NonIndexRouteObject["handle"];
|
||||
index?: false;
|
||||
children?: React.ReactNode;
|
||||
element?: React.ReactNode | null;
|
||||
hydrateFallbackElement?: React.ReactNode | null;
|
||||
errorElement?: React.ReactNode | null;
|
||||
Component?: React.ComponentType | null;
|
||||
HydrateFallback?: React.ComponentType | null;
|
||||
ErrorBoundary?: React.ComponentType | null;
|
||||
}
|
||||
export interface LayoutRouteProps extends PathRouteProps {
|
||||
}
|
||||
export interface IndexRouteProps {
|
||||
caseSensitive?: IndexRouteObject["caseSensitive"];
|
||||
path?: IndexRouteObject["path"];
|
||||
id?: IndexRouteObject["id"];
|
||||
lazy?: LazyRouteFunction<IndexRouteObject>;
|
||||
loader?: IndexRouteObject["loader"];
|
||||
action?: IndexRouteObject["action"];
|
||||
hasErrorBoundary?: IndexRouteObject["hasErrorBoundary"];
|
||||
shouldRevalidate?: IndexRouteObject["shouldRevalidate"];
|
||||
handle?: IndexRouteObject["handle"];
|
||||
index: true;
|
||||
children?: undefined;
|
||||
element?: React.ReactNode | null;
|
||||
hydrateFallbackElement?: React.ReactNode | null;
|
||||
errorElement?: React.ReactNode | null;
|
||||
Component?: React.ComponentType | null;
|
||||
HydrateFallback?: React.ComponentType | null;
|
||||
ErrorBoundary?: React.ComponentType | null;
|
||||
}
|
||||
export type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps;
|
||||
/**
|
||||
* Declares an element that should be rendered at a certain URL path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/route
|
||||
*/
|
||||
export declare function Route(_props: RouteProps): React.ReactElement | null;
|
||||
export interface RouterProps {
|
||||
basename?: string;
|
||||
children?: React.ReactNode;
|
||||
location: Partial<Location> | string;
|
||||
navigationType?: NavigationType;
|
||||
navigator: Navigator;
|
||||
static?: boolean;
|
||||
future?: Partial<Pick<FutureConfig, "v7_relativeSplatPath">>;
|
||||
}
|
||||
/**
|
||||
* Provides location context for the rest of the app.
|
||||
*
|
||||
* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
|
||||
* router that is more specific to your environment such as a `<BrowserRouter>`
|
||||
* in web browsers or a `<StaticRouter>` for server rendering.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/router
|
||||
*/
|
||||
export declare function Router({ basename: basenameProp, children, location: locationProp, navigationType, navigator, static: staticProp, future, }: RouterProps): React.ReactElement | null;
|
||||
export interface RoutesProps {
|
||||
children?: React.ReactNode;
|
||||
location?: Partial<Location> | string;
|
||||
}
|
||||
/**
|
||||
* A container for a nested tree of `<Route>` elements that renders the branch
|
||||
* that best matches the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/routes
|
||||
*/
|
||||
export declare function Routes({ children, location, }: RoutesProps): React.ReactElement | null;
|
||||
export interface AwaitResolveRenderFunction {
|
||||
(data: Awaited<any>): React.ReactNode;
|
||||
}
|
||||
export interface AwaitProps {
|
||||
children: React.ReactNode | AwaitResolveRenderFunction;
|
||||
errorElement?: React.ReactNode;
|
||||
resolve: TrackedPromise | any;
|
||||
}
|
||||
/**
|
||||
* Component to use for rendering lazily loaded data from returning defer()
|
||||
* in a loader function
|
||||
*/
|
||||
export declare function Await({ children, errorElement, resolve }: AwaitProps): React.JSX.Element;
|
||||
/**
|
||||
* Creates a route config from a React "children" object, which is usually
|
||||
* either a `<Route>` element or an array of them. Used internally by
|
||||
* `<Routes>` to create a route config from its children.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/utils/create-routes-from-children
|
||||
*/
|
||||
export declare function createRoutesFromChildren(children: React.ReactNode, parentPath?: number[]): RouteObject[];
|
||||
/**
|
||||
* Renders the result of `matchRoutes()` into a React element.
|
||||
*/
|
||||
export declare function renderMatches(matches: RouteMatch[] | null): React.ReactElement | null;
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
import * as React from "react";
|
||||
import type { AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, History, LazyRouteFunction, Location, Action as NavigationType, RelativeRoutingType, Router, StaticHandlerContext, To, TrackedPromise } from "@remix-run/router";
|
||||
export interface IndexRouteObject {
|
||||
caseSensitive?: AgnosticIndexRouteObject["caseSensitive"];
|
||||
path?: AgnosticIndexRouteObject["path"];
|
||||
id?: AgnosticIndexRouteObject["id"];
|
||||
loader?: AgnosticIndexRouteObject["loader"];
|
||||
action?: AgnosticIndexRouteObject["action"];
|
||||
hasErrorBoundary?: AgnosticIndexRouteObject["hasErrorBoundary"];
|
||||
shouldRevalidate?: AgnosticIndexRouteObject["shouldRevalidate"];
|
||||
handle?: AgnosticIndexRouteObject["handle"];
|
||||
index: true;
|
||||
children?: undefined;
|
||||
element?: React.ReactNode | null;
|
||||
hydrateFallbackElement?: React.ReactNode | null;
|
||||
errorElement?: React.ReactNode | null;
|
||||
Component?: React.ComponentType | null;
|
||||
HydrateFallback?: React.ComponentType | null;
|
||||
ErrorBoundary?: React.ComponentType | null;
|
||||
lazy?: LazyRouteFunction<RouteObject>;
|
||||
}
|
||||
export interface NonIndexRouteObject {
|
||||
caseSensitive?: AgnosticNonIndexRouteObject["caseSensitive"];
|
||||
path?: AgnosticNonIndexRouteObject["path"];
|
||||
id?: AgnosticNonIndexRouteObject["id"];
|
||||
loader?: AgnosticNonIndexRouteObject["loader"];
|
||||
action?: AgnosticNonIndexRouteObject["action"];
|
||||
hasErrorBoundary?: AgnosticNonIndexRouteObject["hasErrorBoundary"];
|
||||
shouldRevalidate?: AgnosticNonIndexRouteObject["shouldRevalidate"];
|
||||
handle?: AgnosticNonIndexRouteObject["handle"];
|
||||
index?: false;
|
||||
children?: RouteObject[];
|
||||
element?: React.ReactNode | null;
|
||||
hydrateFallbackElement?: React.ReactNode | null;
|
||||
errorElement?: React.ReactNode | null;
|
||||
Component?: React.ComponentType | null;
|
||||
HydrateFallback?: React.ComponentType | null;
|
||||
ErrorBoundary?: React.ComponentType | null;
|
||||
lazy?: LazyRouteFunction<RouteObject>;
|
||||
}
|
||||
export type RouteObject = IndexRouteObject | NonIndexRouteObject;
|
||||
export type DataRouteObject = RouteObject & {
|
||||
children?: DataRouteObject[];
|
||||
id: string;
|
||||
};
|
||||
export interface RouteMatch<ParamKey extends string = string, RouteObjectType extends RouteObject = RouteObject> extends AgnosticRouteMatch<ParamKey, RouteObjectType> {
|
||||
}
|
||||
export interface DataRouteMatch extends RouteMatch<string, DataRouteObject> {
|
||||
}
|
||||
export interface DataRouterContextObject extends Omit<NavigationContextObject, "future"> {
|
||||
router: Router;
|
||||
staticContext?: StaticHandlerContext;
|
||||
}
|
||||
export declare const DataRouterContext: React.Context<DataRouterContextObject | null>;
|
||||
export declare const DataRouterStateContext: React.Context<import("@remix-run/router").RouterState | null>;
|
||||
export declare const AwaitContext: React.Context<TrackedPromise | null>;
|
||||
export interface NavigateOptions {
|
||||
replace?: boolean;
|
||||
state?: any;
|
||||
preventScrollReset?: boolean;
|
||||
relative?: RelativeRoutingType;
|
||||
flushSync?: boolean;
|
||||
viewTransition?: boolean;
|
||||
}
|
||||
/**
|
||||
* A Navigator is a "location changer"; it's how you get to different locations.
|
||||
*
|
||||
* Every history instance conforms to the Navigator interface, but the
|
||||
* distinction is useful primarily when it comes to the low-level `<Router>` API
|
||||
* where both the location and a navigator must be provided separately in order
|
||||
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
||||
* and/or location were to be read directly from the history instance.
|
||||
*/
|
||||
export interface Navigator {
|
||||
createHref: History["createHref"];
|
||||
encodeLocation?: History["encodeLocation"];
|
||||
go: History["go"];
|
||||
push(to: To, state?: any, opts?: NavigateOptions): void;
|
||||
replace(to: To, state?: any, opts?: NavigateOptions): void;
|
||||
}
|
||||
interface NavigationContextObject {
|
||||
basename: string;
|
||||
navigator: Navigator;
|
||||
static: boolean;
|
||||
future: {
|
||||
v7_relativeSplatPath: boolean;
|
||||
};
|
||||
}
|
||||
export declare const NavigationContext: React.Context<NavigationContextObject>;
|
||||
interface LocationContextObject {
|
||||
location: Location;
|
||||
navigationType: NavigationType;
|
||||
}
|
||||
export declare const LocationContext: React.Context<LocationContextObject>;
|
||||
export interface RouteContextObject {
|
||||
outlet: React.ReactElement | null;
|
||||
matches: RouteMatch[];
|
||||
isDataRoute: boolean;
|
||||
}
|
||||
export declare const RouteContext: React.Context<RouteContextObject>;
|
||||
export declare const RouteErrorContext: React.Context<any>;
|
||||
export {};
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { FutureConfig as RouterFutureConfig } from "@remix-run/router";
|
||||
import type { FutureConfig as RenderFutureConfig } from "./components";
|
||||
export declare function warnOnce(key: string, message: string): void;
|
||||
export declare function logV6DeprecationWarnings(renderFuture: Partial<RenderFutureConfig> | undefined, routerFuture?: Omit<RouterFutureConfig, "v7_prependBasename">): void;
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
import * as React from "react";
|
||||
import type { Blocker, BlockerFunction, Location, ParamParseKey, Params, Path, PathMatch, PathPattern, RelativeRoutingType, Router as RemixRouter, RevalidationState, To, UIMatch } from "@remix-run/router";
|
||||
import { Action as NavigationType } from "@remix-run/router";
|
||||
import type { NavigateOptions, RouteContextObject, RouteMatch, RouteObject } from "./context";
|
||||
/**
|
||||
* Returns the full href for the given "to" value. This is useful for building
|
||||
* custom links that are also accessible and preserve right-click behavior.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-href
|
||||
*/
|
||||
export declare function useHref(to: To, { relative }?: {
|
||||
relative?: RelativeRoutingType;
|
||||
}): string;
|
||||
/**
|
||||
* Returns true if this component is a descendant of a `<Router>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-in-router-context
|
||||
*/
|
||||
export declare function useInRouterContext(): boolean;
|
||||
/**
|
||||
* Returns the current location object, which represents the current URL in web
|
||||
* browsers.
|
||||
*
|
||||
* Note: If you're using this it may mean you're doing some of your own
|
||||
* "routing" in your app, and we'd like to know what your use case is. We may
|
||||
* be able to provide something higher-level to better suit your needs.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-location
|
||||
*/
|
||||
export declare function useLocation(): Location;
|
||||
/**
|
||||
* Returns the current navigation action which describes how the router came to
|
||||
* the current location, either by a pop, push, or replace on the history stack.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigation-type
|
||||
*/
|
||||
export declare function useNavigationType(): NavigationType;
|
||||
/**
|
||||
* Returns a PathMatch object if the given pattern matches the current URL.
|
||||
* This is useful for components that need to know "active" state, e.g.
|
||||
* `<NavLink>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-match
|
||||
*/
|
||||
export declare function useMatch<ParamKey extends ParamParseKey<Path>, Path extends string>(pattern: PathPattern<Path> | Path): PathMatch<ParamKey> | null;
|
||||
/**
|
||||
* The interface for the navigate() function returned from useNavigate().
|
||||
*/
|
||||
export interface NavigateFunction {
|
||||
(to: To, options?: NavigateOptions): void;
|
||||
(delta: number): void;
|
||||
}
|
||||
/**
|
||||
* Returns an imperative method for changing the location. Used by `<Link>`s, but
|
||||
* may also be used by other elements to change the location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigate
|
||||
*/
|
||||
export declare function useNavigate(): NavigateFunction;
|
||||
/**
|
||||
* Returns the context (if provided) for the child route at this level of the route
|
||||
* hierarchy.
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet-context
|
||||
*/
|
||||
export declare function useOutletContext<Context = unknown>(): Context;
|
||||
/**
|
||||
* Returns the element for the child route at this level of the route
|
||||
* hierarchy. Used internally by `<Outlet>` to render child routes.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet
|
||||
*/
|
||||
export declare function useOutlet(context?: unknown): React.ReactElement | null;
|
||||
/**
|
||||
* Returns an object of key/value pairs of the dynamic params from the current
|
||||
* URL that were matched by the route path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-params
|
||||
*/
|
||||
export declare function useParams<ParamsOrKey extends string | Record<string, string | undefined> = string>(): Readonly<[
|
||||
ParamsOrKey
|
||||
] extends [string] ? Params<ParamsOrKey> : Partial<ParamsOrKey>>;
|
||||
/**
|
||||
* Resolves the pathname of the given `to` value against the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-resolved-path
|
||||
*/
|
||||
export declare function useResolvedPath(to: To, { relative }?: {
|
||||
relative?: RelativeRoutingType;
|
||||
}): Path;
|
||||
/**
|
||||
* Returns the element of the route that matched the current location, prepared
|
||||
* with the correct context to render the remainder of the route tree. Route
|
||||
* elements in the tree must render an `<Outlet>` to render their child route's
|
||||
* element.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-routes
|
||||
*/
|
||||
export declare function useRoutes(routes: RouteObject[], locationArg?: Partial<Location> | string): React.ReactElement | null;
|
||||
export declare function useRoutesImpl(routes: RouteObject[], locationArg?: Partial<Location> | string, dataRouterState?: RemixRouter["state"], future?: RemixRouter["future"]): React.ReactElement | null;
|
||||
type RenderErrorBoundaryProps = React.PropsWithChildren<{
|
||||
location: Location;
|
||||
revalidation: RevalidationState;
|
||||
error: any;
|
||||
component: React.ReactNode;
|
||||
routeContext: RouteContextObject;
|
||||
}>;
|
||||
type RenderErrorBoundaryState = {
|
||||
location: Location;
|
||||
revalidation: RevalidationState;
|
||||
error: any;
|
||||
};
|
||||
export declare class RenderErrorBoundary extends React.Component<RenderErrorBoundaryProps, RenderErrorBoundaryState> {
|
||||
constructor(props: RenderErrorBoundaryProps);
|
||||
static getDerivedStateFromError(error: any): {
|
||||
error: any;
|
||||
};
|
||||
static getDerivedStateFromProps(props: RenderErrorBoundaryProps, state: RenderErrorBoundaryState): {
|
||||
error: any;
|
||||
location: Location<any>;
|
||||
revalidation: RevalidationState;
|
||||
};
|
||||
componentDidCatch(error: any, errorInfo: any): void;
|
||||
render(): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
|
||||
}
|
||||
export declare function _renderMatches(matches: RouteMatch[] | null, parentMatches?: RouteMatch[], dataRouterState?: RemixRouter["state"] | null, future?: RemixRouter["future"] | null): React.ReactElement | null;
|
||||
/**
|
||||
* Returns the ID for the nearest contextual route
|
||||
*/
|
||||
export declare function useRouteId(): string;
|
||||
/**
|
||||
* Returns the current navigation, defaulting to an "idle" navigation when
|
||||
* no navigation is in progress
|
||||
*/
|
||||
export declare function useNavigation(): import("@remix-run/router").Navigation;
|
||||
/**
|
||||
* Returns a revalidate function for manually triggering revalidation, as well
|
||||
* as the current state of any manual revalidations
|
||||
*/
|
||||
export declare function useRevalidator(): {
|
||||
revalidate: () => void;
|
||||
state: RevalidationState;
|
||||
};
|
||||
/**
|
||||
* Returns the active route matches, useful for accessing loaderData for
|
||||
* parent/child routes or the route "handle" property
|
||||
*/
|
||||
export declare function useMatches(): UIMatch[];
|
||||
/**
|
||||
* Returns the loader data for the nearest ancestor Route loader
|
||||
*/
|
||||
export declare function useLoaderData(): unknown;
|
||||
/**
|
||||
* Returns the loaderData for the given routeId
|
||||
*/
|
||||
export declare function useRouteLoaderData(routeId: string): unknown;
|
||||
/**
|
||||
* Returns the action data for the nearest ancestor Route action
|
||||
*/
|
||||
export declare function useActionData(): unknown;
|
||||
/**
|
||||
* Returns the nearest ancestor Route error, which could be a loader/action
|
||||
* error or a render error. This is intended to be called from your
|
||||
* ErrorBoundary/errorElement to display a proper error message.
|
||||
*/
|
||||
export declare function useRouteError(): unknown;
|
||||
/**
|
||||
* Returns the happy-path data from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
export declare function useAsyncValue(): unknown;
|
||||
/**
|
||||
* Returns the error from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
export declare function useAsyncError(): unknown;
|
||||
/**
|
||||
* Allow the application to block navigations within the SPA and present the
|
||||
* user a confirmation dialog to confirm the navigation. Mostly used to avoid
|
||||
* using half-filled form data. This does not handle hard-reloads or
|
||||
* cross-origin navigations.
|
||||
*/
|
||||
export declare function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker;
|
||||
export {};
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* React Router v6.30.4
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
module.exports = require("./umd/react-router.production.min.js");
|
||||
} else {
|
||||
module.exports = require("./umd/react-router.development.js");
|
||||
}
|
||||
+1396
@@ -0,0 +1,1396 @@
|
||||
/**
|
||||
* React Router v6.30.4
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_decodePath, UNSAFE_getResolveToMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router';
|
||||
export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, resolvePath } from '@remix-run/router';
|
||||
|
||||
const DataRouterContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
DataRouterContext.displayName = "DataRouter";
|
||||
}
|
||||
const DataRouterStateContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
DataRouterStateContext.displayName = "DataRouterState";
|
||||
}
|
||||
const AwaitContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
AwaitContext.displayName = "Await";
|
||||
}
|
||||
const NavigationContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
NavigationContext.displayName = "Navigation";
|
||||
}
|
||||
const LocationContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
LocationContext.displayName = "Location";
|
||||
}
|
||||
const RouteContext = /*#__PURE__*/React.createContext({
|
||||
outlet: null,
|
||||
matches: [],
|
||||
isDataRoute: false
|
||||
});
|
||||
{
|
||||
RouteContext.displayName = "Route";
|
||||
}
|
||||
const RouteErrorContext = /*#__PURE__*/React.createContext(null);
|
||||
{
|
||||
RouteErrorContext.displayName = "RouteError";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full href for the given "to" value. This is useful for building
|
||||
* custom links that are also accessible and preserve right-click behavior.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-href
|
||||
*/
|
||||
function useHref(to, {
|
||||
relative
|
||||
} = {}) {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
`useHref() may be used only in the context of a <Router> component.`) : void 0;
|
||||
let {
|
||||
basename,
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
hash,
|
||||
pathname,
|
||||
search
|
||||
} = useResolvedPath(to, {
|
||||
relative
|
||||
});
|
||||
let joinedPathname = pathname;
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to creating the href. If this is a root navigation, then just use the raw
|
||||
// basename which allows the basename to have full control over the presence
|
||||
// of a trailing slash on root links
|
||||
if (basename !== "/") {
|
||||
joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
|
||||
}
|
||||
return navigator.createHref({
|
||||
pathname: joinedPathname,
|
||||
search,
|
||||
hash
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Returns true if this component is a descendant of a `<Router>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-in-router-context
|
||||
*/
|
||||
function useInRouterContext() {
|
||||
return React.useContext(LocationContext) != null;
|
||||
}
|
||||
/**
|
||||
* Returns the current location object, which represents the current URL in web
|
||||
* browsers.
|
||||
*
|
||||
* Note: If you're using this it may mean you're doing some of your own
|
||||
* "routing" in your app, and we'd like to know what your use case is. We may
|
||||
* be able to provide something higher-level to better suit your needs.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-location
|
||||
*/
|
||||
function useLocation() {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
`useLocation() may be used only in the context of a <Router> component.`) : void 0;
|
||||
return React.useContext(LocationContext).location;
|
||||
}
|
||||
/**
|
||||
* Returns the current navigation action which describes how the router came to
|
||||
* the current location, either by a pop, push, or replace on the history stack.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigation-type
|
||||
*/
|
||||
function useNavigationType() {
|
||||
return React.useContext(LocationContext).navigationType;
|
||||
}
|
||||
/**
|
||||
* Returns a PathMatch object if the given pattern matches the current URL.
|
||||
* This is useful for components that need to know "active" state, e.g.
|
||||
* `<NavLink>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-match
|
||||
*/
|
||||
function useMatch(pattern) {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
`useMatch() may be used only in the context of a <Router> component.`) : void 0;
|
||||
let {
|
||||
pathname
|
||||
} = useLocation();
|
||||
return React.useMemo(() => matchPath(pattern, UNSAFE_decodePath(pathname)), [pathname, pattern]);
|
||||
}
|
||||
const navigateEffectWarning = `You should call navigate() in a React.useEffect(), not when ` + `your component is first rendered.`;
|
||||
// Mute warnings for calls to useNavigate in SSR environments
|
||||
function useIsomorphicLayoutEffect(cb) {
|
||||
let isStatic = React.useContext(NavigationContext).static;
|
||||
if (!isStatic) {
|
||||
// We should be able to get rid of this once react 18.3 is released
|
||||
// See: https://github.com/facebook/react/pull/26395
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
React.useLayoutEffect(cb);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns an imperative method for changing the location. Used by `<Link>`s, but
|
||||
* may also be used by other elements to change the location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigate
|
||||
*/
|
||||
function useNavigate() {
|
||||
let {
|
||||
isDataRoute
|
||||
} = React.useContext(RouteContext);
|
||||
// Conditional usage is OK here because the usage of a data router is static
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
return isDataRoute ? useNavigateStable() : useNavigateUnstable();
|
||||
}
|
||||
function useNavigateUnstable() {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
`useNavigate() may be used only in the context of a <Router> component.`) : void 0;
|
||||
let dataRouterContext = React.useContext(DataRouterContext);
|
||||
let {
|
||||
basename,
|
||||
future,
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
let activeRef = React.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React.useCallback((to, options = {}) => {
|
||||
UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our history listener yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
navigator.go(to);
|
||||
return;
|
||||
}
|
||||
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to handing off to history (but only if we're not in a data router,
|
||||
// otherwise it'll prepend the basename inside of the router).
|
||||
// If this is a root navigation, then we navigate to the raw basename
|
||||
// which allows the basename to have full control over the presence of a
|
||||
// trailing slash on root links
|
||||
if (dataRouterContext == null && basename !== "/") {
|
||||
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
||||
}
|
||||
(!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
|
||||
}, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]);
|
||||
return navigate;
|
||||
}
|
||||
const OutletContext = /*#__PURE__*/React.createContext(null);
|
||||
/**
|
||||
* Returns the context (if provided) for the child route at this level of the route
|
||||
* hierarchy.
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet-context
|
||||
*/
|
||||
function useOutletContext() {
|
||||
return React.useContext(OutletContext);
|
||||
}
|
||||
/**
|
||||
* Returns the element for the child route at this level of the route
|
||||
* hierarchy. Used internally by `<Outlet>` to render child routes.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet
|
||||
*/
|
||||
function useOutlet(context) {
|
||||
let outlet = React.useContext(RouteContext).outlet;
|
||||
if (outlet) {
|
||||
return /*#__PURE__*/React.createElement(OutletContext.Provider, {
|
||||
value: context
|
||||
}, outlet);
|
||||
}
|
||||
return outlet;
|
||||
}
|
||||
/**
|
||||
* Returns an object of key/value pairs of the dynamic params from the current
|
||||
* URL that were matched by the route path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-params
|
||||
*/
|
||||
function useParams() {
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let routeMatch = matches[matches.length - 1];
|
||||
return routeMatch ? routeMatch.params : {};
|
||||
}
|
||||
/**
|
||||
* Resolves the pathname of the given `to` value against the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-resolved-path
|
||||
*/
|
||||
function useResolvedPath(to, {
|
||||
relative
|
||||
} = {}) {
|
||||
let {
|
||||
future
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
|
||||
}
|
||||
/**
|
||||
* Returns the element of the route that matched the current location, prepared
|
||||
* with the correct context to render the remainder of the route tree. Route
|
||||
* elements in the tree must render an `<Outlet>` to render their child route's
|
||||
* element.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-routes
|
||||
*/
|
||||
function useRoutes(routes, locationArg) {
|
||||
return useRoutesImpl(routes, locationArg);
|
||||
}
|
||||
// Internal implementation with accept optional param for RouterProvider usage
|
||||
function useRoutesImpl(routes, locationArg, dataRouterState, future) {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
`useRoutes() may be used only in the context of a <Router> component.`) : void 0;
|
||||
let {
|
||||
navigator
|
||||
} = React.useContext(NavigationContext);
|
||||
let {
|
||||
matches: parentMatches
|
||||
} = React.useContext(RouteContext);
|
||||
let routeMatch = parentMatches[parentMatches.length - 1];
|
||||
let parentParams = routeMatch ? routeMatch.params : {};
|
||||
let parentPathname = routeMatch ? routeMatch.pathname : "/";
|
||||
let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
||||
let parentRoute = routeMatch && routeMatch.route;
|
||||
{
|
||||
// You won't get a warning about 2 different <Routes> under a <Route>
|
||||
// without a trailing *, but this is a best-effort warning anyway since we
|
||||
// cannot even give the warning unless they land at the parent route.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// <Routes>
|
||||
// {/* This route path MUST end with /* because otherwise
|
||||
// it will never match /blog/post/123 */}
|
||||
// <Route path="blog" element={<Blog />} />
|
||||
// <Route path="blog/feed" element={<BlogFeed />} />
|
||||
// </Routes>
|
||||
//
|
||||
// function Blog() {
|
||||
// return (
|
||||
// <Routes>
|
||||
// <Route path="post/:id" element={<Post />} />
|
||||
// </Routes>
|
||||
// );
|
||||
// }
|
||||
let parentPath = parentRoute && parentRoute.path || "";
|
||||
warningOnce(parentPathname, !parentRoute || parentPath.endsWith("*"), `You rendered descendant <Routes> (or called \`useRoutes()\`) at ` + `"${parentPathname}" (under <Route path="${parentPath}">) but the ` + `parent route path has no trailing "*". This means if you navigate ` + `deeper, the parent won't match anymore and therefore the child ` + `routes will never render.\n\n` + `Please change the parent <Route path="${parentPath}"> to <Route ` + `path="${parentPath === "/" ? "*" : `${parentPath}/*`}">.`);
|
||||
}
|
||||
let locationFromContext = useLocation();
|
||||
let location;
|
||||
if (locationArg) {
|
||||
let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
||||
!(parentPathnameBase === "/" || parsedLocationArg.pathname?.startsWith(parentPathnameBase)) ? UNSAFE_invariant(false, `When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, ` + `the location pathname must begin with the portion of the URL pathname that was ` + `matched by all parent routes. The current pathname base is "${parentPathnameBase}" ` + `but pathname "${parsedLocationArg.pathname}" was given in the \`location\` prop.`) : void 0;
|
||||
location = parsedLocationArg;
|
||||
} else {
|
||||
location = locationFromContext;
|
||||
}
|
||||
let pathname = location.pathname || "/";
|
||||
let remainingPathname = pathname;
|
||||
if (parentPathnameBase !== "/") {
|
||||
// Determine the remaining pathname by removing the # of URL segments the
|
||||
// parentPathnameBase has, instead of removing based on character count.
|
||||
// This is because we can't guarantee that incoming/outgoing encodings/
|
||||
// decodings will match exactly.
|
||||
// We decode paths before matching on a per-segment basis with
|
||||
// decodeURIComponent(), but we re-encode pathnames via `new URL()` so they
|
||||
// match what `window.location.pathname` would reflect. Those don't 100%
|
||||
// align when it comes to encoded URI characters such as % and &.
|
||||
//
|
||||
// So we may end up with:
|
||||
// pathname: "/descendant/a%25b/match"
|
||||
// parentPathnameBase: "/descendant/a%b"
|
||||
//
|
||||
// And the direct substring removal approach won't work :/
|
||||
let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
|
||||
let segments = pathname.replace(/^\//, "").split("/");
|
||||
remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
|
||||
}
|
||||
let matches = matchRoutes(routes, {
|
||||
pathname: remainingPathname
|
||||
});
|
||||
{
|
||||
UNSAFE_warning(parentRoute || matches != null, `No routes matched location "${location.pathname}${location.search}${location.hash}" `) ;
|
||||
UNSAFE_warning(matches == null || matches[matches.length - 1].route.element !== undefined || matches[matches.length - 1].route.Component !== undefined || matches[matches.length - 1].route.lazy !== undefined, `Matched leaf route at location "${location.pathname}${location.search}${location.hash}" ` + `does not have an element or Component. This means it will render an <Outlet /> with a ` + `null value by default resulting in an "empty" page.`) ;
|
||||
}
|
||||
let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
||||
params: Object.assign({}, parentParams, match.params),
|
||||
pathname: joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathname).pathname : match.pathname]),
|
||||
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
|
||||
})), parentMatches, dataRouterState, future);
|
||||
// When a user passes in a `locationArg`, the associated routes need to
|
||||
// be wrapped in a new `LocationContext.Provider` in order for `useLocation`
|
||||
// to use the scoped location instead of the global location.
|
||||
if (locationArg && renderedMatches) {
|
||||
return /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
||||
value: {
|
||||
location: {
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
state: null,
|
||||
key: "default",
|
||||
...location
|
||||
},
|
||||
navigationType: Action.Pop
|
||||
}
|
||||
}, renderedMatches);
|
||||
}
|
||||
return renderedMatches;
|
||||
}
|
||||
function DefaultErrorComponent() {
|
||||
let error = useRouteError();
|
||||
let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
|
||||
let stack = error instanceof Error ? error.stack : null;
|
||||
let lightgrey = "rgba(200,200,200, 0.5)";
|
||||
let preStyles = {
|
||||
padding: "0.5rem",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let codeStyles = {
|
||||
padding: "2px 4px",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let devInfo = null;
|
||||
{
|
||||
console.error("Error handled by React Router default ErrorBoundary:", error);
|
||||
devInfo = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", null, "\uD83D\uDCBF Hey developer \uD83D\uDC4B"), /*#__PURE__*/React.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own ", /*#__PURE__*/React.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "ErrorBoundary"), " or", " ", /*#__PURE__*/React.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "errorElement"), " prop on your route."));
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h2", null, "Unexpected Application Error!"), /*#__PURE__*/React.createElement("h3", {
|
||||
style: {
|
||||
fontStyle: "italic"
|
||||
}
|
||||
}, message), stack ? /*#__PURE__*/React.createElement("pre", {
|
||||
style: preStyles
|
||||
}, stack) : null, devInfo);
|
||||
}
|
||||
const defaultErrorElement = /*#__PURE__*/React.createElement(DefaultErrorComponent, null);
|
||||
class RenderErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
location: props.location,
|
||||
revalidation: props.revalidation,
|
||||
error: props.error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error: error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
// When we get into an error state, the user will likely click "back" to the
|
||||
// previous page that didn't have an error. Because this wraps the entire
|
||||
// application, that will have no effect--the error page continues to display.
|
||||
// This gives us a mechanism to recover from the error when the location changes.
|
||||
//
|
||||
// Whether we're in an error state or not, we update the location in state
|
||||
// so that when we are in an error state, it gets reset when a new location
|
||||
// comes in and the user recovers from the error.
|
||||
if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
|
||||
return {
|
||||
error: props.error,
|
||||
location: props.location,
|
||||
revalidation: props.revalidation
|
||||
};
|
||||
}
|
||||
// If we're not changing locations, preserve the location but still surface
|
||||
// any new errors that may come through. We retain the existing error, we do
|
||||
// this because the error provided from the app state may be cleared without
|
||||
// the location changing.
|
||||
return {
|
||||
error: props.error !== undefined ? props.error : state.error,
|
||||
location: state.location,
|
||||
revalidation: props.revalidation || state.revalidation
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("React Router caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
return this.state.error !== undefined ? (/*#__PURE__*/React.createElement(RouteContext.Provider, {
|
||||
value: this.props.routeContext
|
||||
}, /*#__PURE__*/React.createElement(RouteErrorContext.Provider, {
|
||||
value: this.state.error,
|
||||
children: this.props.component
|
||||
}))) : this.props.children;
|
||||
}
|
||||
}
|
||||
function RenderedRoute({
|
||||
routeContext,
|
||||
match,
|
||||
children
|
||||
}) {
|
||||
let dataRouterContext = React.useContext(DataRouterContext);
|
||||
// Track how deep we got in our render pass to emulate SSR componentDidCatch
|
||||
// in a DataStaticRouter
|
||||
if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
|
||||
dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
||||
value: routeContext
|
||||
}, children);
|
||||
}
|
||||
function _renderMatches(matches, parentMatches = [], dataRouterState = null, future = null) {
|
||||
if (matches == null) {
|
||||
if (!dataRouterState) {
|
||||
return null;
|
||||
}
|
||||
if (dataRouterState.errors) {
|
||||
// Don't bail if we have data router errors so we can render them in the
|
||||
// boundary. Use the pre-matched (or shimmed) matches
|
||||
matches = dataRouterState.matches;
|
||||
} else if (future?.v7_partialHydration && parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
|
||||
// Don't bail if we're initializing with partial hydration and we have
|
||||
// router matches. That means we're actively running `patchRoutesOnNavigation`
|
||||
// so we should render down the partial matches to the appropriate
|
||||
// `HydrateFallback`. We only do this if `parentMatches` is empty so it
|
||||
// only impacts the root matches for `RouterProvider` and no descendant
|
||||
// `<Routes>`
|
||||
matches = dataRouterState.matches;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let renderedMatches = matches;
|
||||
// If we have data errors, trim matches to the highest error boundary
|
||||
let errors = dataRouterState?.errors;
|
||||
if (errors != null) {
|
||||
let errorIndex = renderedMatches.findIndex(m => m.route.id && errors?.[m.route.id] !== undefined);
|
||||
!(errorIndex >= 0) ? UNSAFE_invariant(false, `Could not find a matching route for errors on route IDs: ${Object.keys(errors).join(",")}`) : void 0;
|
||||
renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
|
||||
}
|
||||
// If we're in a partial hydration mode, detect if we need to render down to
|
||||
// a given HydrateFallback while we load the rest of the hydration data
|
||||
let renderFallback = false;
|
||||
let fallbackIndex = -1;
|
||||
if (dataRouterState && future && future.v7_partialHydration) {
|
||||
for (let i = 0; i < renderedMatches.length; i++) {
|
||||
let match = renderedMatches[i];
|
||||
// Track the deepest fallback up until the first route without data
|
||||
if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
|
||||
fallbackIndex = i;
|
||||
}
|
||||
if (match.route.id) {
|
||||
let {
|
||||
loaderData,
|
||||
errors: _errors
|
||||
} = dataRouterState;
|
||||
let needsToRunLoader = match.route.loader && loaderData[match.route.id] === undefined && (!_errors || _errors[match.route.id] === undefined);
|
||||
if (match.route.lazy || needsToRunLoader) {
|
||||
// We found the first route that's not ready to render (waiting on
|
||||
// lazy, or has a loader that hasn't run yet). Flag that we need to
|
||||
// render a fallback and render up until the appropriate fallback
|
||||
renderFallback = true;
|
||||
if (fallbackIndex >= 0) {
|
||||
renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
|
||||
} else {
|
||||
renderedMatches = [renderedMatches[0]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderedMatches.reduceRight((outlet, match, index) => {
|
||||
// Only data routers handle errors/fallbacks
|
||||
let error;
|
||||
let shouldRenderHydrateFallback = false;
|
||||
let errorElement = null;
|
||||
let hydrateFallbackElement = null;
|
||||
if (dataRouterState) {
|
||||
error = errors && match.route.id ? errors[match.route.id] : undefined;
|
||||
errorElement = match.route.errorElement || defaultErrorElement;
|
||||
if (renderFallback) {
|
||||
if (fallbackIndex < 0 && index === 0) {
|
||||
warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration");
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = null;
|
||||
} else if (fallbackIndex === index) {
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = match.route.hydrateFallbackElement || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
|
||||
let getChildren = () => {
|
||||
let children;
|
||||
if (error) {
|
||||
children = errorElement;
|
||||
} else if (shouldRenderHydrateFallback) {
|
||||
children = hydrateFallbackElement;
|
||||
} else if (match.route.Component) {
|
||||
// Note: This is a de-optimized path since React won't re-use the
|
||||
// ReactElement since it's identity changes with each new
|
||||
// React.createElement call. We keep this so folks can use
|
||||
// `<Route Component={...}>` in `<Routes>` but generally `Component`
|
||||
// usage is only advised in `RouterProvider` when we can convert it to
|
||||
// `element` ahead of time.
|
||||
children = /*#__PURE__*/React.createElement(match.route.Component, null);
|
||||
} else if (match.route.element) {
|
||||
children = match.route.element;
|
||||
} else {
|
||||
children = outlet;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(RenderedRoute, {
|
||||
match: match,
|
||||
routeContext: {
|
||||
outlet,
|
||||
matches,
|
||||
isDataRoute: dataRouterState != null
|
||||
},
|
||||
children: children
|
||||
});
|
||||
};
|
||||
// Only wrap in an error boundary within data router usages when we have an
|
||||
// ErrorBoundary/errorElement on this route. Otherwise let it bubble up to
|
||||
// an ancestor ErrorBoundary/errorElement
|
||||
return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? (/*#__PURE__*/React.createElement(RenderErrorBoundary, {
|
||||
location: dataRouterState.location,
|
||||
revalidation: dataRouterState.revalidation,
|
||||
component: errorElement,
|
||||
error: error,
|
||||
children: getChildren(),
|
||||
routeContext: {
|
||||
outlet: null,
|
||||
matches,
|
||||
isDataRoute: true
|
||||
}
|
||||
})) : getChildren();
|
||||
}, null);
|
||||
}
|
||||
var DataRouterHook;
|
||||
(function (DataRouterHook) {
|
||||
DataRouterHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterHook["UseNavigateStable"] = "useNavigate";
|
||||
})(DataRouterHook || (DataRouterHook = {}));
|
||||
var DataRouterStateHook;
|
||||
(function (DataRouterStateHook) {
|
||||
DataRouterStateHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterStateHook["UseLoaderData"] = "useLoaderData";
|
||||
DataRouterStateHook["UseActionData"] = "useActionData";
|
||||
DataRouterStateHook["UseRouteError"] = "useRouteError";
|
||||
DataRouterStateHook["UseNavigation"] = "useNavigation";
|
||||
DataRouterStateHook["UseRouteLoaderData"] = "useRouteLoaderData";
|
||||
DataRouterStateHook["UseMatches"] = "useMatches";
|
||||
DataRouterStateHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterStateHook["UseNavigateStable"] = "useNavigate";
|
||||
DataRouterStateHook["UseRouteId"] = "useRouteId";
|
||||
})(DataRouterStateHook || (DataRouterStateHook = {}));
|
||||
function getDataRouterConsoleError(hookName) {
|
||||
return `${hookName} must be used within a data router. See https://reactrouter.com/v6/routers/picking-a-router.`;
|
||||
}
|
||||
function useDataRouterContext(hookName) {
|
||||
let ctx = React.useContext(DataRouterContext);
|
||||
!ctx ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return ctx;
|
||||
}
|
||||
function useDataRouterState(hookName) {
|
||||
let state = React.useContext(DataRouterStateContext);
|
||||
!state ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return state;
|
||||
}
|
||||
function useRouteContext(hookName) {
|
||||
let route = React.useContext(RouteContext);
|
||||
!route ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return route;
|
||||
}
|
||||
// Internal version with hookName-aware debugging
|
||||
function useCurrentRouteId(hookName) {
|
||||
let route = useRouteContext(hookName);
|
||||
let thisRoute = route.matches[route.matches.length - 1];
|
||||
!thisRoute.route.id ? UNSAFE_invariant(false, `${hookName} can only be used on routes that contain a unique "id"`) : void 0;
|
||||
return thisRoute.route.id;
|
||||
}
|
||||
/**
|
||||
* Returns the ID for the nearest contextual route
|
||||
*/
|
||||
function useRouteId() {
|
||||
return useCurrentRouteId(DataRouterStateHook.UseRouteId);
|
||||
}
|
||||
/**
|
||||
* Returns the current navigation, defaulting to an "idle" navigation when
|
||||
* no navigation is in progress
|
||||
*/
|
||||
function useNavigation() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseNavigation);
|
||||
return state.navigation;
|
||||
}
|
||||
/**
|
||||
* Returns a revalidate function for manually triggering revalidation, as well
|
||||
* as the current state of any manual revalidations
|
||||
*/
|
||||
function useRevalidator() {
|
||||
let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRevalidator);
|
||||
return React.useMemo(() => ({
|
||||
revalidate: dataRouterContext.router.revalidate,
|
||||
state: state.revalidation
|
||||
}), [dataRouterContext.router.revalidate, state.revalidation]);
|
||||
}
|
||||
/**
|
||||
* Returns the active route matches, useful for accessing loaderData for
|
||||
* parent/child routes or the route "handle" property
|
||||
*/
|
||||
function useMatches() {
|
||||
let {
|
||||
matches,
|
||||
loaderData
|
||||
} = useDataRouterState(DataRouterStateHook.UseMatches);
|
||||
return React.useMemo(() => matches.map(m => UNSAFE_convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
|
||||
}
|
||||
/**
|
||||
* Returns the loader data for the nearest ancestor Route loader
|
||||
*/
|
||||
function useLoaderData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseLoaderData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
if (state.errors && state.errors[routeId] != null) {
|
||||
console.error(`You cannot \`useLoaderData\` in an errorElement (routeId: ${routeId})`);
|
||||
return undefined;
|
||||
}
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
/**
|
||||
* Returns the loaderData for the given routeId
|
||||
*/
|
||||
function useRouteLoaderData(routeId) {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
/**
|
||||
* Returns the action data for the nearest ancestor Route action
|
||||
*/
|
||||
function useActionData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseActionData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
return state.actionData ? state.actionData[routeId] : undefined;
|
||||
}
|
||||
/**
|
||||
* Returns the nearest ancestor Route error, which could be a loader/action
|
||||
* error or a render error. This is intended to be called from your
|
||||
* ErrorBoundary/errorElement to display a proper error message.
|
||||
*/
|
||||
function useRouteError() {
|
||||
let error = React.useContext(RouteErrorContext);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteError);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);
|
||||
// If this was a render error, we put it in a RouteError context inside
|
||||
// of RenderErrorBoundary
|
||||
if (error !== undefined) {
|
||||
return error;
|
||||
}
|
||||
// Otherwise look for errors from our data router state
|
||||
return state.errors?.[routeId];
|
||||
}
|
||||
/**
|
||||
* Returns the happy-path data from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncValue() {
|
||||
let value = React.useContext(AwaitContext);
|
||||
return value?._data;
|
||||
}
|
||||
/**
|
||||
* Returns the error from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncError() {
|
||||
let value = React.useContext(AwaitContext);
|
||||
return value?._error;
|
||||
}
|
||||
let blockerId = 0;
|
||||
/**
|
||||
* Allow the application to block navigations within the SPA and present the
|
||||
* user a confirmation dialog to confirm the navigation. Mostly used to avoid
|
||||
* using half-filled form data. This does not handle hard-reloads or
|
||||
* cross-origin navigations.
|
||||
*/
|
||||
function useBlocker(shouldBlock) {
|
||||
let {
|
||||
router,
|
||||
basename
|
||||
} = useDataRouterContext(DataRouterHook.UseBlocker);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseBlocker);
|
||||
let [blockerKey, setBlockerKey] = React.useState("");
|
||||
let blockerFunction = React.useCallback(arg => {
|
||||
if (typeof shouldBlock !== "function") {
|
||||
return !!shouldBlock;
|
||||
}
|
||||
if (basename === "/") {
|
||||
return shouldBlock(arg);
|
||||
}
|
||||
// If they provided us a function and we've got an active basename, strip
|
||||
// it from the locations we expose to the user to match the behavior of
|
||||
// useLocation
|
||||
let {
|
||||
currentLocation,
|
||||
nextLocation,
|
||||
historyAction
|
||||
} = arg;
|
||||
return shouldBlock({
|
||||
currentLocation: {
|
||||
...currentLocation,
|
||||
pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
|
||||
},
|
||||
nextLocation: {
|
||||
...nextLocation,
|
||||
pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
|
||||
},
|
||||
historyAction
|
||||
});
|
||||
}, [basename, shouldBlock]);
|
||||
// This effect is in charge of blocker key assignment and deletion (which is
|
||||
// tightly coupled to the key)
|
||||
React.useEffect(() => {
|
||||
let key = String(++blockerId);
|
||||
setBlockerKey(key);
|
||||
return () => router.deleteBlocker(key);
|
||||
}, [router]);
|
||||
// This effect handles assigning the blockerFunction. This is to handle
|
||||
// unstable blocker function identities, and happens only after the prior
|
||||
// effect so we don't get an orphaned blockerFunction in the router with a
|
||||
// key of "". Until then we just have the IDLE_BLOCKER.
|
||||
React.useEffect(() => {
|
||||
if (blockerKey !== "") {
|
||||
router.getBlocker(blockerKey, blockerFunction);
|
||||
}
|
||||
}, [router, blockerKey, blockerFunction]);
|
||||
// Prefer the blocker from `state` not `router.state` since DataRouterContext
|
||||
// is memoized so this ensures we update on blocker state updates
|
||||
return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
|
||||
}
|
||||
/**
|
||||
* Stable version of useNavigate that is used when we are in the context of
|
||||
* a RouterProvider.
|
||||
*/
|
||||
function useNavigateStable() {
|
||||
let {
|
||||
router
|
||||
} = useDataRouterContext(DataRouterHook.UseNavigateStable);
|
||||
let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
|
||||
let activeRef = React.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React.useCallback((to, options = {}) => {
|
||||
UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our router subscriber yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
router.navigate(to);
|
||||
} else {
|
||||
router.navigate(to, {
|
||||
fromRouteId: id,
|
||||
...options
|
||||
});
|
||||
}
|
||||
}, [router, id]);
|
||||
return navigate;
|
||||
}
|
||||
const alreadyWarned$1 = {};
|
||||
function warningOnce(key, cond, message) {
|
||||
if (!cond && !alreadyWarned$1[key]) {
|
||||
alreadyWarned$1[key] = true;
|
||||
UNSAFE_warning(false, message) ;
|
||||
}
|
||||
}
|
||||
|
||||
const alreadyWarned = {};
|
||||
function warnOnce(key, message) {
|
||||
if (!alreadyWarned[message]) {
|
||||
alreadyWarned[message] = true;
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
const logDeprecation = (flag, msg, link) => warnOnce(flag, `⚠️ React Router Future Flag Warning: ${msg}. ` + `You can use the \`${flag}\` future flag to opt-in early. ` + `For more information, see ${link}.`);
|
||||
function logV6DeprecationWarnings(renderFuture, routerFuture) {
|
||||
if (renderFuture?.v7_startTransition === undefined) {
|
||||
logDeprecation("v7_startTransition", "React Router will begin wrapping state updates in `React.startTransition` in v7", "https://reactrouter.com/v6/upgrading/future#v7_starttransition");
|
||||
}
|
||||
if (renderFuture?.v7_relativeSplatPath === undefined && (!routerFuture || routerFuture.v7_relativeSplatPath === undefined)) {
|
||||
logDeprecation("v7_relativeSplatPath", "Relative route resolution within Splat routes is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_relativesplatpath");
|
||||
}
|
||||
if (routerFuture) {
|
||||
if (routerFuture.v7_fetcherPersist === undefined) {
|
||||
logDeprecation("v7_fetcherPersist", "The persistence behavior of fetchers is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_fetcherpersist");
|
||||
}
|
||||
if (routerFuture.v7_normalizeFormMethod === undefined) {
|
||||
logDeprecation("v7_normalizeFormMethod", "Casing of `formMethod` fields is being normalized to uppercase in v7", "https://reactrouter.com/v6/upgrading/future#v7_normalizeformmethod");
|
||||
}
|
||||
if (routerFuture.v7_partialHydration === undefined) {
|
||||
logDeprecation("v7_partialHydration", "`RouterProvider` hydration behavior is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_partialhydration");
|
||||
}
|
||||
if (routerFuture.v7_skipActionErrorRevalidation === undefined) {
|
||||
logDeprecation("v7_skipActionErrorRevalidation", "The revalidation behavior after 4xx/5xx `action` responses is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_skipactionerrorrevalidation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Webpack + React 17 fails to compile on any of the following because webpack
|
||||
complains that `startTransition` doesn't exist in `React`:
|
||||
* import { startTransition } from "react"
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React.startTransition(() => setState()) : setState()
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React["startTransition"](() => setState()) : setState()
|
||||
|
||||
Moving it to a constant such as the following solves the Webpack/React 17 issue:
|
||||
* import * as React from from "react";
|
||||
const START_TRANSITION = "startTransition";
|
||||
START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()
|
||||
|
||||
However, that introduces webpack/terser minification issues in production builds
|
||||
in React 18 where minification/obfuscation ends up removing the call of
|
||||
React.startTransition entirely from the first half of the ternary. Grabbing
|
||||
this exported reference once up front resolves that issue.
|
||||
|
||||
See https://github.com/remix-run/react-router/issues/10579
|
||||
*/
|
||||
const START_TRANSITION = "startTransition";
|
||||
const startTransitionImpl = React[START_TRANSITION];
|
||||
/**
|
||||
* Given a Remix Router instance, render the appropriate UI
|
||||
*/
|
||||
function RouterProvider({
|
||||
fallbackElement,
|
||||
router,
|
||||
future
|
||||
}) {
|
||||
let [state, setStateImpl] = React.useState(router.state);
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React.useCallback(newState => {
|
||||
if (v7_startTransition && startTransitionImpl) {
|
||||
startTransitionImpl(() => setStateImpl(newState));
|
||||
} else {
|
||||
setStateImpl(newState);
|
||||
}
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
// Need to use a layout effect here so we are subscribed early enough to
|
||||
// pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
|
||||
React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
|
||||
React.useEffect(() => {
|
||||
UNSAFE_warning(fallbackElement == null || !router.future.v7_partialHydration, "`<RouterProvider fallbackElement>` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead") ;
|
||||
// Only log this once on initial mount
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
let navigator = React.useMemo(() => {
|
||||
return {
|
||||
createHref: router.createHref,
|
||||
encodeLocation: router.encodeLocation,
|
||||
go: n => router.navigate(n),
|
||||
push: (to, state, opts) => router.navigate(to, {
|
||||
state,
|
||||
preventScrollReset: opts?.preventScrollReset
|
||||
}),
|
||||
replace: (to, state, opts) => router.navigate(to, {
|
||||
replace: true,
|
||||
state,
|
||||
preventScrollReset: opts?.preventScrollReset
|
||||
})
|
||||
};
|
||||
}, [router]);
|
||||
let basename = router.basename || "/";
|
||||
let dataRouterContext = React.useMemo(() => ({
|
||||
router,
|
||||
navigator,
|
||||
static: false,
|
||||
basename
|
||||
}), [router, navigator, basename]);
|
||||
React.useEffect(() => logV6DeprecationWarnings(future, router.future), [router, future]);
|
||||
// The fragment and {null} here are important! We need them to keep React 18's
|
||||
// useId happy when we are server-rendering since we may have a <script> here
|
||||
// containing the hydrated server-side staticContext (from StaticRouterProvider).
|
||||
// useId relies on the component tree structure to generate deterministic id's
|
||||
// so we need to ensure it remains the same on the client even though
|
||||
// we don't need the <script> tag
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DataRouterContext.Provider, {
|
||||
value: dataRouterContext
|
||||
}, /*#__PURE__*/React.createElement(DataRouterStateContext.Provider, {
|
||||
value: state
|
||||
}, /*#__PURE__*/React.createElement(Router, {
|
||||
basename: basename,
|
||||
location: state.location,
|
||||
navigationType: state.historyAction,
|
||||
navigator: navigator,
|
||||
future: {
|
||||
v7_relativeSplatPath: router.future.v7_relativeSplatPath
|
||||
}
|
||||
}, state.initialized || router.future.v7_partialHydration ? (/*#__PURE__*/React.createElement(DataRoutes, {
|
||||
routes: router.routes,
|
||||
future: router.future,
|
||||
state: state
|
||||
})) : fallbackElement))), null);
|
||||
}
|
||||
function DataRoutes({
|
||||
routes,
|
||||
future,
|
||||
state
|
||||
}) {
|
||||
return useRoutesImpl(routes, undefined, state, future);
|
||||
}
|
||||
/**
|
||||
* A `<Router>` that stores all entries in memory.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/memory-router
|
||||
*/
|
||||
function MemoryRouter({
|
||||
basename,
|
||||
children,
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
future
|
||||
}) {
|
||||
let historyRef = React.useRef();
|
||||
if (historyRef.current == null) {
|
||||
historyRef.current = createMemoryHistory({
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
v5Compat: true
|
||||
});
|
||||
}
|
||||
let history = historyRef.current;
|
||||
let [state, setStateImpl] = React.useState({
|
||||
action: history.action,
|
||||
location: history.location
|
||||
});
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React.useCallback(newState => {
|
||||
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
||||
React.useEffect(() => logV6DeprecationWarnings(future), [future]);
|
||||
return /*#__PURE__*/React.createElement(Router, {
|
||||
basename: basename,
|
||||
children: children,
|
||||
location: state.location,
|
||||
navigationType: state.action,
|
||||
navigator: history,
|
||||
future: future
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Changes the current location.
|
||||
*
|
||||
* Note: This API is mostly useful in React.Component subclasses that are not
|
||||
* able to use hooks. In functional components, we recommend you use the
|
||||
* `useNavigate` hook instead.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/navigate
|
||||
*/
|
||||
function Navigate({
|
||||
to,
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
}) {
|
||||
!useInRouterContext() ? UNSAFE_invariant(false,
|
||||
// TODO: This error is probably because they somehow have 2 versions of
|
||||
// the router loaded. We can help them understand how to avoid that.
|
||||
`<Navigate> may be used only in the context of a <Router> component.`) : void 0;
|
||||
let {
|
||||
future,
|
||||
static: isStatic
|
||||
} = React.useContext(NavigationContext);
|
||||
UNSAFE_warning(!isStatic, `<Navigate> must not be used on the initial render in a <StaticRouter>. ` + `This is a no-op, but you should modify your code so the <Navigate> is ` + `only ever rendered in response to some user interaction or state change.`) ;
|
||||
let {
|
||||
matches
|
||||
} = React.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let navigate = useNavigate();
|
||||
// Resolve the path outside of the effect so that when effects run twice in
|
||||
// StrictMode they navigate to the same place
|
||||
let path = resolveTo(to, UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath), locationPathname, relative === "path");
|
||||
let jsonPath = JSON.stringify(path);
|
||||
React.useEffect(() => navigate(JSON.parse(jsonPath), {
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
}), [navigate, jsonPath, relative, replace, state]);
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Renders the child route's element, if there is one.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/outlet
|
||||
*/
|
||||
function Outlet(props) {
|
||||
return useOutlet(props.context);
|
||||
}
|
||||
/**
|
||||
* Declares an element that should be rendered at a certain URL path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/route
|
||||
*/
|
||||
function Route(_props) {
|
||||
UNSAFE_invariant(false, `A <Route> is only ever to be used as the child of <Routes> element, ` + `never rendered directly. Please wrap your <Route> in a <Routes>.`) ;
|
||||
}
|
||||
/**
|
||||
* Provides location context for the rest of the app.
|
||||
*
|
||||
* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
|
||||
* router that is more specific to your environment such as a `<BrowserRouter>`
|
||||
* in web browsers or a `<StaticRouter>` for server rendering.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/router
|
||||
*/
|
||||
function Router({
|
||||
basename: basenameProp = "/",
|
||||
children = null,
|
||||
location: locationProp,
|
||||
navigationType = Action.Pop,
|
||||
navigator,
|
||||
static: staticProp = false,
|
||||
future
|
||||
}) {
|
||||
!!useInRouterContext() ? UNSAFE_invariant(false, `You cannot render a <Router> inside another <Router>.` + ` You should never have more than one in your app.`) : void 0;
|
||||
// Preserve trailing slashes on basename, so we can let the user control
|
||||
// the enforcement of trailing slashes throughout the app
|
||||
let basename = basenameProp.replace(/^\/*/, "/");
|
||||
let navigationContext = React.useMemo(() => ({
|
||||
basename,
|
||||
navigator,
|
||||
static: staticProp,
|
||||
future: {
|
||||
v7_relativeSplatPath: false,
|
||||
...future
|
||||
}
|
||||
}), [basename, future, navigator, staticProp]);
|
||||
if (typeof locationProp === "string") {
|
||||
locationProp = parsePath(locationProp);
|
||||
}
|
||||
let {
|
||||
pathname = "/",
|
||||
search = "",
|
||||
hash = "",
|
||||
state = null,
|
||||
key = "default"
|
||||
} = locationProp;
|
||||
let locationContext = React.useMemo(() => {
|
||||
let trailingPathname = stripBasename(pathname, basename);
|
||||
if (trailingPathname == null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
location: {
|
||||
pathname: trailingPathname,
|
||||
search,
|
||||
hash,
|
||||
state,
|
||||
key
|
||||
},
|
||||
navigationType
|
||||
};
|
||||
}, [basename, pathname, search, hash, state, key, navigationType]);
|
||||
UNSAFE_warning(locationContext != null, `<Router basename="${basename}"> is not able to match the URL ` + `"${pathname}${search}${hash}" because it does not start with the ` + `basename, so the <Router> won't render anything.`) ;
|
||||
if (locationContext == null) {
|
||||
return null;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement(NavigationContext.Provider, {
|
||||
value: navigationContext
|
||||
}, /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
||||
children: children,
|
||||
value: locationContext
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* A container for a nested tree of `<Route>` elements that renders the branch
|
||||
* that best matches the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/routes
|
||||
*/
|
||||
function Routes({
|
||||
children,
|
||||
location
|
||||
}) {
|
||||
return useRoutes(createRoutesFromChildren(children), location);
|
||||
}
|
||||
/**
|
||||
* Component to use for rendering lazily loaded data from returning defer()
|
||||
* in a loader function
|
||||
*/
|
||||
function Await({
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
}) {
|
||||
return /*#__PURE__*/React.createElement(AwaitErrorBoundary, {
|
||||
resolve: resolve,
|
||||
errorElement: errorElement
|
||||
}, /*#__PURE__*/React.createElement(ResolveAwait, null, children));
|
||||
}
|
||||
var AwaitRenderStatus;
|
||||
(function (AwaitRenderStatus) {
|
||||
AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
|
||||
AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
|
||||
AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
|
||||
})(AwaitRenderStatus || (AwaitRenderStatus = {}));
|
||||
const neverSettledPromise = new Promise(() => {});
|
||||
class AwaitErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: null
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("<Await> caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
} = this.props;
|
||||
let promise = null;
|
||||
let status = AwaitRenderStatus.pending;
|
||||
if (!(resolve instanceof Promise)) {
|
||||
// Didn't get a promise - provide as a resolved promise
|
||||
status = AwaitRenderStatus.success;
|
||||
promise = Promise.resolve();
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_data", {
|
||||
get: () => resolve
|
||||
});
|
||||
} else if (this.state.error) {
|
||||
// Caught a render error, provide it as a rejected promise
|
||||
status = AwaitRenderStatus.error;
|
||||
let renderError = this.state.error;
|
||||
promise = Promise.reject().catch(() => {}); // Avoid unhandled rejection warnings
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_error", {
|
||||
get: () => renderError
|
||||
});
|
||||
} else if (resolve._tracked) {
|
||||
// Already tracked promise - check contents
|
||||
promise = resolve;
|
||||
status = "_error" in promise ? AwaitRenderStatus.error : "_data" in promise ? AwaitRenderStatus.success : AwaitRenderStatus.pending;
|
||||
} else {
|
||||
// Raw (untracked) promise - track it
|
||||
status = AwaitRenderStatus.pending;
|
||||
Object.defineProperty(resolve, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
promise = resolve.then(data => Object.defineProperty(resolve, "_data", {
|
||||
get: () => data
|
||||
}), error => Object.defineProperty(resolve, "_error", {
|
||||
get: () => error
|
||||
}));
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && promise._error instanceof AbortedDeferredError) {
|
||||
// Freeze the UI by throwing a never resolved promise
|
||||
throw neverSettledPromise;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && !errorElement) {
|
||||
// No errorElement, throw to the nearest route-level error boundary
|
||||
throw promise._error;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error) {
|
||||
// Render via our errorElement
|
||||
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: errorElement
|
||||
});
|
||||
}
|
||||
if (status === AwaitRenderStatus.success) {
|
||||
// Render children with resolved value
|
||||
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
// Throw to the suspense boundary
|
||||
throw promise;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* Indirection to leverage useAsyncValue for a render-prop API on `<Await>`
|
||||
*/
|
||||
function ResolveAwait({
|
||||
children
|
||||
}) {
|
||||
let data = useAsyncValue();
|
||||
let toRender = typeof children === "function" ? children(data) : children;
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, toRender);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTILS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Creates a route config from a React "children" object, which is usually
|
||||
* either a `<Route>` element or an array of them. Used internally by
|
||||
* `<Routes>` to create a route config from its children.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/utils/create-routes-from-children
|
||||
*/
|
||||
function createRoutesFromChildren(children, parentPath = []) {
|
||||
let routes = [];
|
||||
React.Children.forEach(children, (element, index) => {
|
||||
if (! /*#__PURE__*/React.isValidElement(element)) {
|
||||
// Ignore non-elements. This allows people to more easily inline
|
||||
// conditionals in their route config.
|
||||
return;
|
||||
}
|
||||
let treePath = [...parentPath, index];
|
||||
if (element.type === React.Fragment) {
|
||||
// Transparently support React.Fragment and its children.
|
||||
routes.push.apply(routes, createRoutesFromChildren(element.props.children, treePath));
|
||||
return;
|
||||
}
|
||||
!(element.type === Route) ? UNSAFE_invariant(false, `[${typeof element.type === "string" ? element.type : element.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`) : void 0;
|
||||
!(!element.props.index || !element.props.children) ? UNSAFE_invariant(false, "An index route cannot have child routes.") : void 0;
|
||||
let route = {
|
||||
id: element.props.id || treePath.join("-"),
|
||||
caseSensitive: element.props.caseSensitive,
|
||||
element: element.props.element,
|
||||
Component: element.props.Component,
|
||||
index: element.props.index,
|
||||
path: element.props.path,
|
||||
loader: element.props.loader,
|
||||
action: element.props.action,
|
||||
errorElement: element.props.errorElement,
|
||||
ErrorBoundary: element.props.ErrorBoundary,
|
||||
hasErrorBoundary: element.props.ErrorBoundary != null || element.props.errorElement != null,
|
||||
shouldRevalidate: element.props.shouldRevalidate,
|
||||
handle: element.props.handle,
|
||||
lazy: element.props.lazy
|
||||
};
|
||||
if (element.props.children) {
|
||||
route.children = createRoutesFromChildren(element.props.children, treePath);
|
||||
}
|
||||
routes.push(route);
|
||||
});
|
||||
return routes;
|
||||
}
|
||||
/**
|
||||
* Renders the result of `matchRoutes()` into a React element.
|
||||
*/
|
||||
function renderMatches(matches) {
|
||||
return _renderMatches(matches);
|
||||
}
|
||||
|
||||
function mapRouteProperties(route) {
|
||||
let updates = {
|
||||
// Note: this check also occurs in createRoutesFromChildren so update
|
||||
// there if you change this -- please and thank you!
|
||||
hasErrorBoundary: route.ErrorBoundary != null || route.errorElement != null
|
||||
};
|
||||
if (route.Component) {
|
||||
{
|
||||
if (route.element) {
|
||||
UNSAFE_warning(false, "You should not include both `Component` and `element` on your route - " + "`Component` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
element: /*#__PURE__*/React.createElement(route.Component),
|
||||
Component: undefined
|
||||
});
|
||||
}
|
||||
if (route.HydrateFallback) {
|
||||
{
|
||||
if (route.hydrateFallbackElement) {
|
||||
UNSAFE_warning(false, "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - " + "`HydrateFallback` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
hydrateFallbackElement: /*#__PURE__*/React.createElement(route.HydrateFallback),
|
||||
HydrateFallback: undefined
|
||||
});
|
||||
}
|
||||
if (route.ErrorBoundary) {
|
||||
{
|
||||
if (route.errorElement) {
|
||||
UNSAFE_warning(false, "You should not include both `ErrorBoundary` and `errorElement` on your route - " + "`ErrorBoundary` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
errorElement: /*#__PURE__*/React.createElement(route.ErrorBoundary),
|
||||
ErrorBoundary: undefined
|
||||
});
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
function createMemoryRouter(routes, opts) {
|
||||
return createRouter({
|
||||
basename: opts?.basename,
|
||||
future: {
|
||||
...opts?.future,
|
||||
v7_prependBasename: true
|
||||
},
|
||||
history: createMemoryHistory({
|
||||
initialEntries: opts?.initialEntries,
|
||||
initialIndex: opts?.initialIndex
|
||||
}),
|
||||
hydrationData: opts?.hydrationData,
|
||||
routes,
|
||||
mapRouteProperties,
|
||||
dataStrategy: opts?.dataStrategy,
|
||||
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation
|
||||
}).initialize();
|
||||
}
|
||||
|
||||
export { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, logV6DeprecationWarnings as UNSAFE_logV6DeprecationWarnings, mapRouteProperties as UNSAFE_mapRouteProperties, useRouteId as UNSAFE_useRouteId, useRoutesImpl as UNSAFE_useRoutesImpl, createMemoryRouter, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, renderMatches, useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes };
|
||||
//# sourceMappingURL=react-router.development.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1619
@@ -0,0 +1,1619 @@
|
||||
/**
|
||||
* React Router v6.30.4
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@remix-run/router')) :
|
||||
typeof define === 'function' && define.amd ? define(['exports', 'react', '@remix-run/router'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactRouter = {}, global.React, global.RemixRouter));
|
||||
})(this, (function (exports, React, router) { 'use strict';
|
||||
|
||||
function _interopNamespace(e) {
|
||||
if (e && e.__esModule) return e;
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n["default"] = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
||||
|
||||
function _extends() {
|
||||
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
||||
for (var e = 1; e < arguments.length; e++) {
|
||||
var t = arguments[e];
|
||||
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
||||
}
|
||||
return n;
|
||||
}, _extends.apply(null, arguments);
|
||||
}
|
||||
|
||||
// Create react-specific types from the agnostic types in @remix-run/router to
|
||||
// export from react-router
|
||||
|
||||
const DataRouterContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
DataRouterContext.displayName = "DataRouter";
|
||||
}
|
||||
const DataRouterStateContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
DataRouterStateContext.displayName = "DataRouterState";
|
||||
}
|
||||
const AwaitContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
AwaitContext.displayName = "Await";
|
||||
}
|
||||
|
||||
/**
|
||||
* A Navigator is a "location changer"; it's how you get to different locations.
|
||||
*
|
||||
* Every history instance conforms to the Navigator interface, but the
|
||||
* distinction is useful primarily when it comes to the low-level `<Router>` API
|
||||
* where both the location and a navigator must be provided separately in order
|
||||
* to avoid "tearing" that may occur in a suspense-enabled app if the action
|
||||
* and/or location were to be read directly from the history instance.
|
||||
*/
|
||||
|
||||
const NavigationContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
NavigationContext.displayName = "Navigation";
|
||||
}
|
||||
const LocationContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
LocationContext.displayName = "Location";
|
||||
}
|
||||
const RouteContext = /*#__PURE__*/React__namespace.createContext({
|
||||
outlet: null,
|
||||
matches: [],
|
||||
isDataRoute: false
|
||||
});
|
||||
{
|
||||
RouteContext.displayName = "Route";
|
||||
}
|
||||
const RouteErrorContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
{
|
||||
RouteErrorContext.displayName = "RouteError";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full href for the given "to" value. This is useful for building
|
||||
* custom links that are also accessible and preserve right-click behavior.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-href
|
||||
*/
|
||||
function useHref(to, _temp) {
|
||||
let {
|
||||
relative
|
||||
} = _temp === void 0 ? {} : _temp;
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useHref() may be used only in the context of a <Router> component.") : void 0;
|
||||
let {
|
||||
basename,
|
||||
navigator
|
||||
} = React__namespace.useContext(NavigationContext);
|
||||
let {
|
||||
hash,
|
||||
pathname,
|
||||
search
|
||||
} = useResolvedPath(to, {
|
||||
relative
|
||||
});
|
||||
let joinedPathname = pathname;
|
||||
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to creating the href. If this is a root navigation, then just use the raw
|
||||
// basename which allows the basename to have full control over the presence
|
||||
// of a trailing slash on root links
|
||||
if (basename !== "/") {
|
||||
joinedPathname = pathname === "/" ? basename : router.joinPaths([basename, pathname]);
|
||||
}
|
||||
return navigator.createHref({
|
||||
pathname: joinedPathname,
|
||||
search,
|
||||
hash
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this component is a descendant of a `<Router>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-in-router-context
|
||||
*/
|
||||
function useInRouterContext() {
|
||||
return React__namespace.useContext(LocationContext) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current location object, which represents the current URL in web
|
||||
* browsers.
|
||||
*
|
||||
* Note: If you're using this it may mean you're doing some of your own
|
||||
* "routing" in your app, and we'd like to know what your use case is. We may
|
||||
* be able to provide something higher-level to better suit your needs.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-location
|
||||
*/
|
||||
function useLocation() {
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useLocation() may be used only in the context of a <Router> component.") : void 0;
|
||||
return React__namespace.useContext(LocationContext).location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current navigation action which describes how the router came to
|
||||
* the current location, either by a pop, push, or replace on the history stack.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigation-type
|
||||
*/
|
||||
function useNavigationType() {
|
||||
return React__namespace.useContext(LocationContext).navigationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PathMatch object if the given pattern matches the current URL.
|
||||
* This is useful for components that need to know "active" state, e.g.
|
||||
* `<NavLink>`.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-match
|
||||
*/
|
||||
function useMatch(pattern) {
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useMatch() may be used only in the context of a <Router> component.") : void 0;
|
||||
let {
|
||||
pathname
|
||||
} = useLocation();
|
||||
return React__namespace.useMemo(() => router.matchPath(pattern, router.UNSAFE_decodePath(pathname)), [pathname, pattern]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for the navigate() function returned from useNavigate().
|
||||
*/
|
||||
|
||||
const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered.";
|
||||
|
||||
// Mute warnings for calls to useNavigate in SSR environments
|
||||
function useIsomorphicLayoutEffect(cb) {
|
||||
let isStatic = React__namespace.useContext(NavigationContext).static;
|
||||
if (!isStatic) {
|
||||
// We should be able to get rid of this once react 18.3 is released
|
||||
// See: https://github.com/facebook/react/pull/26395
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
React__namespace.useLayoutEffect(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an imperative method for changing the location. Used by `<Link>`s, but
|
||||
* may also be used by other elements to change the location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-navigate
|
||||
*/
|
||||
function useNavigate() {
|
||||
let {
|
||||
isDataRoute
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
// Conditional usage is OK here because the usage of a data router is static
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
return isDataRoute ? useNavigateStable() : useNavigateUnstable();
|
||||
}
|
||||
function useNavigateUnstable() {
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useNavigate() may be used only in the context of a <Router> component.") : void 0;
|
||||
let dataRouterContext = React__namespace.useContext(DataRouterContext);
|
||||
let {
|
||||
basename,
|
||||
future,
|
||||
navigator
|
||||
} = React__namespace.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(router.UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
let activeRef = React__namespace.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React__namespace.useCallback(function (to, options) {
|
||||
if (options === void 0) {
|
||||
options = {};
|
||||
}
|
||||
router.UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
|
||||
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our history listener yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
navigator.go(to);
|
||||
return;
|
||||
}
|
||||
let path = router.resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path");
|
||||
|
||||
// If we're operating within a basename, prepend it to the pathname prior
|
||||
// to handing off to history (but only if we're not in a data router,
|
||||
// otherwise it'll prepend the basename inside of the router).
|
||||
// If this is a root navigation, then we navigate to the raw basename
|
||||
// which allows the basename to have full control over the presence of a
|
||||
// trailing slash on root links
|
||||
if (dataRouterContext == null && basename !== "/") {
|
||||
path.pathname = path.pathname === "/" ? basename : router.joinPaths([basename, path.pathname]);
|
||||
}
|
||||
(!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
|
||||
}, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]);
|
||||
return navigate;
|
||||
}
|
||||
const OutletContext = /*#__PURE__*/React__namespace.createContext(null);
|
||||
|
||||
/**
|
||||
* Returns the context (if provided) for the child route at this level of the route
|
||||
* hierarchy.
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet-context
|
||||
*/
|
||||
function useOutletContext() {
|
||||
return React__namespace.useContext(OutletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element for the child route at this level of the route
|
||||
* hierarchy. Used internally by `<Outlet>` to render child routes.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-outlet
|
||||
*/
|
||||
function useOutlet(context) {
|
||||
let outlet = React__namespace.useContext(RouteContext).outlet;
|
||||
if (outlet) {
|
||||
return /*#__PURE__*/React__namespace.createElement(OutletContext.Provider, {
|
||||
value: context
|
||||
}, outlet);
|
||||
}
|
||||
return outlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object of key/value pairs of the dynamic params from the current
|
||||
* URL that were matched by the route path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-params
|
||||
*/
|
||||
function useParams() {
|
||||
let {
|
||||
matches
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
let routeMatch = matches[matches.length - 1];
|
||||
return routeMatch ? routeMatch.params : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the pathname of the given `to` value against the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-resolved-path
|
||||
*/
|
||||
function useResolvedPath(to, _temp2) {
|
||||
let {
|
||||
relative
|
||||
} = _temp2 === void 0 ? {} : _temp2;
|
||||
let {
|
||||
future
|
||||
} = React__namespace.useContext(NavigationContext);
|
||||
let {
|
||||
matches
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let routePathnamesJson = JSON.stringify(router.UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath));
|
||||
return React__namespace.useMemo(() => router.resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element of the route that matched the current location, prepared
|
||||
* with the correct context to render the remainder of the route tree. Route
|
||||
* elements in the tree must render an `<Outlet>` to render their child route's
|
||||
* element.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/hooks/use-routes
|
||||
*/
|
||||
function useRoutes(routes, locationArg) {
|
||||
return useRoutesImpl(routes, locationArg);
|
||||
}
|
||||
|
||||
// Internal implementation with accept optional param for RouterProvider usage
|
||||
function useRoutesImpl(routes, locationArg, dataRouterState, future) {
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
||||
// router loaded. We can help them understand how to avoid that.
|
||||
"useRoutes() may be used only in the context of a <Router> component.") : void 0;
|
||||
let {
|
||||
navigator
|
||||
} = React__namespace.useContext(NavigationContext);
|
||||
let {
|
||||
matches: parentMatches
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
let routeMatch = parentMatches[parentMatches.length - 1];
|
||||
let parentParams = routeMatch ? routeMatch.params : {};
|
||||
let parentPathname = routeMatch ? routeMatch.pathname : "/";
|
||||
let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
||||
let parentRoute = routeMatch && routeMatch.route;
|
||||
{
|
||||
// You won't get a warning about 2 different <Routes> under a <Route>
|
||||
// without a trailing *, but this is a best-effort warning anyway since we
|
||||
// cannot even give the warning unless they land at the parent route.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// <Routes>
|
||||
// {/* This route path MUST end with /* because otherwise
|
||||
// it will never match /blog/post/123 */}
|
||||
// <Route path="blog" element={<Blog />} />
|
||||
// <Route path="blog/feed" element={<BlogFeed />} />
|
||||
// </Routes>
|
||||
//
|
||||
// function Blog() {
|
||||
// return (
|
||||
// <Routes>
|
||||
// <Route path="post/:id" element={<Post />} />
|
||||
// </Routes>
|
||||
// );
|
||||
// }
|
||||
let parentPath = parentRoute && parentRoute.path || "";
|
||||
warningOnce(parentPathname, !parentRoute || parentPath.endsWith("*"), "You rendered descendant <Routes> (or called `useRoutes()`) at " + ("\"" + parentPathname + "\" (under <Route path=\"" + parentPath + "\">) but the ") + "parent route path has no trailing \"*\". This means if you navigate " + "deeper, the parent won't match anymore and therefore the child " + "routes will never render.\n\n" + ("Please change the parent <Route path=\"" + parentPath + "\"> to <Route ") + ("path=\"" + (parentPath === "/" ? "*" : parentPath + "/*") + "\">."));
|
||||
}
|
||||
let locationFromContext = useLocation();
|
||||
let location;
|
||||
if (locationArg) {
|
||||
var _parsedLocationArg$pa;
|
||||
let parsedLocationArg = typeof locationArg === "string" ? router.parsePath(locationArg) : locationArg;
|
||||
!(parentPathnameBase === "/" || ((_parsedLocationArg$pa = parsedLocationArg.pathname) == null ? void 0 : _parsedLocationArg$pa.startsWith(parentPathnameBase))) ? router.UNSAFE_invariant(false, "When overriding the location using `<Routes location>` or `useRoutes(routes, location)`, " + "the location pathname must begin with the portion of the URL pathname that was " + ("matched by all parent routes. The current pathname base is \"" + parentPathnameBase + "\" ") + ("but pathname \"" + parsedLocationArg.pathname + "\" was given in the `location` prop.")) : void 0;
|
||||
location = parsedLocationArg;
|
||||
} else {
|
||||
location = locationFromContext;
|
||||
}
|
||||
let pathname = location.pathname || "/";
|
||||
let remainingPathname = pathname;
|
||||
if (parentPathnameBase !== "/") {
|
||||
// Determine the remaining pathname by removing the # of URL segments the
|
||||
// parentPathnameBase has, instead of removing based on character count.
|
||||
// This is because we can't guarantee that incoming/outgoing encodings/
|
||||
// decodings will match exactly.
|
||||
// We decode paths before matching on a per-segment basis with
|
||||
// decodeURIComponent(), but we re-encode pathnames via `new URL()` so they
|
||||
// match what `window.location.pathname` would reflect. Those don't 100%
|
||||
// align when it comes to encoded URI characters such as % and &.
|
||||
//
|
||||
// So we may end up with:
|
||||
// pathname: "/descendant/a%25b/match"
|
||||
// parentPathnameBase: "/descendant/a%b"
|
||||
//
|
||||
// And the direct substring removal approach won't work :/
|
||||
let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
|
||||
let segments = pathname.replace(/^\//, "").split("/");
|
||||
remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
|
||||
}
|
||||
let matches = router.matchRoutes(routes, {
|
||||
pathname: remainingPathname
|
||||
});
|
||||
{
|
||||
router.UNSAFE_warning(parentRoute || matches != null, "No routes matched location \"" + location.pathname + location.search + location.hash + "\" ") ;
|
||||
router.UNSAFE_warning(matches == null || matches[matches.length - 1].route.element !== undefined || matches[matches.length - 1].route.Component !== undefined || matches[matches.length - 1].route.lazy !== undefined, "Matched leaf route at location \"" + location.pathname + location.search + location.hash + "\" " + "does not have an element or Component. This means it will render an <Outlet /> with a " + "null value by default resulting in an \"empty\" page.") ;
|
||||
}
|
||||
let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
||||
params: Object.assign({}, parentParams, match.params),
|
||||
pathname: router.joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathname).pathname : match.pathname]),
|
||||
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : router.joinPaths([parentPathnameBase,
|
||||
// Re-encode pathnames that were decoded inside matchRoutes
|
||||
navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
|
||||
})), parentMatches, dataRouterState, future);
|
||||
|
||||
// When a user passes in a `locationArg`, the associated routes need to
|
||||
// be wrapped in a new `LocationContext.Provider` in order for `useLocation`
|
||||
// to use the scoped location instead of the global location.
|
||||
if (locationArg && renderedMatches) {
|
||||
return /*#__PURE__*/React__namespace.createElement(LocationContext.Provider, {
|
||||
value: {
|
||||
location: _extends({
|
||||
pathname: "/",
|
||||
search: "",
|
||||
hash: "",
|
||||
state: null,
|
||||
key: "default"
|
||||
}, location),
|
||||
navigationType: router.Action.Pop
|
||||
}
|
||||
}, renderedMatches);
|
||||
}
|
||||
return renderedMatches;
|
||||
}
|
||||
function DefaultErrorComponent() {
|
||||
let error = useRouteError();
|
||||
let message = router.isRouteErrorResponse(error) ? error.status + " " + error.statusText : error instanceof Error ? error.message : JSON.stringify(error);
|
||||
let stack = error instanceof Error ? error.stack : null;
|
||||
let lightgrey = "rgba(200,200,200, 0.5)";
|
||||
let preStyles = {
|
||||
padding: "0.5rem",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let codeStyles = {
|
||||
padding: "2px 4px",
|
||||
backgroundColor: lightgrey
|
||||
};
|
||||
let devInfo = null;
|
||||
{
|
||||
console.error("Error handled by React Router default ErrorBoundary:", error);
|
||||
devInfo = /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("p", null, "\uD83D\uDCBF Hey developer \uD83D\uDC4B"), /*#__PURE__*/React__namespace.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own ", /*#__PURE__*/React__namespace.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "ErrorBoundary"), " or", " ", /*#__PURE__*/React__namespace.createElement("code", {
|
||||
style: codeStyles
|
||||
}, "errorElement"), " prop on your route."));
|
||||
}
|
||||
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("h2", null, "Unexpected Application Error!"), /*#__PURE__*/React__namespace.createElement("h3", {
|
||||
style: {
|
||||
fontStyle: "italic"
|
||||
}
|
||||
}, message), stack ? /*#__PURE__*/React__namespace.createElement("pre", {
|
||||
style: preStyles
|
||||
}, stack) : null, devInfo);
|
||||
}
|
||||
const defaultErrorElement = /*#__PURE__*/React__namespace.createElement(DefaultErrorComponent, null);
|
||||
class RenderErrorBoundary extends React__namespace.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
location: props.location,
|
||||
revalidation: props.revalidation,
|
||||
error: props.error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error: error
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
// When we get into an error state, the user will likely click "back" to the
|
||||
// previous page that didn't have an error. Because this wraps the entire
|
||||
// application, that will have no effect--the error page continues to display.
|
||||
// This gives us a mechanism to recover from the error when the location changes.
|
||||
//
|
||||
// Whether we're in an error state or not, we update the location in state
|
||||
// so that when we are in an error state, it gets reset when a new location
|
||||
// comes in and the user recovers from the error.
|
||||
if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
|
||||
return {
|
||||
error: props.error,
|
||||
location: props.location,
|
||||
revalidation: props.revalidation
|
||||
};
|
||||
}
|
||||
|
||||
// If we're not changing locations, preserve the location but still surface
|
||||
// any new errors that may come through. We retain the existing error, we do
|
||||
// this because the error provided from the app state may be cleared without
|
||||
// the location changing.
|
||||
return {
|
||||
error: props.error !== undefined ? props.error : state.error,
|
||||
location: state.location,
|
||||
revalidation: props.revalidation || state.revalidation
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("React Router caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
return this.state.error !== undefined ? /*#__PURE__*/React__namespace.createElement(RouteContext.Provider, {
|
||||
value: this.props.routeContext
|
||||
}, /*#__PURE__*/React__namespace.createElement(RouteErrorContext.Provider, {
|
||||
value: this.state.error,
|
||||
children: this.props.component
|
||||
})) : this.props.children;
|
||||
}
|
||||
}
|
||||
function RenderedRoute(_ref) {
|
||||
let {
|
||||
routeContext,
|
||||
match,
|
||||
children
|
||||
} = _ref;
|
||||
let dataRouterContext = React__namespace.useContext(DataRouterContext);
|
||||
|
||||
// Track how deep we got in our render pass to emulate SSR componentDidCatch
|
||||
// in a DataStaticRouter
|
||||
if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
|
||||
dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
|
||||
}
|
||||
return /*#__PURE__*/React__namespace.createElement(RouteContext.Provider, {
|
||||
value: routeContext
|
||||
}, children);
|
||||
}
|
||||
function _renderMatches(matches, parentMatches, dataRouterState, future) {
|
||||
var _dataRouterState;
|
||||
if (parentMatches === void 0) {
|
||||
parentMatches = [];
|
||||
}
|
||||
if (dataRouterState === void 0) {
|
||||
dataRouterState = null;
|
||||
}
|
||||
if (future === void 0) {
|
||||
future = null;
|
||||
}
|
||||
if (matches == null) {
|
||||
var _future;
|
||||
if (!dataRouterState) {
|
||||
return null;
|
||||
}
|
||||
if (dataRouterState.errors) {
|
||||
// Don't bail if we have data router errors so we can render them in the
|
||||
// boundary. Use the pre-matched (or shimmed) matches
|
||||
matches = dataRouterState.matches;
|
||||
} else if ((_future = future) != null && _future.v7_partialHydration && parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
|
||||
// Don't bail if we're initializing with partial hydration and we have
|
||||
// router matches. That means we're actively running `patchRoutesOnNavigation`
|
||||
// so we should render down the partial matches to the appropriate
|
||||
// `HydrateFallback`. We only do this if `parentMatches` is empty so it
|
||||
// only impacts the root matches for `RouterProvider` and no descendant
|
||||
// `<Routes>`
|
||||
matches = dataRouterState.matches;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let renderedMatches = matches;
|
||||
|
||||
// If we have data errors, trim matches to the highest error boundary
|
||||
let errors = (_dataRouterState = dataRouterState) == null ? void 0 : _dataRouterState.errors;
|
||||
if (errors != null) {
|
||||
let errorIndex = renderedMatches.findIndex(m => m.route.id && (errors == null ? void 0 : errors[m.route.id]) !== undefined);
|
||||
!(errorIndex >= 0) ? router.UNSAFE_invariant(false, "Could not find a matching route for errors on route IDs: " + Object.keys(errors).join(",")) : void 0;
|
||||
renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
|
||||
}
|
||||
|
||||
// If we're in a partial hydration mode, detect if we need to render down to
|
||||
// a given HydrateFallback while we load the rest of the hydration data
|
||||
let renderFallback = false;
|
||||
let fallbackIndex = -1;
|
||||
if (dataRouterState && future && future.v7_partialHydration) {
|
||||
for (let i = 0; i < renderedMatches.length; i++) {
|
||||
let match = renderedMatches[i];
|
||||
// Track the deepest fallback up until the first route without data
|
||||
if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
|
||||
fallbackIndex = i;
|
||||
}
|
||||
if (match.route.id) {
|
||||
let {
|
||||
loaderData,
|
||||
errors
|
||||
} = dataRouterState;
|
||||
let needsToRunLoader = match.route.loader && loaderData[match.route.id] === undefined && (!errors || errors[match.route.id] === undefined);
|
||||
if (match.route.lazy || needsToRunLoader) {
|
||||
// We found the first route that's not ready to render (waiting on
|
||||
// lazy, or has a loader that hasn't run yet). Flag that we need to
|
||||
// render a fallback and render up until the appropriate fallback
|
||||
renderFallback = true;
|
||||
if (fallbackIndex >= 0) {
|
||||
renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
|
||||
} else {
|
||||
renderedMatches = [renderedMatches[0]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderedMatches.reduceRight((outlet, match, index) => {
|
||||
// Only data routers handle errors/fallbacks
|
||||
let error;
|
||||
let shouldRenderHydrateFallback = false;
|
||||
let errorElement = null;
|
||||
let hydrateFallbackElement = null;
|
||||
if (dataRouterState) {
|
||||
error = errors && match.route.id ? errors[match.route.id] : undefined;
|
||||
errorElement = match.route.errorElement || defaultErrorElement;
|
||||
if (renderFallback) {
|
||||
if (fallbackIndex < 0 && index === 0) {
|
||||
warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration");
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = null;
|
||||
} else if (fallbackIndex === index) {
|
||||
shouldRenderHydrateFallback = true;
|
||||
hydrateFallbackElement = match.route.hydrateFallbackElement || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
|
||||
let getChildren = () => {
|
||||
let children;
|
||||
if (error) {
|
||||
children = errorElement;
|
||||
} else if (shouldRenderHydrateFallback) {
|
||||
children = hydrateFallbackElement;
|
||||
} else if (match.route.Component) {
|
||||
// Note: This is a de-optimized path since React won't re-use the
|
||||
// ReactElement since it's identity changes with each new
|
||||
// React.createElement call. We keep this so folks can use
|
||||
// `<Route Component={...}>` in `<Routes>` but generally `Component`
|
||||
// usage is only advised in `RouterProvider` when we can convert it to
|
||||
// `element` ahead of time.
|
||||
children = /*#__PURE__*/React__namespace.createElement(match.route.Component, null);
|
||||
} else if (match.route.element) {
|
||||
children = match.route.element;
|
||||
} else {
|
||||
children = outlet;
|
||||
}
|
||||
return /*#__PURE__*/React__namespace.createElement(RenderedRoute, {
|
||||
match: match,
|
||||
routeContext: {
|
||||
outlet,
|
||||
matches,
|
||||
isDataRoute: dataRouterState != null
|
||||
},
|
||||
children: children
|
||||
});
|
||||
};
|
||||
// Only wrap in an error boundary within data router usages when we have an
|
||||
// ErrorBoundary/errorElement on this route. Otherwise let it bubble up to
|
||||
// an ancestor ErrorBoundary/errorElement
|
||||
return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /*#__PURE__*/React__namespace.createElement(RenderErrorBoundary, {
|
||||
location: dataRouterState.location,
|
||||
revalidation: dataRouterState.revalidation,
|
||||
component: errorElement,
|
||||
error: error,
|
||||
children: getChildren(),
|
||||
routeContext: {
|
||||
outlet: null,
|
||||
matches,
|
||||
isDataRoute: true
|
||||
}
|
||||
}) : getChildren();
|
||||
}, null);
|
||||
}
|
||||
var DataRouterHook = /*#__PURE__*/function (DataRouterHook) {
|
||||
DataRouterHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterHook["UseNavigateStable"] = "useNavigate";
|
||||
return DataRouterHook;
|
||||
}(DataRouterHook || {});
|
||||
var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) {
|
||||
DataRouterStateHook["UseBlocker"] = "useBlocker";
|
||||
DataRouterStateHook["UseLoaderData"] = "useLoaderData";
|
||||
DataRouterStateHook["UseActionData"] = "useActionData";
|
||||
DataRouterStateHook["UseRouteError"] = "useRouteError";
|
||||
DataRouterStateHook["UseNavigation"] = "useNavigation";
|
||||
DataRouterStateHook["UseRouteLoaderData"] = "useRouteLoaderData";
|
||||
DataRouterStateHook["UseMatches"] = "useMatches";
|
||||
DataRouterStateHook["UseRevalidator"] = "useRevalidator";
|
||||
DataRouterStateHook["UseNavigateStable"] = "useNavigate";
|
||||
DataRouterStateHook["UseRouteId"] = "useRouteId";
|
||||
return DataRouterStateHook;
|
||||
}(DataRouterStateHook || {});
|
||||
function getDataRouterConsoleError(hookName) {
|
||||
return hookName + " must be used within a data router. See https://reactrouter.com/v6/routers/picking-a-router.";
|
||||
}
|
||||
function useDataRouterContext(hookName) {
|
||||
let ctx = React__namespace.useContext(DataRouterContext);
|
||||
!ctx ? router.UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return ctx;
|
||||
}
|
||||
function useDataRouterState(hookName) {
|
||||
let state = React__namespace.useContext(DataRouterStateContext);
|
||||
!state ? router.UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return state;
|
||||
}
|
||||
function useRouteContext(hookName) {
|
||||
let route = React__namespace.useContext(RouteContext);
|
||||
!route ? router.UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : void 0;
|
||||
return route;
|
||||
}
|
||||
|
||||
// Internal version with hookName-aware debugging
|
||||
function useCurrentRouteId(hookName) {
|
||||
let route = useRouteContext(hookName);
|
||||
let thisRoute = route.matches[route.matches.length - 1];
|
||||
!thisRoute.route.id ? router.UNSAFE_invariant(false, hookName + " can only be used on routes that contain a unique \"id\"") : void 0;
|
||||
return thisRoute.route.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID for the nearest contextual route
|
||||
*/
|
||||
function useRouteId() {
|
||||
return useCurrentRouteId(DataRouterStateHook.UseRouteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current navigation, defaulting to an "idle" navigation when
|
||||
* no navigation is in progress
|
||||
*/
|
||||
function useNavigation() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseNavigation);
|
||||
return state.navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a revalidate function for manually triggering revalidation, as well
|
||||
* as the current state of any manual revalidations
|
||||
*/
|
||||
function useRevalidator() {
|
||||
let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRevalidator);
|
||||
return React__namespace.useMemo(() => ({
|
||||
revalidate: dataRouterContext.router.revalidate,
|
||||
state: state.revalidation
|
||||
}), [dataRouterContext.router.revalidate, state.revalidation]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active route matches, useful for accessing loaderData for
|
||||
* parent/child routes or the route "handle" property
|
||||
*/
|
||||
function useMatches() {
|
||||
let {
|
||||
matches,
|
||||
loaderData
|
||||
} = useDataRouterState(DataRouterStateHook.UseMatches);
|
||||
return React__namespace.useMemo(() => matches.map(m => router.UNSAFE_convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loader data for the nearest ancestor Route loader
|
||||
*/
|
||||
function useLoaderData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseLoaderData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
if (state.errors && state.errors[routeId] != null) {
|
||||
console.error("You cannot `useLoaderData` in an errorElement (routeId: " + routeId + ")");
|
||||
return undefined;
|
||||
}
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loaderData for the given routeId
|
||||
*/
|
||||
function useRouteLoaderData(routeId) {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);
|
||||
return state.loaderData[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action data for the nearest ancestor Route action
|
||||
*/
|
||||
function useActionData() {
|
||||
let state = useDataRouterState(DataRouterStateHook.UseActionData);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
|
||||
return state.actionData ? state.actionData[routeId] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nearest ancestor Route error, which could be a loader/action
|
||||
* error or a render error. This is intended to be called from your
|
||||
* ErrorBoundary/errorElement to display a proper error message.
|
||||
*/
|
||||
function useRouteError() {
|
||||
var _state$errors;
|
||||
let error = React__namespace.useContext(RouteErrorContext);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseRouteError);
|
||||
let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);
|
||||
|
||||
// If this was a render error, we put it in a RouteError context inside
|
||||
// of RenderErrorBoundary
|
||||
if (error !== undefined) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// Otherwise look for errors from our data router state
|
||||
return (_state$errors = state.errors) == null ? void 0 : _state$errors[routeId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the happy-path data from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncValue() {
|
||||
let value = React__namespace.useContext(AwaitContext);
|
||||
return value == null ? void 0 : value._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error from the nearest ancestor `<Await />` value
|
||||
*/
|
||||
function useAsyncError() {
|
||||
let value = React__namespace.useContext(AwaitContext);
|
||||
return value == null ? void 0 : value._error;
|
||||
}
|
||||
let blockerId = 0;
|
||||
|
||||
/**
|
||||
* Allow the application to block navigations within the SPA and present the
|
||||
* user a confirmation dialog to confirm the navigation. Mostly used to avoid
|
||||
* using half-filled form data. This does not handle hard-reloads or
|
||||
* cross-origin navigations.
|
||||
*/
|
||||
function useBlocker(shouldBlock) {
|
||||
let {
|
||||
router: router$1,
|
||||
basename
|
||||
} = useDataRouterContext(DataRouterHook.UseBlocker);
|
||||
let state = useDataRouterState(DataRouterStateHook.UseBlocker);
|
||||
let [blockerKey, setBlockerKey] = React__namespace.useState("");
|
||||
let blockerFunction = React__namespace.useCallback(arg => {
|
||||
if (typeof shouldBlock !== "function") {
|
||||
return !!shouldBlock;
|
||||
}
|
||||
if (basename === "/") {
|
||||
return shouldBlock(arg);
|
||||
}
|
||||
|
||||
// If they provided us a function and we've got an active basename, strip
|
||||
// it from the locations we expose to the user to match the behavior of
|
||||
// useLocation
|
||||
let {
|
||||
currentLocation,
|
||||
nextLocation,
|
||||
historyAction
|
||||
} = arg;
|
||||
return shouldBlock({
|
||||
currentLocation: _extends({}, currentLocation, {
|
||||
pathname: router.stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
|
||||
}),
|
||||
nextLocation: _extends({}, nextLocation, {
|
||||
pathname: router.stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
|
||||
}),
|
||||
historyAction
|
||||
});
|
||||
}, [basename, shouldBlock]);
|
||||
|
||||
// This effect is in charge of blocker key assignment and deletion (which is
|
||||
// tightly coupled to the key)
|
||||
React__namespace.useEffect(() => {
|
||||
let key = String(++blockerId);
|
||||
setBlockerKey(key);
|
||||
return () => router$1.deleteBlocker(key);
|
||||
}, [router$1]);
|
||||
|
||||
// This effect handles assigning the blockerFunction. This is to handle
|
||||
// unstable blocker function identities, and happens only after the prior
|
||||
// effect so we don't get an orphaned blockerFunction in the router with a
|
||||
// key of "". Until then we just have the IDLE_BLOCKER.
|
||||
React__namespace.useEffect(() => {
|
||||
if (blockerKey !== "") {
|
||||
router$1.getBlocker(blockerKey, blockerFunction);
|
||||
}
|
||||
}, [router$1, blockerKey, blockerFunction]);
|
||||
|
||||
// Prefer the blocker from `state` not `router.state` since DataRouterContext
|
||||
// is memoized so this ensures we update on blocker state updates
|
||||
return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : router.IDLE_BLOCKER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable version of useNavigate that is used when we are in the context of
|
||||
* a RouterProvider.
|
||||
*/
|
||||
function useNavigateStable() {
|
||||
let {
|
||||
router: router$1
|
||||
} = useDataRouterContext(DataRouterHook.UseNavigateStable);
|
||||
let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
|
||||
let activeRef = React__namespace.useRef(false);
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
activeRef.current = true;
|
||||
});
|
||||
let navigate = React__namespace.useCallback(function (to, options) {
|
||||
if (options === void 0) {
|
||||
options = {};
|
||||
}
|
||||
router.UNSAFE_warning(activeRef.current, navigateEffectWarning) ;
|
||||
|
||||
// Short circuit here since if this happens on first render the navigate
|
||||
// is useless because we haven't wired up our router subscriber yet
|
||||
if (!activeRef.current) return;
|
||||
if (typeof to === "number") {
|
||||
router$1.navigate(to);
|
||||
} else {
|
||||
router$1.navigate(to, _extends({
|
||||
fromRouteId: id
|
||||
}, options));
|
||||
}
|
||||
}, [router$1, id]);
|
||||
return navigate;
|
||||
}
|
||||
const alreadyWarned$1 = {};
|
||||
function warningOnce(key, cond, message) {
|
||||
if (!cond && !alreadyWarned$1[key]) {
|
||||
alreadyWarned$1[key] = true;
|
||||
router.UNSAFE_warning(false, message) ;
|
||||
}
|
||||
}
|
||||
|
||||
const alreadyWarned = {};
|
||||
function warnOnce(key, message) {
|
||||
if (!alreadyWarned[message]) {
|
||||
alreadyWarned[message] = true;
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
const logDeprecation = (flag, msg, link) => warnOnce(flag, "\u26A0\uFE0F React Router Future Flag Warning: " + msg + ". " + ("You can use the `" + flag + "` future flag to opt-in early. ") + ("For more information, see " + link + "."));
|
||||
function logV6DeprecationWarnings(renderFuture, routerFuture) {
|
||||
if ((renderFuture == null ? void 0 : renderFuture.v7_startTransition) === undefined) {
|
||||
logDeprecation("v7_startTransition", "React Router will begin wrapping state updates in `React.startTransition` in v7", "https://reactrouter.com/v6/upgrading/future#v7_starttransition");
|
||||
}
|
||||
if ((renderFuture == null ? void 0 : renderFuture.v7_relativeSplatPath) === undefined && (!routerFuture || routerFuture.v7_relativeSplatPath === undefined)) {
|
||||
logDeprecation("v7_relativeSplatPath", "Relative route resolution within Splat routes is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_relativesplatpath");
|
||||
}
|
||||
if (routerFuture) {
|
||||
if (routerFuture.v7_fetcherPersist === undefined) {
|
||||
logDeprecation("v7_fetcherPersist", "The persistence behavior of fetchers is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_fetcherpersist");
|
||||
}
|
||||
if (routerFuture.v7_normalizeFormMethod === undefined) {
|
||||
logDeprecation("v7_normalizeFormMethod", "Casing of `formMethod` fields is being normalized to uppercase in v7", "https://reactrouter.com/v6/upgrading/future#v7_normalizeformmethod");
|
||||
}
|
||||
if (routerFuture.v7_partialHydration === undefined) {
|
||||
logDeprecation("v7_partialHydration", "`RouterProvider` hydration behavior is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_partialhydration");
|
||||
}
|
||||
if (routerFuture.v7_skipActionErrorRevalidation === undefined) {
|
||||
logDeprecation("v7_skipActionErrorRevalidation", "The revalidation behavior after 4xx/5xx `action` responses is changing in v7", "https://reactrouter.com/v6/upgrading/future#v7_skipactionerrorrevalidation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Webpack + React 17 fails to compile on any of the following because webpack
|
||||
complains that `startTransition` doesn't exist in `React`:
|
||||
* import { startTransition } from "react"
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React.startTransition(() => setState()) : setState()
|
||||
* import * as React from from "react";
|
||||
"startTransition" in React ? React["startTransition"](() => setState()) : setState()
|
||||
|
||||
Moving it to a constant such as the following solves the Webpack/React 17 issue:
|
||||
* import * as React from from "react";
|
||||
const START_TRANSITION = "startTransition";
|
||||
START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()
|
||||
|
||||
However, that introduces webpack/terser minification issues in production builds
|
||||
in React 18 where minification/obfuscation ends up removing the call of
|
||||
React.startTransition entirely from the first half of the ternary. Grabbing
|
||||
this exported reference once up front resolves that issue.
|
||||
|
||||
See https://github.com/remix-run/react-router/issues/10579
|
||||
*/
|
||||
const START_TRANSITION = "startTransition";
|
||||
const startTransitionImpl = React__namespace[START_TRANSITION];
|
||||
|
||||
/**
|
||||
* Given a Remix Router instance, render the appropriate UI
|
||||
*/
|
||||
function RouterProvider(_ref) {
|
||||
let {
|
||||
fallbackElement,
|
||||
router: router$1,
|
||||
future
|
||||
} = _ref;
|
||||
let [state, setStateImpl] = React__namespace.useState(router$1.state);
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React__namespace.useCallback(newState => {
|
||||
if (v7_startTransition && startTransitionImpl) {
|
||||
startTransitionImpl(() => setStateImpl(newState));
|
||||
} else {
|
||||
setStateImpl(newState);
|
||||
}
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
|
||||
// Need to use a layout effect here so we are subscribed early enough to
|
||||
// pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
|
||||
React__namespace.useLayoutEffect(() => router$1.subscribe(setState), [router$1, setState]);
|
||||
React__namespace.useEffect(() => {
|
||||
router.UNSAFE_warning(fallbackElement == null || !router$1.future.v7_partialHydration, "`<RouterProvider fallbackElement>` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead") ;
|
||||
// Only log this once on initial mount
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
let navigator = React__namespace.useMemo(() => {
|
||||
return {
|
||||
createHref: router$1.createHref,
|
||||
encodeLocation: router$1.encodeLocation,
|
||||
go: n => router$1.navigate(n),
|
||||
push: (to, state, opts) => router$1.navigate(to, {
|
||||
state,
|
||||
preventScrollReset: opts == null ? void 0 : opts.preventScrollReset
|
||||
}),
|
||||
replace: (to, state, opts) => router$1.navigate(to, {
|
||||
replace: true,
|
||||
state,
|
||||
preventScrollReset: opts == null ? void 0 : opts.preventScrollReset
|
||||
})
|
||||
};
|
||||
}, [router$1]);
|
||||
let basename = router$1.basename || "/";
|
||||
let dataRouterContext = React__namespace.useMemo(() => ({
|
||||
router: router$1,
|
||||
navigator,
|
||||
static: false,
|
||||
basename
|
||||
}), [router$1, navigator, basename]);
|
||||
React__namespace.useEffect(() => logV6DeprecationWarnings(future, router$1.future), [router$1, future]);
|
||||
|
||||
// The fragment and {null} here are important! We need them to keep React 18's
|
||||
// useId happy when we are server-rendering since we may have a <script> here
|
||||
// containing the hydrated server-side staticContext (from StaticRouterProvider).
|
||||
// useId relies on the component tree structure to generate deterministic id's
|
||||
// so we need to ensure it remains the same on the client even though
|
||||
// we don't need the <script> tag
|
||||
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(DataRouterContext.Provider, {
|
||||
value: dataRouterContext
|
||||
}, /*#__PURE__*/React__namespace.createElement(DataRouterStateContext.Provider, {
|
||||
value: state
|
||||
}, /*#__PURE__*/React__namespace.createElement(Router, {
|
||||
basename: basename,
|
||||
location: state.location,
|
||||
navigationType: state.historyAction,
|
||||
navigator: navigator,
|
||||
future: {
|
||||
v7_relativeSplatPath: router$1.future.v7_relativeSplatPath
|
||||
}
|
||||
}, state.initialized || router$1.future.v7_partialHydration ? /*#__PURE__*/React__namespace.createElement(DataRoutes, {
|
||||
routes: router$1.routes,
|
||||
future: router$1.future,
|
||||
state: state
|
||||
}) : fallbackElement))), null);
|
||||
}
|
||||
function DataRoutes(_ref2) {
|
||||
let {
|
||||
routes,
|
||||
future,
|
||||
state
|
||||
} = _ref2;
|
||||
return useRoutesImpl(routes, undefined, state, future);
|
||||
}
|
||||
/**
|
||||
* A `<Router>` that stores all entries in memory.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/memory-router
|
||||
*/
|
||||
function MemoryRouter(_ref3) {
|
||||
let {
|
||||
basename,
|
||||
children,
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
future
|
||||
} = _ref3;
|
||||
let historyRef = React__namespace.useRef();
|
||||
if (historyRef.current == null) {
|
||||
historyRef.current = router.createMemoryHistory({
|
||||
initialEntries,
|
||||
initialIndex,
|
||||
v5Compat: true
|
||||
});
|
||||
}
|
||||
let history = historyRef.current;
|
||||
let [state, setStateImpl] = React__namespace.useState({
|
||||
action: history.action,
|
||||
location: history.location
|
||||
});
|
||||
let {
|
||||
v7_startTransition
|
||||
} = future || {};
|
||||
let setState = React__namespace.useCallback(newState => {
|
||||
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
||||
}, [setStateImpl, v7_startTransition]);
|
||||
React__namespace.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
||||
React__namespace.useEffect(() => logV6DeprecationWarnings(future), [future]);
|
||||
return /*#__PURE__*/React__namespace.createElement(Router, {
|
||||
basename: basename,
|
||||
children: children,
|
||||
location: state.location,
|
||||
navigationType: state.action,
|
||||
navigator: history,
|
||||
future: future
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Changes the current location.
|
||||
*
|
||||
* Note: This API is mostly useful in React.Component subclasses that are not
|
||||
* able to use hooks. In functional components, we recommend you use the
|
||||
* `useNavigate` hook instead.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/navigate
|
||||
*/
|
||||
function Navigate(_ref4) {
|
||||
let {
|
||||
to,
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
} = _ref4;
|
||||
!useInRouterContext() ? router.UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of
|
||||
// the router loaded. We can help them understand how to avoid that.
|
||||
"<Navigate> may be used only in the context of a <Router> component.") : void 0;
|
||||
let {
|
||||
future,
|
||||
static: isStatic
|
||||
} = React__namespace.useContext(NavigationContext);
|
||||
router.UNSAFE_warning(!isStatic, "<Navigate> must not be used on the initial render in a <StaticRouter>. " + "This is a no-op, but you should modify your code so the <Navigate> is " + "only ever rendered in response to some user interaction or state change.") ;
|
||||
let {
|
||||
matches
|
||||
} = React__namespace.useContext(RouteContext);
|
||||
let {
|
||||
pathname: locationPathname
|
||||
} = useLocation();
|
||||
let navigate = useNavigate();
|
||||
|
||||
// Resolve the path outside of the effect so that when effects run twice in
|
||||
// StrictMode they navigate to the same place
|
||||
let path = router.resolveTo(to, router.UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath), locationPathname, relative === "path");
|
||||
let jsonPath = JSON.stringify(path);
|
||||
React__namespace.useEffect(() => navigate(JSON.parse(jsonPath), {
|
||||
replace,
|
||||
state,
|
||||
relative
|
||||
}), [navigate, jsonPath, relative, replace, state]);
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Renders the child route's element, if there is one.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/outlet
|
||||
*/
|
||||
function Outlet(props) {
|
||||
return useOutlet(props.context);
|
||||
}
|
||||
/**
|
||||
* Declares an element that should be rendered at a certain URL path.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/route
|
||||
*/
|
||||
function Route(_props) {
|
||||
router.UNSAFE_invariant(false, "A <Route> is only ever to be used as the child of <Routes> element, " + "never rendered directly. Please wrap your <Route> in a <Routes>.") ;
|
||||
}
|
||||
/**
|
||||
* Provides location context for the rest of the app.
|
||||
*
|
||||
* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
|
||||
* router that is more specific to your environment such as a `<BrowserRouter>`
|
||||
* in web browsers or a `<StaticRouter>` for server rendering.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/router-components/router
|
||||
*/
|
||||
function Router(_ref5) {
|
||||
let {
|
||||
basename: basenameProp = "/",
|
||||
children = null,
|
||||
location: locationProp,
|
||||
navigationType = router.Action.Pop,
|
||||
navigator,
|
||||
static: staticProp = false,
|
||||
future
|
||||
} = _ref5;
|
||||
!!useInRouterContext() ? router.UNSAFE_invariant(false, "You cannot render a <Router> inside another <Router>." + " You should never have more than one in your app.") : void 0;
|
||||
|
||||
// Preserve trailing slashes on basename, so we can let the user control
|
||||
// the enforcement of trailing slashes throughout the app
|
||||
let basename = basenameProp.replace(/^\/*/, "/");
|
||||
let navigationContext = React__namespace.useMemo(() => ({
|
||||
basename,
|
||||
navigator,
|
||||
static: staticProp,
|
||||
future: _extends({
|
||||
v7_relativeSplatPath: false
|
||||
}, future)
|
||||
}), [basename, future, navigator, staticProp]);
|
||||
if (typeof locationProp === "string") {
|
||||
locationProp = router.parsePath(locationProp);
|
||||
}
|
||||
let {
|
||||
pathname = "/",
|
||||
search = "",
|
||||
hash = "",
|
||||
state = null,
|
||||
key = "default"
|
||||
} = locationProp;
|
||||
let locationContext = React__namespace.useMemo(() => {
|
||||
let trailingPathname = router.stripBasename(pathname, basename);
|
||||
if (trailingPathname == null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
location: {
|
||||
pathname: trailingPathname,
|
||||
search,
|
||||
hash,
|
||||
state,
|
||||
key
|
||||
},
|
||||
navigationType
|
||||
};
|
||||
}, [basename, pathname, search, hash, state, key, navigationType]);
|
||||
router.UNSAFE_warning(locationContext != null, "<Router basename=\"" + basename + "\"> is not able to match the URL " + ("\"" + pathname + search + hash + "\" because it does not start with the ") + "basename, so the <Router> won't render anything.") ;
|
||||
if (locationContext == null) {
|
||||
return null;
|
||||
}
|
||||
return /*#__PURE__*/React__namespace.createElement(NavigationContext.Provider, {
|
||||
value: navigationContext
|
||||
}, /*#__PURE__*/React__namespace.createElement(LocationContext.Provider, {
|
||||
children: children,
|
||||
value: locationContext
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* A container for a nested tree of `<Route>` elements that renders the branch
|
||||
* that best matches the current location.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/components/routes
|
||||
*/
|
||||
function Routes(_ref6) {
|
||||
let {
|
||||
children,
|
||||
location
|
||||
} = _ref6;
|
||||
return useRoutes(createRoutesFromChildren(children), location);
|
||||
}
|
||||
/**
|
||||
* Component to use for rendering lazily loaded data from returning defer()
|
||||
* in a loader function
|
||||
*/
|
||||
function Await(_ref7) {
|
||||
let {
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
} = _ref7;
|
||||
return /*#__PURE__*/React__namespace.createElement(AwaitErrorBoundary, {
|
||||
resolve: resolve,
|
||||
errorElement: errorElement
|
||||
}, /*#__PURE__*/React__namespace.createElement(ResolveAwait, null, children));
|
||||
}
|
||||
var AwaitRenderStatus = /*#__PURE__*/function (AwaitRenderStatus) {
|
||||
AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
|
||||
AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
|
||||
AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
|
||||
return AwaitRenderStatus;
|
||||
}(AwaitRenderStatus || {});
|
||||
const neverSettledPromise = new Promise(() => {});
|
||||
class AwaitErrorBoundary extends React__namespace.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: null
|
||||
};
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
return {
|
||||
error
|
||||
};
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("<Await> caught the following error during render", error, errorInfo);
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
children,
|
||||
errorElement,
|
||||
resolve
|
||||
} = this.props;
|
||||
let promise = null;
|
||||
let status = AwaitRenderStatus.pending;
|
||||
if (!(resolve instanceof Promise)) {
|
||||
// Didn't get a promise - provide as a resolved promise
|
||||
status = AwaitRenderStatus.success;
|
||||
promise = Promise.resolve();
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_data", {
|
||||
get: () => resolve
|
||||
});
|
||||
} else if (this.state.error) {
|
||||
// Caught a render error, provide it as a rejected promise
|
||||
status = AwaitRenderStatus.error;
|
||||
let renderError = this.state.error;
|
||||
promise = Promise.reject().catch(() => {}); // Avoid unhandled rejection warnings
|
||||
Object.defineProperty(promise, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
Object.defineProperty(promise, "_error", {
|
||||
get: () => renderError
|
||||
});
|
||||
} else if (resolve._tracked) {
|
||||
// Already tracked promise - check contents
|
||||
promise = resolve;
|
||||
status = "_error" in promise ? AwaitRenderStatus.error : "_data" in promise ? AwaitRenderStatus.success : AwaitRenderStatus.pending;
|
||||
} else {
|
||||
// Raw (untracked) promise - track it
|
||||
status = AwaitRenderStatus.pending;
|
||||
Object.defineProperty(resolve, "_tracked", {
|
||||
get: () => true
|
||||
});
|
||||
promise = resolve.then(data => Object.defineProperty(resolve, "_data", {
|
||||
get: () => data
|
||||
}), error => Object.defineProperty(resolve, "_error", {
|
||||
get: () => error
|
||||
}));
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && promise._error instanceof router.AbortedDeferredError) {
|
||||
// Freeze the UI by throwing a never resolved promise
|
||||
throw neverSettledPromise;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error && !errorElement) {
|
||||
// No errorElement, throw to the nearest route-level error boundary
|
||||
throw promise._error;
|
||||
}
|
||||
if (status === AwaitRenderStatus.error) {
|
||||
// Render via our errorElement
|
||||
return /*#__PURE__*/React__namespace.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: errorElement
|
||||
});
|
||||
}
|
||||
if (status === AwaitRenderStatus.success) {
|
||||
// Render children with resolved value
|
||||
return /*#__PURE__*/React__namespace.createElement(AwaitContext.Provider, {
|
||||
value: promise,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
// Throw to the suspense boundary
|
||||
throw promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Indirection to leverage useAsyncValue for a render-prop API on `<Await>`
|
||||
*/
|
||||
function ResolveAwait(_ref8) {
|
||||
let {
|
||||
children
|
||||
} = _ref8;
|
||||
let data = useAsyncValue();
|
||||
let toRender = typeof children === "function" ? children(data) : children;
|
||||
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, toRender);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTILS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Creates a route config from a React "children" object, which is usually
|
||||
* either a `<Route>` element or an array of them. Used internally by
|
||||
* `<Routes>` to create a route config from its children.
|
||||
*
|
||||
* @see https://reactrouter.com/v6/utils/create-routes-from-children
|
||||
*/
|
||||
function createRoutesFromChildren(children, parentPath) {
|
||||
if (parentPath === void 0) {
|
||||
parentPath = [];
|
||||
}
|
||||
let routes = [];
|
||||
React__namespace.Children.forEach(children, (element, index) => {
|
||||
if (! /*#__PURE__*/React__namespace.isValidElement(element)) {
|
||||
// Ignore non-elements. This allows people to more easily inline
|
||||
// conditionals in their route config.
|
||||
return;
|
||||
}
|
||||
let treePath = [...parentPath, index];
|
||||
if (element.type === React__namespace.Fragment) {
|
||||
// Transparently support React.Fragment and its children.
|
||||
routes.push.apply(routes, createRoutesFromChildren(element.props.children, treePath));
|
||||
return;
|
||||
}
|
||||
!(element.type === Route) ? router.UNSAFE_invariant(false, "[" + (typeof element.type === "string" ? element.type : element.type.name) + "] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>") : void 0;
|
||||
!(!element.props.index || !element.props.children) ? router.UNSAFE_invariant(false, "An index route cannot have child routes.") : void 0;
|
||||
let route = {
|
||||
id: element.props.id || treePath.join("-"),
|
||||
caseSensitive: element.props.caseSensitive,
|
||||
element: element.props.element,
|
||||
Component: element.props.Component,
|
||||
index: element.props.index,
|
||||
path: element.props.path,
|
||||
loader: element.props.loader,
|
||||
action: element.props.action,
|
||||
errorElement: element.props.errorElement,
|
||||
ErrorBoundary: element.props.ErrorBoundary,
|
||||
hasErrorBoundary: element.props.ErrorBoundary != null || element.props.errorElement != null,
|
||||
shouldRevalidate: element.props.shouldRevalidate,
|
||||
handle: element.props.handle,
|
||||
lazy: element.props.lazy
|
||||
};
|
||||
if (element.props.children) {
|
||||
route.children = createRoutesFromChildren(element.props.children, treePath);
|
||||
}
|
||||
routes.push(route);
|
||||
});
|
||||
return routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the result of `matchRoutes()` into a React element.
|
||||
*/
|
||||
function renderMatches(matches) {
|
||||
return _renderMatches(matches);
|
||||
}
|
||||
|
||||
function mapRouteProperties(route) {
|
||||
let updates = {
|
||||
// Note: this check also occurs in createRoutesFromChildren so update
|
||||
// there if you change this -- please and thank you!
|
||||
hasErrorBoundary: route.ErrorBoundary != null || route.errorElement != null
|
||||
};
|
||||
if (route.Component) {
|
||||
{
|
||||
if (route.element) {
|
||||
router.UNSAFE_warning(false, "You should not include both `Component` and `element` on your route - " + "`Component` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
element: /*#__PURE__*/React__namespace.createElement(route.Component),
|
||||
Component: undefined
|
||||
});
|
||||
}
|
||||
if (route.HydrateFallback) {
|
||||
{
|
||||
if (route.hydrateFallbackElement) {
|
||||
router.UNSAFE_warning(false, "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - " + "`HydrateFallback` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
hydrateFallbackElement: /*#__PURE__*/React__namespace.createElement(route.HydrateFallback),
|
||||
HydrateFallback: undefined
|
||||
});
|
||||
}
|
||||
if (route.ErrorBoundary) {
|
||||
{
|
||||
if (route.errorElement) {
|
||||
router.UNSAFE_warning(false, "You should not include both `ErrorBoundary` and `errorElement` on your route - " + "`ErrorBoundary` will be used.") ;
|
||||
}
|
||||
}
|
||||
Object.assign(updates, {
|
||||
errorElement: /*#__PURE__*/React__namespace.createElement(route.ErrorBoundary),
|
||||
ErrorBoundary: undefined
|
||||
});
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
function createMemoryRouter(routes, opts) {
|
||||
return router.createRouter({
|
||||
basename: opts == null ? void 0 : opts.basename,
|
||||
future: _extends({}, opts == null ? void 0 : opts.future, {
|
||||
v7_prependBasename: true
|
||||
}),
|
||||
history: router.createMemoryHistory({
|
||||
initialEntries: opts == null ? void 0 : opts.initialEntries,
|
||||
initialIndex: opts == null ? void 0 : opts.initialIndex
|
||||
}),
|
||||
hydrationData: opts == null ? void 0 : opts.hydrationData,
|
||||
routes,
|
||||
mapRouteProperties,
|
||||
dataStrategy: opts == null ? void 0 : opts.dataStrategy,
|
||||
patchRoutesOnNavigation: opts == null ? void 0 : opts.patchRoutesOnNavigation
|
||||
}).initialize();
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, 'AbortedDeferredError', {
|
||||
enumerable: true,
|
||||
get: function () { return router.AbortedDeferredError; }
|
||||
});
|
||||
Object.defineProperty(exports, 'NavigationType', {
|
||||
enumerable: true,
|
||||
get: function () { return router.Action; }
|
||||
});
|
||||
Object.defineProperty(exports, 'createPath', {
|
||||
enumerable: true,
|
||||
get: function () { return router.createPath; }
|
||||
});
|
||||
Object.defineProperty(exports, 'defer', {
|
||||
enumerable: true,
|
||||
get: function () { return router.defer; }
|
||||
});
|
||||
Object.defineProperty(exports, 'generatePath', {
|
||||
enumerable: true,
|
||||
get: function () { return router.generatePath; }
|
||||
});
|
||||
Object.defineProperty(exports, 'isRouteErrorResponse', {
|
||||
enumerable: true,
|
||||
get: function () { return router.isRouteErrorResponse; }
|
||||
});
|
||||
Object.defineProperty(exports, 'json', {
|
||||
enumerable: true,
|
||||
get: function () { return router.json; }
|
||||
});
|
||||
Object.defineProperty(exports, 'matchPath', {
|
||||
enumerable: true,
|
||||
get: function () { return router.matchPath; }
|
||||
});
|
||||
Object.defineProperty(exports, 'matchRoutes', {
|
||||
enumerable: true,
|
||||
get: function () { return router.matchRoutes; }
|
||||
});
|
||||
Object.defineProperty(exports, 'parsePath', {
|
||||
enumerable: true,
|
||||
get: function () { return router.parsePath; }
|
||||
});
|
||||
Object.defineProperty(exports, 'redirect', {
|
||||
enumerable: true,
|
||||
get: function () { return router.redirect; }
|
||||
});
|
||||
Object.defineProperty(exports, 'redirectDocument', {
|
||||
enumerable: true,
|
||||
get: function () { return router.redirectDocument; }
|
||||
});
|
||||
Object.defineProperty(exports, 'replace', {
|
||||
enumerable: true,
|
||||
get: function () { return router.replace; }
|
||||
});
|
||||
Object.defineProperty(exports, 'resolvePath', {
|
||||
enumerable: true,
|
||||
get: function () { return router.resolvePath; }
|
||||
});
|
||||
exports.Await = Await;
|
||||
exports.MemoryRouter = MemoryRouter;
|
||||
exports.Navigate = Navigate;
|
||||
exports.Outlet = Outlet;
|
||||
exports.Route = Route;
|
||||
exports.Router = Router;
|
||||
exports.RouterProvider = RouterProvider;
|
||||
exports.Routes = Routes;
|
||||
exports.UNSAFE_DataRouterContext = DataRouterContext;
|
||||
exports.UNSAFE_DataRouterStateContext = DataRouterStateContext;
|
||||
exports.UNSAFE_LocationContext = LocationContext;
|
||||
exports.UNSAFE_NavigationContext = NavigationContext;
|
||||
exports.UNSAFE_RouteContext = RouteContext;
|
||||
exports.UNSAFE_logV6DeprecationWarnings = logV6DeprecationWarnings;
|
||||
exports.UNSAFE_mapRouteProperties = mapRouteProperties;
|
||||
exports.UNSAFE_useRouteId = useRouteId;
|
||||
exports.UNSAFE_useRoutesImpl = useRoutesImpl;
|
||||
exports.createMemoryRouter = createMemoryRouter;
|
||||
exports.createRoutesFromChildren = createRoutesFromChildren;
|
||||
exports.createRoutesFromElements = createRoutesFromChildren;
|
||||
exports.renderMatches = renderMatches;
|
||||
exports.useActionData = useActionData;
|
||||
exports.useAsyncError = useAsyncError;
|
||||
exports.useAsyncValue = useAsyncValue;
|
||||
exports.useBlocker = useBlocker;
|
||||
exports.useHref = useHref;
|
||||
exports.useInRouterContext = useInRouterContext;
|
||||
exports.useLoaderData = useLoaderData;
|
||||
exports.useLocation = useLocation;
|
||||
exports.useMatch = useMatch;
|
||||
exports.useMatches = useMatches;
|
||||
exports.useNavigate = useNavigate;
|
||||
exports.useNavigation = useNavigation;
|
||||
exports.useNavigationType = useNavigationType;
|
||||
exports.useOutlet = useOutlet;
|
||||
exports.useOutletContext = useOutletContext;
|
||||
exports.useParams = useParams;
|
||||
exports.useResolvedPath = useResolvedPath;
|
||||
exports.useRevalidator = useRevalidator;
|
||||
exports.useRouteError = useRouteError;
|
||||
exports.useRouteLoaderData = useRouteLoaderData;
|
||||
exports.useRoutes = useRoutes;
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
}));
|
||||
//# sourceMappingURL=react-router.development.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "react-router",
|
||||
"version": "6.30.4",
|
||||
"description": "Declarative routing for React",
|
||||
"keywords": [
|
||||
"react",
|
||||
"router",
|
||||
"route",
|
||||
"routing",
|
||||
"history",
|
||||
"link"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/remix-run/react-router",
|
||||
"directory": "packages/react-router"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Remix Software <hello@remix.run>",
|
||||
"sideEffects": false,
|
||||
"main": "./dist/main.js",
|
||||
"unpkg": "./dist/umd/react-router.production.min.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "6.30.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE.md",
|
||||
"README.md"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user