react-router-dom 0.0.0-experimental-af76d50e → 0.0.0-experimental-dc8656c8

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # `react-router-dom`
2
2
 
3
+ ## 6.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - `react-router@6.11.1`
9
+ - `@remix-run/router@1.6.1`
10
+
11
+ ## 6.11.0
12
+
13
+ ### Minor Changes
14
+
15
+ - Enable `basename` support in `useFetcher` ([#10336](https://github.com/remix-run/react-router/pull/10336))
16
+ - 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')`)
17
+
18
+ ### Patch Changes
19
+
20
+ - Fix inadvertent re-renders when using `Component` instead of `element` on a route definition ([#10287](https://github.com/remix-run/react-router/pull/10287))
21
+ - Fail gracefully on `<Link to="//">` and other invalid URL values ([#10367](https://github.com/remix-run/react-router/pull/10367))
22
+ - 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))
23
+ - Add static prop to `StaticRouterProvider`'s internal `Router` component ([#10401](https://github.com/remix-run/react-router/pull/10401))
24
+ - 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))
25
+ - Updated dependencies:
26
+ - `react-router@6.11.0`
27
+ - `@remix-run/router@1.6.0`
28
+
3
29
  ## 6.10.0
4
30
 
5
31
  ### Minor Changes
package/LICENSE.md CHANGED
@@ -1,7 +1,8 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) React Training 2015-2019
4
- Copyright (c) Remix Software 2020-2022
3
+ Copyright (c) React Training LLC 2015-2019
4
+ Copyright (c) Remix Software Inc. 2020-2021
5
+ Copyright (c) Shopify Inc. 2022-2023
5
6
 
6
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
8
  of this software and associated documentation files (the "Software"), to deal
package/dist/dom.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActionFunction, FormEncType, HTMLFormMethod, RelativeRoutingType } from "@remix-run/router";
1
+ import type { FormEncType, HTMLFormMethod, RelativeRoutingType } from "@remix-run/router";
2
2
  export declare const defaultMethod: HTMLFormMethod;
3
3
  export declare function isHtmlElement(object: any): object is HTMLElement;
4
4
  export declare function isButtonElement(object: any): object is HTMLButtonElement;
@@ -31,9 +31,6 @@ 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
- export declare type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | {
35
- [name: string]: string;
36
- } | NonNullable<unknown> | null;
37
34
  export interface SubmitOptions {
38
35
  /**
39
36
  * The HTTP method used to submit the form. Overrides `<form method>`.
@@ -44,17 +41,12 @@ export interface SubmitOptions {
44
41
  * The action URL path used to submit the form. Overrides `<form action>`.
45
42
  * Defaults to the path of the current route.
46
43
  */
47
- action?: string | ActionFunction;
44
+ action?: string;
48
45
  /**
49
46
  * The action URL used to submit the form. Overrides `<form encType>`.
50
- * Defaults to "application/x-www-form-urlencoded". Specifying `null` will
51
- * opt-out of serialization and will submit the data directly to your action
52
- * in the `payload` parameter.
53
- *
54
- * In v7, the default behavior will change from "application/x-www-form-urlencoded"
55
- * to `null` and will make serialization opt-in
47
+ * Defaults to "application/x-www-form-urlencoded".
56
48
  */
57
- encType?: FormEncType | null;
49
+ encType?: FormEncType;
58
50
  /**
59
51
  * Set `true` to replace the current entry in the browser's history stack
60
52
  * instead of creating a new one (i.e. stay on "the same page"). Defaults
@@ -73,11 +65,12 @@ export interface SubmitOptions {
73
65
  */
74
66
  preventScrollReset?: boolean;
75
67
  }
76
- export declare function getFormSubmissionInfo(target: SubmitTarget, formEncType: FormEncType | undefined, basename: string): {
68
+ export declare function getFormSubmissionInfo(target: HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | {
69
+ [name: string]: string;
70
+ } | null, options: SubmitOptions, basename: string): {
77
71
  action: string | null;
78
72
  method: string;
79
- encType: string | null;
80
- formData: FormData | undefined;
81
- payload: any;
73
+ encType: string;
74
+ formData: FormData;
82
75
  };
83
76
  export {};
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  */
5
5
  import * as React from "react";
6
6
  import type { NavigateOptions, RelativeRoutingType, RouteObject, To } from "react-router";
7
- import type { Fetcher, FormEncType, FormMethod, FutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, LoaderFunction, Router as RemixRouter, V7_FormMethod } from "@remix-run/router";
8
- import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit, SubmitTarget } from "./dom";
7
+ import type { Fetcher, FormEncType, FormMethod, FutureConfig, GetScrollRestorationKeyFunction, History, HTMLFormMethod, HydrationState, Router as RemixRouter, V7_FormMethod } from "@remix-run/router";
8
+ import type { SubmitOptions, ParamKeyValuePair, URLSearchParamsInit } from "./dom";
9
9
  import { createSearchParams } from "./dom";
10
10
  export type { FormEncType, FormMethod, GetScrollRestorationKeyFunction, ParamKeyValuePair, SubmitOptions, URLSearchParamsInit, V7_FormMethod, };
11
11
  export { createSearchParams };
@@ -164,7 +164,10 @@ export declare function useLinkClickHandler<E extends Element = HTMLAnchorElemen
164
164
  * URLSearchParams interface.
165
165
  */
166
166
  export declare function useSearchParams(defaultInit?: URLSearchParamsInit): [URLSearchParams, SetURLSearchParams];
167
- declare type SetURLSearchParams = (nextInit?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), navigateOpts?: NavigateOptions) => void;
167
+ export declare type SetURLSearchParams = (nextInit?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), navigateOpts?: NavigateOptions) => void;
168
+ declare type SubmitTarget = HTMLFormElement | HTMLButtonElement | HTMLInputElement | FormData | URLSearchParams | {
169
+ [name: string]: string;
170
+ } | null;
168
171
  /**
169
172
  * Submits a HTML `<form>` to the server without reloading the page.
170
173
  */
@@ -197,7 +200,7 @@ declare function createFetcherForm(fetcherKey: string, routeId: string): React.F
197
200
  export declare type FetcherWithComponents<TData> = Fetcher<TData> & {
198
201
  Form: ReturnType<typeof createFetcherForm>;
199
202
  submit: (target: SubmitTarget, options?: Omit<SubmitOptions, "replace" | "preventScrollReset">) => void;
200
- load: (href: string | LoaderFunction) => void;
203
+ load: (href: string) => void;
201
204
  };
202
205
  /**
203
206
  * Interacts with route loaders and actions without causing a navigation. Great
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router DOM v0.0.0-experimental-af76d50e
2
+ * React Router DOM v0.0.0-experimental-dc8656c8
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -117,37 +117,52 @@ function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
117
117
 
118
118
  return searchParams;
119
119
  }
120
- function getFormSubmissionInfo(target, formEncType, basename) {
120
+ function getFormSubmissionInfo(target, options, basename) {
121
121
  let method;
122
- let action;
122
+ let action = null;
123
123
  let encType;
124
- let formData = undefined;
125
- let payload = undefined;
124
+ let formData;
126
125
 
127
126
  if (isFormElement(target)) {
128
- // When grabbing the action from the element, it will have had the basename
129
- // prefixed to ensure non-JS scenarios work, so strip it since we'll
130
- // re-prefix in the router
131
- let attr = target.getAttribute("action");
132
- action = attr ? stripBasename(attr, basename) : null;
133
- method = target.getAttribute("method") || defaultMethod;
134
- encType = target.getAttribute("enctype") || defaultEncType;
127
+ let submissionTrigger = options.submissionTrigger;
128
+
129
+ if (options.action) {
130
+ action = options.action;
131
+ } else {
132
+ // When grabbing the action from the element, it will have had the basename
133
+ // prefixed to ensure non-JS scenarios work, so strip it since we'll
134
+ // re-prefix in the router
135
+ let attr = target.getAttribute("action");
136
+ action = attr ? stripBasename(attr, basename) : null;
137
+ }
138
+
139
+ method = options.method || target.getAttribute("method") || defaultMethod;
140
+ encType = options.encType || target.getAttribute("enctype") || defaultEncType;
135
141
  formData = new FormData(target);
142
+
143
+ if (submissionTrigger && submissionTrigger.name) {
144
+ formData.append(submissionTrigger.name, submissionTrigger.value);
145
+ }
136
146
  } else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
137
147
  let form = target.form;
138
148
 
139
149
  if (form == null) {
140
150
  throw new Error("Cannot submit a <button> or <input type=\"submit\"> without a <form>");
141
151
  } // <button>/<input type="submit"> may override attributes of <form>
142
- // When grabbing the action from the element, it will have had the basename
143
- // prefixed to ensure non-JS scenarios work, so strip it since we'll
144
- // re-prefix in the router
145
152
 
146
153
 
147
- let attr = target.getAttribute("formaction") || form.getAttribute("action");
148
- action = attr ? stripBasename(attr, basename) : null;
149
- method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
150
- encType = target.getAttribute("formenctype") || form.getAttribute("enctype") || defaultEncType;
154
+ if (options.action) {
155
+ action = options.action;
156
+ } else {
157
+ // When grabbing the action from the element, it will have had the basename
158
+ // prefixed to ensure non-JS scenarios work, so strip it since we'll
159
+ // re-prefix in the router
160
+ let attr = target.getAttribute("formaction") || form.getAttribute("action");
161
+ action = attr ? stripBasename(attr, basename) : null;
162
+ }
163
+
164
+ method = options.method || target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
165
+ encType = options.encType || target.getAttribute("formenctype") || form.getAttribute("enctype") || defaultEncType;
151
166
  formData = new FormData(form); // Include name + value from a <button>, appending in case the button name
152
167
  // matches an existing input name
153
168
 
@@ -156,22 +171,10 @@ function getFormSubmissionInfo(target, formEncType, basename) {
156
171
  }
157
172
  } else if (isHtmlElement(target)) {
158
173
  throw new Error("Cannot submit element that is not <form>, <button>, or " + "<input type=\"submit|image\">");
159
- } else if (formEncType !== undefined && formEncType !== "application/x-www-form-urlencoded") {
160
- // The default behavior is to encode as application/x-www-form-urlencoded
161
- // into FormData which is handled in the else block below.
162
- //
163
- // Any other encType value (null, application/json, text/plain) means
164
- // we will not be submitting as FormData so send the payload through
165
- // directly. The @remix-run/router will handle serialization of the
166
- // payload upon Request creation if needed.
167
- method = defaultMethod;
168
- action = null;
169
- encType = null;
170
- payload = target;
171
174
  } else {
172
- method = defaultMethod;
173
- action = null;
174
- encType = defaultEncType;
175
+ method = options.method || defaultMethod;
176
+ action = options.action || null;
177
+ encType = options.encType || defaultEncType;
175
178
 
176
179
  if (target instanceof FormData) {
177
180
  formData = target;
@@ -183,14 +186,7 @@ function getFormSubmissionInfo(target, formEncType, basename) {
183
186
  formData.append(name, value);
184
187
  }
185
188
  } else if (target != null) {
186
- // When a raw object is sent - even though we encode it into formData,
187
- // we still expose it as payload so it aligns with the behavior if
188
- // encType were application/json or text/plain
189
- payload = target; // To be deprecated in v7 so the default behavior of undefined matches
190
- // the null behavior of no-serialization
191
-
192
189
  for (let name of Object.keys(target)) {
193
- // @ts-expect-error
194
190
  formData.append(name, target[name]);
195
191
  }
196
192
  }
@@ -201,8 +197,7 @@ function getFormSubmissionInfo(target, formEncType, basename) {
201
197
  action,
202
198
  method: method.toLowerCase(),
203
199
  encType,
204
- formData,
205
- payload
200
+ formData
206
201
  };
207
202
  }
208
203
 
@@ -736,26 +731,21 @@ function useSubmitImpl(fetcherKey, fetcherRouteId) {
736
731
  action,
737
732
  method,
738
733
  encType,
739
- formData,
740
- payload
741
- } = getFormSubmissionInfo(target, options.encType, basename);
742
- let path = typeof options.action === "function" ? null : options.action || action;
743
- let routerAction = typeof options.action === "function" ? options.action : null; // Base options shared between fetch() and navigate()
734
+ formData
735
+ } = getFormSubmissionInfo(target, options, basename); // Base options shared between fetch() and navigate()
744
736
 
745
737
  let opts = {
746
738
  preventScrollReset: options.preventScrollReset,
747
739
  formData,
748
- payload,
749
- formMethod: options.method || method,
750
- formEncType: options.encType || encType,
751
- action: routerAction
740
+ formMethod: method,
741
+ formEncType: encType
752
742
  };
753
743
 
754
744
  if (fetcherKey) {
755
745
  !(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, path, opts);
746
+ router.fetch(fetcherKey, fetcherRouteId, action, opts);
757
747
  } else {
758
- router.navigate(path, _extends({}, opts, {
748
+ router.navigate(action, _extends({}, opts, {
759
749
  replace: options.replace,
760
750
  fromRouteId: currentRouteId
761
751
  }));
@@ -859,14 +849,7 @@ function useFetcher() {
859
849
  let [load] = React.useState(() => href => {
860
850
  !router ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No router available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
861
851
  !routeId ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "No routeId available for fetcher.load()") : UNSAFE_invariant(false) : void 0;
862
-
863
- if (typeof href === "function") {
864
- router.fetch(fetcherKey, routeId, null, {
865
- loader: href
866
- });
867
- } else {
868
- router.fetch(fetcherKey, routeId, href);
869
- }
852
+ router.fetch(fetcherKey, routeId, href);
870
853
  });
871
854
  let submit = useSubmitImpl(fetcherKey, routeId);
872
855
  let fetcher = router.getFetcher(fetcherKey);