react-router-dom
Advanced tools
Comparing version
316
CHANGELOG.md
# `react-router-dom` | ||
## 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 | ||
- Fixes an edge-case affecting web extensions in Firefox that use `URLSearchParams` and the `useSearchParams` hook. ([#10620](https://github.com/remix-run/react-router/pull/10620)) | ||
- Do not include hash in `useFormAction()` for unspecified actions since it cannot be determined on the server and causes hydration issues ([#10758](https://github.com/remix-run/react-router/pull/10758)) | ||
- Reorder effects in `unstable_usePrompt` to avoid throwing an exception if the prompt is unblocked and a navigation is performed synchronously ([#10687](https://github.com/remix-run/react-router/pull/10687), [#10718](https://github.com/remix-run/react-router/pull/10718)) | ||
- Updated dependencies: | ||
- `@remix-run/router@1.8.0` | ||
- `react-router@6.15.0` | ||
## 6.14.2 | ||
### Patch Changes | ||
- Properly decode element id when emulating hash scrolling via `<ScrollRestoration>` ([#10682](https://github.com/remix-run/react-router/pull/10682)) | ||
- Add missing `<Form state>` prop to populate `history.state` on submission navigations ([#10630](https://github.com/remix-run/react-router/pull/10630)) | ||
- Support proper hydration of `Error` subclasses such as `ReferenceError`/`TypeError` ([#10633](https://github.com/remix-run/react-router/pull/10633)) | ||
- Updated dependencies: | ||
- `@remix-run/router@1.7.2` | ||
- `react-router@6.14.2` | ||
## 6.14.1 | ||
### Patch Changes | ||
- Updated dependencies: | ||
- `react-router@6.14.1` | ||
- `@remix-run/router@1.7.1` | ||
## 6.14.0 | ||
### Minor Changes | ||
- Add support for `application/json` and `text/plain` encodings for `useSubmit`/`fetcher.submit`. To reflect these additional types, `useNavigation`/`useFetcher` now also contain `navigation.json`/`navigation.text` and `fetcher.json`/`fetcher.text` which include the json/text submission if applicable ([#10413](https://github.com/remix-run/react-router/pull/10413)) | ||
```jsx | ||
// The default behavior will still serialize as FormData | ||
function Component() { | ||
let navigation = useNavigation(); | ||
let submit = useSubmit(); | ||
submit({ key: "value" }, { method: "post" }); | ||
// navigation.formEncType => "application/x-www-form-urlencoded" | ||
// navigation.formData => FormData instance | ||
} | ||
async function action({ request }) { | ||
// request.headers.get("Content-Type") => "application/x-www-form-urlencoded" | ||
// await request.formData() => FormData instance | ||
} | ||
``` | ||
```js | ||
// Opt-into JSON encoding with `encType: "application/json"` | ||
function Component() { | ||
let navigation = useNavigation(); | ||
let submit = useSubmit(); | ||
submit({ key: "value" }, { method: "post", encType: "application/json" }); | ||
// navigation.formEncType => "application/json" | ||
// navigation.json => { key: "value" } | ||
} | ||
async function action({ request }) { | ||
// request.headers.get("Content-Type") => "application/json" | ||
// await request.json() => { key: "value" } | ||
} | ||
``` | ||
```js | ||
// Opt-into text encoding with `encType: "text/plain"` | ||
function Component() { | ||
let navigation = useNavigation(); | ||
let submit = useSubmit(); | ||
submit("Text submission", { method: "post", encType: "text/plain" }); | ||
// navigation.formEncType => "text/plain" | ||
// navigation.text => "Text submission" | ||
} | ||
async function action({ request }) { | ||
// request.headers.get("Content-Type") => "text/plain" | ||
// await request.text() => "Text submission" | ||
} | ||
``` | ||
### Patch Changes | ||
- When submitting a form from a `submitter` element, prefer the built-in `new FormData(form, submitter)` instead of the previous manual approach in modern browsers (those that support the new `submitter` parameter) ([#9865](https://github.com/remix-run/react-router/pull/9865), [#10627](https://github.com/remix-run/react-router/pull/10627)) | ||
- For browsers that don't support it, we continue to just append the submit button's entry to the end, and we also add rudimentary support for `type="image"` buttons | ||
- If developers want full spec-compliant support for legacy browsers, they can use the `formdata-submitter-polyfill` | ||
- Call `window.history.pushState/replaceState` before updating React Router state (instead of after) so that `window.location` matches `useLocation` during synchronous React 17 rendering ([#10448](https://github.com/remix-run/react-router/pull/10448)) | ||
- ⚠️ However, generally apps should not be relying on `window.location` and should always reference `useLocation` when possible, as `window.location` will not be in sync 100% of the time (due to `popstate` events, concurrent mode, etc.) | ||
- 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: | ||
- `react-router@6.14.0` | ||
- `@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/en/main/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)) | ||
- Updated dependencies: | ||
- `react-router@6.13.0` | ||
## 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)) | ||
- Updated dependencies: | ||
- `react-router@6.12.1` | ||
## 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 | ||
- Re-throw `DOMException` (`DataCloneError`) when attempting to perform a `PUSH` navigation with non-serializable state. ([#10427](https://github.com/remix-run/react-router/pull/10427)) | ||
- Updated dependencies: | ||
- `@remix-run/router@1.6.3` | ||
- `react-router@6.12.0` | ||
## 6.11.2 | ||
### Patch Changes | ||
- Export `SetURLSearchParams` type ([#10444](https://github.com/remix-run/react-router/pull/10444)) | ||
- Updated dependencies: | ||
- `react-router@6.11.2` | ||
- `@remix-run/router@1.6.2` | ||
## 6.11.1 | ||
### Patch Changes | ||
- Updated dependencies: | ||
- `react-router@6.11.1` | ||
- `@remix-run/router@1.6.1` | ||
## 6.11.0 | ||
### Minor Changes | ||
- Enable `basename` support in `useFetcher` ([#10336](https://github.com/remix-run/react-router/pull/10336)) | ||
- If you were previously working around this issue by manually prepending the `basename` then you will need to remove the manually prepended `basename` from your `fetcher` calls (`fetcher.load('/basename/route') -> fetcher.load('/route')`) | ||
### Patch Changes | ||
- Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287)) | ||
- Fail gracefully on `<Link to="//">` and other invalid URL values ([#10367](https://github.com/remix-run/react-router/pull/10367)) | ||
- 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)) | ||
- Add static prop to `StaticRouterProvider`'s internal `Router` component ([#10401](https://github.com/remix-run/react-router/pull/10401)) | ||
- 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: | ||
- `react-router@6.11.0` | ||
- `@remix-run/router@1.6.0` | ||
## 6.10.0 | ||
### Minor Changes | ||
- Added support for [**Future Flags**](https://reactrouter.com/en/main/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 `createStaticHandler` to also check for `ErrorBoundary` on routes in addition to `errorElement` ([#10190](https://github.com/remix-run/react-router/pull/10190)) | ||
- Updated dependencies: | ||
- `@remix-run/router@1.5.0` | ||
- `react-router@6.10.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: | ||
- `react-router@6.9.0` | ||
- `@remix-run/router@1.4.0` | ||
## 6.8.2 | ||
@@ -4,0 +320,0 @@ |
@@ -1,4 +0,3 @@ | ||
import type { FormEncType, FormMethod } from "@remix-run/router"; | ||
import type { RelativeRoutingType } from "react-router"; | ||
export declare const defaultMethod = "get"; | ||
import type { FormEncType, HTMLFormMethod, RelativeRoutingType } from "@remix-run/router"; | ||
export declare const defaultMethod: HTMLFormMethod; | ||
export declare function isHtmlElement(object: any): object is HTMLElement; | ||
@@ -8,6 +7,6 @@ export declare function isButtonElement(object: any): object is HTMLButtonElement; | ||
export declare function isInputElement(object: any): object is HTMLInputElement; | ||
declare type LimitedMouseEvent = Pick<MouseEvent, "button" | "metaKey" | "altKey" | "ctrlKey" | "shiftKey">; | ||
type LimitedMouseEvent = Pick<MouseEvent, "button" | "metaKey" | "altKey" | "ctrlKey" | "shiftKey">; | ||
export declare function shouldProcessLinkClick(event: LimitedMouseEvent, target?: string): boolean; | ||
export declare type ParamKeyValuePair = [string, string]; | ||
export declare type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams; | ||
export type ParamKeyValuePair = [string, string]; | ||
export type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams; | ||
/** | ||
@@ -36,2 +35,11 @@ * Creates a URLSearchParams object using the given initializer. | ||
export declare function getSearchParamsForLocation(locationSearch: string, defaultSearchParams: URLSearchParams | null): URLSearchParams; | ||
type JsonObject = { | ||
[Key in string]: JsonValue; | ||
} & { | ||
[Key in string]?: JsonValue | undefined; | ||
}; | ||
type JsonArray = JsonValue[] | readonly JsonValue[]; | ||
type JsonPrimitive = string | number | boolean | null; | ||
type JsonValue = JsonPrimitive | JsonObject | JsonArray; | ||
export type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | JsonValue | null; | ||
export interface SubmitOptions { | ||
@@ -42,13 +50,10 @@ /** | ||
*/ | ||
method?: FormMethod; | ||
method?: HTMLFormMethod; | ||
/** | ||
* The action URL path used to submit the form. Overrides `<form action>`. | ||
* Defaults to the path of the current route. | ||
* | ||
* Note: It is assumed the path is already resolved. If you need to resolve a | ||
* relative path, use `useFormAction`. | ||
*/ | ||
action?: string; | ||
/** | ||
* The action URL used to submit the form. Overrides `<form encType>`. | ||
* The encoding used to submit the form. Overrides `<form encType>`. | ||
* Defaults to "application/x-www-form-urlencoded". | ||
@@ -64,2 +69,6 @@ */ | ||
/** | ||
* State object to add to the history stack entry for this navigation | ||
*/ | ||
state?: any; | ||
/** | ||
* Determines whether the form action is relative to the route hierarchy or | ||
@@ -76,10 +85,9 @@ * the pathname. Use this if you want to opt out of navigating the route | ||
} | ||
export declare function getFormSubmissionInfo(target: HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | { | ||
[name: string]: string; | ||
} | null, defaultAction: string, options: SubmitOptions): { | ||
url: URL; | ||
export declare function getFormSubmissionInfo(target: SubmitTarget, basename: string): { | ||
action: string | null; | ||
method: string; | ||
encType: string; | ||
formData: FormData; | ||
formData: FormData | undefined; | ||
body: any; | ||
}; | ||
export {}; |
@@ -6,28 +6,27 @@ /** | ||
import * as React from "react"; | ||
import type { NavigateOptions, RelativeRoutingType, RouteObject, To } from "react-router"; | ||
import type { Fetcher, FormEncType, FormMethod, GetScrollRestorationKeyFunction, History, HydrationState, Router as RemixRouter } from "@remix-run/router"; | ||
import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit } from "./dom"; | ||
import type { FutureConfig, NavigateOptions, RelativeRoutingType, RouteObject, To } from "react-router"; | ||
import type { Fetcher, FormEncType, FormMethod, FutureConfig as RouterFutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, Router as RemixRouter, V7_FormMethod } from "@remix-run/router"; | ||
import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit, SubmitTarget } from "./dom"; | ||
import { createSearchParams } from "./dom"; | ||
export type { FormEncType, FormMethod, GetScrollRestorationKeyFunction, ParamKeyValuePair, SubmitOptions, URLSearchParamsInit, }; | ||
export type { FormEncType, FormMethod, GetScrollRestorationKeyFunction, ParamKeyValuePair, SubmitOptions, URLSearchParamsInit, V7_FormMethod, }; | ||
export { createSearchParams }; | ||
export type { ActionFunction, ActionFunctionArgs, AwaitProps, unstable_Blocker, unstable_BlockerFunction, DataRouteMatch, DataRouteObject, Fetcher, Hash, IndexRouteObject, IndexRouteProps, JsonFunction, LazyRouteFunction, LayoutRouteProps, LoaderFunction, LoaderFunctionArgs, Location, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigation, Navigator, NonIndexRouteObject, OutletProps, Params, ParamParseKey, Path, PathMatch, Pathname, PathPattern, PathRouteProps, RedirectFunction, RelativeRoutingType, RouteMatch, RouteObject, RouteProps, RouterProps, RouterProviderProps, RoutesProps, Search, ShouldRevalidateFunction, To, } from "react-router"; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, isRouteErrorResponse, generatePath, json, matchPath, matchRoutes, parsePath, redirect, renderMatches, resolvePath, useActionData, useAsyncError, useAsyncValue, unstable_useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, } from "react-router"; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, isRouteErrorResponse, generatePath, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, useActionData, useAsyncError, useAsyncValue, unstable_useBlocker, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, } from "react-router"; | ||
/** @internal */ | ||
export { UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_NavigationContext, UNSAFE_LocationContext, UNSAFE_RouteContext, } from "react-router"; | ||
export { UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_NavigationContext, UNSAFE_LocationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, } from "react-router"; | ||
declare global { | ||
var __staticRouterHydrationData: HydrationState | undefined; | ||
} | ||
export declare function createBrowserRouter(routes: RouteObject[], opts?: { | ||
interface DOMRouterOpts { | ||
basename?: string; | ||
future?: Partial<Omit<RouterFutureConfig, "v7_prependBasename">>; | ||
hydrationData?: HydrationState; | ||
window?: Window; | ||
}): RemixRouter; | ||
export declare function createHashRouter(routes: RouteObject[], opts?: { | ||
basename?: string; | ||
hydrationData?: HydrationState; | ||
window?: Window; | ||
}): RemixRouter; | ||
} | ||
export declare function createBrowserRouter(routes: RouteObject[], opts?: DOMRouterOpts): RemixRouter; | ||
export declare function createHashRouter(routes: RouteObject[], opts?: DOMRouterOpts): RemixRouter; | ||
export interface BrowserRouterProps { | ||
basename?: string; | ||
children?: React.ReactNode; | ||
future?: FutureConfig; | ||
window?: Window; | ||
@@ -38,6 +37,7 @@ } | ||
*/ | ||
export declare function BrowserRouter({ basename, children, window, }: BrowserRouterProps): JSX.Element; | ||
export declare function BrowserRouter({ basename, children, future, window, }: BrowserRouterProps): React.JSX.Element; | ||
export interface HashRouterProps { | ||
basename?: string; | ||
children?: React.ReactNode; | ||
future?: FutureConfig; | ||
window?: Window; | ||
@@ -49,6 +49,7 @@ } | ||
*/ | ||
export declare function HashRouter({ basename, children, window }: HashRouterProps): JSX.Element; | ||
export declare function HashRouter({ basename, children, future, window, }: HashRouterProps): React.JSX.Element; | ||
export interface HistoryRouterProps { | ||
basename?: string; | ||
children?: React.ReactNode; | ||
future?: FutureConfig; | ||
history: History; | ||
@@ -62,3 +63,3 @@ } | ||
*/ | ||
declare function HistoryRouter({ basename, children, history }: HistoryRouterProps): JSX.Element; | ||
declare function HistoryRouter({ basename, children, future, history, }: HistoryRouterProps): React.JSX.Element; | ||
declare namespace HistoryRouter { | ||
@@ -100,3 +101,3 @@ var displayName: string; | ||
export declare const NavLink: React.ForwardRefExoticComponent<NavLinkProps & React.RefAttributes<HTMLAnchorElement>>; | ||
export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement> { | ||
export interface FetcherFormProps extends React.FormHTMLAttributes<HTMLFormElement> { | ||
/** | ||
@@ -106,4 +107,9 @@ * The HTTP verb to use when the form is submit. Supports "get", "post", | ||
*/ | ||
method?: FormMethod; | ||
method?: HTMLFormMethod; | ||
/** | ||
* `<form encType>` - enhancing beyond the normal string type and limiting | ||
* to the built-in browser supported values | ||
*/ | ||
encType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain"; | ||
/** | ||
* Normal `<form action>` but supports React Router's relative paths. | ||
@@ -113,12 +119,2 @@ */ | ||
/** | ||
* Forces a full document navigation instead of a fetch. | ||
*/ | ||
reloadDocument?: boolean; | ||
/** | ||
* Replaces the current entry in the browser history stack when the form | ||
* navigates. Use this if you don't want the user to be able to click "back" | ||
* to the page with the form on it. | ||
*/ | ||
replace?: boolean; | ||
/** | ||
* Determines whether the form action is relative to the route hierarchy or | ||
@@ -140,2 +136,18 @@ * the pathname. Use this if you want to opt out of navigating the route | ||
} | ||
export interface FormProps extends FetcherFormProps { | ||
/** | ||
* Forces a full document navigation instead of a fetch. | ||
*/ | ||
reloadDocument?: boolean; | ||
/** | ||
* Replaces the current entry in the browser history stack when the form | ||
* navigates. Use this if you don't want the user to be able to click "back" | ||
* to the page with the form on it. | ||
*/ | ||
replace?: boolean; | ||
/** | ||
* State object to add to the history stack entry for this navigation | ||
*/ | ||
state?: any; | ||
} | ||
/** | ||
@@ -177,6 +189,3 @@ * A `@remix-run/router`-aware `<form>`. It behaves like a normal form except | ||
export declare function useSearchParams(defaultInit?: URLSearchParamsInit): [URLSearchParams, SetURLSearchParams]; | ||
declare type SetURLSearchParams = (nextInit?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), navigateOpts?: NavigateOptions) => void; | ||
declare type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | { | ||
[name: string]: string; | ||
} | null; | ||
export type SetURLSearchParams = (nextInit?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), navigateOpts?: NavigateOptions) => void; | ||
/** | ||
@@ -203,2 +212,8 @@ * Submits a HTML `<form>` to the server without reloading the page. | ||
/** | ||
* Submits a fetcher `<form>` to the server without reloading the page. | ||
*/ | ||
export interface FetcherSubmitFunction { | ||
(target: SubmitTarget, options?: Omit<SubmitOptions, "replace" | "state">): void; | ||
} | ||
/** | ||
* Returns a function that may be used to programmatically submit a form (or | ||
@@ -211,6 +226,6 @@ * some arbitrary data) to the server. | ||
}): string; | ||
declare function createFetcherForm(fetcherKey: string, routeId: string): React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>; | ||
export declare type FetcherWithComponents<TData> = Fetcher<TData> & { | ||
declare function createFetcherForm(fetcherKey: string, routeId: string): React.ForwardRefExoticComponent<FetcherFormProps & React.RefAttributes<HTMLFormElement>>; | ||
export type FetcherWithComponents<TData> = Fetcher<TData> & { | ||
Form: ReturnType<typeof createFetcherForm>; | ||
submit: (target: SubmitTarget, options?: Omit<SubmitOptions, "replace" | "preventScrollReset">) => void; | ||
submit: FetcherSubmitFunction; | ||
load: (href: string) => void; | ||
@@ -217,0 +232,0 @@ }; |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -12,5 +12,5 @@ * Copyright (c) Remix Software Inc. | ||
import * as React from 'react'; | ||
import { UNSAFE_detectErrorBoundary, Router, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, UNSAFE_DataRouterStateContext, useNavigate, createPath, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker, UNSAFE_DataRouterContext } from 'react-router'; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router'; | ||
import { createRouter, createBrowserHistory, createHashHistory, ErrorResponse, stripBasename, UNSAFE_warning, UNSAFE_invariant, joinPaths } from '@remix-run/router'; | ||
import { UNSAFE_mapRouteProperties, Router, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, UNSAFE_DataRouterStateContext, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker, UNSAFE_DataRouterContext } from 'react-router'; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router'; | ||
import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, ErrorResponse, UNSAFE_invariant, joinPaths } from '@remix-run/router'; | ||
@@ -21,3 +21,2 @@ function _extends() { | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
@@ -29,3 +28,2 @@ if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
} | ||
return target; | ||
@@ -35,3 +33,2 @@ }; | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -42,3 +39,2 @@ if (source == null) return {}; | ||
var key, i; | ||
for (i = 0; i < sourceKeys.length; i++) { | ||
@@ -49,3 +45,2 @@ key = sourceKeys[i]; | ||
} | ||
return target; | ||
@@ -68,10 +63,10 @@ } | ||
} | ||
function isModifiedEvent(event) { | ||
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); | ||
} | ||
function shouldProcessLinkClick(event, target) { | ||
return event.button === 0 && ( // Ignore everything but left clicks | ||
!target || target === "_self") && // Let browser handle "target=_blank" etc. | ||
return event.button === 0 && ( | ||
// Ignore everything but left clicks | ||
!target || target === "_self") && | ||
// Let browser handle "target=_blank" etc. | ||
!isModifiedEvent(event) // Ignore clicks with modifier keys | ||
@@ -101,3 +96,2 @@ ; | ||
*/ | ||
function createSearchParams(init) { | ||
@@ -107,3 +101,2 @@ if (init === void 0) { | ||
} | ||
return new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo, key) => { | ||
@@ -116,5 +109,9 @@ let value = init[key]; | ||
let searchParams = createSearchParams(locationSearch); | ||
if (defaultSearchParams) { | ||
for (let key of defaultSearchParams.keys()) { | ||
// Use `defaultSearchParams.forEach(...)` here instead of iterating of | ||
// `defaultSearchParams.keys()` to work-around a bug in Firefox related to | ||
// web extensions. Relevant Bugzilla tickets: | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1414602 | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1023984 | ||
defaultSearchParams.forEach((_, key) => { | ||
if (!searchParams.has(key)) { | ||
@@ -125,8 +122,30 @@ defaultSearchParams.getAll(key).forEach(value => { | ||
} | ||
} | ||
}); | ||
} | ||
return searchParams; | ||
} | ||
function getFormSubmissionInfo(target, defaultAction, options) { | ||
// One-time check for submitter support | ||
let _formDataSupportsSubmitter = null; | ||
function isFormDataSubmitterSupported() { | ||
if (_formDataSupportsSubmitter === null) { | ||
try { | ||
new FormData(document.createElement("form"), | ||
// @ts-expect-error if FormData supports the submitter parameter, this will throw | ||
0); | ||
_formDataSupportsSubmitter = false; | ||
} catch (e) { | ||
_formDataSupportsSubmitter = true; | ||
} | ||
} | ||
return _formDataSupportsSubmitter; | ||
} | ||
const supportedFormEncTypes = new Set(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]); | ||
function getFormEncType(encType) { | ||
if (encType != null && !supportedFormEncTypes.has(encType)) { | ||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "\"" + encType + "\" is not a valid `encType` for `<Form>`/`<fetcher.Form>` " + ("and will default to \"" + defaultEncType + "\"")) : void 0; | ||
return null; | ||
} | ||
return encType; | ||
} | ||
function getFormSubmissionInfo(target, basename) { | ||
let method; | ||
@@ -136,64 +155,64 @@ let action; | ||
let formData; | ||
let body; | ||
if (isFormElement(target)) { | ||
let submissionTrigger = options.submissionTrigger; | ||
method = options.method || target.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("enctype") || defaultEncType; | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("action"); | ||
action = attr ? stripBasename(attr, basename) : null; | ||
method = target.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType; | ||
formData = new FormData(target); | ||
if (submissionTrigger && submissionTrigger.name) { | ||
formData.append(submissionTrigger.name, submissionTrigger.value); | ||
} | ||
} else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) { | ||
let form = target.form; | ||
if (form == null) { | ||
throw new Error("Cannot submit a <button> or <input type=\"submit\"> without a <form>"); | ||
} // <button>/<input type="submit"> may override attributes of <form> | ||
method = options.method || target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("formaction") || form.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("formenctype") || form.getAttribute("enctype") || defaultEncType; | ||
formData = new FormData(form); // Include name + value from a <button>, appending in case the button name | ||
// matches an existing input name | ||
if (target.name) { | ||
formData.append(target.name, target.value); | ||
} | ||
// <button>/<input type="submit"> may override attributes of <form> | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("formaction") || form.getAttribute("action"); | ||
action = attr ? stripBasename(attr, basename) : null; | ||
method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType; | ||
// Build a FormData object populated from a form and submitter | ||
formData = new FormData(form, target); | ||
// If this browser doesn't support the `FormData(el, submitter)` format, | ||
// then tack on the submitter value at the end. This is a lightweight | ||
// solution that is not 100% spec compliant. For complete support in older | ||
// browsers, consider using the `formdata-submitter-polyfill` package | ||
if (!isFormDataSubmitterSupported()) { | ||
let { | ||
name, | ||
type, | ||
value | ||
} = target; | ||
if (type === "image") { | ||
let prefix = name ? name + "." : ""; | ||
formData.append(prefix + "x", "0"); | ||
formData.append(prefix + "y", "0"); | ||
} else if (name) { | ||
formData.append(name, value); | ||
} | ||
} | ||
} else if (isHtmlElement(target)) { | ||
throw new Error("Cannot submit element that is not <form>, <button>, or " + "<input type=\"submit|image\">"); | ||
} else { | ||
method = options.method || defaultMethod; | ||
action = options.action || defaultAction; | ||
encType = options.encType || defaultEncType; | ||
if (target instanceof FormData) { | ||
formData = target; | ||
} else { | ||
formData = new FormData(); | ||
if (target instanceof URLSearchParams) { | ||
for (let [name, value] of target) { | ||
formData.append(name, value); | ||
} | ||
} else if (target != null) { | ||
for (let name of Object.keys(target)) { | ||
formData.append(name, target[name]); | ||
} | ||
} | ||
} | ||
method = defaultMethod; | ||
action = null; | ||
encType = defaultEncType; | ||
body = target; | ||
} | ||
let { | ||
protocol, | ||
host | ||
} = window.location; | ||
let url = new URL(action, protocol + "//" + host); | ||
// Send body for <Form encType="text/plain" so we encode it into text | ||
if (formData && encType === "text/plain") { | ||
body = formData; | ||
formData = undefined; | ||
} | ||
return { | ||
url, | ||
action, | ||
method: method.toLowerCase(), | ||
encType, | ||
formData | ||
formData, | ||
body | ||
}; | ||
@@ -203,10 +222,10 @@ } | ||
const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset"], | ||
_excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "children"], | ||
_excluded3 = ["reloadDocument", "replace", "method", "action", "onSubmit", "fetcherKey", "routeId", "relative", "preventScrollReset"]; | ||
//#region Routers | ||
//////////////////////////////////////////////////////////////////////////////// | ||
_excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "children"], | ||
_excluded3 = ["reloadDocument", "replace", "state", "method", "action", "onSubmit", "submit", "relative", "preventScrollReset"]; | ||
function createBrowserRouter(routes, opts) { | ||
return createRouter({ | ||
basename: opts == null ? void 0 : opts.basename, | ||
future: _extends({}, opts == null ? void 0 : opts.future, { | ||
v7_prependBasename: true | ||
}), | ||
history: createBrowserHistory({ | ||
@@ -217,3 +236,3 @@ window: opts == null ? void 0 : opts.window | ||
routes, | ||
detectErrorBoundary: UNSAFE_detectErrorBoundary | ||
mapRouteProperties: UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
@@ -224,2 +243,5 @@ } | ||
basename: opts == null ? void 0 : opts.basename, | ||
future: _extends({}, opts == null ? void 0 : opts.future, { | ||
v7_prependBasename: true | ||
}), | ||
history: createHashHistory({ | ||
@@ -230,11 +252,8 @@ window: opts == null ? void 0 : opts.window | ||
routes, | ||
detectErrorBoundary: UNSAFE_detectErrorBoundary | ||
mapRouteProperties: UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
} | ||
function parseHydrationData() { | ||
var _window; | ||
let state = (_window = window) == null ? void 0 : _window.__staticRouterHydrationData; | ||
if (state && state.errors) { | ||
@@ -245,6 +264,4 @@ state = _extends({}, state, { | ||
} | ||
return state; | ||
} | ||
function deserializeErrors(errors) { | ||
@@ -254,3 +271,2 @@ if (!errors) return null; | ||
let serialized = {}; | ||
for (let [key, val] of entries) { | ||
@@ -262,7 +278,25 @@ // Hey you! If you change this, please change the corresponding logic in | ||
} else if (val && val.__type === "Error") { | ||
let error = new Error(val.message); // Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
// Attempt to reconstruct the right type of Error (i.e., ReferenceError) | ||
if (val.__subType) { | ||
let ErrorConstructor = window[val.__subType]; | ||
if (typeof ErrorConstructor === "function") { | ||
try { | ||
// @ts-expect-error | ||
let error = new ErrorConstructor(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} catch (e) { | ||
// no-op - fall through and create a normal Error | ||
} | ||
} | ||
} | ||
if (serialized[key] == null) { | ||
let error = new Error(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} | ||
} else { | ||
@@ -272,10 +306,34 @@ serialized[key] = val; | ||
} | ||
return serialized; | ||
} | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
//#region Components | ||
//////////////////////////////////////////////////////////////////////////////// | ||
/** | ||
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]; | ||
/** | ||
* A `<Router>` for use in web browsers. Provides the cleanest URLs. | ||
*/ | ||
function BrowserRouter(_ref) { | ||
@@ -285,6 +343,6 @@ let { | ||
children, | ||
future, | ||
window | ||
} = _ref; | ||
let historyRef = React.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -296,9 +354,14 @@ historyRef.current = createBrowserHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -316,3 +379,2 @@ basename: basename, | ||
*/ | ||
function HashRouter(_ref2) { | ||
@@ -322,6 +384,6 @@ let { | ||
children, | ||
future, | ||
window | ||
} = _ref2; | ||
let historyRef = React.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -333,9 +395,14 @@ historyRef.current = createHashHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -355,3 +422,2 @@ basename: basename, | ||
*/ | ||
function HistoryRouter(_ref3) { | ||
@@ -361,9 +427,16 @@ let { | ||
children, | ||
future, | ||
history | ||
} = _ref3; | ||
const [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -377,3 +450,2 @@ basename: basename, | ||
} | ||
if (process.env.NODE_ENV !== "production") { | ||
@@ -387,42 +459,42 @@ HistoryRouter.displayName = "unstable_HistoryRouter"; | ||
*/ | ||
const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef(_ref4, ref) { | ||
let { | ||
onClick, | ||
relative, | ||
reloadDocument, | ||
replace, | ||
state, | ||
target, | ||
to, | ||
preventScrollReset | ||
} = _ref4, | ||
rest = _objectWithoutPropertiesLoose(_ref4, _excluded); | ||
onClick, | ||
relative, | ||
reloadDocument, | ||
replace, | ||
state, | ||
target, | ||
to, | ||
preventScrollReset | ||
} = _ref4, | ||
rest = _objectWithoutPropertiesLoose(_ref4, _excluded); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); // Rendered into <a href> for absolute URLs | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
// Rendered into <a href> for absolute URLs | ||
let absoluteHref; | ||
let isExternal = false; | ||
if (typeof to === "string" && ABSOLUTE_URL_REGEX.test(to)) { | ||
// Render the absolute href server- and client-side | ||
absoluteHref = to; // Only check for external origins client-side | ||
absoluteHref = to; | ||
// Only check for external origins client-side | ||
if (isBrowser) { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
try { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
} | ||
} catch (e) { | ||
// We can't do external URL detection without a valid URL | ||
process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "<Link to=\"" + to + "\"> contains an invalid URL which will probably break " + "when clicked - please update to a valid URL path.") : void 0; | ||
} | ||
} | ||
} // Rendered into <a href> for relative URLs | ||
} | ||
// Rendered into <a href> for relative URLs | ||
let href = useHref(to, { | ||
@@ -438,6 +510,4 @@ relative | ||
}); | ||
function handleClick(event) { | ||
if (onClick) onClick(event); | ||
if (!event.defaultPrevented) { | ||
@@ -447,3 +517,2 @@ internalOnClick(event); | ||
} | ||
return ( | ||
@@ -460,3 +529,2 @@ /*#__PURE__*/ | ||
}); | ||
if (process.env.NODE_ENV !== "production") { | ||
@@ -468,16 +536,13 @@ Link.displayName = "Link"; | ||
*/ | ||
const NavLink = /*#__PURE__*/React.forwardRef(function NavLinkWithRef(_ref5, ref) { | ||
let { | ||
"aria-current": ariaCurrentProp = "page", | ||
caseSensitive = false, | ||
className: classNameProp = "", | ||
end = false, | ||
style: styleProp, | ||
to, | ||
children | ||
} = _ref5, | ||
rest = _objectWithoutPropertiesLoose(_ref5, _excluded2); | ||
"aria-current": ariaCurrentProp = "page", | ||
caseSensitive = false, | ||
className: classNameProp = "", | ||
end = false, | ||
style: styleProp, | ||
to, | ||
children | ||
} = _ref5, | ||
rest = _objectWithoutPropertiesLoose(_ref5, _excluded2); | ||
let path = useResolvedPath(to, { | ||
@@ -494,3 +559,2 @@ relative: rest.relative | ||
let nextLocationPathname = routerState && routerState.navigation && routerState.navigation.location ? routerState.navigation.location.pathname : null; | ||
if (!caseSensitive) { | ||
@@ -501,3 +565,2 @@ locationPathname = locationPathname.toLowerCase(); | ||
} | ||
let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(toPathname.length) === "/"; | ||
@@ -507,3 +570,2 @@ let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/"); | ||
let className; | ||
if (typeof classNameProp === "function") { | ||
@@ -522,3 +584,2 @@ className = classNameProp({ | ||
} | ||
let style = typeof styleProp === "function" ? styleProp({ | ||
@@ -539,3 +600,2 @@ isActive, | ||
}); | ||
if (process.env.NODE_ENV !== "production") { | ||
@@ -550,29 +610,25 @@ NavLink.displayName = "NavLink"; | ||
*/ | ||
const Form = /*#__PURE__*/React.forwardRef((props, ref) => { | ||
let submit = useSubmit(); | ||
return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, { | ||
submit: submit, | ||
ref: ref | ||
})); | ||
}); | ||
if (process.env.NODE_ENV !== "production") { | ||
Form.displayName = "Form"; | ||
} | ||
const FormImpl = /*#__PURE__*/React.forwardRef((_ref6, forwardedRef) => { | ||
let { | ||
reloadDocument, | ||
replace, | ||
method = defaultMethod, | ||
action, | ||
onSubmit, | ||
fetcherKey, | ||
routeId, | ||
relative, | ||
preventScrollReset | ||
} = _ref6, | ||
props = _objectWithoutPropertiesLoose(_ref6, _excluded3); | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
reloadDocument, | ||
replace, | ||
state, | ||
method = defaultMethod, | ||
action, | ||
onSubmit, | ||
submit, | ||
relative, | ||
preventScrollReset | ||
} = _ref6, | ||
props = _objectWithoutPropertiesLoose(_ref6, _excluded3); | ||
let formMethod = method.toLowerCase() === "get" ? "get" : "post"; | ||
@@ -582,3 +638,2 @@ let formAction = useFormAction(action, { | ||
}); | ||
let submitHandler = event => { | ||
@@ -593,2 +648,3 @@ onSubmit && onSubmit(event); | ||
replace, | ||
state, | ||
relative, | ||
@@ -598,3 +654,2 @@ preventScrollReset | ||
}; | ||
return /*#__PURE__*/React.createElement("form", _extends({ | ||
@@ -607,3 +662,2 @@ ref: forwardedRef, | ||
}); | ||
if (process.env.NODE_ENV !== "production") { | ||
@@ -616,4 +670,2 @@ FormImpl.displayName = "FormImpl"; | ||
*/ | ||
function ScrollRestoration(_ref7) { | ||
@@ -630,21 +682,17 @@ let { | ||
} | ||
if (process.env.NODE_ENV !== "production") { | ||
ScrollRestoration.displayName = "ScrollRestoration"; | ||
} //#endregion | ||
} | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
//#region Hooks | ||
//////////////////////////////////////////////////////////////////////////////// | ||
var DataRouterHook; | ||
(function (DataRouterHook) { | ||
DataRouterHook["UseScrollRestoration"] = "useScrollRestoration"; | ||
DataRouterHook["UseSubmitImpl"] = "useSubmitImpl"; | ||
DataRouterHook["UseSubmit"] = "useSubmit"; | ||
DataRouterHook["UseSubmitFetcher"] = "useSubmitFetcher"; | ||
DataRouterHook["UseFetcher"] = "useFetcher"; | ||
})(DataRouterHook || (DataRouterHook = {})); | ||
var DataRouterStateHook; | ||
(function (DataRouterStateHook) { | ||
@@ -654,7 +702,5 @@ DataRouterStateHook["UseFetchers"] = "useFetchers"; | ||
})(DataRouterStateHook || (DataRouterStateHook = {})); | ||
function getDataRouterConsoleError(hookName) { | ||
return hookName + " must be used within a data router. See https://reactrouter.com/routers/picking-a-router."; | ||
} | ||
function useDataRouterContext(hookName) { | ||
@@ -665,3 +711,2 @@ let ctx = React.useContext(UNSAFE_DataRouterContext); | ||
} | ||
function useDataRouterState(hookName) { | ||
@@ -677,4 +722,2 @@ let state = React.useContext(UNSAFE_DataRouterStateContext); | ||
*/ | ||
function useLinkClickHandler(to, _temp) { | ||
@@ -695,5 +738,5 @@ let { | ||
if (shouldProcessLinkClick(event, target)) { | ||
event.preventDefault(); // If the URL hasn't changed, a regular <a> will do a replace instead of | ||
event.preventDefault(); | ||
// If the URL hasn't changed, a regular <a> will do a replace instead of | ||
// a push, so do the same here unless the replace prop is explicitly set | ||
let replace = replaceProp !== undefined ? replaceProp : createPath(location) === createPath(path); | ||
@@ -713,3 +756,2 @@ navigate(to, { | ||
*/ | ||
function useSearchParams(defaultInit) { | ||
@@ -720,3 +762,4 @@ process.env.NODE_ENV !== "production" ? UNSAFE_warning(typeof URLSearchParams !== "undefined", "You cannot use the `useSearchParams` hook in a browser that does not " + "support the URLSearchParams API. If you need to support Internet " + "Explorer 11, we recommend you load a polyfill such as " + "https://github.com/ungap/url-search-params\n\n" + "If you're unsure how to load polyfills, we recommend you check out " + "https://polyfill.io/v3/ which provides some recommendations about how " + "to load polyfills only for users that need them, instead of for every " + "user.") : void 0; | ||
let location = useLocation(); | ||
let searchParams = React.useMemo(() => // Only merge in the defaults if we haven't yet called setSearchParams. | ||
let searchParams = React.useMemo(() => | ||
// Only merge in the defaults if we haven't yet called setSearchParams. | ||
// Once we call that we want those to take precedence, otherwise you can't | ||
@@ -733,2 +776,7 @@ // remove a param with setSearchParams({}) if it has an initial value | ||
} | ||
function validateClientSideSubmission() { | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
} | ||
/** | ||
@@ -738,12 +786,44 @@ * Returns a function that may be used to programmatically submit a form (or | ||
*/ | ||
function useSubmit() { | ||
return useSubmitImpl(); | ||
let { | ||
router | ||
} = useDataRouterContext(DataRouterHook.UseSubmit); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
let currentRouteId = UNSAFE_useRouteId(); | ||
return React.useCallback(function (target, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
router.navigate(options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType, | ||
replace: options.replace, | ||
state: options.state, | ||
fromRouteId: currentRouteId | ||
}); | ||
}, [router, basename, currentRouteId]); | ||
} | ||
function useSubmitImpl(fetcherKey, routeId) { | ||
/** | ||
* Returns the implementation for fetcher.submit | ||
*/ | ||
function useSubmitFetcher(fetcherKey, fetcherRouteId) { | ||
let { | ||
router | ||
} = useDataRouterContext(DataRouterHook.UseSubmitImpl); | ||
let defaultAction = useFormAction(); | ||
} = useDataRouterContext(DataRouterHook.UseSubmitFetcher); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
return React.useCallback(function (target, options) { | ||
@@ -753,31 +833,22 @@ if (options === void 0) { | ||
} | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
url | ||
} = getFormSubmissionInfo(target, defaultAction, options); | ||
let href = url.pathname + url.search; | ||
let opts = { | ||
replace: options.replace, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
!(fetcherRouteId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : UNSAFE_invariant(false) : void 0; | ||
router.fetch(fetcherKey, fetcherRouteId, options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
formMethod: method, | ||
formEncType: encType | ||
}; | ||
if (fetcherKey) { | ||
!(routeId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : UNSAFE_invariant(false) : void 0; | ||
router.fetch(fetcherKey, routeId, href, opts); | ||
} else { | ||
router.navigate(href, opts); | ||
} | ||
}, [defaultAction, router, fetcherKey, routeId]); | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType | ||
}); | ||
}, [router, basename, fetcherKey, fetcherRouteId]); | ||
} | ||
// v7: Eventually we should deprecate this entirely in favor of using the | ||
// router method directly? | ||
function useFormAction(action, _temp2) { | ||
@@ -792,25 +863,21 @@ let { | ||
!routeContext ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useFormAction must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0; | ||
let [match] = routeContext.matches.slice(-1); // Shallow clone path so we can modify it below, otherwise we modify the | ||
let [match] = routeContext.matches.slice(-1); | ||
// Shallow clone path so we can modify it below, otherwise we modify the | ||
// object referenced by useMemo inside useResolvedPath | ||
let path = _extends({}, useResolvedPath(action ? action : ".", { | ||
relative | ||
})); // Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params and the hash of the resolved | ||
// URL. This is the intended behavior of when "." is specifically provided as | ||
})); | ||
// Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params of the resolved URL. This is | ||
// the intended behavior of when "." is specifically provided as | ||
// the form action, but inconsistent w/ browsers when the action is omitted. | ||
// https://github.com/remix-run/remix/issues/927 | ||
let location = useLocation(); | ||
if (action == null) { | ||
// Safe to write to these directly here since if action was undefined, we | ||
// Safe to write to this directly here since if action was undefined, we | ||
// would have called useResolvedPath(".") which will never include a search | ||
// or hash | ||
path.search = location.search; | ||
path.hash = location.hash; // When grabbing search params from the URL, remove the automatically | ||
// When grabbing search params from the URL, remove the automatically | ||
// inserted ?index param so we match the useResolvedPath search behavior | ||
// which would not include ?index | ||
if (match.route.index) { | ||
@@ -822,34 +889,27 @@ let params = new URLSearchParams(path.search); | ||
} | ||
if ((!action || action === ".") && match.route.index) { | ||
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; | ||
} // If we're operating within a basename, prepend it to the pathname prior | ||
} | ||
// If we're operating within a basename, prepend it to the pathname prior | ||
// to creating the form action. 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 actions | ||
if (basename !== "/") { | ||
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]); | ||
} | ||
return createPath(path); | ||
} | ||
function createFetcherForm(fetcherKey, routeId) { | ||
let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => { | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, { | ||
ref: ref, | ||
fetcherKey: fetcherKey, | ||
routeId: routeId | ||
submit: submit | ||
})); | ||
}); | ||
if (process.env.NODE_ENV !== "production") { | ||
FetcherForm.displayName = "fetcher.Form"; | ||
} | ||
return FetcherForm; | ||
} | ||
let fetcherId = 0; | ||
@@ -860,6 +920,4 @@ /** | ||
*/ | ||
function useFetcher() { | ||
var _route$matches; | ||
let { | ||
@@ -882,3 +940,3 @@ router | ||
}); | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
let fetcher = router.getFetcher(fetcherKey); | ||
@@ -896,6 +954,5 @@ let fetcherWithComponents = React.useMemo(() => _extends({ | ||
if (!router) { | ||
console.warn("No fetcher available to clean up from useFetcher()"); | ||
console.warn("No router available to clean up from useFetcher()"); | ||
return; | ||
} | ||
router.deleteFetcher(fetcherKey); | ||
@@ -910,3 +967,2 @@ }; | ||
*/ | ||
function useFetchers() { | ||
@@ -921,3 +977,2 @@ let state = useDataRouterState(DataRouterStateHook.UseFetchers); | ||
*/ | ||
function useScrollRestoration(_temp3) { | ||
@@ -935,6 +990,9 @@ let { | ||
} = useDataRouterState(DataRouterStateHook.UseScrollRestoration); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
let location = useLocation(); | ||
let matches = useMatches(); | ||
let navigation = useNavigation(); // Trigger manual scroll restoration while we're active | ||
let navigation = useNavigation(); | ||
// Trigger manual scroll restoration while we're active | ||
React.useEffect(() => { | ||
@@ -945,4 +1003,4 @@ window.history.scrollRestoration = "manual"; | ||
}; | ||
}, []); // Save positions on pagehide | ||
}, []); | ||
// Save positions on pagehide | ||
usePageHide(React.useCallback(() => { | ||
@@ -953,7 +1011,6 @@ if (navigation.state === "idle") { | ||
} | ||
sessionStorage.setItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY, JSON.stringify(savedScrollPositions)); | ||
window.history.scrollRestoration = "auto"; | ||
}, [storageKey, getKey, navigation.state, location, matches])); // Read in any saved scroll locations | ||
}, [storageKey, getKey, navigation.state, location, matches])); | ||
// Read in any saved scroll locations | ||
if (typeof document !== "undefined") { | ||
@@ -964,17 +1021,21 @@ // eslint-disable-next-line react-hooks/rules-of-hooks | ||
let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY); | ||
if (sessionPositions) { | ||
savedScrollPositions = JSON.parse(sessionPositions); | ||
} | ||
} catch (e) {// no-op, use default empty object | ||
} catch (e) { | ||
// no-op, use default empty object | ||
} | ||
}, [storageKey]); // Enable scroll restoration in the router | ||
}, [storageKey]); | ||
// Enable scroll restoration in the router | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React.useLayoutEffect(() => { | ||
let disableScrollRestoration = router == null ? void 0 : router.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey); | ||
let getKeyWithoutBasename = getKey && basename !== "/" ? (location, matches) => getKey( // Strip the basename to match useLocation() | ||
_extends({}, location, { | ||
pathname: stripBasename(location.pathname, basename) || location.pathname | ||
}), matches) : getKey; | ||
let disableScrollRestoration = router == null ? void 0 : router.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKeyWithoutBasename); | ||
return () => disableScrollRestoration && disableScrollRestoration(); | ||
}, [router, getKey]); // Restore scrolling when state.restoreScrollPosition changes | ||
}, [router, basename, getKey]); | ||
// Restore scrolling when state.restoreScrollPosition changes | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React.useLayoutEffect(() => { | ||
@@ -984,14 +1045,11 @@ // Explicit false means don't do anything (used for submissions) | ||
return; | ||
} // been here before, scroll to it | ||
} | ||
// been here before, scroll to it | ||
if (typeof restoreScrollPosition === "number") { | ||
window.scrollTo(0, restoreScrollPosition); | ||
return; | ||
} // try to scroll to the hash | ||
} | ||
// try to scroll to the hash | ||
if (location.hash) { | ||
let el = document.getElementById(location.hash.slice(1)); | ||
let el = document.getElementById(decodeURIComponent(location.hash.slice(1))); | ||
if (el) { | ||
@@ -1001,10 +1059,8 @@ el.scrollIntoView(); | ||
} | ||
} // Don't reset if this navigation opted out | ||
} | ||
// Don't reset if this navigation opted out | ||
if (preventScrollReset === true) { | ||
return; | ||
} // otherwise go to the top on new locations | ||
} | ||
// otherwise go to the top on new locations | ||
window.scrollTo(0, 0); | ||
@@ -1022,3 +1078,2 @@ }, [location, restoreScrollPosition, preventScrollReset]); | ||
*/ | ||
function useBeforeUnload(callback, options) { | ||
@@ -1046,3 +1101,2 @@ let { | ||
*/ | ||
function usePageHide(callback, options) { | ||
@@ -1070,4 +1124,2 @@ let { | ||
*/ | ||
function usePrompt(_ref8) { | ||
@@ -1080,11 +1132,8 @@ let { | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked") { | ||
let proceed = window.confirm(message); | ||
if (proceed) { | ||
// This timeout is needed to avoid a weird "race" on POP navigations | ||
// between the `window.history` revert navigation and the result of | ||
// `window.confirm` | ||
setTimeout(blocker.proceed, 0); | ||
@@ -1096,6 +1145,11 @@ } else { | ||
}, [blocker, message]); | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
} | ||
//#endregion | ||
//#endregion | ||
export { BrowserRouter, Form, HashRouter, Link, NavLink, ScrollRestoration, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createHashRouter, createSearchParams, HistoryRouter as unstable_HistoryRouter, usePrompt as unstable_usePrompt, useBeforeUnload, useFetcher, useFetchers, useFormAction, useLinkClickHandler, useSearchParams, useSubmit }; | ||
//# sourceMappingURL=index.js.map |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -12,5 +12,5 @@ * Copyright (c) Remix Software Inc. | ||
import * as React from 'react'; | ||
import { UNSAFE_detectErrorBoundary, Router, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, UNSAFE_DataRouterStateContext, useNavigate, createPath, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker, UNSAFE_DataRouterContext } from 'react-router'; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router'; | ||
import { createRouter, createBrowserHistory, createHashHistory, ErrorResponse, stripBasename, UNSAFE_warning, UNSAFE_invariant, joinPaths } from '@remix-run/router'; | ||
import { UNSAFE_mapRouteProperties, Router, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, UNSAFE_DataRouterStateContext, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, unstable_useBlocker, UNSAFE_DataRouterContext } from 'react-router'; | ||
export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, unstable_useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes } from 'react-router'; | ||
import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, ErrorResponse, UNSAFE_invariant, joinPaths } from '@remix-run/router'; | ||
@@ -31,10 +31,10 @@ const defaultMethod = "get"; | ||
} | ||
function isModifiedEvent(event) { | ||
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); | ||
} | ||
function shouldProcessLinkClick(event, target) { | ||
return event.button === 0 && ( // Ignore everything but left clicks | ||
!target || target === "_self") && // Let browser handle "target=_blank" etc. | ||
return event.button === 0 && ( | ||
// Ignore everything but left clicks | ||
!target || target === "_self") && | ||
// Let browser handle "target=_blank" etc. | ||
!isModifiedEvent(event) // Ignore clicks with modifier keys | ||
@@ -73,5 +73,9 @@ ; | ||
let searchParams = createSearchParams(locationSearch); | ||
if (defaultSearchParams) { | ||
for (let key of defaultSearchParams.keys()) { | ||
// Use `defaultSearchParams.forEach(...)` here instead of iterating of | ||
// `defaultSearchParams.keys()` to work-around a bug in Firefox related to | ||
// web extensions. Relevant Bugzilla tickets: | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1414602 | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1023984 | ||
defaultSearchParams.forEach((_, key) => { | ||
if (!searchParams.has(key)) { | ||
@@ -82,8 +86,33 @@ defaultSearchParams.getAll(key).forEach(value => { | ||
} | ||
} | ||
}); | ||
} | ||
return searchParams; | ||
} | ||
function getFormSubmissionInfo(target, defaultAction, options) { | ||
// Thanks https://github.com/sindresorhus/type-fest! | ||
// One-time check for submitter support | ||
let _formDataSupportsSubmitter = null; | ||
function isFormDataSubmitterSupported() { | ||
if (_formDataSupportsSubmitter === null) { | ||
try { | ||
new FormData(document.createElement("form"), | ||
// @ts-expect-error if FormData supports the submitter parameter, this will throw | ||
0); | ||
_formDataSupportsSubmitter = false; | ||
} catch (e) { | ||
_formDataSupportsSubmitter = true; | ||
} | ||
} | ||
return _formDataSupportsSubmitter; | ||
} | ||
const supportedFormEncTypes = new Set(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]); | ||
function getFormEncType(encType) { | ||
if (encType != null && !supportedFormEncTypes.has(encType)) { | ||
UNSAFE_warning(false, `"${encType}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` ` + `and will default to "${defaultEncType}"`) ; | ||
return null; | ||
} | ||
return encType; | ||
} | ||
function getFormSubmissionInfo(target, basename) { | ||
let method; | ||
@@ -93,29 +122,48 @@ let action; | ||
let formData; | ||
let body; | ||
if (isFormElement(target)) { | ||
let submissionTrigger = options.submissionTrigger; | ||
method = options.method || target.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("enctype") || defaultEncType; | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("action"); | ||
action = attr ? stripBasename(attr, basename) : null; | ||
method = target.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType; | ||
formData = new FormData(target); | ||
if (submissionTrigger && submissionTrigger.name) { | ||
formData.append(submissionTrigger.name, submissionTrigger.value); | ||
} | ||
} else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) { | ||
let form = target.form; | ||
if (form == null) { | ||
throw new Error(`Cannot submit a <button> or <input type="submit"> without a <form>`); | ||
} // <button>/<input type="submit"> may override attributes of <form> | ||
} | ||
// <button>/<input type="submit"> may override attributes of <form> | ||
method = options.method || target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("formaction") || form.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("formenctype") || form.getAttribute("enctype") || defaultEncType; | ||
formData = new FormData(form); // Include name + value from a <button>, appending in case the button name | ||
// matches an existing input name | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("formaction") || form.getAttribute("action"); | ||
action = attr ? stripBasename(attr, basename) : null; | ||
method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType; | ||
if (target.name) { | ||
formData.append(target.name, target.value); | ||
// Build a FormData object populated from a form and submitter | ||
formData = new FormData(form, target); | ||
// If this browser doesn't support the `FormData(el, submitter)` format, | ||
// then tack on the submitter value at the end. This is a lightweight | ||
// solution that is not 100% spec compliant. For complete support in older | ||
// browsers, consider using the `formdata-submitter-polyfill` package | ||
if (!isFormDataSubmitterSupported()) { | ||
let { | ||
name, | ||
type, | ||
value | ||
} = target; | ||
if (type === "image") { | ||
let prefix = name ? `${name}.` : ""; | ||
formData.append(`${prefix}x`, "0"); | ||
formData.append(`${prefix}y`, "0"); | ||
} else if (name) { | ||
formData.append(name, value); | ||
} | ||
} | ||
@@ -125,33 +173,19 @@ } else if (isHtmlElement(target)) { | ||
} else { | ||
method = options.method || defaultMethod; | ||
action = options.action || defaultAction; | ||
encType = options.encType || defaultEncType; | ||
method = defaultMethod; | ||
action = null; | ||
encType = defaultEncType; | ||
body = target; | ||
} | ||
if (target instanceof FormData) { | ||
formData = target; | ||
} else { | ||
formData = new FormData(); | ||
if (target instanceof URLSearchParams) { | ||
for (let [name, value] of target) { | ||
formData.append(name, value); | ||
} | ||
} else if (target != null) { | ||
for (let name of Object.keys(target)) { | ||
formData.append(name, target[name]); | ||
} | ||
} | ||
} | ||
// Send body for <Form encType="text/plain" so we encode it into text | ||
if (formData && encType === "text/plain") { | ||
body = formData; | ||
formData = undefined; | ||
} | ||
let { | ||
protocol, | ||
host | ||
} = window.location; | ||
let url = new URL(action, `${protocol}//${host}`); | ||
return { | ||
url, | ||
action, | ||
method: method.toLowerCase(), | ||
encType, | ||
formData | ||
formData, | ||
body | ||
}; | ||
@@ -164,2 +198,3 @@ } | ||
*/ | ||
//#endregion | ||
@@ -172,2 +207,6 @@ //////////////////////////////////////////////////////////////////////////////// | ||
basename: opts?.basename, | ||
future: { | ||
...opts?.future, | ||
v7_prependBasename: true | ||
}, | ||
history: createBrowserHistory({ | ||
@@ -178,3 +217,3 @@ window: opts?.window | ||
routes, | ||
detectErrorBoundary: UNSAFE_detectErrorBoundary | ||
mapRouteProperties: UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
@@ -185,2 +224,6 @@ } | ||
basename: opts?.basename, | ||
future: { | ||
...opts?.future, | ||
v7_prependBasename: true | ||
}, | ||
history: createHashHistory({ | ||
@@ -191,18 +234,15 @@ window: opts?.window | ||
routes, | ||
detectErrorBoundary: UNSAFE_detectErrorBoundary | ||
mapRouteProperties: UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
} | ||
function parseHydrationData() { | ||
let state = window?.__staticRouterHydrationData; | ||
if (state && state.errors) { | ||
state = { ...state, | ||
state = { | ||
...state, | ||
errors: deserializeErrors(state.errors) | ||
}; | ||
} | ||
return state; | ||
} | ||
function deserializeErrors(errors) { | ||
@@ -212,3 +252,2 @@ if (!errors) return null; | ||
let serialized = {}; | ||
for (let [key, val] of entries) { | ||
@@ -220,7 +259,25 @@ // Hey you! If you change this, please change the corresponding logic in | ||
} else if (val && val.__type === "Error") { | ||
let error = new Error(val.message); // Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
// Attempt to reconstruct the right type of Error (i.e., ReferenceError) | ||
if (val.__subType) { | ||
let ErrorConstructor = window[val.__subType]; | ||
if (typeof ErrorConstructor === "function") { | ||
try { | ||
// @ts-expect-error | ||
let error = new ErrorConstructor(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} catch (e) { | ||
// no-op - fall through and create a normal Error | ||
} | ||
} | ||
} | ||
if (serialized[key] == null) { | ||
let error = new Error(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} | ||
} else { | ||
@@ -230,5 +287,7 @@ serialized[key] = val; | ||
} | ||
return serialized; | ||
} | ||
return serialized; | ||
} //#endregion | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
@@ -238,3 +297,25 @@ //#region Components | ||
/** | ||
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]; | ||
/** | ||
@@ -246,6 +327,6 @@ * A `<Router>` for use in web browsers. Provides the cleanest URLs. | ||
children, | ||
future, | ||
window | ||
}) { | ||
let historyRef = React.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -257,9 +338,14 @@ historyRef.current = createBrowserHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -273,3 +359,2 @@ basename: basename, | ||
} | ||
/** | ||
@@ -282,6 +367,6 @@ * A `<Router>` for use in web browsers. Stores the location in the hash | ||
children, | ||
future, | ||
window | ||
}) { | ||
let historyRef = React.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -293,9 +378,14 @@ historyRef.current = createHashHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -309,3 +399,2 @@ basename: basename, | ||
} | ||
/** | ||
@@ -320,9 +409,16 @@ * A `<Router>` that accepts a pre-instantiated history object. It's important | ||
children, | ||
future, | ||
history | ||
}) { | ||
const [state, setState] = React.useState({ | ||
let [state, setStateImpl] = React.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React.createElement(Router, { | ||
@@ -336,3 +432,2 @@ basename: basename, | ||
} | ||
{ | ||
@@ -343,6 +438,6 @@ HistoryRouter.displayName = "unstable_HistoryRouter"; | ||
const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i; | ||
/** | ||
* The public API for rendering a history-aware <a>. | ||
*/ | ||
const Link = /*#__PURE__*/React.forwardRef(function LinkWithRef({ | ||
@@ -361,26 +456,31 @@ onClick, | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); // Rendered into <a href> for absolute URLs | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
// Rendered into <a href> for absolute URLs | ||
let absoluteHref; | ||
let isExternal = false; | ||
if (typeof to === "string" && ABSOLUTE_URL_REGEX.test(to)) { | ||
// Render the absolute href server- and client-side | ||
absoluteHref = to; // Only check for external origins client-side | ||
absoluteHref = to; | ||
// Only check for external origins client-side | ||
if (isBrowser) { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
try { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
} | ||
} catch (e) { | ||
// We can't do external URL detection without a valid URL | ||
UNSAFE_warning(false, `<Link to="${to}"> contains an invalid URL which will probably break ` + `when clicked - please update to a valid URL path.`) ; | ||
} | ||
} | ||
} // Rendered into <a href> for relative URLs | ||
} | ||
// Rendered into <a href> for relative URLs | ||
let href = useHref(to, { | ||
@@ -396,6 +496,4 @@ relative | ||
}); | ||
function handleClick(event) { | ||
if (onClick) onClick(event); | ||
if (!event.defaultPrevented) { | ||
@@ -405,3 +503,2 @@ internalOnClick(event); | ||
} | ||
return ( | ||
@@ -418,7 +515,5 @@ /*#__PURE__*/ | ||
}); | ||
{ | ||
Link.displayName = "Link"; | ||
} | ||
/** | ||
@@ -448,3 +543,2 @@ * A <Link> wrapper that knows if it's "active" or not. | ||
let nextLocationPathname = routerState && routerState.navigation && routerState.navigation.location ? routerState.navigation.location.pathname : null; | ||
if (!caseSensitive) { | ||
@@ -455,3 +549,2 @@ locationPathname = locationPathname.toLowerCase(); | ||
} | ||
let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(toPathname.length) === "/"; | ||
@@ -461,3 +554,2 @@ let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/"); | ||
let className; | ||
if (typeof classNameProp === "function") { | ||
@@ -476,3 +568,2 @@ className = classNameProp({ | ||
} | ||
let style = typeof styleProp === "function" ? styleProp({ | ||
@@ -493,7 +584,5 @@ isActive, | ||
}); | ||
{ | ||
NavLink.displayName = "NavLink"; | ||
} | ||
/** | ||
@@ -506,19 +595,19 @@ * A `@remix-run/router`-aware `<form>`. It behaves like a normal form except | ||
const Form = /*#__PURE__*/React.forwardRef((props, ref) => { | ||
let submit = useSubmit(); | ||
return /*#__PURE__*/React.createElement(FormImpl, Object.assign({}, props, { | ||
submit: submit, | ||
ref: ref | ||
})); | ||
}); | ||
{ | ||
Form.displayName = "Form"; | ||
} | ||
const FormImpl = /*#__PURE__*/React.forwardRef(({ | ||
reloadDocument, | ||
replace, | ||
state, | ||
method: _method = defaultMethod, | ||
action, | ||
onSubmit, | ||
fetcherKey, | ||
routeId, | ||
submit, | ||
relative, | ||
@@ -528,3 +617,2 @@ preventScrollReset, | ||
}, forwardedRef) => { | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
let formMethod = _method.toLowerCase() === "get" ? "get" : "post"; | ||
@@ -534,3 +622,2 @@ let formAction = useFormAction(action, { | ||
}); | ||
let submitHandler = event => { | ||
@@ -541,8 +628,7 @@ onSubmit && onSubmit(event); | ||
let submitter = event.nativeEvent.submitter; | ||
let submitMethod = submitter?.getAttribute("formmethod") || _method; | ||
submit(submitter || event.currentTarget, { | ||
method: submitMethod, | ||
replace, | ||
state, | ||
relative, | ||
@@ -552,3 +638,2 @@ preventScrollReset | ||
}; | ||
return /*#__PURE__*/React.createElement("form", Object.assign({ | ||
@@ -561,7 +646,5 @@ ref: forwardedRef, | ||
}); | ||
{ | ||
FormImpl.displayName = "FormImpl"; | ||
} | ||
/** | ||
@@ -581,30 +664,25 @@ * This component will emulate the browser's scroll restoration on location | ||
} | ||
{ | ||
ScrollRestoration.displayName = "ScrollRestoration"; | ||
} //#endregion | ||
} | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
//#region Hooks | ||
//////////////////////////////////////////////////////////////////////////////// | ||
var DataRouterHook; | ||
(function (DataRouterHook) { | ||
var DataRouterHook = /*#__PURE__*/function (DataRouterHook) { | ||
DataRouterHook["UseScrollRestoration"] = "useScrollRestoration"; | ||
DataRouterHook["UseSubmitImpl"] = "useSubmitImpl"; | ||
DataRouterHook["UseSubmit"] = "useSubmit"; | ||
DataRouterHook["UseSubmitFetcher"] = "useSubmitFetcher"; | ||
DataRouterHook["UseFetcher"] = "useFetcher"; | ||
})(DataRouterHook || (DataRouterHook = {})); | ||
var DataRouterStateHook; | ||
(function (DataRouterStateHook) { | ||
return DataRouterHook; | ||
}(DataRouterHook || {}); | ||
var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) { | ||
DataRouterStateHook["UseFetchers"] = "useFetchers"; | ||
DataRouterStateHook["UseScrollRestoration"] = "useScrollRestoration"; | ||
})(DataRouterStateHook || (DataRouterStateHook = {})); | ||
return DataRouterStateHook; | ||
}(DataRouterStateHook || {}); | ||
function getDataRouterConsoleError(hookName) { | ||
return `${hookName} must be used within a data router. See https://reactrouter.com/routers/picking-a-router.`; | ||
} | ||
function useDataRouterContext(hookName) { | ||
@@ -615,3 +693,2 @@ let ctx = React.useContext(UNSAFE_DataRouterContext); | ||
} | ||
function useDataRouterState(hookName) { | ||
@@ -622,2 +699,3 @@ let state = React.useContext(UNSAFE_DataRouterStateContext); | ||
} | ||
/** | ||
@@ -628,4 +706,2 @@ * Handles the click behavior for router `<Link>` components. This is useful if | ||
*/ | ||
function useLinkClickHandler(to, { | ||
@@ -645,5 +721,6 @@ target, | ||
if (shouldProcessLinkClick(event, target)) { | ||
event.preventDefault(); // If the URL hasn't changed, a regular <a> will do a replace instead of | ||
event.preventDefault(); | ||
// If the URL hasn't changed, a regular <a> will do a replace instead of | ||
// a push, so do the same here unless the replace prop is explicitly set | ||
let replace = replaceProp !== undefined ? replaceProp : createPath(location) === createPath(path); | ||
@@ -659,2 +736,3 @@ navigate(to, { | ||
} | ||
/** | ||
@@ -664,3 +742,2 @@ * A convenient wrapper for reading and writing search parameters via the | ||
*/ | ||
function useSearchParams(defaultInit) { | ||
@@ -671,3 +748,4 @@ UNSAFE_warning(typeof URLSearchParams !== "undefined", `You cannot use the \`useSearchParams\` hook in a browser that does not ` + `support the URLSearchParams API. If you need to support Internet ` + `Explorer 11, we recommend you load a polyfill such as ` + `https://github.com/ungap/url-search-params\n\n` + `If you're unsure how to load polyfills, we recommend you check out ` + `https://polyfill.io/v3/ which provides some recommendations about how ` + `to load polyfills only for users that need them, instead of for every ` + `user.`) ; | ||
let location = useLocation(); | ||
let searchParams = React.useMemo(() => // Only merge in the defaults if we haven't yet called setSearchParams. | ||
let searchParams = React.useMemo(() => | ||
// Only merge in the defaults if we haven't yet called setSearchParams. | ||
// Once we call that we want those to take precedence, otherwise you can't | ||
@@ -686,2 +764,16 @@ // remove a param with setSearchParams({}) if it has an initial value | ||
/** | ||
* Submits a HTML `<form>` to the server without reloading the page. | ||
*/ | ||
/** | ||
* Submits a fetcher `<form>` to the server without reloading the page. | ||
*/ | ||
function validateClientSideSubmission() { | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
} | ||
/** | ||
* Returns a function that may be used to programmatically submit a form (or | ||
@@ -691,39 +783,63 @@ * some arbitrary data) to the server. | ||
function useSubmit() { | ||
return useSubmitImpl(); | ||
let { | ||
router | ||
} = useDataRouterContext(DataRouterHook.UseSubmit); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
let currentRouteId = UNSAFE_useRouteId(); | ||
return React.useCallback((target, options = {}) => { | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
router.navigate(options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType, | ||
replace: options.replace, | ||
state: options.state, | ||
fromRouteId: currentRouteId | ||
}); | ||
}, [router, basename, currentRouteId]); | ||
} | ||
function useSubmitImpl(fetcherKey, routeId) { | ||
/** | ||
* Returns the implementation for fetcher.submit | ||
*/ | ||
function useSubmitFetcher(fetcherKey, fetcherRouteId) { | ||
let { | ||
router | ||
} = useDataRouterContext(DataRouterHook.UseSubmitImpl); | ||
let defaultAction = useFormAction(); | ||
} = useDataRouterContext(DataRouterHook.UseSubmitFetcher); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
return React.useCallback((target, options = {}) => { | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
url | ||
} = getFormSubmissionInfo(target, defaultAction, options); | ||
let href = url.pathname + url.search; | ||
let opts = { | ||
replace: options.replace, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
!(fetcherRouteId != null) ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : void 0; | ||
router.fetch(fetcherKey, fetcherRouteId, options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
formMethod: method, | ||
formEncType: encType | ||
}; | ||
if (fetcherKey) { | ||
!(routeId != null) ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : void 0; | ||
router.fetch(fetcherKey, routeId, href, opts); | ||
} else { | ||
router.navigate(href, opts); | ||
} | ||
}, [defaultAction, router, fetcherKey, routeId]); | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType | ||
}); | ||
}, [router, basename, fetcherKey, fetcherRouteId]); | ||
} | ||
// v7: Eventually we should deprecate this entirely in favor of using the | ||
// router method directly? | ||
function useFormAction(action, { | ||
@@ -737,25 +853,25 @@ relative | ||
!routeContext ? UNSAFE_invariant(false, "useFormAction must be used inside a RouteContext") : void 0; | ||
let [match] = routeContext.matches.slice(-1); // Shallow clone path so we can modify it below, otherwise we modify the | ||
let [match] = routeContext.matches.slice(-1); | ||
// Shallow clone path so we can modify it below, otherwise we modify the | ||
// object referenced by useMemo inside useResolvedPath | ||
let path = { ...useResolvedPath(action ? action : ".", { | ||
let path = { | ||
...useResolvedPath(action ? action : ".", { | ||
relative | ||
}) | ||
}; // Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params and the hash of the resolved | ||
// URL. This is the intended behavior of when "." is specifically provided as | ||
}; | ||
// Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params of the resolved URL. This is | ||
// the intended behavior of when "." is specifically provided as | ||
// the form action, but inconsistent w/ browsers when the action is omitted. | ||
// https://github.com/remix-run/remix/issues/927 | ||
let location = useLocation(); | ||
if (action == null) { | ||
// Safe to write to these directly here since if action was undefined, we | ||
// Safe to write to this directly here since if action was undefined, we | ||
// would have called useResolvedPath(".") which will never include a search | ||
// or hash | ||
path.search = location.search; | ||
path.hash = location.hash; // When grabbing search params from the URL, remove the automatically | ||
// When grabbing search params from the URL, remove the automatically | ||
// inserted ?index param so we match the useResolvedPath search behavior | ||
// which would not include ?index | ||
if (match.route.index) { | ||
@@ -767,36 +883,29 @@ let params = new URLSearchParams(path.search); | ||
} | ||
if ((!action || action === ".") && match.route.index) { | ||
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; | ||
} // If we're operating within a basename, prepend it to the pathname prior | ||
} | ||
// If we're operating within a basename, prepend it to the pathname prior | ||
// to creating the form action. 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 actions | ||
if (basename !== "/") { | ||
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]); | ||
} | ||
return createPath(path); | ||
} | ||
function createFetcherForm(fetcherKey, routeId) { | ||
let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => { | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
return /*#__PURE__*/React.createElement(FormImpl, Object.assign({}, props, { | ||
ref: ref, | ||
fetcherKey: fetcherKey, | ||
routeId: routeId | ||
submit: submit | ||
})); | ||
}); | ||
{ | ||
FetcherForm.displayName = "fetcher.Form"; | ||
} | ||
return FetcherForm; | ||
} | ||
let fetcherId = 0; | ||
/** | ||
@@ -824,3 +933,3 @@ * Interacts with route loaders and actions without causing a navigation. Great | ||
}); | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
let fetcher = router.getFetcher(fetcherKey); | ||
@@ -839,6 +948,5 @@ let fetcherWithComponents = React.useMemo(() => ({ | ||
if (!router) { | ||
console.warn(`No fetcher available to clean up from useFetcher()`); | ||
console.warn(`No router available to clean up from useFetcher()`); | ||
return; | ||
} | ||
router.deleteFetcher(fetcherKey); | ||
@@ -849,2 +957,3 @@ }; | ||
} | ||
/** | ||
@@ -854,3 +963,2 @@ * Provides all fetchers currently on the page. Useful for layouts and parent | ||
*/ | ||
function useFetchers() { | ||
@@ -862,6 +970,6 @@ let state = useDataRouterState(DataRouterStateHook.UseFetchers); | ||
let savedScrollPositions = {}; | ||
/** | ||
* When rendered inside a RouterProvider, will restore scroll positions on navigations | ||
*/ | ||
function useScrollRestoration({ | ||
@@ -878,6 +986,10 @@ getKey, | ||
} = useDataRouterState(DataRouterStateHook.UseScrollRestoration); | ||
let { | ||
basename | ||
} = React.useContext(UNSAFE_NavigationContext); | ||
let location = useLocation(); | ||
let matches = useMatches(); | ||
let navigation = useNavigation(); // Trigger manual scroll restoration while we're active | ||
let navigation = useNavigation(); | ||
// Trigger manual scroll restoration while we're active | ||
React.useEffect(() => { | ||
@@ -888,4 +1000,5 @@ window.history.scrollRestoration = "manual"; | ||
}; | ||
}, []); // Save positions on pagehide | ||
}, []); | ||
// Save positions on pagehide | ||
usePageHide(React.useCallback(() => { | ||
@@ -896,7 +1009,7 @@ if (navigation.state === "idle") { | ||
} | ||
sessionStorage.setItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY, JSON.stringify(savedScrollPositions)); | ||
window.history.scrollRestoration = "auto"; | ||
}, [storageKey, getKey, navigation.state, location, matches])); // Read in any saved scroll locations | ||
}, [storageKey, getKey, navigation.state, location, matches])); | ||
// Read in any saved scroll locations | ||
if (typeof document !== "undefined") { | ||
@@ -907,17 +1020,25 @@ // eslint-disable-next-line react-hooks/rules-of-hooks | ||
let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY); | ||
if (sessionPositions) { | ||
savedScrollPositions = JSON.parse(sessionPositions); | ||
} | ||
} catch (e) {// no-op, use default empty object | ||
} catch (e) { | ||
// no-op, use default empty object | ||
} | ||
}, [storageKey]); // Enable scroll restoration in the router | ||
}, [storageKey]); | ||
// Enable scroll restoration in the router | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React.useLayoutEffect(() => { | ||
let disableScrollRestoration = router?.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey); | ||
let getKeyWithoutBasename = getKey && basename !== "/" ? (location, matches) => getKey( | ||
// Strip the basename to match useLocation() | ||
{ | ||
...location, | ||
pathname: stripBasename(location.pathname, basename) || location.pathname | ||
}, matches) : getKey; | ||
let disableScrollRestoration = router?.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKeyWithoutBasename); | ||
return () => disableScrollRestoration && disableScrollRestoration(); | ||
}, [router, getKey]); // Restore scrolling when state.restoreScrollPosition changes | ||
}, [router, basename, getKey]); | ||
// Restore scrolling when state.restoreScrollPosition changes | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React.useLayoutEffect(() => { | ||
@@ -927,14 +1048,13 @@ // Explicit false means don't do anything (used for submissions) | ||
return; | ||
} // been here before, scroll to it | ||
} | ||
// been here before, scroll to it | ||
if (typeof restoreScrollPosition === "number") { | ||
window.scrollTo(0, restoreScrollPosition); | ||
return; | ||
} // try to scroll to the hash | ||
} | ||
// try to scroll to the hash | ||
if (location.hash) { | ||
let el = document.getElementById(location.hash.slice(1)); | ||
let el = document.getElementById(decodeURIComponent(location.hash.slice(1))); | ||
if (el) { | ||
@@ -944,10 +1064,10 @@ el.scrollIntoView(); | ||
} | ||
} // Don't reset if this navigation opted out | ||
} | ||
// Don't reset if this navigation opted out | ||
if (preventScrollReset === true) { | ||
return; | ||
} // otherwise go to the top on new locations | ||
} | ||
// otherwise go to the top on new locations | ||
window.scrollTo(0, 0); | ||
@@ -957,2 +1077,3 @@ }, [location, restoreScrollPosition, preventScrollReset]); | ||
} | ||
/** | ||
@@ -966,3 +1087,2 @@ * Setup a callback to be fired on the window's `beforeunload` event. This is | ||
*/ | ||
function useBeforeUnload(callback, options) { | ||
@@ -982,2 +1102,3 @@ let { | ||
} | ||
/** | ||
@@ -991,3 +1112,2 @@ * Setup a callback to be fired on the window's `pagehide` event. This is | ||
*/ | ||
function usePageHide(callback, options) { | ||
@@ -1007,2 +1127,3 @@ let { | ||
} | ||
/** | ||
@@ -1016,4 +1137,2 @@ * Wrapper around useBlocker to show a window.confirm prompt to users instead | ||
*/ | ||
function usePrompt({ | ||
@@ -1025,11 +1144,8 @@ when, | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked") { | ||
let proceed = window.confirm(message); | ||
if (proceed) { | ||
// This timeout is needed to avoid a weird "race" on POP navigations | ||
// between the `window.history` revert navigation and the result of | ||
// `window.confirm` | ||
setTimeout(blocker.proceed, 0); | ||
@@ -1041,6 +1157,12 @@ } else { | ||
}, [blocker, message]); | ||
React.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
} | ||
//#endregion | ||
//#endregion | ||
export { BrowserRouter, Form, HashRouter, Link, NavLink, ScrollRestoration, useScrollRestoration as UNSAFE_useScrollRestoration, createBrowserRouter, createHashRouter, createSearchParams, HistoryRouter as unstable_HistoryRouter, usePrompt as unstable_usePrompt, useBeforeUnload, useFetcher, useFetchers, useFormAction, useLinkClickHandler, useSearchParams, useSubmit }; | ||
//# sourceMappingURL=react-router-dom.development.js.map |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -11,3 +11,3 @@ * Copyright (c) Remix Software Inc. | ||
*/ | ||
import*as e from"react";import{UNSAFE_detectErrorBoundary as t,Router as r,UNSAFE_NavigationContext as n,useHref as o,useResolvedPath as a,useLocation as i,UNSAFE_DataRouterStateContext as s,useNavigate as u,createPath as l,UNSAFE_RouteContext as c,useMatches as f,useNavigation as m,unstable_useBlocker as d,UNSAFE_DataRouterContext as h}from"react-router";export{AbortedDeferredError,Await,MemoryRouter,Navigate,NavigationType,Outlet,Route,Router,RouterProvider,Routes,UNSAFE_DataRouterContext,UNSAFE_DataRouterStateContext,UNSAFE_LocationContext,UNSAFE_NavigationContext,UNSAFE_RouteContext,createMemoryRouter,createPath,createRoutesFromChildren,createRoutesFromElements,defer,generatePath,isRouteErrorResponse,json,matchPath,matchRoutes,parsePath,redirect,renderMatches,resolvePath,unstable_useBlocker,useActionData,useAsyncError,useAsyncValue,useHref,useInRouterContext,useLoaderData,useLocation,useMatch,useMatches,useNavigate,useNavigation,useNavigationType,useOutlet,useOutletContext,useParams,useResolvedPath,useRevalidator,useRouteError,useRouteLoaderData,useRoutes}from"react-router";import{createRouter as p,createBrowserHistory as w,createHashHistory as g,ErrorResponse as y,stripBasename as v,UNSAFE_invariant as b,joinPaths as R}from"@remix-run/router";const E="application/x-www-form-urlencoded";function S(e){return null!=e&&"string"==typeof e.tagName}function C(e=""){return new URLSearchParams("string"==typeof e||Array.isArray(e)||e instanceof URLSearchParams?e:Object.keys(e).reduce(((t,r)=>{let n=e[r];return t.concat(Array.isArray(n)?n.map((e=>[r,e])):[[r,n]])}),[]))}function L(e,t,r){let n,o,a,i;if(S(s=e)&&"form"===s.tagName.toLowerCase()){let s=r.submissionTrigger;n=r.method||e.getAttribute("method")||"get",o=r.action||e.getAttribute("action")||t,a=r.encType||e.getAttribute("enctype")||E,i=new FormData(e),s&&s.name&&i.append(s.name,s.value)}else if(function(e){return S(e)&&"button"===e.tagName.toLowerCase()}(e)||function(e){return S(e)&&"input"===e.tagName.toLowerCase()}(e)&&("submit"===e.type||"image"===e.type)){let s=e.form;if(null==s)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');n=r.method||e.getAttribute("formmethod")||s.getAttribute("method")||"get",o=r.action||e.getAttribute("formaction")||s.getAttribute("action")||t,a=r.encType||e.getAttribute("formenctype")||s.getAttribute("enctype")||E,i=new FormData(s),e.name&&i.append(e.name,e.value)}else{if(S(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');if(n=r.method||"get",o=r.action||t,a=r.encType||E,e instanceof FormData)i=e;else if(i=new FormData,e instanceof URLSearchParams)for(let[t,r]of e)i.append(t,r);else if(null!=e)for(let t of Object.keys(e))i.append(t,e[t])}var s;let{protocol:u,host:l}=window.location;return{url:new URL(o,`${u}//${l}`),method:n.toLowerCase(),encType:a,formData:i}}function A(e,r){return p({basename:r?.basename,history:w({window:r?.window}),hydrationData:r?.hydrationData||U(),routes:e,detectErrorBoundary:t}).initialize()}function x(e,r){return p({basename:r?.basename,history:g({window:r?.window}),hydrationData:r?.hydrationData||U(),routes:e,detectErrorBoundary:t}).initialize()}function U(){let e=window?.__staticRouterHydrationData;return e&&e.errors&&(e={...e,errors:D(e.errors)}),e}function D(e){if(!e)return null;let t=Object.entries(e),r={};for(let[n,o]of t)if(o&&"RouteErrorResponse"===o.__type)r[n]=new y(o.status,o.statusText,o.data,!0===o.internal);else if(o&&"Error"===o.__type){let e=new Error(o.message);e.stack="",r[n]=e}else r[n]=o;return r}function F({basename:t,children:n,window:o}){let a=e.useRef();null==a.current&&(a.current=w({window:o,v5Compat:!0}));let i=a.current,[s,u]=e.useState({action:i.action,location:i.location});return e.useLayoutEffect((()=>i.listen(u)),[i]),e.createElement(r,{basename:t,children:n,location:s.location,navigationType:s.action,navigator:i})}function N({basename:t,children:n,window:o}){let a=e.useRef();null==a.current&&(a.current=g({window:o,v5Compat:!0}));let i=a.current,[s,u]=e.useState({action:i.action,location:i.location});return e.useLayoutEffect((()=>i.listen(u)),[i]),e.createElement(r,{basename:t,children:n,location:s.location,navigationType:s.action,navigator:i})}function P({basename:t,children:n,history:o}){const[a,i]=e.useState({action:o.action,location:o.location});return e.useLayoutEffect((()=>o.listen(i)),[o]),e.createElement(r,{basename:t,children:n,location:a.location,navigationType:a.action,navigator:o})}const T="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,_=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,k=e.forwardRef((function({onClick:t,relative:r,reloadDocument:a,replace:i,state:s,target:u,to:l,preventScrollReset:c,...f},m){let d,{basename:h}=e.useContext(n),p=!1;if("string"==typeof l&&_.test(l)&&(d=l,T)){let e=new URL(window.location.href),t=l.startsWith("//")?new URL(e.protocol+l):new URL(l),r=v(t.pathname,h);t.origin===e.origin&&null!=r?l=r+t.search+t.hash:p=!0}let w=o(l,{relative:r}),g=W(l,{replace:i,state:s,target:u,preventScrollReset:c,relative:r});return e.createElement("a",Object.assign({},f,{href:d||w,onClick:p||a?t:function(e){t&&t(e),e.defaultPrevented||g(e)},ref:m,target:u}))})),O=e.forwardRef((function({"aria-current":t="page",caseSensitive:r=!1,className:o="",end:u=!1,style:l,to:c,children:f,...m},d){let h=a(c,{relative:m.relative}),p=i(),w=e.useContext(s),{navigator:g}=e.useContext(n),y=g.encodeLocation?g.encodeLocation(h).pathname:h.pathname,v=p.pathname,b=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;r||(v=v.toLowerCase(),b=b?b.toLowerCase():null,y=y.toLowerCase());let R,E=v===y||!u&&v.startsWith(y)&&"/"===v.charAt(y.length),S=null!=b&&(b===y||!u&&b.startsWith(y)&&"/"===b.charAt(y.length)),C=E?t:void 0;R="function"==typeof o?o({isActive:E,isPending:S}):[o,E?"active":null,S?"pending":null].filter(Boolean).join(" ");let L="function"==typeof l?l({isActive:E,isPending:S}):l;return e.createElement(k,Object.assign({},m,{"aria-current":C,className:R,ref:d,style:L,to:c}),"function"==typeof f?f({isActive:E,isPending:S}):f)})),K=e.forwardRef(((t,r)=>e.createElement(j,Object.assign({},t,{ref:r})))),j=e.forwardRef((({reloadDocument:t,replace:r,method:n="get",action:o,onSubmit:a,fetcherKey:i,routeId:s,relative:u,preventScrollReset:l,...c},f)=>{let m=J(i,s),d="get"===n.toLowerCase()?"get":"post",h=V(o,{relative:u});return e.createElement("form",Object.assign({ref:f,method:d,action:h,onSubmit:t?a:e=>{if(a&&a(e),e.defaultPrevented)return;e.preventDefault();let t=e.nativeEvent.submitter,o=t?.getAttribute("formmethod")||n;m(t||e.currentTarget,{method:o,replace:r,relative:u,preventScrollReset:l})}},c))}));function I({getKey:e,storageKey:t}){return Z({getKey:e,storageKey:t}),null}var M,B;function z(t){let r=e.useContext(h);return r||b(!1),r}function H(t){let r=e.useContext(s);return r||b(!1),r}function W(t,{target:r,replace:n,state:o,preventScrollReset:s,relative:c}={}){let f=u(),m=i(),d=a(t,{relative:c});return e.useCallback((e=>{if(function(e,t){return!(0!==e.button||t&&"_self"!==t||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e))}(e,r)){e.preventDefault();let r=void 0!==n?n:l(m)===l(d);f(t,{replace:r,state:o,preventScrollReset:s,relative:c})}}),[m,f,d,n,o,r,t,s,c])}function Y(t){let r=e.useRef(C(t)),n=e.useRef(!1),o=i(),a=e.useMemo((()=>function(e,t){let r=C(e);if(t)for(let n of t.keys())r.has(n)||t.getAll(n).forEach((e=>{r.append(n,e)}));return r}(o.search,n.current?null:r.current)),[o.search]),s=u(),l=e.useCallback(((e,t)=>{const r=C("function"==typeof e?e(a):e);n.current=!0,s("?"+r,t)}),[s,a]);return[a,l]}function $(){return J()}function J(t,r){let{router:n}=z(M.UseSubmitImpl),o=V();return e.useCallback(((e,a={})=>{if("undefined"==typeof document)throw new Error("You are calling submit during the server render. Try calling submit within a `useEffect` or callback instead.");let{method:i,encType:s,formData:u,url:l}=L(e,o,a),c=l.pathname+l.search,f={replace:a.replace,preventScrollReset:a.preventScrollReset,formData:u,formMethod:i,formEncType:s};t?(null==r&&b(!1),n.fetch(t,r,c,f)):n.navigate(c,f)}),[o,n,t,r])}function V(t,{relative:r}={}){let{basename:o}=e.useContext(n),s=e.useContext(c);s||b(!1);let[u]=s.matches.slice(-1),f={...a(t||".",{relative:r})},m=i();if(null==t&&(f.search=m.search,f.hash=m.hash,u.route.index)){let e=new URLSearchParams(f.search);e.delete("index"),f.search=e.toString()?`?${e.toString()}`:""}return t&&"."!==t||!u.route.index||(f.search=f.search?f.search.replace(/^\?/,"?index&"):"?index"),"/"!==o&&(f.pathname="/"===f.pathname?o:R([o,f.pathname])),l(f)}!function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmitImpl="useSubmitImpl",e.UseFetcher="useFetcher"}(M||(M={})),function(e){e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"}(B||(B={}));let q=0;function G(){let{router:t}=z(M.UseFetcher),r=e.useContext(c);r||b(!1);let n=r.matches[r.matches.length-1]?.route.id;null==n&&b(!1);let[o]=e.useState((()=>String(++q))),[a]=e.useState((()=>(n||b(!1),function(t,r){return e.forwardRef(((n,o)=>e.createElement(j,Object.assign({},n,{ref:o,fetcherKey:t,routeId:r}))))}(o,n)))),[i]=e.useState((()=>e=>{t||b(!1),n||b(!1),t.fetch(o,n,e)})),s=J(o,n),u=t.getFetcher(o),l=e.useMemo((()=>({Form:a,submit:s,load:i,...u})),[u,a,s,i]);return e.useEffect((()=>()=>{t?t.deleteFetcher(o):console.warn("No fetcher available to clean up from useFetcher()")}),[t,o]),l}function Q(){return[...H(B.UseFetchers).fetchers.values()]}let X={};function Z({getKey:t,storageKey:r}={}){let{router:n}=z(M.UseScrollRestoration),{restoreScrollPosition:o,preventScrollReset:a}=H(B.UseScrollRestoration),s=i(),u=f(),l=m();e.useEffect((()=>(window.history.scrollRestoration="manual",()=>{window.history.scrollRestoration="auto"})),[]),function(t,r){let{capture:n}=r||{};e.useEffect((()=>{let e=null!=n?{capture:n}:void 0;return window.addEventListener("pagehide",t,e),()=>{window.removeEventListener("pagehide",t,e)}}),[t,n])}(e.useCallback((()=>{if("idle"===l.state){let e=(t?t(s,u):null)||s.key;X[e]=window.scrollY}sessionStorage.setItem(r||"react-router-scroll-positions",JSON.stringify(X)),window.history.scrollRestoration="auto"}),[r,t,l.state,s,u])),"undefined"!=typeof document&&(e.useLayoutEffect((()=>{try{let e=sessionStorage.getItem(r||"react-router-scroll-positions");e&&(X=JSON.parse(e))}catch(e){}}),[r]),e.useLayoutEffect((()=>{let e=n?.enableScrollRestoration(X,(()=>window.scrollY),t);return()=>e&&e()}),[n,t]),e.useLayoutEffect((()=>{if(!1!==o)if("number"!=typeof o){if(s.hash){let e=document.getElementById(s.hash.slice(1));if(e)return void e.scrollIntoView()}!0!==a&&window.scrollTo(0,0)}else window.scrollTo(0,o)}),[s,o,a]))}function ee(t,r){let{capture:n}=r||{};e.useEffect((()=>{let e=null!=n?{capture:n}:void 0;return window.addEventListener("beforeunload",t,e),()=>{window.removeEventListener("beforeunload",t,e)}}),[t,n])}function te({when:t,message:r}){let n=d(t);e.useEffect((()=>{"blocked"!==n.state||t||n.reset()}),[n,t]),e.useEffect((()=>{if("blocked"===n.state){window.confirm(r)?setTimeout(n.proceed,0):n.reset()}}),[n,r])}export{F as BrowserRouter,K as Form,N as HashRouter,k as Link,O as NavLink,I as ScrollRestoration,Z as UNSAFE_useScrollRestoration,A as createBrowserRouter,x as createHashRouter,C as createSearchParams,P as unstable_HistoryRouter,te as unstable_usePrompt,ee as useBeforeUnload,G as useFetcher,Q as useFetchers,V as useFormAction,W as useLinkClickHandler,Y as useSearchParams,$ as useSubmit}; | ||
import*as e from"react";import{UNSAFE_mapRouteProperties as t,Router as r,UNSAFE_NavigationContext as n,useHref as o,useResolvedPath as a,useLocation as i,UNSAFE_DataRouterStateContext as s,useNavigate as u,createPath as l,UNSAFE_useRouteId as c,UNSAFE_RouteContext as f,useMatches as m,useNavigation as d,unstable_useBlocker as p,UNSAFE_DataRouterContext as h}from"react-router";export{AbortedDeferredError,Await,MemoryRouter,Navigate,NavigationType,Outlet,Route,Router,RouterProvider,Routes,UNSAFE_DataRouterContext,UNSAFE_DataRouterStateContext,UNSAFE_LocationContext,UNSAFE_NavigationContext,UNSAFE_RouteContext,UNSAFE_useRouteId,createMemoryRouter,createPath,createRoutesFromChildren,createRoutesFromElements,defer,generatePath,isRouteErrorResponse,json,matchPath,matchRoutes,parsePath,redirect,redirectDocument,renderMatches,resolvePath,unstable_useBlocker,useActionData,useAsyncError,useAsyncValue,useHref,useInRouterContext,useLoaderData,useLocation,useMatch,useMatches,useNavigate,useNavigation,useNavigationType,useOutlet,useOutletContext,useParams,useResolvedPath,useRevalidator,useRouteError,useRouteLoaderData,useRoutes}from"react-router";import{stripBasename as w,createRouter as y,createBrowserHistory as g,createHashHistory as b,ErrorResponse as v,UNSAFE_invariant as R,joinPaths as S}from"@remix-run/router";const E="application/x-www-form-urlencoded";function C(e){return null!=e&&"string"==typeof e.tagName}function x(e=""){return new URLSearchParams("string"==typeof e||Array.isArray(e)||e instanceof URLSearchParams?e:Object.keys(e).reduce(((t,r)=>{let n=e[r];return t.concat(Array.isArray(n)?n.map((e=>[r,e])):[[r,n]])}),[]))}let A=null;const L=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function U(e){return null==e||L.has(e)?e:null}function _(e,t){let r,n,o,a,i;if(C(s=e)&&"form"===s.tagName.toLowerCase()){let i=e.getAttribute("action");n=i?w(i,t):null,r=e.getAttribute("method")||"get",o=U(e.getAttribute("enctype"))||E,a=new FormData(e)}else if(function(e){return C(e)&&"button"===e.tagName.toLowerCase()}(e)||function(e){return C(e)&&"input"===e.tagName.toLowerCase()}(e)&&("submit"===e.type||"image"===e.type)){let i=e.form;if(null==i)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let s=e.getAttribute("formaction")||i.getAttribute("action");if(n=s?w(s,t):null,r=e.getAttribute("formmethod")||i.getAttribute("method")||"get",o=U(e.getAttribute("formenctype"))||U(i.getAttribute("enctype"))||E,a=new FormData(i,e),!function(){if(null===A)try{new FormData(document.createElement("form"),0),A=!1}catch(e){A=!0}return A}()){let{name:t,type:r,value:n}=e;if("image"===r){let e=t?`${t}.`:"";a.append(`${e}x`,"0"),a.append(`${e}y`,"0")}else t&&a.append(t,n)}}else{if(C(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');r="get",n=null,o=E,i=e}var s;return a&&"text/plain"===o&&(i=a,a=void 0),{action:n,method:r.toLowerCase(),encType:o,formData:a,body:i}}function F(e,r){return y({basename:r?.basename,future:{...r?.future,v7_prependBasename:!0},history:g({window:r?.window}),hydrationData:r?.hydrationData||T(),routes:e,mapRouteProperties:t}).initialize()}function D(e,r){return y({basename:r?.basename,future:{...r?.future,v7_prependBasename:!0},history:b({window:r?.window}),hydrationData:r?.hydrationData||T(),routes:e,mapRouteProperties:t}).initialize()}function T(){let e=window?.__staticRouterHydrationData;return e&&e.errors&&(e={...e,errors:N(e.errors)}),e}function N(e){if(!e)return null;let t=Object.entries(e),r={};for(let[o,a]of t)if(a&&"RouteErrorResponse"===a.__type)r[o]=new v(a.status,a.statusText,a.data,!0===a.internal);else if(a&&"Error"===a.__type){if(a.__subType){let e=window[a.__subType];if("function"==typeof e)try{let t=new e(a.message);t.stack="",r[o]=t}catch(n){}}if(null==r[o]){let e=new Error(a.message);e.stack="",r[o]=e}}else r[o]=a;return r}const P=e.startTransition;function k({basename:t,children:n,future:o,window:a}){let i=e.useRef();null==i.current&&(i.current=g({window:a,v5Compat:!0}));let s=i.current,[u,l]=e.useState({action:s.action,location:s.location}),{v7_startTransition:c}=o||{},f=e.useCallback((e=>{c&&P?P((()=>l(e))):l(e)}),[l,c]);return e.useLayoutEffect((()=>s.listen(f)),[s,f]),e.createElement(r,{basename:t,children:n,location:u.location,navigationType:u.action,navigator:s})}function O({basename:t,children:n,future:o,window:a}){let i=e.useRef();null==i.current&&(i.current=b({window:a,v5Compat:!0}));let s=i.current,[u,l]=e.useState({action:s.action,location:s.location}),{v7_startTransition:c}=o||{},f=e.useCallback((e=>{c&&P?P((()=>l(e))):l(e)}),[l,c]);return e.useLayoutEffect((()=>s.listen(f)),[s,f]),e.createElement(r,{basename:t,children:n,location:u.location,navigationType:u.action,navigator:s})}function K({basename:t,children:n,future:o,history:a}){let[i,s]=e.useState({action:a.action,location:a.location}),{v7_startTransition:u}=o||{},l=e.useCallback((e=>{u&&P?P((()=>s(e))):s(e)}),[s,u]);return e.useLayoutEffect((()=>a.listen(l)),[a,l]),e.createElement(r,{basename:t,children:n,location:i.location,navigationType:i.action,navigator:a})}const j="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,M=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,I=e.forwardRef((function({onClick:t,relative:r,reloadDocument:a,replace:i,state:s,target:u,to:l,preventScrollReset:c,...f},m){let d,{basename:p}=e.useContext(n),h=!1;if("string"==typeof l&&M.test(l)&&(d=l,j))try{let e=new URL(window.location.href),t=l.startsWith("//")?new URL(e.protocol+l):new URL(l),r=w(t.pathname,p);t.origin===e.origin&&null!=r?l=r+t.search+t.hash:h=!0}catch(b){}let y=o(l,{relative:r}),g=q(l,{replace:i,state:s,target:u,preventScrollReset:c,relative:r});return e.createElement("a",Object.assign({},f,{href:d||y,onClick:h||a?t:function(e){t&&t(e),e.defaultPrevented||g(e)},ref:m,target:u}))})),B=e.forwardRef((function({"aria-current":t="page",caseSensitive:r=!1,className:o="",end:u=!1,style:l,to:c,children:f,...m},d){let p=a(c,{relative:m.relative}),h=i(),w=e.useContext(s),{navigator:y}=e.useContext(n),g=y.encodeLocation?y.encodeLocation(p).pathname:p.pathname,b=h.pathname,v=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;r||(b=b.toLowerCase(),v=v?v.toLowerCase():null,g=g.toLowerCase());let R,S=b===g||!u&&b.startsWith(g)&&"/"===b.charAt(g.length),E=null!=v&&(v===g||!u&&v.startsWith(g)&&"/"===v.charAt(g.length)),C=S?t:void 0;R="function"==typeof o?o({isActive:S,isPending:E}):[o,S?"active":null,E?"pending":null].filter(Boolean).join(" ");let x="function"==typeof l?l({isActive:S,isPending:E}):l;return e.createElement(I,Object.assign({},m,{"aria-current":C,className:R,ref:d,style:x,to:c}),"function"==typeof f?f({isActive:S,isPending:E}):f)})),z=e.forwardRef(((t,r)=>{let n=X();return e.createElement($,Object.assign({},t,{submit:n,ref:r}))})),$=e.forwardRef((({reloadDocument:t,replace:r,state:n,method:o="get",action:a,onSubmit:i,submit:s,relative:u,preventScrollReset:l,...c},f)=>{let m="get"===o.toLowerCase()?"get":"post",d=ee(a,{relative:u});return e.createElement("form",Object.assign({ref:f,method:m,action:d,onSubmit:t?i:e=>{if(i&&i(e),e.defaultPrevented)return;e.preventDefault();let t=e.nativeEvent.submitter,a=t?.getAttribute("formmethod")||o;s(t||e.currentTarget,{method:a,replace:r,state:n,relative:u,preventScrollReset:l})}},c))}));function H({getKey:e,storageKey:t}){return ae({getKey:e,storageKey:t}),null}var W=function(e){return e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e}(W||{}),Y=function(e){return e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration",e}(Y||{});function J(t){let r=e.useContext(h);return r||R(!1),r}function V(t){let r=e.useContext(s);return r||R(!1),r}function q(t,{target:r,replace:n,state:o,preventScrollReset:s,relative:c}={}){let f=u(),m=i(),d=a(t,{relative:c});return e.useCallback((e=>{if(function(e,t){return!(0!==e.button||t&&"_self"!==t||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e))}(e,r)){e.preventDefault();let r=void 0!==n?n:l(m)===l(d);f(t,{replace:r,state:o,preventScrollReset:s,relative:c})}}),[m,f,d,n,o,r,t,s,c])}function G(t){let r=e.useRef(x(t)),n=e.useRef(!1),o=i(),a=e.useMemo((()=>function(e,t){let r=x(e);return t&&t.forEach(((e,n)=>{r.has(n)||t.getAll(n).forEach((e=>{r.append(n,e)}))})),r}(o.search,n.current?null:r.current)),[o.search]),s=u(),l=e.useCallback(((e,t)=>{const r=x("function"==typeof e?e(a):e);n.current=!0,s("?"+r,t)}),[s,a]);return[a,l]}function Q(){if("undefined"==typeof document)throw new Error("You are calling submit during the server render. Try calling submit within a `useEffect` or callback instead.")}function X(){let{router:t}=J(W.UseSubmit),{basename:r}=e.useContext(n),o=c();return e.useCallback(((e,n={})=>{Q();let{action:a,method:i,encType:s,formData:u,body:l}=_(e,r);t.navigate(n.action||a,{preventScrollReset:n.preventScrollReset,formData:u,body:l,formMethod:n.method||i,formEncType:n.encType||s,replace:n.replace,state:n.state,fromRouteId:o})}),[t,r,o])}function Z(t,r){let{router:o}=J(W.UseSubmitFetcher),{basename:a}=e.useContext(n);return e.useCallback(((e,n={})=>{Q();let{action:i,method:s,encType:u,formData:l,body:c}=_(e,a);null==r&&R(!1),o.fetch(t,r,n.action||i,{preventScrollReset:n.preventScrollReset,formData:l,body:c,formMethod:n.method||s,formEncType:n.encType||u})}),[o,a,t,r])}function ee(t,{relative:r}={}){let{basename:o}=e.useContext(n),s=e.useContext(f);s||R(!1);let[u]=s.matches.slice(-1),c={...a(t||".",{relative:r})},m=i();if(null==t&&(c.search=m.search,u.route.index)){let e=new URLSearchParams(c.search);e.delete("index"),c.search=e.toString()?`?${e.toString()}`:""}return t&&"."!==t||!u.route.index||(c.search=c.search?c.search.replace(/^\?/,"?index&"):"?index"),"/"!==o&&(c.pathname="/"===c.pathname?o:S([o,c.pathname])),l(c)}let te=0;function re(){let{router:t}=J(W.UseFetcher),r=e.useContext(f);r||R(!1);let n=r.matches[r.matches.length-1]?.route.id;null==n&&R(!1);let[o]=e.useState((()=>String(++te))),[a]=e.useState((()=>(n||R(!1),function(t,r){return e.forwardRef(((n,o)=>{let a=Z(t,r);return e.createElement($,Object.assign({},n,{ref:o,submit:a}))}))}(o,n)))),[i]=e.useState((()=>e=>{t||R(!1),n||R(!1),t.fetch(o,n,e)})),s=Z(o,n),u=t.getFetcher(o),l=e.useMemo((()=>({Form:a,submit:s,load:i,...u})),[u,a,s,i]);return e.useEffect((()=>()=>{t?t.deleteFetcher(o):console.warn("No router available to clean up from useFetcher()")}),[t,o]),l}function ne(){return[...V(Y.UseFetchers).fetchers.values()]}let oe={};function ae({getKey:t,storageKey:r}={}){let{router:o}=J(W.UseScrollRestoration),{restoreScrollPosition:a,preventScrollReset:s}=V(Y.UseScrollRestoration),{basename:u}=e.useContext(n),l=i(),c=m(),f=d();e.useEffect((()=>(window.history.scrollRestoration="manual",()=>{window.history.scrollRestoration="auto"})),[]),function(t,r){let{capture:n}=r||{};e.useEffect((()=>{let e=null!=n?{capture:n}:void 0;return window.addEventListener("pagehide",t,e),()=>{window.removeEventListener("pagehide",t,e)}}),[t,n])}(e.useCallback((()=>{if("idle"===f.state){let e=(t?t(l,c):null)||l.key;oe[e]=window.scrollY}sessionStorage.setItem(r||"react-router-scroll-positions",JSON.stringify(oe)),window.history.scrollRestoration="auto"}),[r,t,f.state,l,c])),"undefined"!=typeof document&&(e.useLayoutEffect((()=>{try{let e=sessionStorage.getItem(r||"react-router-scroll-positions");e&&(oe=JSON.parse(e))}catch(e){}}),[r]),e.useLayoutEffect((()=>{let e=t&&"/"!==u?(e,r)=>t({...e,pathname:w(e.pathname,u)||e.pathname},r):t,r=o?.enableScrollRestoration(oe,(()=>window.scrollY),e);return()=>r&&r()}),[o,u,t]),e.useLayoutEffect((()=>{if(!1!==a)if("number"!=typeof a){if(l.hash){let e=document.getElementById(decodeURIComponent(l.hash.slice(1)));if(e)return void e.scrollIntoView()}!0!==s&&window.scrollTo(0,0)}else window.scrollTo(0,a)}),[l,a,s]))}function ie(t,r){let{capture:n}=r||{};e.useEffect((()=>{let e=null!=n?{capture:n}:void 0;return window.addEventListener("beforeunload",t,e),()=>{window.removeEventListener("beforeunload",t,e)}}),[t,n])}function se({when:t,message:r}){let n=p(t);e.useEffect((()=>{if("blocked"===n.state){window.confirm(r)?setTimeout(n.proceed,0):n.reset()}}),[n,r]),e.useEffect((()=>{"blocked"!==n.state||t||n.reset()}),[n,t])}export{k as BrowserRouter,z as Form,O as HashRouter,I as Link,B as NavLink,H as ScrollRestoration,ae as UNSAFE_useScrollRestoration,F as createBrowserRouter,D as createHashRouter,x as createSearchParams,K as unstable_HistoryRouter,se as unstable_usePrompt,ie as useBeforeUnload,re as useFetcher,ne as useFetchers,ee as useFormAction,q as useLinkClickHandler,G as useSearchParams,X as useSubmit}; | ||
//# sourceMappingURL=react-router-dom.production.min.js.map |
@@ -13,3 +13,3 @@ import * as React from "react"; | ||
*/ | ||
export declare function StaticRouter({ basename, children, location: locationProp, }: StaticRouterProps): JSX.Element; | ||
export declare function StaticRouter({ basename, children, location: locationProp, }: StaticRouterProps): React.JSX.Element; | ||
export { StaticHandlerContext }; | ||
@@ -26,5 +26,5 @@ export interface StaticRouterProviderProps { | ||
*/ | ||
export declare function StaticRouterProvider({ context, router, hydrate, nonce, }: StaticRouterProviderProps): JSX.Element; | ||
declare type CreateStaticHandlerOptions = Omit<RouterCreateStaticHandlerOptions, "detectErrorBoundary">; | ||
export declare function StaticRouterProvider({ context, router, hydrate, nonce, }: StaticRouterProviderProps): React.JSX.Element; | ||
type CreateStaticHandlerOptions = Omit<RouterCreateStaticHandlerOptions, "detectErrorBoundary" | "mapRouteProperties">; | ||
export declare function createStaticHandler(routes: RouteObject[], opts?: CreateStaticHandlerOptions): import("@remix-run/router").StaticHandler; | ||
export declare function createStaticRouter(routes: RouteObject[], context: StaticHandlerContext): RemixRouter; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var router = require('@remix-run/router'); | ||
var reactRouter = require('react-router'); | ||
var reactRouterDom = require('react-router-dom'); | ||
@@ -34,3 +35,2 @@ | ||
*/ | ||
function StaticRouter({ | ||
@@ -44,3 +44,2 @@ basename, | ||
} | ||
let action = router.Action.Pop; | ||
@@ -68,3 +67,2 @@ let location = { | ||
*/ | ||
function StaticRouterProvider({ | ||
@@ -85,3 +83,2 @@ context, | ||
let hydrateScript = ""; | ||
if (hydrate !== false) { | ||
@@ -92,21 +89,27 @@ let data = { | ||
errors: serializeErrors(context.errors) | ||
}; // Use JSON.parse here instead of embedding a raw JS object here to speed | ||
}; | ||
// Use JSON.parse here instead of embedding a raw JS object here to speed | ||
// up parsing on the client. Dual-stringify is needed to ensure all quotes | ||
// are properly escaped in the resulting string. See: | ||
// https://v8.dev/blog/cost-of-javascript-2019#json | ||
let json = htmlEscape(JSON.stringify(JSON.stringify(data))); | ||
hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`; | ||
} | ||
let { | ||
state | ||
} = dataRouterContext.router; | ||
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterContext.Provider, { | ||
value: dataRouterContext | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterStateContext.Provider, { | ||
value: dataRouterContext.router.state | ||
value: state | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, { | ||
basename: dataRouterContext.basename, | ||
location: dataRouterContext.router.state.location, | ||
navigationType: dataRouterContext.router.state.historyAction, | ||
navigator: dataRouterContext.navigator | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Routes, null)))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", { | ||
location: state.location, | ||
navigationType: state.historyAction, | ||
navigator: dataRouterContext.navigator, | ||
static: dataRouterContext.static | ||
}, /*#__PURE__*/React__namespace.createElement(DataRoutes, { | ||
routes: router$1.routes, | ||
state: state | ||
})))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", { | ||
suppressHydrationWarning: true, | ||
@@ -119,3 +122,8 @@ nonce: nonce, | ||
} | ||
function DataRoutes({ | ||
routes, | ||
state | ||
}) { | ||
return reactRouter.UNSAFE_useRoutesImpl(routes, undefined, state); | ||
} | ||
function serializeErrors(errors) { | ||
@@ -125,3 +133,2 @@ if (!errors) return null; | ||
let serialized = {}; | ||
for (let [key, val] of entries) { | ||
@@ -131,3 +138,4 @@ // Hey you! If you change this, please change the corresponding logic in | ||
if (router.isRouteErrorResponse(val)) { | ||
serialized[key] = { ...val, | ||
serialized[key] = { | ||
...val, | ||
__type: "RouteErrorResponse" | ||
@@ -139,3 +147,8 @@ }; | ||
message: val.message, | ||
__type: "Error" | ||
__type: "Error", | ||
// If this is a subclass (i.e., ReferenceError), send up the type so we | ||
// can re-create the same type during hydration. | ||
...(val.name !== "Error" ? { | ||
__subType: val.name | ||
} : {}) | ||
}; | ||
@@ -146,6 +159,4 @@ } else { | ||
} | ||
return serialized; | ||
} | ||
function getStatelessNavigator() { | ||
@@ -155,31 +166,23 @@ return { | ||
encodeLocation, | ||
push(to) { | ||
throw new Error(`You cannot use navigator.push() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)})\` somewhere in your app.`); | ||
}, | ||
replace(to) { | ||
throw new Error(`You cannot use navigator.replace() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere ` + `in your app.`); | ||
}, | ||
go(delta) { | ||
throw new Error(`You cannot use navigator.go() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${delta})\` somewhere in your app.`); | ||
}, | ||
back() { | ||
throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`); | ||
}, | ||
forward() { | ||
throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`); | ||
} | ||
}; | ||
} | ||
let detectErrorBoundary = route => Boolean(route.errorElement); | ||
function createStaticHandler(routes, opts) { | ||
return router.createStaticHandler(routes, { ...opts, | ||
detectErrorBoundary | ||
return router.createStaticHandler(routes, { | ||
...opts, | ||
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties | ||
}); | ||
@@ -189,15 +192,14 @@ } | ||
let manifest = {}; | ||
let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, detectErrorBoundary, undefined, manifest); // Because our context matches may be from a framework-agnostic set of | ||
let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, reactRouter.UNSAFE_mapRouteProperties, undefined, manifest); | ||
// Because our context matches may be from a framework-agnostic set of | ||
// routes passed to createStaticHandler(), we update them here with our | ||
// newly created/enhanced data routes | ||
let matches = context.matches.map(match => { | ||
let route = manifest[match.route.id] || match.route; | ||
return { ...match, | ||
return { | ||
...match, | ||
route | ||
}; | ||
}); | ||
let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`; | ||
return { | ||
@@ -207,3 +209,2 @@ get basename() { | ||
}, | ||
get state() { | ||
@@ -226,68 +227,50 @@ return { | ||
}, | ||
get routes() { | ||
return dataRoutes; | ||
}, | ||
initialize() { | ||
throw msg("initialize"); | ||
}, | ||
subscribe() { | ||
throw msg("subscribe"); | ||
}, | ||
enableScrollRestoration() { | ||
throw msg("enableScrollRestoration"); | ||
}, | ||
navigate() { | ||
throw msg("navigate"); | ||
}, | ||
fetch() { | ||
throw msg("fetch"); | ||
}, | ||
revalidate() { | ||
throw msg("revalidate"); | ||
}, | ||
createHref, | ||
encodeLocation, | ||
getFetcher() { | ||
return router.IDLE_FETCHER; | ||
}, | ||
deleteFetcher() { | ||
throw msg("deleteFetcher"); | ||
}, | ||
dispose() { | ||
throw msg("dispose"); | ||
}, | ||
getBlocker() { | ||
return router.IDLE_BLOCKER; | ||
}, | ||
deleteBlocker() { | ||
throw msg("deleteBlocker"); | ||
}, | ||
_internalFetchControllers: new Map(), | ||
_internalActiveDeferreds: new Map(), | ||
_internalSetRoutes() { | ||
throw msg("_internalSetRoutes"); | ||
} | ||
}; | ||
} | ||
function createHref(to) { | ||
return typeof to === "string" ? to : reactRouterDom.createPath(to); | ||
} | ||
function encodeLocation(to) { | ||
@@ -301,6 +284,5 @@ // Locations should already be encoded on the server, so just return as-is | ||
}; | ||
} // This utility is based on https://github.com/zertosh/htmlescape | ||
} | ||
// This utility is based on https://github.com/zertosh/htmlescape | ||
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE | ||
const ESCAPE_LOOKUP = { | ||
@@ -314,3 +296,2 @@ "&": "\\u0026", | ||
const ESCAPE_REGEX = /[&><\u2028\u2029]/g; | ||
function htmlEscape(str) { | ||
@@ -317,0 +298,0 @@ return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -41,3 +41,2 @@ * Copyright (c) Remix Software Inc. | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
@@ -49,3 +48,2 @@ if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
} | ||
return target; | ||
@@ -55,3 +53,2 @@ }; | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -62,3 +59,2 @@ if (source == null) return {}; | ||
var key, i; | ||
for (i = 0; i < sourceKeys.length; i++) { | ||
@@ -69,3 +65,2 @@ key = sourceKeys[i]; | ||
} | ||
return target; | ||
@@ -88,10 +83,10 @@ } | ||
} | ||
function isModifiedEvent(event) { | ||
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); | ||
} | ||
function shouldProcessLinkClick(event, target) { | ||
return event.button === 0 && ( // Ignore everything but left clicks | ||
!target || target === "_self") && // Let browser handle "target=_blank" etc. | ||
return event.button === 0 && ( | ||
// Ignore everything but left clicks | ||
!target || target === "_self") && | ||
// Let browser handle "target=_blank" etc. | ||
!isModifiedEvent(event) // Ignore clicks with modifier keys | ||
@@ -126,3 +121,2 @@ ; | ||
} | ||
return new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo, key) => { | ||
@@ -135,5 +129,9 @@ let value = init[key]; | ||
let searchParams = createSearchParams(locationSearch); | ||
if (defaultSearchParams) { | ||
for (let key of defaultSearchParams.keys()) { | ||
// Use `defaultSearchParams.forEach(...)` here instead of iterating of | ||
// `defaultSearchParams.keys()` to work-around a bug in Firefox related to | ||
// web extensions. Relevant Bugzilla tickets: | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1414602 | ||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1023984 | ||
defaultSearchParams.forEach((_, key) => { | ||
if (!searchParams.has(key)) { | ||
@@ -144,8 +142,33 @@ defaultSearchParams.getAll(key).forEach(value => { | ||
} | ||
} | ||
}); | ||
} | ||
return searchParams; | ||
} | ||
function getFormSubmissionInfo(target, defaultAction, options) { | ||
// Thanks https://github.com/sindresorhus/type-fest! | ||
// One-time check for submitter support | ||
let _formDataSupportsSubmitter = null; | ||
function isFormDataSubmitterSupported() { | ||
if (_formDataSupportsSubmitter === null) { | ||
try { | ||
new FormData(document.createElement("form"), | ||
// @ts-expect-error if FormData supports the submitter parameter, this will throw | ||
0); | ||
_formDataSupportsSubmitter = false; | ||
} catch (e) { | ||
_formDataSupportsSubmitter = true; | ||
} | ||
} | ||
return _formDataSupportsSubmitter; | ||
} | ||
const supportedFormEncTypes = new Set(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]); | ||
function getFormEncType(encType) { | ||
if (encType != null && !supportedFormEncTypes.has(encType)) { | ||
router.UNSAFE_warning(false, "\"" + encType + "\" is not a valid `encType` for `<Form>`/`<fetcher.Form>` " + ("and will default to \"" + defaultEncType + "\"")) ; | ||
return null; | ||
} | ||
return encType; | ||
} | ||
function getFormSubmissionInfo(target, basename) { | ||
let method; | ||
@@ -155,29 +178,48 @@ let action; | ||
let formData; | ||
let body; | ||
if (isFormElement(target)) { | ||
let submissionTrigger = options.submissionTrigger; | ||
method = options.method || target.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("enctype") || defaultEncType; | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("action"); | ||
action = attr ? router.stripBasename(attr, basename) : null; | ||
method = target.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType; | ||
formData = new FormData(target); | ||
if (submissionTrigger && submissionTrigger.name) { | ||
formData.append(submissionTrigger.name, submissionTrigger.value); | ||
} | ||
} else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) { | ||
let form = target.form; | ||
if (form == null) { | ||
throw new Error("Cannot submit a <button> or <input type=\"submit\"> without a <form>"); | ||
} // <button>/<input type="submit"> may override attributes of <form> | ||
} | ||
// <button>/<input type="submit"> may override attributes of <form> | ||
method = options.method || target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
action = options.action || target.getAttribute("formaction") || form.getAttribute("action") || defaultAction; | ||
encType = options.encType || target.getAttribute("formenctype") || form.getAttribute("enctype") || defaultEncType; | ||
formData = new FormData(form); // Include name + value from a <button>, appending in case the button name | ||
// matches an existing input name | ||
// When grabbing the action from the element, it will have had the basename | ||
// prefixed to ensure non-JS scenarios work, so strip it since we'll | ||
// re-prefix in the router | ||
let attr = target.getAttribute("formaction") || form.getAttribute("action"); | ||
action = attr ? router.stripBasename(attr, basename) : null; | ||
method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod; | ||
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType; | ||
if (target.name) { | ||
formData.append(target.name, target.value); | ||
// Build a FormData object populated from a form and submitter | ||
formData = new FormData(form, target); | ||
// If this browser doesn't support the `FormData(el, submitter)` format, | ||
// then tack on the submitter value at the end. This is a lightweight | ||
// solution that is not 100% spec compliant. For complete support in older | ||
// browsers, consider using the `formdata-submitter-polyfill` package | ||
if (!isFormDataSubmitterSupported()) { | ||
let { | ||
name, | ||
type, | ||
value | ||
} = target; | ||
if (type === "image") { | ||
let prefix = name ? name + "." : ""; | ||
formData.append(prefix + "x", "0"); | ||
formData.append(prefix + "y", "0"); | ||
} else if (name) { | ||
formData.append(name, value); | ||
} | ||
} | ||
@@ -187,33 +229,19 @@ } else if (isHtmlElement(target)) { | ||
} else { | ||
method = options.method || defaultMethod; | ||
action = options.action || defaultAction; | ||
encType = options.encType || defaultEncType; | ||
method = defaultMethod; | ||
action = null; | ||
encType = defaultEncType; | ||
body = target; | ||
} | ||
if (target instanceof FormData) { | ||
formData = target; | ||
} else { | ||
formData = new FormData(); | ||
if (target instanceof URLSearchParams) { | ||
for (let [name, value] of target) { | ||
formData.append(name, value); | ||
} | ||
} else if (target != null) { | ||
for (let name of Object.keys(target)) { | ||
formData.append(name, target[name]); | ||
} | ||
} | ||
} | ||
// Send body for <Form encType="text/plain" so we encode it into text | ||
if (formData && encType === "text/plain") { | ||
body = formData; | ||
formData = undefined; | ||
} | ||
let { | ||
protocol, | ||
host | ||
} = window.location; | ||
let url = new URL(action, protocol + "//" + host); | ||
return { | ||
url, | ||
action, | ||
method: method.toLowerCase(), | ||
encType, | ||
formData | ||
formData, | ||
body | ||
}; | ||
@@ -223,4 +251,5 @@ } | ||
const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset"], | ||
_excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "children"], | ||
_excluded3 = ["reloadDocument", "replace", "method", "action", "onSubmit", "fetcherKey", "routeId", "relative", "preventScrollReset"]; | ||
_excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "children"], | ||
_excluded3 = ["reloadDocument", "replace", "state", "method", "action", "onSubmit", "submit", "relative", "preventScrollReset"]; | ||
//#endregion | ||
@@ -233,2 +262,5 @@ //////////////////////////////////////////////////////////////////////////////// | ||
basename: opts == null ? void 0 : opts.basename, | ||
future: _extends({}, opts == null ? void 0 : opts.future, { | ||
v7_prependBasename: true | ||
}), | ||
history: router.createBrowserHistory({ | ||
@@ -239,3 +271,3 @@ window: opts == null ? void 0 : opts.window | ||
routes, | ||
detectErrorBoundary: reactRouter.UNSAFE_detectErrorBoundary | ||
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
@@ -246,2 +278,5 @@ } | ||
basename: opts == null ? void 0 : opts.basename, | ||
future: _extends({}, opts == null ? void 0 : opts.future, { | ||
v7_prependBasename: true | ||
}), | ||
history: router.createHashHistory({ | ||
@@ -252,11 +287,8 @@ window: opts == null ? void 0 : opts.window | ||
routes, | ||
detectErrorBoundary: reactRouter.UNSAFE_detectErrorBoundary | ||
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties | ||
}).initialize(); | ||
} | ||
function parseHydrationData() { | ||
var _window; | ||
let state = (_window = window) == null ? void 0 : _window.__staticRouterHydrationData; | ||
if (state && state.errors) { | ||
@@ -267,6 +299,4 @@ state = _extends({}, state, { | ||
} | ||
return state; | ||
} | ||
function deserializeErrors(errors) { | ||
@@ -276,3 +306,2 @@ if (!errors) return null; | ||
let serialized = {}; | ||
for (let [key, val] of entries) { | ||
@@ -284,7 +313,25 @@ // Hey you! If you change this, please change the corresponding logic in | ||
} else if (val && val.__type === "Error") { | ||
let error = new Error(val.message); // Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
// Attempt to reconstruct the right type of Error (i.e., ReferenceError) | ||
if (val.__subType) { | ||
let ErrorConstructor = window[val.__subType]; | ||
if (typeof ErrorConstructor === "function") { | ||
try { | ||
// @ts-expect-error | ||
let error = new ErrorConstructor(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} catch (e) { | ||
// no-op - fall through and create a normal Error | ||
} | ||
} | ||
} | ||
if (serialized[key] == null) { | ||
let error = new Error(val.message); | ||
// Wipe away the client-side stack trace. Nothing to fill it in with | ||
// because we don't serialize SSR stack traces for security reasons | ||
error.stack = ""; | ||
serialized[key] = error; | ||
} | ||
} else { | ||
@@ -294,5 +341,7 @@ serialized[key] = val; | ||
} | ||
return serialized; | ||
} | ||
return serialized; | ||
} //#endregion | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
@@ -302,3 +351,25 @@ //#region Components | ||
/** | ||
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]; | ||
/** | ||
@@ -311,6 +382,6 @@ * A `<Router>` for use in web browsers. Provides the cleanest URLs. | ||
children, | ||
future, | ||
window | ||
} = _ref; | ||
let historyRef = React__namespace.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -322,9 +393,14 @@ historyRef.current = router.createBrowserHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React__namespace.useState({ | ||
let [state, setStateImpl] = React__namespace.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React__namespace.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React__namespace.createElement(reactRouter.Router, { | ||
@@ -338,3 +414,2 @@ basename: basename, | ||
} | ||
/** | ||
@@ -348,6 +423,6 @@ * A `<Router>` for use in web browsers. Stores the location in the hash | ||
children, | ||
future, | ||
window | ||
} = _ref2; | ||
let historyRef = React__namespace.useRef(); | ||
if (historyRef.current == null) { | ||
@@ -359,9 +434,14 @@ historyRef.current = router.createHashHistory({ | ||
} | ||
let history = historyRef.current; | ||
let [state, setState] = React__namespace.useState({ | ||
let [state, setStateImpl] = React__namespace.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React__namespace.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React__namespace.createElement(reactRouter.Router, { | ||
@@ -375,3 +455,2 @@ basename: basename, | ||
} | ||
/** | ||
@@ -387,9 +466,16 @@ * A `<Router>` that accepts a pre-instantiated history object. It's important | ||
children, | ||
future, | ||
history | ||
} = _ref3; | ||
const [state, setState] = React__namespace.useState({ | ||
let [state, setStateImpl] = React__namespace.useState({ | ||
action: history.action, | ||
location: history.location | ||
}); | ||
React__namespace.useLayoutEffect(() => history.listen(setState), [history]); | ||
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]); | ||
return /*#__PURE__*/React__namespace.createElement(reactRouter.Router, { | ||
@@ -403,3 +489,2 @@ basename: basename, | ||
} | ||
{ | ||
@@ -410,45 +495,49 @@ HistoryRouter.displayName = "unstable_HistoryRouter"; | ||
const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i; | ||
/** | ||
* The public API for rendering a history-aware <a>. | ||
*/ | ||
const Link = /*#__PURE__*/React__namespace.forwardRef(function LinkWithRef(_ref4, ref) { | ||
let { | ||
onClick, | ||
relative, | ||
reloadDocument, | ||
replace, | ||
state, | ||
target, | ||
to, | ||
preventScrollReset | ||
} = _ref4, | ||
rest = _objectWithoutPropertiesLoose(_ref4, _excluded); | ||
onClick, | ||
relative, | ||
reloadDocument, | ||
replace, | ||
state, | ||
target, | ||
to, | ||
preventScrollReset | ||
} = _ref4, | ||
rest = _objectWithoutPropertiesLoose(_ref4, _excluded); | ||
let { | ||
basename | ||
} = React__namespace.useContext(reactRouter.UNSAFE_NavigationContext); // Rendered into <a href> for absolute URLs | ||
} = React__namespace.useContext(reactRouter.UNSAFE_NavigationContext); | ||
// Rendered into <a href> for absolute URLs | ||
let absoluteHref; | ||
let isExternal = false; | ||
if (typeof to === "string" && ABSOLUTE_URL_REGEX.test(to)) { | ||
// Render the absolute href server- and client-side | ||
absoluteHref = to; // Only check for external origins client-side | ||
absoluteHref = to; | ||
// Only check for external origins client-side | ||
if (isBrowser) { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = router.stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
try { | ||
let currentUrl = new URL(window.location.href); | ||
let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to); | ||
let path = router.stripBasename(targetUrl.pathname, basename); | ||
if (targetUrl.origin === currentUrl.origin && path != null) { | ||
// Strip the protocol/origin/basename for same-origin absolute URLs | ||
to = path + targetUrl.search + targetUrl.hash; | ||
} else { | ||
isExternal = true; | ||
} | ||
} catch (e) { | ||
// We can't do external URL detection without a valid URL | ||
router.UNSAFE_warning(false, "<Link to=\"" + to + "\"> contains an invalid URL which will probably break " + "when clicked - please update to a valid URL path.") ; | ||
} | ||
} | ||
} // Rendered into <a href> for relative URLs | ||
} | ||
// Rendered into <a href> for relative URLs | ||
let href = reactRouter.useHref(to, { | ||
@@ -464,6 +553,4 @@ relative | ||
}); | ||
function handleClick(event) { | ||
if (onClick) onClick(event); | ||
if (!event.defaultPrevented) { | ||
@@ -473,3 +560,2 @@ internalOnClick(event); | ||
} | ||
return ( | ||
@@ -486,7 +572,5 @@ /*#__PURE__*/ | ||
}); | ||
{ | ||
Link.displayName = "Link"; | ||
} | ||
/** | ||
@@ -497,12 +581,11 @@ * A <Link> wrapper that knows if it's "active" or not. | ||
let { | ||
"aria-current": ariaCurrentProp = "page", | ||
caseSensitive = false, | ||
className: classNameProp = "", | ||
end = false, | ||
style: styleProp, | ||
to, | ||
children | ||
} = _ref5, | ||
rest = _objectWithoutPropertiesLoose(_ref5, _excluded2); | ||
"aria-current": ariaCurrentProp = "page", | ||
caseSensitive = false, | ||
className: classNameProp = "", | ||
end = false, | ||
style: styleProp, | ||
to, | ||
children | ||
} = _ref5, | ||
rest = _objectWithoutPropertiesLoose(_ref5, _excluded2); | ||
let path = reactRouter.useResolvedPath(to, { | ||
@@ -519,3 +602,2 @@ relative: rest.relative | ||
let nextLocationPathname = routerState && routerState.navigation && routerState.navigation.location ? routerState.navigation.location.pathname : null; | ||
if (!caseSensitive) { | ||
@@ -526,3 +608,2 @@ locationPathname = locationPathname.toLowerCase(); | ||
} | ||
let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(toPathname.length) === "/"; | ||
@@ -532,3 +613,2 @@ let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/"); | ||
let className; | ||
if (typeof classNameProp === "function") { | ||
@@ -547,3 +627,2 @@ className = classNameProp({ | ||
} | ||
let style = typeof styleProp === "function" ? styleProp({ | ||
@@ -564,7 +643,5 @@ isActive, | ||
}); | ||
{ | ||
NavLink.displayName = "NavLink"; | ||
} | ||
/** | ||
@@ -577,26 +654,24 @@ * A `@remix-run/router`-aware `<form>`. It behaves like a normal form except | ||
const Form = /*#__PURE__*/React__namespace.forwardRef((props, ref) => { | ||
let submit = useSubmit(); | ||
return /*#__PURE__*/React__namespace.createElement(FormImpl, _extends({}, props, { | ||
submit: submit, | ||
ref: ref | ||
})); | ||
}); | ||
{ | ||
Form.displayName = "Form"; | ||
} | ||
const FormImpl = /*#__PURE__*/React__namespace.forwardRef((_ref6, forwardedRef) => { | ||
let { | ||
reloadDocument, | ||
replace, | ||
method = defaultMethod, | ||
action, | ||
onSubmit, | ||
fetcherKey, | ||
routeId, | ||
relative, | ||
preventScrollReset | ||
} = _ref6, | ||
props = _objectWithoutPropertiesLoose(_ref6, _excluded3); | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
reloadDocument, | ||
replace, | ||
state, | ||
method = defaultMethod, | ||
action, | ||
onSubmit, | ||
submit, | ||
relative, | ||
preventScrollReset | ||
} = _ref6, | ||
props = _objectWithoutPropertiesLoose(_ref6, _excluded3); | ||
let formMethod = method.toLowerCase() === "get" ? "get" : "post"; | ||
@@ -606,3 +681,2 @@ let formAction = useFormAction(action, { | ||
}); | ||
let submitHandler = event => { | ||
@@ -617,2 +691,3 @@ onSubmit && onSubmit(event); | ||
replace, | ||
state, | ||
relative, | ||
@@ -622,3 +697,2 @@ preventScrollReset | ||
}; | ||
return /*#__PURE__*/React__namespace.createElement("form", _extends({ | ||
@@ -631,7 +705,5 @@ ref: forwardedRef, | ||
}); | ||
{ | ||
FormImpl.displayName = "FormImpl"; | ||
} | ||
/** | ||
@@ -652,30 +724,25 @@ * This component will emulate the browser's scroll restoration on location | ||
} | ||
{ | ||
ScrollRestoration.displayName = "ScrollRestoration"; | ||
} //#endregion | ||
} | ||
//#endregion | ||
//////////////////////////////////////////////////////////////////////////////// | ||
//#region Hooks | ||
//////////////////////////////////////////////////////////////////////////////// | ||
var DataRouterHook; | ||
(function (DataRouterHook) { | ||
var DataRouterHook = /*#__PURE__*/function (DataRouterHook) { | ||
DataRouterHook["UseScrollRestoration"] = "useScrollRestoration"; | ||
DataRouterHook["UseSubmitImpl"] = "useSubmitImpl"; | ||
DataRouterHook["UseSubmit"] = "useSubmit"; | ||
DataRouterHook["UseSubmitFetcher"] = "useSubmitFetcher"; | ||
DataRouterHook["UseFetcher"] = "useFetcher"; | ||
})(DataRouterHook || (DataRouterHook = {})); | ||
var DataRouterStateHook; | ||
(function (DataRouterStateHook) { | ||
return DataRouterHook; | ||
}(DataRouterHook || {}); | ||
var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) { | ||
DataRouterStateHook["UseFetchers"] = "useFetchers"; | ||
DataRouterStateHook["UseScrollRestoration"] = "useScrollRestoration"; | ||
})(DataRouterStateHook || (DataRouterStateHook = {})); | ||
return DataRouterStateHook; | ||
}(DataRouterStateHook || {}); | ||
function getDataRouterConsoleError(hookName) { | ||
return hookName + " must be used within a data router. See https://reactrouter.com/routers/picking-a-router."; | ||
} | ||
function useDataRouterContext(hookName) { | ||
@@ -686,3 +753,2 @@ let ctx = React__namespace.useContext(reactRouter.UNSAFE_DataRouterContext); | ||
} | ||
function useDataRouterState(hookName) { | ||
@@ -693,2 +759,3 @@ let state = React__namespace.useContext(reactRouter.UNSAFE_DataRouterStateContext); | ||
} | ||
/** | ||
@@ -699,4 +766,2 @@ * Handles the click behavior for router `<Link>` components. This is useful if | ||
*/ | ||
function useLinkClickHandler(to, _temp) { | ||
@@ -717,5 +782,6 @@ let { | ||
if (shouldProcessLinkClick(event, target)) { | ||
event.preventDefault(); // If the URL hasn't changed, a regular <a> will do a replace instead of | ||
event.preventDefault(); | ||
// If the URL hasn't changed, a regular <a> will do a replace instead of | ||
// a push, so do the same here unless the replace prop is explicitly set | ||
let replace = replaceProp !== undefined ? replaceProp : reactRouter.createPath(location) === reactRouter.createPath(path); | ||
@@ -731,2 +797,3 @@ navigate(to, { | ||
} | ||
/** | ||
@@ -736,3 +803,2 @@ * A convenient wrapper for reading and writing search parameters via the | ||
*/ | ||
function useSearchParams(defaultInit) { | ||
@@ -743,3 +809,4 @@ router.UNSAFE_warning(typeof URLSearchParams !== "undefined", "You cannot use the `useSearchParams` hook in a browser that does not " + "support the URLSearchParams API. If you need to support Internet " + "Explorer 11, we recommend you load a polyfill such as " + "https://github.com/ungap/url-search-params\n\n" + "If you're unsure how to load polyfills, we recommend you check out " + "https://polyfill.io/v3/ which provides some recommendations about how " + "to load polyfills only for users that need them, instead of for every " + "user.") ; | ||
let location = reactRouter.useLocation(); | ||
let searchParams = React__namespace.useMemo(() => // Only merge in the defaults if we haven't yet called setSearchParams. | ||
let searchParams = React__namespace.useMemo(() => | ||
// Only merge in the defaults if we haven't yet called setSearchParams. | ||
// Once we call that we want those to take precedence, otherwise you can't | ||
@@ -758,2 +825,16 @@ // remove a param with setSearchParams({}) if it has an initial value | ||
/** | ||
* Submits a HTML `<form>` to the server without reloading the page. | ||
*/ | ||
/** | ||
* Submits a fetcher `<form>` to the server without reloading the page. | ||
*/ | ||
function validateClientSideSubmission() { | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
} | ||
/** | ||
* Returns a function that may be used to programmatically submit a form (or | ||
@@ -763,10 +844,44 @@ * some arbitrary data) to the server. | ||
function useSubmit() { | ||
return useSubmitImpl(); | ||
let { | ||
router | ||
} = useDataRouterContext(DataRouterHook.UseSubmit); | ||
let { | ||
basename | ||
} = React__namespace.useContext(reactRouter.UNSAFE_NavigationContext); | ||
let currentRouteId = reactRouter.UNSAFE_useRouteId(); | ||
return React__namespace.useCallback(function (target, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
router.navigate(options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType, | ||
replace: options.replace, | ||
state: options.state, | ||
fromRouteId: currentRouteId | ||
}); | ||
}, [router, basename, currentRouteId]); | ||
} | ||
function useSubmitImpl(fetcherKey, routeId) { | ||
/** | ||
* Returns the implementation for fetcher.submit | ||
*/ | ||
function useSubmitFetcher(fetcherKey, fetcherRouteId) { | ||
let { | ||
router: router$1 | ||
} = useDataRouterContext(DataRouterHook.UseSubmitImpl); | ||
let defaultAction = useFormAction(); | ||
} = useDataRouterContext(DataRouterHook.UseSubmitFetcher); | ||
let { | ||
basename | ||
} = React__namespace.useContext(reactRouter.UNSAFE_NavigationContext); | ||
return React__namespace.useCallback(function (target, options) { | ||
@@ -776,31 +891,23 @@ if (options === void 0) { | ||
} | ||
if (typeof document === "undefined") { | ||
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead."); | ||
} | ||
validateClientSideSubmission(); | ||
let { | ||
action, | ||
method, | ||
encType, | ||
formData, | ||
url | ||
} = getFormSubmissionInfo(target, defaultAction, options); | ||
let href = url.pathname + url.search; | ||
let opts = { | ||
replace: options.replace, | ||
body | ||
} = getFormSubmissionInfo(target, basename); | ||
!(fetcherRouteId != null) ? router.UNSAFE_invariant(false, "No routeId available for useFetcher()") : void 0; | ||
router$1.fetch(fetcherKey, fetcherRouteId, options.action || action, { | ||
preventScrollReset: options.preventScrollReset, | ||
formData, | ||
formMethod: method, | ||
formEncType: encType | ||
}; | ||
if (fetcherKey) { | ||
!(routeId != null) ? router.UNSAFE_invariant(false, "No routeId available for useFetcher()") : void 0; | ||
router$1.fetch(fetcherKey, routeId, href, opts); | ||
} else { | ||
router$1.navigate(href, opts); | ||
} | ||
}, [defaultAction, router$1, fetcherKey, routeId]); | ||
body, | ||
formMethod: options.method || method, | ||
formEncType: options.encType || encType | ||
}); | ||
}, [router$1, basename, fetcherKey, fetcherRouteId]); | ||
} | ||
// v7: Eventually we should deprecate this entirely in favor of using the | ||
// router method directly? | ||
function useFormAction(action, _temp2) { | ||
@@ -815,25 +922,23 @@ let { | ||
!routeContext ? router.UNSAFE_invariant(false, "useFormAction must be used inside a RouteContext") : void 0; | ||
let [match] = routeContext.matches.slice(-1); // Shallow clone path so we can modify it below, otherwise we modify the | ||
let [match] = routeContext.matches.slice(-1); | ||
// Shallow clone path so we can modify it below, otherwise we modify the | ||
// object referenced by useMemo inside useResolvedPath | ||
let path = _extends({}, reactRouter.useResolvedPath(action ? action : ".", { | ||
relative | ||
})); // Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params and the hash of the resolved | ||
// URL. This is the intended behavior of when "." is specifically provided as | ||
})); | ||
// Previously we set the default action to ".". The problem with this is that | ||
// `useResolvedPath(".")` excludes search params of the resolved URL. This is | ||
// the intended behavior of when "." is specifically provided as | ||
// the form action, but inconsistent w/ browsers when the action is omitted. | ||
// https://github.com/remix-run/remix/issues/927 | ||
let location = reactRouter.useLocation(); | ||
if (action == null) { | ||
// Safe to write to these directly here since if action was undefined, we | ||
// Safe to write to this directly here since if action was undefined, we | ||
// would have called useResolvedPath(".") which will never include a search | ||
// or hash | ||
path.search = location.search; | ||
path.hash = location.hash; // When grabbing search params from the URL, remove the automatically | ||
// When grabbing search params from the URL, remove the automatically | ||
// inserted ?index param so we match the useResolvedPath search behavior | ||
// which would not include ?index | ||
if (match.route.index) { | ||
@@ -845,36 +950,29 @@ let params = new URLSearchParams(path.search); | ||
} | ||
if ((!action || action === ".") && match.route.index) { | ||
path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; | ||
} // If we're operating within a basename, prepend it to the pathname prior | ||
} | ||
// If we're operating within a basename, prepend it to the pathname prior | ||
// to creating the form action. 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 actions | ||
if (basename !== "/") { | ||
path.pathname = path.pathname === "/" ? basename : router.joinPaths([basename, path.pathname]); | ||
} | ||
return reactRouter.createPath(path); | ||
} | ||
function createFetcherForm(fetcherKey, routeId) { | ||
let FetcherForm = /*#__PURE__*/React__namespace.forwardRef((props, ref) => { | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
return /*#__PURE__*/React__namespace.createElement(FormImpl, _extends({}, props, { | ||
ref: ref, | ||
fetcherKey: fetcherKey, | ||
routeId: routeId | ||
submit: submit | ||
})); | ||
}); | ||
{ | ||
FetcherForm.displayName = "fetcher.Form"; | ||
} | ||
return FetcherForm; | ||
} | ||
let fetcherId = 0; | ||
/** | ||
@@ -886,3 +984,2 @@ * Interacts with route loaders and actions without causing a navigation. Great | ||
var _route$matches; | ||
let { | ||
@@ -905,3 +1002,3 @@ router: router$1 | ||
}); | ||
let submit = useSubmitImpl(fetcherKey, routeId); | ||
let submit = useSubmitFetcher(fetcherKey, routeId); | ||
let fetcher = router$1.getFetcher(fetcherKey); | ||
@@ -919,6 +1016,5 @@ let fetcherWithComponents = React__namespace.useMemo(() => _extends({ | ||
if (!router$1) { | ||
console.warn("No fetcher available to clean up from useFetcher()"); | ||
console.warn("No router available to clean up from useFetcher()"); | ||
return; | ||
} | ||
router$1.deleteFetcher(fetcherKey); | ||
@@ -929,2 +1025,3 @@ }; | ||
} | ||
/** | ||
@@ -934,3 +1031,2 @@ * Provides all fetchers currently on the page. Useful for layouts and parent | ||
*/ | ||
function useFetchers() { | ||
@@ -942,6 +1038,6 @@ let state = useDataRouterState(DataRouterStateHook.UseFetchers); | ||
let savedScrollPositions = {}; | ||
/** | ||
* When rendered inside a RouterProvider, will restore scroll positions on navigations | ||
*/ | ||
function useScrollRestoration(_temp3) { | ||
@@ -953,3 +1049,3 @@ let { | ||
let { | ||
router | ||
router: router$1 | ||
} = useDataRouterContext(DataRouterHook.UseScrollRestoration); | ||
@@ -960,6 +1056,10 @@ let { | ||
} = useDataRouterState(DataRouterStateHook.UseScrollRestoration); | ||
let { | ||
basename | ||
} = React__namespace.useContext(reactRouter.UNSAFE_NavigationContext); | ||
let location = reactRouter.useLocation(); | ||
let matches = reactRouter.useMatches(); | ||
let navigation = reactRouter.useNavigation(); // Trigger manual scroll restoration while we're active | ||
let navigation = reactRouter.useNavigation(); | ||
// Trigger manual scroll restoration while we're active | ||
React__namespace.useEffect(() => { | ||
@@ -970,4 +1070,5 @@ window.history.scrollRestoration = "manual"; | ||
}; | ||
}, []); // Save positions on pagehide | ||
}, []); | ||
// Save positions on pagehide | ||
usePageHide(React__namespace.useCallback(() => { | ||
@@ -978,7 +1079,7 @@ if (navigation.state === "idle") { | ||
} | ||
sessionStorage.setItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY, JSON.stringify(savedScrollPositions)); | ||
window.history.scrollRestoration = "auto"; | ||
}, [storageKey, getKey, navigation.state, location, matches])); // Read in any saved scroll locations | ||
}, [storageKey, getKey, navigation.state, location, matches])); | ||
// Read in any saved scroll locations | ||
if (typeof document !== "undefined") { | ||
@@ -989,17 +1090,23 @@ // eslint-disable-next-line react-hooks/rules-of-hooks | ||
let sessionPositions = sessionStorage.getItem(storageKey || SCROLL_RESTORATION_STORAGE_KEY); | ||
if (sessionPositions) { | ||
savedScrollPositions = JSON.parse(sessionPositions); | ||
} | ||
} catch (e) {// no-op, use default empty object | ||
} catch (e) { | ||
// no-op, use default empty object | ||
} | ||
}, [storageKey]); // Enable scroll restoration in the router | ||
}, [storageKey]); | ||
// Enable scroll restoration in the router | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React__namespace.useLayoutEffect(() => { | ||
let disableScrollRestoration = router == null ? void 0 : router.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKey); | ||
let getKeyWithoutBasename = getKey && basename !== "/" ? (location, matches) => getKey( // Strip the basename to match useLocation() | ||
_extends({}, location, { | ||
pathname: router.stripBasename(location.pathname, basename) || location.pathname | ||
}), matches) : getKey; | ||
let disableScrollRestoration = router$1 == null ? void 0 : router$1.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKeyWithoutBasename); | ||
return () => disableScrollRestoration && disableScrollRestoration(); | ||
}, [router, getKey]); // Restore scrolling when state.restoreScrollPosition changes | ||
}, [router$1, basename, getKey]); | ||
// Restore scrolling when state.restoreScrollPosition changes | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
React__namespace.useLayoutEffect(() => { | ||
@@ -1009,14 +1116,13 @@ // Explicit false means don't do anything (used for submissions) | ||
return; | ||
} // been here before, scroll to it | ||
} | ||
// been here before, scroll to it | ||
if (typeof restoreScrollPosition === "number") { | ||
window.scrollTo(0, restoreScrollPosition); | ||
return; | ||
} // try to scroll to the hash | ||
} | ||
// try to scroll to the hash | ||
if (location.hash) { | ||
let el = document.getElementById(location.hash.slice(1)); | ||
let el = document.getElementById(decodeURIComponent(location.hash.slice(1))); | ||
if (el) { | ||
@@ -1026,10 +1132,10 @@ el.scrollIntoView(); | ||
} | ||
} // Don't reset if this navigation opted out | ||
} | ||
// Don't reset if this navigation opted out | ||
if (preventScrollReset === true) { | ||
return; | ||
} // otherwise go to the top on new locations | ||
} | ||
// otherwise go to the top on new locations | ||
window.scrollTo(0, 0); | ||
@@ -1039,2 +1145,3 @@ }, [location, restoreScrollPosition, preventScrollReset]); | ||
} | ||
/** | ||
@@ -1048,3 +1155,2 @@ * Setup a callback to be fired on the window's `beforeunload` event. This is | ||
*/ | ||
function useBeforeUnload(callback, options) { | ||
@@ -1064,2 +1170,3 @@ let { | ||
} | ||
/** | ||
@@ -1073,3 +1180,2 @@ * Setup a callback to be fired on the window's `pagehide` event. This is | ||
*/ | ||
function usePageHide(callback, options) { | ||
@@ -1089,2 +1195,3 @@ let { | ||
} | ||
/** | ||
@@ -1098,4 +1205,2 @@ * Wrapper around useBlocker to show a window.confirm prompt to users instead | ||
*/ | ||
function usePrompt(_ref8) { | ||
@@ -1108,11 +1213,8 @@ let { | ||
React__namespace.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
React__namespace.useEffect(() => { | ||
if (blocker.state === "blocked") { | ||
let proceed = window.confirm(message); | ||
if (proceed) { | ||
// This timeout is needed to avoid a weird "race" on POP navigations | ||
// between the `window.history` revert navigation and the result of | ||
// `window.confirm` | ||
setTimeout(blocker.proceed, 0); | ||
@@ -1124,5 +1226,11 @@ } else { | ||
}, [blocker, message]); | ||
React__namespace.useEffect(() => { | ||
if (blocker.state === "blocked" && !when) { | ||
blocker.reset(); | ||
} | ||
}, [blocker, when]); | ||
} | ||
//#endregion | ||
//#endregion | ||
Object.defineProperty(exports, 'AbortedDeferredError', { | ||
@@ -1188,2 +1296,6 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(exports, 'UNSAFE_useRouteId', { | ||
enumerable: true, | ||
get: function () { return reactRouter.UNSAFE_useRouteId; } | ||
}); | ||
Object.defineProperty(exports, 'createMemoryRouter', { | ||
@@ -1237,2 +1349,6 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(exports, 'redirectDocument', { | ||
enumerable: true, | ||
get: function () { return reactRouter.redirectDocument; } | ||
}); | ||
Object.defineProperty(exports, 'renderMatches', { | ||
@@ -1239,0 +1355,0 @@ enumerable: true, |
/** | ||
* React Router DOM v0.0.0-experimental-91f2bf54 | ||
* React Router DOM v0.0.0-experimental-ad6954b7 | ||
* | ||
@@ -11,3 +11,3 @@ * Copyright (c) Remix Software Inc. | ||
*/ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-router"),require("@remix-run/router")):"function"==typeof define&&define.amd?define(["exports","react","react-router","@remix-run/router"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactRouterDOM={},e.React,e.ReactRouter,e.RemixRouter)}(this,(function(e,t,r,n){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=o(t);function u(){return u=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},u.apply(this,arguments)}function i(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}const c="get",l="application/x-www-form-urlencoded";function s(e){return null!=e&&"string"==typeof e.tagName}function f(e){return void 0===e&&(e=""),new URLSearchParams("string"==typeof e||Array.isArray(e)||e instanceof URLSearchParams?e:Object.keys(e).reduce(((t,r)=>{let n=e[r];return t.concat(Array.isArray(n)?n.map((e=>[r,e])):[[r,n]])}),[]))}function d(e,t,r){let n,o,a,u;if(s(i=e)&&"form"===i.tagName.toLowerCase()){let i=r.submissionTrigger;n=r.method||e.getAttribute("method")||c,o=r.action||e.getAttribute("action")||t,a=r.encType||e.getAttribute("enctype")||l,u=new FormData(e),i&&i.name&&u.append(i.name,i.value)}else if(function(e){return s(e)&&"button"===e.tagName.toLowerCase()}(e)||function(e){return s(e)&&"input"===e.tagName.toLowerCase()}(e)&&("submit"===e.type||"image"===e.type)){let i=e.form;if(null==i)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');n=r.method||e.getAttribute("formmethod")||i.getAttribute("method")||c,o=r.action||e.getAttribute("formaction")||i.getAttribute("action")||t,a=r.encType||e.getAttribute("formenctype")||i.getAttribute("enctype")||l,u=new FormData(i),e.name&&u.append(e.name,e.value)}else{if(s(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');if(n=r.method||c,o=r.action||t,a=r.encType||l,e instanceof FormData)u=e;else if(u=new FormData,e instanceof URLSearchParams)for(let[t,r]of e)u.append(t,r);else if(null!=e)for(let t of Object.keys(e))u.append(t,e[t])}var i;let{protocol:f,host:d}=window.location;return{url:new URL(o,f+"//"+d),method:n.toLowerCase(),encType:a,formData:u}}const m=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset"],b=["aria-current","caseSensitive","className","end","style","to","children"],p=["reloadDocument","replace","method","action","onSubmit","fetcherKey","routeId","relative","preventScrollReset"];function h(){var e;let t=null==(e=window)?void 0:e.__staticRouterHydrationData;return t&&t.errors&&(t=u({},t,{errors:y(t.errors)})),t}function y(e){if(!e)return null;let t=Object.entries(e),r={};for(let[e,o]of t)if(o&&"RouteErrorResponse"===o.__type)r[e]=new n.ErrorResponse(o.status,o.statusText,o.data,!0===o.internal);else if(o&&"Error"===o.__type){let t=new Error(o.message);t.stack="",r[e]=t}else r[e]=o;return r}const g="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,v=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,R=a.forwardRef((function(e,t){let o,{onClick:c,relative:l,reloadDocument:s,replace:f,state:d,target:b,to:p,preventScrollReset:h}=e,y=i(e,m),{basename:R}=a.useContext(r.UNSAFE_NavigationContext),w=!1;if("string"==typeof p&&v.test(p)&&(o=p,g)){let e=new URL(window.location.href),t=p.startsWith("//")?new URL(e.protocol+p):new URL(p),r=n.stripBasename(t.pathname,R);t.origin===e.origin&&null!=r?p=r+t.search+t.hash:w=!0}let P=r.useHref(p,{relative:l}),S=N(p,{replace:f,state:d,target:b,preventScrollReset:h,relative:l});return a.createElement("a",u({},y,{href:o||P,onClick:w||s?c:function(e){c&&c(e),e.defaultPrevented||S(e)},ref:t,target:b}))})),w=a.forwardRef((function(e,t){let{"aria-current":n="page",caseSensitive:o=!1,className:c="",end:l=!1,style:s,to:f,children:d}=e,m=i(e,b),p=r.useResolvedPath(f,{relative:m.relative}),h=r.useLocation(),y=a.useContext(r.UNSAFE_DataRouterStateContext),{navigator:g}=a.useContext(r.UNSAFE_NavigationContext),v=g.encodeLocation?g.encodeLocation(p).pathname:p.pathname,w=h.pathname,P=y&&y.navigation&&y.navigation.location?y.navigation.location.pathname:null;o||(w=w.toLowerCase(),P=P?P.toLowerCase():null,v=v.toLowerCase());let S,E=w===v||!l&&w.startsWith(v)&&"/"===w.charAt(v.length),O=null!=P&&(P===v||!l&&P.startsWith(v)&&"/"===P.charAt(v.length)),j=E?n:void 0;S="function"==typeof c?c({isActive:E,isPending:O}):[c,E?"active":null,O?"pending":null].filter(Boolean).join(" ");let A="function"==typeof s?s({isActive:E,isPending:O}):s;return a.createElement(R,u({},m,{"aria-current":j,className:S,ref:t,style:A,to:f}),"function"==typeof d?d({isActive:E,isPending:O}):d)})),P=a.forwardRef(((e,t)=>a.createElement(S,u({},e,{ref:t})))),S=a.forwardRef(((e,t)=>{let{reloadDocument:r,replace:n,method:o=c,action:l,onSubmit:s,fetcherKey:f,routeId:d,relative:m,preventScrollReset:b}=e,h=i(e,p),y=C(f,d),g="get"===o.toLowerCase()?"get":"post",v=F(l,{relative:m});return a.createElement("form",u({ref:t,method:g,action:v,onSubmit:r?s:e=>{if(s&&s(e),e.defaultPrevented)return;e.preventDefault();let t=e.nativeEvent.submitter,r=(null==t?void 0:t.getAttribute("formmethod"))||o;y(t||e.currentTarget,{method:r,replace:n,relative:m,preventScrollReset:b})}},h))}));var E,O;function j(e){let t=a.useContext(r.UNSAFE_DataRouterContext);return t||n.UNSAFE_invariant(!1),t}function A(e){let t=a.useContext(r.UNSAFE_DataRouterStateContext);return t||n.UNSAFE_invariant(!1),t}function N(e,t){let{target:n,replace:o,state:u,preventScrollReset:i,relative:c}=void 0===t?{}:t,l=r.useNavigate(),s=r.useLocation(),f=r.useResolvedPath(e,{relative:c});return a.useCallback((t=>{if(function(e,t){return!(0!==e.button||t&&"_self"!==t||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e))}(t,n)){t.preventDefault();let n=void 0!==o?o:r.createPath(s)===r.createPath(f);l(e,{replace:n,state:u,preventScrollReset:i,relative:c})}}),[s,l,f,o,u,n,e,i,c])}function C(e,t){let{router:r}=j(E.UseSubmitImpl),o=F();return a.useCallback((function(a,u){if(void 0===u&&(u={}),"undefined"==typeof document)throw new Error("You are calling submit during the server render. Try calling submit within a `useEffect` or callback instead.");let{method:i,encType:c,formData:l,url:s}=d(a,o,u),f=s.pathname+s.search,m={replace:u.replace,preventScrollReset:u.preventScrollReset,formData:l,formMethod:i,formEncType:c};e?(null==t&&n.UNSAFE_invariant(!1),r.fetch(e,t,f,m)):r.navigate(f,m)}),[o,r,e,t])}function F(e,t){let{relative:o}=void 0===t?{}:t,{basename:i}=a.useContext(r.UNSAFE_NavigationContext),c=a.useContext(r.UNSAFE_RouteContext);c||n.UNSAFE_invariant(!1);let[l]=c.matches.slice(-1),s=u({},r.useResolvedPath(e||".",{relative:o})),f=r.useLocation();if(null==e&&(s.search=f.search,s.hash=f.hash,l.route.index)){let e=new URLSearchParams(s.search);e.delete("index"),s.search=e.toString()?"?"+e.toString():""}return e&&"."!==e||!l.route.index||(s.search=s.search?s.search.replace(/^\?/,"?index&"):"?index"),"/"!==i&&(s.pathname="/"===s.pathname?i:n.joinPaths([i,s.pathname])),r.createPath(s)}!function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmitImpl="useSubmitImpl",e.UseFetcher="useFetcher"}(E||(E={})),function(e){e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"}(O||(O={}));let U=0;const _="react-router-scroll-positions";let x={};function L(e){let{getKey:t,storageKey:n}=void 0===e?{}:e,{router:o}=j(E.UseScrollRestoration),{restoreScrollPosition:u,preventScrollReset:i}=A(O.UseScrollRestoration),c=r.useLocation(),l=r.useMatches(),s=r.useNavigation();a.useEffect((()=>(window.history.scrollRestoration="manual",()=>{window.history.scrollRestoration="auto"})),[]),function(e,t){let{capture:r}=t||{};a.useEffect((()=>{let t=null!=r?{capture:r}:void 0;return window.addEventListener("pagehide",e,t),()=>{window.removeEventListener("pagehide",e,t)}}),[e,r])}(a.useCallback((()=>{if("idle"===s.state){let e=(t?t(c,l):null)||c.key;x[e]=window.scrollY}sessionStorage.setItem(n||_,JSON.stringify(x)),window.history.scrollRestoration="auto"}),[n,t,s.state,c,l])),"undefined"!=typeof document&&(a.useLayoutEffect((()=>{try{let e=sessionStorage.getItem(n||_);e&&(x=JSON.parse(e))}catch(e){}}),[n]),a.useLayoutEffect((()=>{let e=null==o?void 0:o.enableScrollRestoration(x,(()=>window.scrollY),t);return()=>e&&e()}),[o,t]),a.useLayoutEffect((()=>{if(!1!==u)if("number"!=typeof u){if(c.hash){let e=document.getElementById(c.hash.slice(1));if(e)return void e.scrollIntoView()}!0!==i&&window.scrollTo(0,0)}else window.scrollTo(0,u)}),[c,u,i]))}Object.defineProperty(e,"AbortedDeferredError",{enumerable:!0,get:function(){return r.AbortedDeferredError}}),Object.defineProperty(e,"Await",{enumerable:!0,get:function(){return r.Await}}),Object.defineProperty(e,"MemoryRouter",{enumerable:!0,get:function(){return r.MemoryRouter}}),Object.defineProperty(e,"Navigate",{enumerable:!0,get:function(){return r.Navigate}}),Object.defineProperty(e,"NavigationType",{enumerable:!0,get:function(){return r.NavigationType}}),Object.defineProperty(e,"Outlet",{enumerable:!0,get:function(){return r.Outlet}}),Object.defineProperty(e,"Route",{enumerable:!0,get:function(){return r.Route}}),Object.defineProperty(e,"Router",{enumerable:!0,get:function(){return r.Router}}),Object.defineProperty(e,"RouterProvider",{enumerable:!0,get:function(){return r.RouterProvider}}),Object.defineProperty(e,"Routes",{enumerable:!0,get:function(){return r.Routes}}),Object.defineProperty(e,"UNSAFE_DataRouterContext",{enumerable:!0,get:function(){return r.UNSAFE_DataRouterContext}}),Object.defineProperty(e,"UNSAFE_DataRouterStateContext",{enumerable:!0,get:function(){return r.UNSAFE_DataRouterStateContext}}),Object.defineProperty(e,"UNSAFE_LocationContext",{enumerable:!0,get:function(){return r.UNSAFE_LocationContext}}),Object.defineProperty(e,"UNSAFE_NavigationContext",{enumerable:!0,get:function(){return r.UNSAFE_NavigationContext}}),Object.defineProperty(e,"UNSAFE_RouteContext",{enumerable:!0,get:function(){return r.UNSAFE_RouteContext}}),Object.defineProperty(e,"createMemoryRouter",{enumerable:!0,get:function(){return r.createMemoryRouter}}),Object.defineProperty(e,"createPath",{enumerable:!0,get:function(){return r.createPath}}),Object.defineProperty(e,"createRoutesFromChildren",{enumerable:!0,get:function(){return r.createRoutesFromChildren}}),Object.defineProperty(e,"createRoutesFromElements",{enumerable:!0,get:function(){return r.createRoutesFromElements}}),Object.defineProperty(e,"defer",{enumerable:!0,get:function(){return r.defer}}),Object.defineProperty(e,"generatePath",{enumerable:!0,get:function(){return r.generatePath}}),Object.defineProperty(e,"isRouteErrorResponse",{enumerable:!0,get:function(){return r.isRouteErrorResponse}}),Object.defineProperty(e,"json",{enumerable:!0,get:function(){return r.json}}),Object.defineProperty(e,"matchPath",{enumerable:!0,get:function(){return r.matchPath}}),Object.defineProperty(e,"matchRoutes",{enumerable:!0,get:function(){return r.matchRoutes}}),Object.defineProperty(e,"parsePath",{enumerable:!0,get:function(){return r.parsePath}}),Object.defineProperty(e,"redirect",{enumerable:!0,get:function(){return r.redirect}}),Object.defineProperty(e,"renderMatches",{enumerable:!0,get:function(){return r.renderMatches}}),Object.defineProperty(e,"resolvePath",{enumerable:!0,get:function(){return r.resolvePath}}),Object.defineProperty(e,"unstable_useBlocker",{enumerable:!0,get:function(){return r.unstable_useBlocker}}),Object.defineProperty(e,"useActionData",{enumerable:!0,get:function(){return r.useActionData}}),Object.defineProperty(e,"useAsyncError",{enumerable:!0,get:function(){return r.useAsyncError}}),Object.defineProperty(e,"useAsyncValue",{enumerable:!0,get:function(){return r.useAsyncValue}}),Object.defineProperty(e,"useHref",{enumerable:!0,get:function(){return r.useHref}}),Object.defineProperty(e,"useInRouterContext",{enumerable:!0,get:function(){return r.useInRouterContext}}),Object.defineProperty(e,"useLoaderData",{enumerable:!0,get:function(){return r.useLoaderData}}),Object.defineProperty(e,"useLocation",{enumerable:!0,get:function(){return r.useLocation}}),Object.defineProperty(e,"useMatch",{enumerable:!0,get:function(){return r.useMatch}}),Object.defineProperty(e,"useMatches",{enumerable:!0,get:function(){return r.useMatches}}),Object.defineProperty(e,"useNavigate",{enumerable:!0,get:function(){return r.useNavigate}}),Object.defineProperty(e,"useNavigation",{enumerable:!0,get:function(){return r.useNavigation}}),Object.defineProperty(e,"useNavigationType",{enumerable:!0,get:function(){return r.useNavigationType}}),Object.defineProperty(e,"useOutlet",{enumerable:!0,get:function(){return r.useOutlet}}),Object.defineProperty(e,"useOutletContext",{enumerable:!0,get:function(){return r.useOutletContext}}),Object.defineProperty(e,"useParams",{enumerable:!0,get:function(){return r.useParams}}),Object.defineProperty(e,"useResolvedPath",{enumerable:!0,get:function(){return r.useResolvedPath}}),Object.defineProperty(e,"useRevalidator",{enumerable:!0,get:function(){return r.useRevalidator}}),Object.defineProperty(e,"useRouteError",{enumerable:!0,get:function(){return r.useRouteError}}),Object.defineProperty(e,"useRouteLoaderData",{enumerable:!0,get:function(){return r.useRouteLoaderData}}),Object.defineProperty(e,"useRoutes",{enumerable:!0,get:function(){return r.useRoutes}}),e.BrowserRouter=function(e){let{basename:t,children:o,window:u}=e,i=a.useRef();null==i.current&&(i.current=n.createBrowserHistory({window:u,v5Compat:!0}));let c=i.current,[l,s]=a.useState({action:c.action,location:c.location});return a.useLayoutEffect((()=>c.listen(s)),[c]),a.createElement(r.Router,{basename:t,children:o,location:l.location,navigationType:l.action,navigator:c})},e.Form=P,e.HashRouter=function(e){let{basename:t,children:o,window:u}=e,i=a.useRef();null==i.current&&(i.current=n.createHashHistory({window:u,v5Compat:!0}));let c=i.current,[l,s]=a.useState({action:c.action,location:c.location});return a.useLayoutEffect((()=>c.listen(s)),[c]),a.createElement(r.Router,{basename:t,children:o,location:l.location,navigationType:l.action,navigator:c})},e.Link=R,e.NavLink=w,e.ScrollRestoration=function(e){let{getKey:t,storageKey:r}=e;return L({getKey:t,storageKey:r}),null},e.UNSAFE_useScrollRestoration=L,e.createBrowserRouter=function(e,t){return n.createRouter({basename:null==t?void 0:t.basename,history:n.createBrowserHistory({window:null==t?void 0:t.window}),hydrationData:(null==t?void 0:t.hydrationData)||h(),routes:e,detectErrorBoundary:r.UNSAFE_detectErrorBoundary}).initialize()},e.createHashRouter=function(e,t){return n.createRouter({basename:null==t?void 0:t.basename,history:n.createHashHistory({window:null==t?void 0:t.window}),hydrationData:(null==t?void 0:t.hydrationData)||h(),routes:e,detectErrorBoundary:r.UNSAFE_detectErrorBoundary}).initialize()},e.createSearchParams=f,e.unstable_HistoryRouter=function(e){let{basename:t,children:n,history:o}=e;const[u,i]=a.useState({action:o.action,location:o.location});return a.useLayoutEffect((()=>o.listen(i)),[o]),a.createElement(r.Router,{basename:t,children:n,location:u.location,navigationType:u.action,navigator:o})},e.unstable_usePrompt=function(e){let{when:t,message:n}=e,o=r.unstable_useBlocker(t);a.useEffect((()=>{"blocked"!==o.state||t||o.reset()}),[o,t]),a.useEffect((()=>{if("blocked"===o.state){window.confirm(n)?setTimeout(o.proceed,0):o.reset()}}),[o,n])},e.useBeforeUnload=function(e,t){let{capture:r}=t||{};a.useEffect((()=>{let t=null!=r?{capture:r}:void 0;return window.addEventListener("beforeunload",e,t),()=>{window.removeEventListener("beforeunload",e,t)}}),[e,r])},e.useFetcher=function(){var e;let{router:t}=j(E.UseFetcher),o=a.useContext(r.UNSAFE_RouteContext);o||n.UNSAFE_invariant(!1);let i=null==(e=o.matches[o.matches.length-1])?void 0:e.route.id;null==i&&n.UNSAFE_invariant(!1);let[c]=a.useState((()=>String(++U))),[l]=a.useState((()=>(i||n.UNSAFE_invariant(!1),function(e,t){return a.forwardRef(((r,n)=>a.createElement(S,u({},r,{ref:n,fetcherKey:e,routeId:t}))))}(c,i)))),[s]=a.useState((()=>e=>{t||n.UNSAFE_invariant(!1),i||n.UNSAFE_invariant(!1),t.fetch(c,i,e)})),f=C(c,i),d=t.getFetcher(c),m=a.useMemo((()=>u({Form:l,submit:f,load:s},d)),[d,l,f,s]);return a.useEffect((()=>()=>{t?t.deleteFetcher(c):console.warn("No fetcher available to clean up from useFetcher()")}),[t,c]),m},e.useFetchers=function(){return[...A(O.UseFetchers).fetchers.values()]},e.useFormAction=F,e.useLinkClickHandler=N,e.useSearchParams=function(e){let t=a.useRef(f(e)),n=a.useRef(!1),o=r.useLocation(),u=a.useMemo((()=>function(e,t){let r=f(e);if(t)for(let e of t.keys())r.has(e)||t.getAll(e).forEach((t=>{r.append(e,t)}));return r}(o.search,n.current?null:t.current)),[o.search]),i=r.useNavigate(),c=a.useCallback(((e,t)=>{const r=f("function"==typeof e?e(u):e);n.current=!0,i("?"+r,t)}),[i,u]);return[u,c]},e.useSubmit=function(){return C()},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-router"),require("@remix-run/router")):"function"==typeof define&&define.amd?define(["exports","react","react-router","@remix-run/router"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactRouterDOM={},e.React,e.ReactRouter,e.RemixRouter)}(this,(function(e,t,r,n){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=o(t);function u(){return u=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},u.apply(this,arguments)}function i(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}const c="get",s="application/x-www-form-urlencoded";function l(e){return null!=e&&"string"==typeof e.tagName}function f(e){return void 0===e&&(e=""),new URLSearchParams("string"==typeof e||Array.isArray(e)||e instanceof URLSearchParams?e:Object.keys(e).reduce(((t,r)=>{let n=e[r];return t.concat(Array.isArray(n)?n.map((e=>[r,e])):[[r,n]])}),[]))}let d=null;const m=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function b(e){return null==e||m.has(e)?e:null}function p(e,t){let r,o,a,u,i;if(l(f=e)&&"form"===f.tagName.toLowerCase()){let i=e.getAttribute("action");o=i?n.stripBasename(i,t):null,r=e.getAttribute("method")||c,a=b(e.getAttribute("enctype"))||s,u=new FormData(e)}else if(function(e){return l(e)&&"button"===e.tagName.toLowerCase()}(e)||function(e){return l(e)&&"input"===e.tagName.toLowerCase()}(e)&&("submit"===e.type||"image"===e.type)){let i=e.form;if(null==i)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let l=e.getAttribute("formaction")||i.getAttribute("action");if(o=l?n.stripBasename(l,t):null,r=e.getAttribute("formmethod")||i.getAttribute("method")||c,a=b(e.getAttribute("formenctype"))||b(i.getAttribute("enctype"))||s,u=new FormData(i,e),!function(){if(null===d)try{new FormData(document.createElement("form"),0),d=!1}catch(e){d=!0}return d}()){let{name:t,type:r,value:n}=e;if("image"===r){let e=t?t+".":"";u.append(e+"x","0"),u.append(e+"y","0")}else t&&u.append(t,n)}}else{if(l(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');r=c,o=null,a=s,i=e}var f;return u&&"text/plain"===a&&(i=u,u=void 0),{action:o,method:r.toLowerCase(),encType:a,formData:u,body:i}}const y=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset"],g=["aria-current","caseSensitive","className","end","style","to","children"],h=["reloadDocument","replace","state","method","action","onSubmit","submit","relative","preventScrollReset"];function v(){var e;let t=null==(e=window)?void 0:e.__staticRouterHydrationData;return t&&t.errors&&(t=u({},t,{errors:R(t.errors)})),t}function R(e){if(!e)return null;let t=Object.entries(e),r={};for(let[e,o]of t)if(o&&"RouteErrorResponse"===o.__type)r[e]=new n.ErrorResponse(o.status,o.statusText,o.data,!0===o.internal);else if(o&&"Error"===o.__type){if(o.__subType){let t=window[o.__subType];if("function"==typeof t)try{let n=new t(o.message);n.stack="",r[e]=n}catch(e){}}if(null==r[e]){let t=new Error(o.message);t.stack="",r[e]=t}}else r[e]=o;return r}const w=a.startTransition;const P="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,S=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,E=a.forwardRef((function(e,t){let o,{onClick:c,relative:s,reloadDocument:l,replace:f,state:d,target:m,to:b,preventScrollReset:p}=e,g=i(e,y),{basename:h}=a.useContext(r.UNSAFE_NavigationContext),v=!1;if("string"==typeof b&&S.test(b)&&(o=b,P))try{let e=new URL(window.location.href),t=b.startsWith("//")?new URL(e.protocol+b):new URL(b),r=n.stripBasename(t.pathname,h);t.origin===e.origin&&null!=r?b=r+t.search+t.hash:v=!0}catch(e){}let R=r.useHref(b,{relative:s}),w=U(b,{replace:f,state:d,target:m,preventScrollReset:p,relative:s});return a.createElement("a",u({},g,{href:o||R,onClick:v||l?c:function(e){c&&c(e),e.defaultPrevented||w(e)},ref:t,target:m}))})),O=a.forwardRef((function(e,t){let{"aria-current":n="page",caseSensitive:o=!1,className:c="",end:s=!1,style:l,to:f,children:d}=e,m=i(e,g),b=r.useResolvedPath(f,{relative:m.relative}),p=r.useLocation(),y=a.useContext(r.UNSAFE_DataRouterStateContext),{navigator:h}=a.useContext(r.UNSAFE_NavigationContext),v=h.encodeLocation?h.encodeLocation(b).pathname:b.pathname,R=p.pathname,w=y&&y.navigation&&y.navigation.location?y.navigation.location.pathname:null;o||(R=R.toLowerCase(),w=w?w.toLowerCase():null,v=v.toLowerCase());let P,S=R===v||!s&&R.startsWith(v)&&"/"===R.charAt(v.length),O=null!=w&&(w===v||!s&&w.startsWith(v)&&"/"===w.charAt(v.length)),j=S?n:void 0;P="function"==typeof c?c({isActive:S,isPending:O}):[c,S?"active":null,O?"pending":null].filter(Boolean).join(" ");let N="function"==typeof l?l({isActive:S,isPending:O}):l;return a.createElement(E,u({},m,{"aria-current":j,className:P,ref:t,style:N,to:f}),"function"==typeof d?d({isActive:S,isPending:O}):d)})),j=a.forwardRef(((e,t)=>{let r=L();return a.createElement(N,u({},e,{submit:r,ref:t}))})),N=a.forwardRef(((e,t)=>{let{reloadDocument:r,replace:n,state:o,method:s=c,action:l,onSubmit:f,submit:d,relative:m,preventScrollReset:b}=e,p=i(e,h),y="get"===s.toLowerCase()?"get":"post",g=T(l,{relative:m});return a.createElement("form",u({ref:t,method:y,action:g,onSubmit:r?f:e=>{if(f&&f(e),e.defaultPrevented)return;e.preventDefault();let t=e.nativeEvent.submitter,r=(null==t?void 0:t.getAttribute("formmethod"))||s;d(t||e.currentTarget,{method:r,replace:n,state:o,relative:m,preventScrollReset:b})}},p))}));var A=function(e){return e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e}(A||{}),C=function(e){return e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration",e}(C||{});function _(e){let t=a.useContext(r.UNSAFE_DataRouterContext);return t||n.UNSAFE_invariant(!1),t}function F(e){let t=a.useContext(r.UNSAFE_DataRouterStateContext);return t||n.UNSAFE_invariant(!1),t}function U(e,t){let{target:n,replace:o,state:u,preventScrollReset:i,relative:c}=void 0===t?{}:t,s=r.useNavigate(),l=r.useLocation(),f=r.useResolvedPath(e,{relative:c});return a.useCallback((t=>{if(function(e,t){return!(0!==e.button||t&&"_self"!==t||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e))}(t,n)){t.preventDefault();let n=void 0!==o?o:r.createPath(l)===r.createPath(f);s(e,{replace:n,state:u,preventScrollReset:i,relative:c})}}),[l,s,f,o,u,n,e,i,c])}function x(){if("undefined"==typeof document)throw new Error("You are calling submit during the server render. Try calling submit within a `useEffect` or callback instead.")}function L(){let{router:e}=_(A.UseSubmit),{basename:t}=a.useContext(r.UNSAFE_NavigationContext),n=r.UNSAFE_useRouteId();return a.useCallback((function(r,o){void 0===o&&(o={}),x();let{action:a,method:u,encType:i,formData:c,body:s}=p(r,t);e.navigate(o.action||a,{preventScrollReset:o.preventScrollReset,formData:c,body:s,formMethod:o.method||u,formEncType:o.encType||i,replace:o.replace,state:o.state,fromRouteId:n})}),[e,t,n])}function D(e,t){let{router:o}=_(A.UseSubmitFetcher),{basename:u}=a.useContext(r.UNSAFE_NavigationContext);return a.useCallback((function(r,a){void 0===a&&(a={}),x();let{action:i,method:c,encType:s,formData:l,body:f}=p(r,u);null==t&&n.UNSAFE_invariant(!1),o.fetch(e,t,a.action||i,{preventScrollReset:a.preventScrollReset,formData:l,body:f,formMethod:a.method||c,formEncType:a.encType||s})}),[o,u,e,t])}function T(e,t){let{relative:o}=void 0===t?{}:t,{basename:i}=a.useContext(r.UNSAFE_NavigationContext),c=a.useContext(r.UNSAFE_RouteContext);c||n.UNSAFE_invariant(!1);let[s]=c.matches.slice(-1),l=u({},r.useResolvedPath(e||".",{relative:o})),f=r.useLocation();if(null==e&&(l.search=f.search,s.route.index)){let e=new URLSearchParams(l.search);e.delete("index"),l.search=e.toString()?"?"+e.toString():""}return e&&"."!==e||!s.route.index||(l.search=l.search?l.search.replace(/^\?/,"?index&"):"?index"),"/"!==i&&(l.pathname="/"===l.pathname?i:n.joinPaths([i,l.pathname])),r.createPath(l)}let k=0;const M="react-router-scroll-positions";let B={};function H(e){let{getKey:t,storageKey:o}=void 0===e?{}:e,{router:i}=_(A.UseScrollRestoration),{restoreScrollPosition:c,preventScrollReset:s}=F(C.UseScrollRestoration),{basename:l}=a.useContext(r.UNSAFE_NavigationContext),f=r.useLocation(),d=r.useMatches(),m=r.useNavigation();a.useEffect((()=>(window.history.scrollRestoration="manual",()=>{window.history.scrollRestoration="auto"})),[]),function(e,t){let{capture:r}=t||{};a.useEffect((()=>{let t=null!=r?{capture:r}:void 0;return window.addEventListener("pagehide",e,t),()=>{window.removeEventListener("pagehide",e,t)}}),[e,r])}(a.useCallback((()=>{if("idle"===m.state){let e=(t?t(f,d):null)||f.key;B[e]=window.scrollY}sessionStorage.setItem(o||M,JSON.stringify(B)),window.history.scrollRestoration="auto"}),[o,t,m.state,f,d])),"undefined"!=typeof document&&(a.useLayoutEffect((()=>{try{let e=sessionStorage.getItem(o||M);e&&(B=JSON.parse(e))}catch(e){}}),[o]),a.useLayoutEffect((()=>{let e=t&&"/"!==l?(e,r)=>t(u({},e,{pathname:n.stripBasename(e.pathname,l)||e.pathname}),r):t,r=null==i?void 0:i.enableScrollRestoration(B,(()=>window.scrollY),e);return()=>r&&r()}),[i,l,t]),a.useLayoutEffect((()=>{if(!1!==c)if("number"!=typeof c){if(f.hash){let e=document.getElementById(decodeURIComponent(f.hash.slice(1)));if(e)return void e.scrollIntoView()}!0!==s&&window.scrollTo(0,0)}else window.scrollTo(0,c)}),[f,c,s]))}Object.defineProperty(e,"AbortedDeferredError",{enumerable:!0,get:function(){return r.AbortedDeferredError}}),Object.defineProperty(e,"Await",{enumerable:!0,get:function(){return r.Await}}),Object.defineProperty(e,"MemoryRouter",{enumerable:!0,get:function(){return r.MemoryRouter}}),Object.defineProperty(e,"Navigate",{enumerable:!0,get:function(){return r.Navigate}}),Object.defineProperty(e,"NavigationType",{enumerable:!0,get:function(){return r.NavigationType}}),Object.defineProperty(e,"Outlet",{enumerable:!0,get:function(){return r.Outlet}}),Object.defineProperty(e,"Route",{enumerable:!0,get:function(){return r.Route}}),Object.defineProperty(e,"Router",{enumerable:!0,get:function(){return r.Router}}),Object.defineProperty(e,"RouterProvider",{enumerable:!0,get:function(){return r.RouterProvider}}),Object.defineProperty(e,"Routes",{enumerable:!0,get:function(){return r.Routes}}),Object.defineProperty(e,"UNSAFE_DataRouterContext",{enumerable:!0,get:function(){return r.UNSAFE_DataRouterContext}}),Object.defineProperty(e,"UNSAFE_DataRouterStateContext",{enumerable:!0,get:function(){return r.UNSAFE_DataRouterStateContext}}),Object.defineProperty(e,"UNSAFE_LocationContext",{enumerable:!0,get:function(){return r.UNSAFE_LocationContext}}),Object.defineProperty(e,"UNSAFE_NavigationContext",{enumerable:!0,get:function(){return r.UNSAFE_NavigationContext}}),Object.defineProperty(e,"UNSAFE_RouteContext",{enumerable:!0,get:function(){return r.UNSAFE_RouteContext}}),Object.defineProperty(e,"UNSAFE_useRouteId",{enumerable:!0,get:function(){return r.UNSAFE_useRouteId}}),Object.defineProperty(e,"createMemoryRouter",{enumerable:!0,get:function(){return r.createMemoryRouter}}),Object.defineProperty(e,"createPath",{enumerable:!0,get:function(){return r.createPath}}),Object.defineProperty(e,"createRoutesFromChildren",{enumerable:!0,get:function(){return r.createRoutesFromChildren}}),Object.defineProperty(e,"createRoutesFromElements",{enumerable:!0,get:function(){return r.createRoutesFromElements}}),Object.defineProperty(e,"defer",{enumerable:!0,get:function(){return r.defer}}),Object.defineProperty(e,"generatePath",{enumerable:!0,get:function(){return r.generatePath}}),Object.defineProperty(e,"isRouteErrorResponse",{enumerable:!0,get:function(){return r.isRouteErrorResponse}}),Object.defineProperty(e,"json",{enumerable:!0,get:function(){return r.json}}),Object.defineProperty(e,"matchPath",{enumerable:!0,get:function(){return r.matchPath}}),Object.defineProperty(e,"matchRoutes",{enumerable:!0,get:function(){return r.matchRoutes}}),Object.defineProperty(e,"parsePath",{enumerable:!0,get:function(){return r.parsePath}}),Object.defineProperty(e,"redirect",{enumerable:!0,get:function(){return r.redirect}}),Object.defineProperty(e,"redirectDocument",{enumerable:!0,get:function(){return r.redirectDocument}}),Object.defineProperty(e,"renderMatches",{enumerable:!0,get:function(){return r.renderMatches}}),Object.defineProperty(e,"resolvePath",{enumerable:!0,get:function(){return r.resolvePath}}),Object.defineProperty(e,"unstable_useBlocker",{enumerable:!0,get:function(){return r.unstable_useBlocker}}),Object.defineProperty(e,"useActionData",{enumerable:!0,get:function(){return r.useActionData}}),Object.defineProperty(e,"useAsyncError",{enumerable:!0,get:function(){return r.useAsyncError}}),Object.defineProperty(e,"useAsyncValue",{enumerable:!0,get:function(){return r.useAsyncValue}}),Object.defineProperty(e,"useHref",{enumerable:!0,get:function(){return r.useHref}}),Object.defineProperty(e,"useInRouterContext",{enumerable:!0,get:function(){return r.useInRouterContext}}),Object.defineProperty(e,"useLoaderData",{enumerable:!0,get:function(){return r.useLoaderData}}),Object.defineProperty(e,"useLocation",{enumerable:!0,get:function(){return r.useLocation}}),Object.defineProperty(e,"useMatch",{enumerable:!0,get:function(){return r.useMatch}}),Object.defineProperty(e,"useMatches",{enumerable:!0,get:function(){return r.useMatches}}),Object.defineProperty(e,"useNavigate",{enumerable:!0,get:function(){return r.useNavigate}}),Object.defineProperty(e,"useNavigation",{enumerable:!0,get:function(){return r.useNavigation}}),Object.defineProperty(e,"useNavigationType",{enumerable:!0,get:function(){return r.useNavigationType}}),Object.defineProperty(e,"useOutlet",{enumerable:!0,get:function(){return r.useOutlet}}),Object.defineProperty(e,"useOutletContext",{enumerable:!0,get:function(){return r.useOutletContext}}),Object.defineProperty(e,"useParams",{enumerable:!0,get:function(){return r.useParams}}),Object.defineProperty(e,"useResolvedPath",{enumerable:!0,get:function(){return r.useResolvedPath}}),Object.defineProperty(e,"useRevalidator",{enumerable:!0,get:function(){return r.useRevalidator}}),Object.defineProperty(e,"useRouteError",{enumerable:!0,get:function(){return r.useRouteError}}),Object.defineProperty(e,"useRouteLoaderData",{enumerable:!0,get:function(){return r.useRouteLoaderData}}),Object.defineProperty(e,"useRoutes",{enumerable:!0,get:function(){return r.useRoutes}}),e.BrowserRouter=function(e){let{basename:t,children:o,future:u,window:i}=e,c=a.useRef();null==c.current&&(c.current=n.createBrowserHistory({window:i,v5Compat:!0}));let s=c.current,[l,f]=a.useState({action:s.action,location:s.location}),{v7_startTransition:d}=u||{},m=a.useCallback((e=>{d&&w?w((()=>f(e))):f(e)}),[f,d]);return a.useLayoutEffect((()=>s.listen(m)),[s,m]),a.createElement(r.Router,{basename:t,children:o,location:l.location,navigationType:l.action,navigator:s})},e.Form=j,e.HashRouter=function(e){let{basename:t,children:o,future:u,window:i}=e,c=a.useRef();null==c.current&&(c.current=n.createHashHistory({window:i,v5Compat:!0}));let s=c.current,[l,f]=a.useState({action:s.action,location:s.location}),{v7_startTransition:d}=u||{},m=a.useCallback((e=>{d&&w?w((()=>f(e))):f(e)}),[f,d]);return a.useLayoutEffect((()=>s.listen(m)),[s,m]),a.createElement(r.Router,{basename:t,children:o,location:l.location,navigationType:l.action,navigator:s})},e.Link=E,e.NavLink=O,e.ScrollRestoration=function(e){let{getKey:t,storageKey:r}=e;return H({getKey:t,storageKey:r}),null},e.UNSAFE_useScrollRestoration=H,e.createBrowserRouter=function(e,t){return n.createRouter({basename:null==t?void 0:t.basename,future:u({},null==t?void 0:t.future,{v7_prependBasename:!0}),history:n.createBrowserHistory({window:null==t?void 0:t.window}),hydrationData:(null==t?void 0:t.hydrationData)||v(),routes:e,mapRouteProperties:r.UNSAFE_mapRouteProperties}).initialize()},e.createHashRouter=function(e,t){return n.createRouter({basename:null==t?void 0:t.basename,future:u({},null==t?void 0:t.future,{v7_prependBasename:!0}),history:n.createHashHistory({window:null==t?void 0:t.window}),hydrationData:(null==t?void 0:t.hydrationData)||v(),routes:e,mapRouteProperties:r.UNSAFE_mapRouteProperties}).initialize()},e.createSearchParams=f,e.unstable_HistoryRouter=function(e){let{basename:t,children:n,future:o,history:u}=e,[i,c]=a.useState({action:u.action,location:u.location}),{v7_startTransition:s}=o||{},l=a.useCallback((e=>{s&&w?w((()=>c(e))):c(e)}),[c,s]);return a.useLayoutEffect((()=>u.listen(l)),[u,l]),a.createElement(r.Router,{basename:t,children:n,location:i.location,navigationType:i.action,navigator:u})},e.unstable_usePrompt=function(e){let{when:t,message:n}=e,o=r.unstable_useBlocker(t);a.useEffect((()=>{if("blocked"===o.state){window.confirm(n)?setTimeout(o.proceed,0):o.reset()}}),[o,n]),a.useEffect((()=>{"blocked"!==o.state||t||o.reset()}),[o,t])},e.useBeforeUnload=function(e,t){let{capture:r}=t||{};a.useEffect((()=>{let t=null!=r?{capture:r}:void 0;return window.addEventListener("beforeunload",e,t),()=>{window.removeEventListener("beforeunload",e,t)}}),[e,r])},e.useFetcher=function(){var e;let{router:t}=_(A.UseFetcher),o=a.useContext(r.UNSAFE_RouteContext);o||n.UNSAFE_invariant(!1);let i=null==(e=o.matches[o.matches.length-1])?void 0:e.route.id;null==i&&n.UNSAFE_invariant(!1);let[c]=a.useState((()=>String(++k))),[s]=a.useState((()=>(i||n.UNSAFE_invariant(!1),function(e,t){return a.forwardRef(((r,n)=>{let o=D(e,t);return a.createElement(N,u({},r,{ref:n,submit:o}))}))}(c,i)))),[l]=a.useState((()=>e=>{t||n.UNSAFE_invariant(!1),i||n.UNSAFE_invariant(!1),t.fetch(c,i,e)})),f=D(c,i),d=t.getFetcher(c),m=a.useMemo((()=>u({Form:s,submit:f,load:l},d)),[d,s,f,l]);return a.useEffect((()=>()=>{t?t.deleteFetcher(c):console.warn("No router available to clean up from useFetcher()")}),[t,c]),m},e.useFetchers=function(){return[...F(C.UseFetchers).fetchers.values()]},e.useFormAction=T,e.useLinkClickHandler=U,e.useSearchParams=function(e){let t=a.useRef(f(e)),n=a.useRef(!1),o=r.useLocation(),u=a.useMemo((()=>function(e,t){let r=f(e);return t&&t.forEach(((e,n)=>{r.has(n)||t.getAll(n).forEach((e=>{r.append(n,e)}))})),r}(o.search,n.current?null:t.current)),[o.search]),i=r.useNavigate(),c=a.useCallback(((e,t)=>{const r=f("function"==typeof e?e(u):e);n.current=!0,i("?"+r,t)}),[i,u]);return[u,c]},e.useSubmit=L,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=react-router-dom.production.min.js.map |
MIT License | ||
Copyright (c) React Training 2015-2019 | ||
Copyright (c) Remix Software 2020-2022 | ||
Copyright (c) React Training LLC 2015-2019 | ||
Copyright (c) Remix Software Inc. 2020-2021 | ||
Copyright (c) Shopify Inc. 2022-2023 | ||
@@ -6,0 +7,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "react-router-dom", | ||
"version": "0.0.0-experimental-91f2bf54", | ||
"version": "0.0.0-experimental-ad6954b7", | ||
"description": "Declarative routing for React web applications", | ||
@@ -26,4 +26,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@remix-run/router": "0.0.0-experimental-91f2bf54", | ||
"react-router": "0.0.0-experimental-91f2bf54" | ||
"@remix-run/router": "0.0.0-experimental-ad6954b7", | ||
"react-router": "0.0.0-experimental-ad6954b7" | ||
}, | ||
@@ -48,4 +48,4 @@ "devDependencies": { | ||
"engines": { | ||
"node": ">=14" | ||
"node": ">=14.0.0" | ||
} | ||
} |
@@ -13,3 +13,3 @@ import * as React from "react"; | ||
*/ | ||
export declare function StaticRouter({ basename, children, location: locationProp, }: StaticRouterProps): JSX.Element; | ||
export declare function StaticRouter({ basename, children, location: locationProp, }: StaticRouterProps): React.JSX.Element; | ||
export { StaticHandlerContext }; | ||
@@ -26,5 +26,5 @@ export interface StaticRouterProviderProps { | ||
*/ | ||
export declare function StaticRouterProvider({ context, router, hydrate, nonce, }: StaticRouterProviderProps): JSX.Element; | ||
declare type CreateStaticHandlerOptions = Omit<RouterCreateStaticHandlerOptions, "detectErrorBoundary">; | ||
export declare function StaticRouterProvider({ context, router, hydrate, nonce, }: StaticRouterProviderProps): React.JSX.Element; | ||
type CreateStaticHandlerOptions = Omit<RouterCreateStaticHandlerOptions, "detectErrorBoundary" | "mapRouteProperties">; | ||
export declare function createStaticHandler(routes: RouteObject[], opts?: CreateStaticHandlerOptions): import("@remix-run/router").StaticHandler; | ||
export declare function createStaticRouter(routes: RouteObject[], context: StaticHandlerContext): RemixRouter; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var router = require('@remix-run/router'); | ||
var reactRouter = require('react-router'); | ||
var reactRouterDom = require('react-router-dom'); | ||
@@ -34,3 +35,2 @@ | ||
*/ | ||
function StaticRouter({ | ||
@@ -44,3 +44,2 @@ basename, | ||
} | ||
let action = router.Action.Pop; | ||
@@ -68,3 +67,2 @@ let location = { | ||
*/ | ||
function StaticRouterProvider({ | ||
@@ -85,3 +83,2 @@ context, | ||
let hydrateScript = ""; | ||
if (hydrate !== false) { | ||
@@ -92,21 +89,27 @@ let data = { | ||
errors: serializeErrors(context.errors) | ||
}; // Use JSON.parse here instead of embedding a raw JS object here to speed | ||
}; | ||
// Use JSON.parse here instead of embedding a raw JS object here to speed | ||
// up parsing on the client. Dual-stringify is needed to ensure all quotes | ||
// are properly escaped in the resulting string. See: | ||
// https://v8.dev/blog/cost-of-javascript-2019#json | ||
let json = htmlEscape(JSON.stringify(JSON.stringify(data))); | ||
hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`; | ||
} | ||
let { | ||
state | ||
} = dataRouterContext.router; | ||
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterContext.Provider, { | ||
value: dataRouterContext | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterStateContext.Provider, { | ||
value: dataRouterContext.router.state | ||
value: state | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, { | ||
basename: dataRouterContext.basename, | ||
location: dataRouterContext.router.state.location, | ||
navigationType: dataRouterContext.router.state.historyAction, | ||
navigator: dataRouterContext.navigator | ||
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Routes, null)))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", { | ||
location: state.location, | ||
navigationType: state.historyAction, | ||
navigator: dataRouterContext.navigator, | ||
static: dataRouterContext.static | ||
}, /*#__PURE__*/React__namespace.createElement(DataRoutes, { | ||
routes: router$1.routes, | ||
state: state | ||
})))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", { | ||
suppressHydrationWarning: true, | ||
@@ -119,3 +122,8 @@ nonce: nonce, | ||
} | ||
function DataRoutes({ | ||
routes, | ||
state | ||
}) { | ||
return reactRouter.UNSAFE_useRoutesImpl(routes, undefined, state); | ||
} | ||
function serializeErrors(errors) { | ||
@@ -125,3 +133,2 @@ if (!errors) return null; | ||
let serialized = {}; | ||
for (let [key, val] of entries) { | ||
@@ -131,3 +138,4 @@ // Hey you! If you change this, please change the corresponding logic in | ||
if (router.isRouteErrorResponse(val)) { | ||
serialized[key] = { ...val, | ||
serialized[key] = { | ||
...val, | ||
__type: "RouteErrorResponse" | ||
@@ -139,3 +147,8 @@ }; | ||
message: val.message, | ||
__type: "Error" | ||
__type: "Error", | ||
// If this is a subclass (i.e., ReferenceError), send up the type so we | ||
// can re-create the same type during hydration. | ||
...(val.name !== "Error" ? { | ||
__subType: val.name | ||
} : {}) | ||
}; | ||
@@ -146,6 +159,4 @@ } else { | ||
} | ||
return serialized; | ||
} | ||
function getStatelessNavigator() { | ||
@@ -155,31 +166,23 @@ return { | ||
encodeLocation, | ||
push(to) { | ||
throw new Error(`You cannot use navigator.push() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)})\` somewhere in your app.`); | ||
}, | ||
replace(to) { | ||
throw new Error(`You cannot use navigator.replace() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere ` + `in your app.`); | ||
}, | ||
go(delta) { | ||
throw new Error(`You cannot use navigator.go() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${delta})\` somewhere in your app.`); | ||
}, | ||
back() { | ||
throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`); | ||
}, | ||
forward() { | ||
throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`); | ||
} | ||
}; | ||
} | ||
let detectErrorBoundary = route => Boolean(route.errorElement); | ||
function createStaticHandler(routes, opts) { | ||
return router.createStaticHandler(routes, { ...opts, | ||
detectErrorBoundary | ||
return router.createStaticHandler(routes, { | ||
...opts, | ||
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties | ||
}); | ||
@@ -189,15 +192,14 @@ } | ||
let manifest = {}; | ||
let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, detectErrorBoundary, undefined, manifest); // Because our context matches may be from a framework-agnostic set of | ||
let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, reactRouter.UNSAFE_mapRouteProperties, undefined, manifest); | ||
// Because our context matches may be from a framework-agnostic set of | ||
// routes passed to createStaticHandler(), we update them here with our | ||
// newly created/enhanced data routes | ||
let matches = context.matches.map(match => { | ||
let route = manifest[match.route.id] || match.route; | ||
return { ...match, | ||
return { | ||
...match, | ||
route | ||
}; | ||
}); | ||
let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`; | ||
return { | ||
@@ -207,3 +209,2 @@ get basename() { | ||
}, | ||
get state() { | ||
@@ -226,68 +227,50 @@ return { | ||
}, | ||
get routes() { | ||
return dataRoutes; | ||
}, | ||
initialize() { | ||
throw msg("initialize"); | ||
}, | ||
subscribe() { | ||
throw msg("subscribe"); | ||
}, | ||
enableScrollRestoration() { | ||
throw msg("enableScrollRestoration"); | ||
}, | ||
navigate() { | ||
throw msg("navigate"); | ||
}, | ||
fetch() { | ||
throw msg("fetch"); | ||
}, | ||
revalidate() { | ||
throw msg("revalidate"); | ||
}, | ||
createHref, | ||
encodeLocation, | ||
getFetcher() { | ||
return router.IDLE_FETCHER; | ||
}, | ||
deleteFetcher() { | ||
throw msg("deleteFetcher"); | ||
}, | ||
dispose() { | ||
throw msg("dispose"); | ||
}, | ||
getBlocker() { | ||
return router.IDLE_BLOCKER; | ||
}, | ||
deleteBlocker() { | ||
throw msg("deleteBlocker"); | ||
}, | ||
_internalFetchControllers: new Map(), | ||
_internalActiveDeferreds: new Map(), | ||
_internalSetRoutes() { | ||
throw msg("_internalSetRoutes"); | ||
} | ||
}; | ||
} | ||
function createHref(to) { | ||
return typeof to === "string" ? to : reactRouterDom.createPath(to); | ||
} | ||
function encodeLocation(to) { | ||
@@ -301,6 +284,5 @@ // Locations should already be encoded on the server, so just return as-is | ||
}; | ||
} // This utility is based on https://github.com/zertosh/htmlescape | ||
} | ||
// This utility is based on https://github.com/zertosh/htmlescape | ||
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE | ||
const ESCAPE_LOOKUP = { | ||
@@ -314,3 +296,2 @@ "&": "\\u0026", | ||
const ESCAPE_REGEX = /[&><\u2028\u2029]/g; | ||
function htmlEscape(str) { | ||
@@ -317,0 +298,0 @@ return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
664359
17.87%5121
15.52%24
9.09%+ Added
+ Added
- Removed
- Removed