react-router-dom 6.13.0 → 6.14.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/dist/dom.d.ts +16 -8
- package/dist/index.d.ts +15 -7
- package/dist/index.js +163 -90
- package/dist/index.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/react-router-dom.development.js +170 -92
- package/dist/react-router-dom.development.js.map +1 -1
- package/dist/react-router-dom.production.min.js +2 -2
- package/dist/react-router-dom.production.min.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/umd/react-router-dom.development.js +171 -91
- package/dist/umd/react-router-dom.development.js.map +1 -1
- package/dist/umd/react-router-dom.production.min.js +2 -2
- package/dist/umd/react-router-dom.production.min.js.map +1 -1
- package/package.json +3 -3
- package/server.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# `react-router-dom`
|
|
2
2
|
|
|
3
|
+
## 6.14.0-pre.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 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))
|
|
8
|
+
|
|
9
|
+
```jsx
|
|
10
|
+
// The default behavior will still serialize as FormData
|
|
11
|
+
function Component() {
|
|
12
|
+
let navigation = useNavigation();
|
|
13
|
+
let submit = useSubmit();
|
|
14
|
+
submit({ key: "value" });
|
|
15
|
+
// navigation.formEncType => "application/x-www-form-urlencoded"
|
|
16
|
+
// navigation.formData => FormData instance
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function action({ request }) {
|
|
20
|
+
// request.headers.get("Content-Type") => "application/x-www-form-urlencoded"
|
|
21
|
+
// await request.formData() => FormData instance
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// Opt-into JSON encoding with `encType: "application/json"`
|
|
27
|
+
function Component() {
|
|
28
|
+
let submit = useSubmit();
|
|
29
|
+
submit({ key: "value" }, { encType: "application/json" });
|
|
30
|
+
// navigation.formEncType => "application/json"
|
|
31
|
+
// navigation.json => { key: "value" }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function action({ request }) {
|
|
35
|
+
// request.headers.get("Content-Type") => "application/json"
|
|
36
|
+
// await request.json => { key: "value" }
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
// Opt-into JSON encoding with `encType: "application/json"`
|
|
42
|
+
function Component() {
|
|
43
|
+
let submit = useSubmit();
|
|
44
|
+
submit("Text submission", { encType: "text/plain" });
|
|
45
|
+
// navigation.formEncType => "text/plain"
|
|
46
|
+
// navigation.text => "Text submission"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function action({ request }) {
|
|
50
|
+
// request.headers.get("Content-Type") => "text/plain"
|
|
51
|
+
// await request.text() => "Text submission"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- 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). 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`. ([#9865](https://github.com/remix-run/react-router/pull/9865))
|
|
58
|
+
- upgrade `typescript` to 5.1 ([#10581](https://github.com/remix-run/react-router/pull/10581))
|
|
59
|
+
- Call `window.history.pushState/replaceState` before updating React Router state (instead of after) so that `window.location` matches `useLocation` during synchronous React 17 rendering. 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.) ([#10211](https://github.com/remix-run/react-router/pull/10211))
|
|
60
|
+
- Fix `tsc --skipLibCheck:false` issues on React 17 ([#10622](https://github.com/remix-run/react-router/pull/10622))
|
|
61
|
+
- Updated dependencies:
|
|
62
|
+
- `react-router@6.14.0-pre.0`
|
|
63
|
+
- `@remix-run/router@1.7.0-pre.0`
|
|
64
|
+
|
|
3
65
|
## 6.13.0
|
|
4
66
|
|
|
5
67
|
### Minor Changes
|
package/dist/dom.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ export declare function isHtmlElement(object: any): object is HTMLElement;
|
|
|
4
4
|
export declare function isButtonElement(object: any): object is HTMLButtonElement;
|
|
5
5
|
export declare function isFormElement(object: any): object is HTMLFormElement;
|
|
6
6
|
export declare function isInputElement(object: any): object is HTMLInputElement;
|
|
7
|
-
|
|
7
|
+
type LimitedMouseEvent = Pick<MouseEvent, "button" | "metaKey" | "altKey" | "ctrlKey" | "shiftKey">;
|
|
8
8
|
export declare function shouldProcessLinkClick(event: LimitedMouseEvent, target?: string): boolean;
|
|
9
|
-
export
|
|
10
|
-
export
|
|
9
|
+
export type ParamKeyValuePair = [string, string];
|
|
10
|
+
export type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<string, string | string[]> | URLSearchParams;
|
|
11
11
|
/**
|
|
12
12
|
* Creates a URLSearchParams object using the given initializer.
|
|
13
13
|
*
|
|
@@ -31,6 +31,15 @@ export declare type URLSearchParamsInit = string | ParamKeyValuePair[] | Record<
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function createSearchParams(init?: URLSearchParamsInit): URLSearchParams;
|
|
33
33
|
export declare function getSearchParamsForLocation(locationSearch: string, defaultSearchParams: URLSearchParams | null): URLSearchParams;
|
|
34
|
+
type JsonObject = {
|
|
35
|
+
[Key in string]: JsonValue;
|
|
36
|
+
} & {
|
|
37
|
+
[Key in string]?: JsonValue | undefined;
|
|
38
|
+
};
|
|
39
|
+
type JsonArray = JsonValue[] | readonly JsonValue[];
|
|
40
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
41
|
+
type JsonValue = JsonPrimitive | JsonObject | JsonArray;
|
|
42
|
+
export type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | JsonValue | null;
|
|
34
43
|
export interface SubmitOptions {
|
|
35
44
|
/**
|
|
36
45
|
* The HTTP method used to submit the form. Overrides `<form method>`.
|
|
@@ -43,7 +52,7 @@ export interface SubmitOptions {
|
|
|
43
52
|
*/
|
|
44
53
|
action?: string;
|
|
45
54
|
/**
|
|
46
|
-
* The
|
|
55
|
+
* The encoding used to submit the form. Overrides `<form encType>`.
|
|
47
56
|
* Defaults to "application/x-www-form-urlencoded".
|
|
48
57
|
*/
|
|
49
58
|
encType?: FormEncType;
|
|
@@ -65,12 +74,11 @@ export interface SubmitOptions {
|
|
|
65
74
|
*/
|
|
66
75
|
preventScrollReset?: boolean;
|
|
67
76
|
}
|
|
68
|
-
export declare function getFormSubmissionInfo(target:
|
|
69
|
-
[name: string]: string;
|
|
70
|
-
} | null, options: SubmitOptions, basename: string): {
|
|
77
|
+
export declare function getFormSubmissionInfo(target: SubmitTarget, basename: string): {
|
|
71
78
|
action: string | null;
|
|
72
79
|
method: string;
|
|
73
80
|
encType: string;
|
|
74
|
-
formData: FormData;
|
|
81
|
+
formData: FormData | undefined;
|
|
82
|
+
body: any;
|
|
75
83
|
};
|
|
76
84
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import type { FutureConfig, NavigateOptions, RelativeRoutingType, RouteObject, To } from "react-router";
|
|
7
7
|
import type { Fetcher, FormEncType, FormMethod, FutureConfig as RouterFutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, Router as RemixRouter, V7_FormMethod } from "@remix-run/router";
|
|
8
|
-
import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit } from "./dom";
|
|
8
|
+
import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit, SubmitTarget } from "./dom";
|
|
9
9
|
import { createSearchParams } from "./dom";
|
|
10
10
|
export type { FormEncType, FormMethod, GetScrollRestorationKeyFunction, ParamKeyValuePair, SubmitOptions, URLSearchParamsInit, V7_FormMethod, };
|
|
11
11
|
export { createSearchParams };
|
|
@@ -100,6 +100,11 @@ export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement> {
|
|
|
100
100
|
* "put", "delete", "patch".
|
|
101
101
|
*/
|
|
102
102
|
method?: HTMLFormMethod;
|
|
103
|
+
/**
|
|
104
|
+
* `<form encType>` - enhancing beyond the normal string type and limiting
|
|
105
|
+
* to the built-in browser supported values
|
|
106
|
+
*/
|
|
107
|
+
encType?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain";
|
|
103
108
|
/**
|
|
104
109
|
* Normal `<form action>` but supports React Router's relative paths.
|
|
105
110
|
*/
|
|
@@ -167,10 +172,7 @@ export declare function useLinkClickHandler<E extends Element = HTMLAnchorElemen
|
|
|
167
172
|
* URLSearchParams interface.
|
|
168
173
|
*/
|
|
169
174
|
export declare function useSearchParams(defaultInit?: URLSearchParamsInit): [URLSearchParams, SetURLSearchParams];
|
|
170
|
-
export
|
|
171
|
-
declare type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | {
|
|
172
|
-
[name: string]: string;
|
|
173
|
-
} | null;
|
|
175
|
+
export type SetURLSearchParams = (nextInit?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), navigateOpts?: NavigateOptions) => void;
|
|
174
176
|
/**
|
|
175
177
|
* Submits a HTML `<form>` to the server without reloading the page.
|
|
176
178
|
*/
|
|
@@ -191,6 +193,12 @@ export interface SubmitFunction {
|
|
|
191
193
|
*/
|
|
192
194
|
options?: SubmitOptions): void;
|
|
193
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Submits a fetcher `<form>` to the server without reloading the page.
|
|
198
|
+
*/
|
|
199
|
+
export interface FetcherSubmitFunction {
|
|
200
|
+
(target: SubmitTarget, options?: Omit<SubmitOptions, "replace">): void;
|
|
201
|
+
}
|
|
194
202
|
/**
|
|
195
203
|
* Returns a function that may be used to programmatically submit a form (or
|
|
196
204
|
* some arbitrary data) to the server.
|
|
@@ -200,9 +208,9 @@ export declare function useFormAction(action?: string, { relative }?: {
|
|
|
200
208
|
relative?: RelativeRoutingType;
|
|
201
209
|
}): string;
|
|
202
210
|
declare function createFetcherForm(fetcherKey: string, routeId: string): React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
|
|
203
|
-
export
|
|
211
|
+
export type FetcherWithComponents<TData> = Fetcher<TData> & {
|
|
204
212
|
Form: ReturnType<typeof createFetcherForm>;
|
|
205
|
-
submit:
|
|
213
|
+
submit: FetcherSubmitFunction;
|
|
206
214
|
load: (href: string) => void;
|
|
207
215
|
};
|
|
208
216
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React Router DOM v6.
|
|
2
|
+
* React Router DOM v6.14.0-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
import * as React from 'react';
|
|
12
|
-
import { UNSAFE_mapRouteProperties,
|
|
12
|
+
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';
|
|
13
13
|
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, 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';
|
|
14
|
-
import { stripBasename, createRouter, createBrowserHistory, createHashHistory, ErrorResponse,
|
|
14
|
+
import { stripBasename, UNSAFE_warning, createRouter, createBrowserHistory, createHashHistory, ErrorResponse, UNSAFE_invariant, joinPaths } from '@remix-run/router';
|
|
15
15
|
|
|
16
16
|
function _extends() {
|
|
17
17
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
@@ -108,83 +108,95 @@ function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
|
|
|
108
108
|
}
|
|
109
109
|
return searchParams;
|
|
110
110
|
}
|
|
111
|
-
|
|
111
|
+
// One-time check for submitter support
|
|
112
|
+
let formDataSupportsSubmitter = false;
|
|
113
|
+
try {
|
|
114
|
+
// @ts-expect-error if FormData supports the submitter parameter, this will throw
|
|
115
|
+
new FormData(undefined, 0);
|
|
116
|
+
} catch (e) {
|
|
117
|
+
formDataSupportsSubmitter = true;
|
|
118
|
+
}
|
|
119
|
+
const supportedFormEncTypes = new Set(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]);
|
|
120
|
+
function getFormEncType(encType) {
|
|
121
|
+
if (encType != null && !supportedFormEncTypes.has(encType)) {
|
|
122
|
+
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;
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return encType;
|
|
126
|
+
}
|
|
127
|
+
function getFormSubmissionInfo(target, basename) {
|
|
112
128
|
let method;
|
|
113
|
-
let action
|
|
129
|
+
let action;
|
|
114
130
|
let encType;
|
|
115
131
|
let formData;
|
|
132
|
+
let body;
|
|
116
133
|
if (isFormElement(target)) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
let attr = target.getAttribute("action");
|
|
125
|
-
action = attr ? stripBasename(attr, basename) : null;
|
|
126
|
-
}
|
|
127
|
-
method = options.method || target.getAttribute("method") || defaultMethod;
|
|
128
|
-
encType = options.encType || target.getAttribute("enctype") || defaultEncType;
|
|
134
|
+
// When grabbing the action from the element, it will have had the basename
|
|
135
|
+
// prefixed to ensure non-JS scenarios work, so strip it since we'll
|
|
136
|
+
// re-prefix in the router
|
|
137
|
+
let attr = target.getAttribute("action");
|
|
138
|
+
action = attr ? stripBasename(attr, basename) : null;
|
|
139
|
+
method = target.getAttribute("method") || defaultMethod;
|
|
140
|
+
encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType;
|
|
129
141
|
formData = new FormData(target);
|
|
130
|
-
if (submissionTrigger && submissionTrigger.name) {
|
|
131
|
-
formData.append(submissionTrigger.name, submissionTrigger.value);
|
|
132
|
-
}
|
|
133
142
|
} else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
|
|
134
143
|
let form = target.form;
|
|
135
144
|
if (form == null) {
|
|
136
145
|
throw new Error("Cannot submit a <button> or <input type=\"submit\"> without a <form>");
|
|
137
146
|
}
|
|
138
147
|
// <button>/<input type="submit"> may override attributes of <form>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
// When grabbing the action from the element, it will have had the basename
|
|
149
|
+
// prefixed to ensure non-JS scenarios work, so strip it since we'll
|
|
150
|
+
// re-prefix in the router
|
|
151
|
+
let attr = target.getAttribute("formaction") || form.getAttribute("action");
|
|
152
|
+
action = attr ? stripBasename(attr, basename) : null;
|
|
153
|
+
method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
|
|
154
|
+
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
|
|
155
|
+
// Build a FormData object populated from a form and submitter
|
|
156
|
+
formData = new FormData(form, target);
|
|
157
|
+
// If this browser doesn't support the `FormData(el, submitter)` format,
|
|
158
|
+
// then tack on the submitter value at the end. This is a lightweight
|
|
159
|
+
// solution that is not 100% spec compliant. For complete support in older
|
|
160
|
+
// browsers, consider using the `formdata-submitter-polyfill` package
|
|
161
|
+
if (!formDataSupportsSubmitter) {
|
|
162
|
+
let {
|
|
163
|
+
name,
|
|
164
|
+
type,
|
|
165
|
+
value
|
|
166
|
+
} = target;
|
|
167
|
+
if (type === "image") {
|
|
168
|
+
let prefix = name ? name + "." : "";
|
|
169
|
+
formData.append(prefix + "x", "0");
|
|
170
|
+
formData.append(prefix + "y", "0");
|
|
171
|
+
} else if (name) {
|
|
172
|
+
formData.append(name, value);
|
|
173
|
+
}
|
|
155
174
|
}
|
|
156
175
|
} else if (isHtmlElement(target)) {
|
|
157
176
|
throw new Error("Cannot submit element that is not <form>, <button>, or " + "<input type=\"submit|image\">");
|
|
158
177
|
} else {
|
|
159
|
-
method =
|
|
160
|
-
action =
|
|
161
|
-
encType =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
formData.append(name, value);
|
|
169
|
-
}
|
|
170
|
-
} else if (target != null) {
|
|
171
|
-
for (let name of Object.keys(target)) {
|
|
172
|
-
formData.append(name, target[name]);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
178
|
+
method = defaultMethod;
|
|
179
|
+
action = null;
|
|
180
|
+
encType = defaultEncType;
|
|
181
|
+
body = target;
|
|
182
|
+
}
|
|
183
|
+
// Send body for <Form encType="text/plain" so we encode it into text
|
|
184
|
+
if (formData && encType === "text/plain") {
|
|
185
|
+
body = formData;
|
|
186
|
+
formData = undefined;
|
|
176
187
|
}
|
|
177
188
|
return {
|
|
178
189
|
action,
|
|
179
190
|
method: method.toLowerCase(),
|
|
180
191
|
encType,
|
|
181
|
-
formData
|
|
192
|
+
formData,
|
|
193
|
+
body
|
|
182
194
|
};
|
|
183
195
|
}
|
|
184
196
|
|
|
185
197
|
const _excluded = ["onClick", "relative", "reloadDocument", "replace", "state", "target", "to", "preventScrollReset"],
|
|
186
198
|
_excluded2 = ["aria-current", "caseSensitive", "className", "end", "style", "to", "children"],
|
|
187
|
-
_excluded3 = ["reloadDocument", "replace", "method", "action", "onSubmit", "
|
|
199
|
+
_excluded3 = ["reloadDocument", "replace", "method", "action", "onSubmit", "submit", "relative", "preventScrollReset"];
|
|
188
200
|
function createBrowserRouter(routes, opts) {
|
|
189
201
|
return createRouter({
|
|
190
202
|
basename: opts == null ? void 0 : opts.basename,
|
|
@@ -244,6 +256,33 @@ function deserializeErrors(errors) {
|
|
|
244
256
|
}
|
|
245
257
|
return serialized;
|
|
246
258
|
}
|
|
259
|
+
//#endregion
|
|
260
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
261
|
+
//#region Components
|
|
262
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
263
|
+
/**
|
|
264
|
+
Webpack + React 17 fails to compile on any of the following because webpack
|
|
265
|
+
complains that `startTransition` doesn't exist in `React`:
|
|
266
|
+
* import { startTransition } from "react"
|
|
267
|
+
* import * as React from from "react";
|
|
268
|
+
"startTransition" in React ? React.startTransition(() => setState()) : setState()
|
|
269
|
+
* import * as React from from "react";
|
|
270
|
+
"startTransition" in React ? React["startTransition"](() => setState()) : setState()
|
|
271
|
+
|
|
272
|
+
Moving it to a constant such as the following solves the Webpack/React 17 issue:
|
|
273
|
+
* import * as React from from "react";
|
|
274
|
+
const START_TRANSITION = "startTransition";
|
|
275
|
+
START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()
|
|
276
|
+
|
|
277
|
+
However, that introduces webpack/terser minification issues in production builds
|
|
278
|
+
in React 18 where minification/obfuscation ends up removing the call of
|
|
279
|
+
React.startTransition entirely from the first half of the ternary. Grabbing
|
|
280
|
+
this exported reference once up front resolves that issue.
|
|
281
|
+
|
|
282
|
+
See https://github.com/remix-run/react-router/issues/10579
|
|
283
|
+
*/
|
|
284
|
+
const START_TRANSITION = "startTransition";
|
|
285
|
+
const startTransitionImpl = React[START_TRANSITION];
|
|
247
286
|
/**
|
|
248
287
|
* A `<Router>` for use in web browsers. Provides the cleanest URLs.
|
|
249
288
|
*/
|
|
@@ -270,7 +309,7 @@ function BrowserRouter(_ref) {
|
|
|
270
309
|
v7_startTransition
|
|
271
310
|
} = future || {};
|
|
272
311
|
let setState = React.useCallback(newState => {
|
|
273
|
-
v7_startTransition &&
|
|
312
|
+
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
|
274
313
|
}, [setStateImpl, v7_startTransition]);
|
|
275
314
|
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
276
315
|
return /*#__PURE__*/React.createElement(Router, {
|
|
@@ -308,7 +347,7 @@ function HashRouter(_ref2) {
|
|
|
308
347
|
v7_startTransition
|
|
309
348
|
} = future || {};
|
|
310
349
|
let setState = React.useCallback(newState => {
|
|
311
|
-
v7_startTransition &&
|
|
350
|
+
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
|
312
351
|
}, [setStateImpl, v7_startTransition]);
|
|
313
352
|
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
314
353
|
return /*#__PURE__*/React.createElement(Router, {
|
|
@@ -340,7 +379,7 @@ function HistoryRouter(_ref3) {
|
|
|
340
379
|
v7_startTransition
|
|
341
380
|
} = future || {};
|
|
342
381
|
let setState = React.useCallback(newState => {
|
|
343
|
-
v7_startTransition &&
|
|
382
|
+
v7_startTransition && startTransitionImpl ? startTransitionImpl(() => setStateImpl(newState)) : setStateImpl(newState);
|
|
344
383
|
}, [setStateImpl, v7_startTransition]);
|
|
345
384
|
React.useLayoutEffect(() => history.listen(setState), [history, setState]);
|
|
346
385
|
return /*#__PURE__*/React.createElement(Router, {
|
|
@@ -501,7 +540,9 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
501
540
|
* submitted and returns with data.
|
|
502
541
|
*/
|
|
503
542
|
const Form = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
543
|
+
let submit = useSubmit();
|
|
504
544
|
return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
|
|
545
|
+
submit: submit,
|
|
505
546
|
ref: ref
|
|
506
547
|
}));
|
|
507
548
|
});
|
|
@@ -515,13 +556,11 @@ const FormImpl = /*#__PURE__*/React.forwardRef((_ref6, forwardedRef) => {
|
|
|
515
556
|
method = defaultMethod,
|
|
516
557
|
action,
|
|
517
558
|
onSubmit,
|
|
518
|
-
|
|
519
|
-
routeId,
|
|
559
|
+
submit,
|
|
520
560
|
relative,
|
|
521
561
|
preventScrollReset
|
|
522
562
|
} = _ref6,
|
|
523
563
|
props = _objectWithoutPropertiesLoose(_ref6, _excluded3);
|
|
524
|
-
let submit = useSubmitImpl(fetcherKey, routeId);
|
|
525
564
|
let formMethod = method.toLowerCase() === "get" ? "get" : "post";
|
|
526
565
|
let formAction = useFormAction(action, {
|
|
527
566
|
relative
|
|
@@ -574,7 +613,8 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
574
613
|
var DataRouterHook;
|
|
575
614
|
(function (DataRouterHook) {
|
|
576
615
|
DataRouterHook["UseScrollRestoration"] = "useScrollRestoration";
|
|
577
|
-
DataRouterHook["
|
|
616
|
+
DataRouterHook["UseSubmit"] = "useSubmit";
|
|
617
|
+
DataRouterHook["UseSubmitFetcher"] = "useSubmitFetcher";
|
|
578
618
|
DataRouterHook["UseFetcher"] = "useFetcher";
|
|
579
619
|
})(DataRouterHook || (DataRouterHook = {}));
|
|
580
620
|
var DataRouterStateHook;
|
|
@@ -650,17 +690,19 @@ function useSearchParams(defaultInit) {
|
|
|
650
690
|
}, [navigate, searchParams]);
|
|
651
691
|
return [searchParams, setSearchParams];
|
|
652
692
|
}
|
|
693
|
+
function validateClientSideSubmission() {
|
|
694
|
+
if (typeof document === "undefined") {
|
|
695
|
+
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead.");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
653
698
|
/**
|
|
654
699
|
* Returns a function that may be used to programmatically submit a form (or
|
|
655
700
|
* some arbitrary data) to the server.
|
|
656
701
|
*/
|
|
657
702
|
function useSubmit() {
|
|
658
|
-
return useSubmitImpl();
|
|
659
|
-
}
|
|
660
|
-
function useSubmitImpl(fetcherKey, fetcherRouteId) {
|
|
661
703
|
let {
|
|
662
704
|
router
|
|
663
|
-
} = useDataRouterContext(DataRouterHook.
|
|
705
|
+
} = useDataRouterContext(DataRouterHook.UseSubmit);
|
|
664
706
|
let {
|
|
665
707
|
basename
|
|
666
708
|
} = React.useContext(UNSAFE_NavigationContext);
|
|
@@ -669,32 +711,56 @@ function useSubmitImpl(fetcherKey, fetcherRouteId) {
|
|
|
669
711
|
if (options === void 0) {
|
|
670
712
|
options = {};
|
|
671
713
|
}
|
|
672
|
-
|
|
673
|
-
throw new Error("You are calling submit during the server render. " + "Try calling submit within a `useEffect` or callback instead.");
|
|
674
|
-
}
|
|
714
|
+
validateClientSideSubmission();
|
|
675
715
|
let {
|
|
676
716
|
action,
|
|
677
717
|
method,
|
|
678
718
|
encType,
|
|
679
|
-
formData
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
719
|
+
formData,
|
|
720
|
+
body
|
|
721
|
+
} = getFormSubmissionInfo(target, basename);
|
|
722
|
+
router.navigate(options.action || action, {
|
|
683
723
|
preventScrollReset: options.preventScrollReset,
|
|
684
724
|
formData,
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
725
|
+
body,
|
|
726
|
+
formMethod: options.method || method,
|
|
727
|
+
formEncType: options.encType || encType,
|
|
728
|
+
replace: options.replace,
|
|
729
|
+
fromRouteId: currentRouteId
|
|
730
|
+
});
|
|
731
|
+
}, [router, basename, currentRouteId]);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Returns the implementation for fetcher.submit
|
|
735
|
+
*/
|
|
736
|
+
function useSubmitFetcher(fetcherKey, fetcherRouteId) {
|
|
737
|
+
let {
|
|
738
|
+
router
|
|
739
|
+
} = useDataRouterContext(DataRouterHook.UseSubmitFetcher);
|
|
740
|
+
let {
|
|
741
|
+
basename
|
|
742
|
+
} = React.useContext(UNSAFE_NavigationContext);
|
|
743
|
+
return React.useCallback(function (target, options) {
|
|
744
|
+
if (options === void 0) {
|
|
745
|
+
options = {};
|
|
696
746
|
}
|
|
697
|
-
|
|
747
|
+
validateClientSideSubmission();
|
|
748
|
+
let {
|
|
749
|
+
action,
|
|
750
|
+
method,
|
|
751
|
+
encType,
|
|
752
|
+
formData,
|
|
753
|
+
body
|
|
754
|
+
} = getFormSubmissionInfo(target, basename);
|
|
755
|
+
!(fetcherRouteId != null) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for useFetcher()") : UNSAFE_invariant(false) : void 0;
|
|
756
|
+
router.fetch(fetcherKey, fetcherRouteId, options.action || action, {
|
|
757
|
+
preventScrollReset: options.preventScrollReset,
|
|
758
|
+
formData,
|
|
759
|
+
body,
|
|
760
|
+
formMethod: options.method || method,
|
|
761
|
+
formEncType: options.encType || encType
|
|
762
|
+
});
|
|
763
|
+
}, [router, basename, fetcherKey, fetcherRouteId]);
|
|
698
764
|
}
|
|
699
765
|
// v7: Eventually we should deprecate this entirely in favor of using the
|
|
700
766
|
// router method directly?
|
|
@@ -748,10 +814,10 @@ function useFormAction(action, _temp2) {
|
|
|
748
814
|
}
|
|
749
815
|
function createFetcherForm(fetcherKey, routeId) {
|
|
750
816
|
let FetcherForm = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
817
|
+
let submit = useSubmitFetcher(fetcherKey, routeId);
|
|
751
818
|
return /*#__PURE__*/React.createElement(FormImpl, _extends({}, props, {
|
|
752
819
|
ref: ref,
|
|
753
|
-
|
|
754
|
-
routeId: routeId
|
|
820
|
+
submit: submit
|
|
755
821
|
}));
|
|
756
822
|
});
|
|
757
823
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -783,7 +849,7 @@ function useFetcher() {
|
|
|
783
849
|
!routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
|
|
784
850
|
router.fetch(fetcherKey, routeId, href);
|
|
785
851
|
});
|
|
786
|
-
let submit =
|
|
852
|
+
let submit = useSubmitFetcher(fetcherKey, routeId);
|
|
787
853
|
let fetcher = router.getFetcher(fetcherKey);
|
|
788
854
|
let fetcherWithComponents = React.useMemo(() => _extends({
|
|
789
855
|
Form,
|
|
@@ -829,6 +895,9 @@ function useScrollRestoration(_temp3) {
|
|
|
829
895
|
restoreScrollPosition,
|
|
830
896
|
preventScrollReset
|
|
831
897
|
} = useDataRouterState(DataRouterStateHook.UseScrollRestoration);
|
|
898
|
+
let {
|
|
899
|
+
basename
|
|
900
|
+
} = React.useContext(UNSAFE_NavigationContext);
|
|
832
901
|
let location = useLocation();
|
|
833
902
|
let matches = useMatches();
|
|
834
903
|
let navigation = useNavigation();
|
|
@@ -864,9 +933,13 @@ function useScrollRestoration(_temp3) {
|
|
|
864
933
|
// Enable scroll restoration in the router
|
|
865
934
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
866
935
|
React.useLayoutEffect(() => {
|
|
867
|
-
let
|
|
936
|
+
let getKeyWithoutBasename = getKey && basename !== "/" ? (location, matches) => getKey( // Strip the basename to match useLocation()
|
|
937
|
+
_extends({}, location, {
|
|
938
|
+
pathname: stripBasename(location.pathname, basename) || location.pathname
|
|
939
|
+
}), matches) : getKey;
|
|
940
|
+
let disableScrollRestoration = router == null ? void 0 : router.enableScrollRestoration(savedScrollPositions, () => window.scrollY, getKeyWithoutBasename);
|
|
868
941
|
return () => disableScrollRestoration && disableScrollRestoration();
|
|
869
|
-
}, [router, getKey]);
|
|
942
|
+
}, [router, basename, getKey]);
|
|
870
943
|
// Restore scrolling when state.restoreScrollPosition changes
|
|
871
944
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
872
945
|
React.useLayoutEffect(() => {
|