From 0d6d9a736ca37cec32ee51e2ffb61eedb72831e9 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Fri, 7 Jun 2024 11:41:19 -0400 Subject: [PATCH 1/3] Fix fetcher.submit types --- .changeset/gorgeous-geese-sit.md | 5 ++++ packages/react-router-dom/dom.ts | 36 +++++++++++++++-------------- packages/react-router-dom/index.tsx | 3 ++- 3 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 .changeset/gorgeous-geese-sit.md diff --git a/.changeset/gorgeous-geese-sit.md b/.changeset/gorgeous-geese-sit.md new file mode 100644 index 0000000000..c38daf1ce8 --- /dev/null +++ b/.changeset/gorgeous-geese-sit.md @@ -0,0 +1,5 @@ +--- +"react-router-dom": patch +--- + +Fix `fetcher.submit` types - remove incorrect `navigate`/`fetcherKey`/`unstable_viewTransition` options because they are only relevant for `useSubmit` diff --git a/packages/react-router-dom/dom.ts b/packages/react-router-dom/dom.ts index 960e0b5036..7cdecccf76 100644 --- a/packages/react-router-dom/dom.ts +++ b/packages/react-router-dom/dom.ts @@ -150,7 +150,7 @@ function isFormDataSubmitterSupported() { return _formDataSupportsSubmitter; } -export interface SubmitOptions { +export interface FetcherSubmitOptions { /** * The HTTP method used to submit the form. Overrides `
`. * Defaults to "GET". @@ -170,15 +170,25 @@ export interface SubmitOptions { encType?: FormEncType; /** - * Indicate a specific fetcherKey to use when using navigate=false + * Determines whether the form action is relative to the route hierarchy or + * the pathname. Use this if you want to opt out of navigating the route + * hierarchy and want to instead route based on /-delimited URL segments */ - fetcherKey?: string; + relative?: RelativeRoutingType; /** - * navigate=false will use a fetcher instead of a navigation + * In browser-based environments, prevent resetting scroll after this + * navigation when using the component */ - navigate?: boolean; + preventScrollReset?: boolean; + + /** + * Enable flushSync for this submission's state updates + */ + unstable_flushSync?: boolean; +} +export interface SubmitOptions extends FetcherSubmitOptions { /** * Set `true` to replace the current entry in the browser's history stack * instead of creating a new one (i.e. stay on "the same page"). Defaults @@ -192,22 +202,14 @@ export interface SubmitOptions { state?: any; /** - * Determines whether the form action is relative to the route hierarchy or - * the pathname. Use this if you want to opt out of navigating the route - * hierarchy and want to instead route based on /-delimited URL segments - */ - relative?: RelativeRoutingType; - - /** - * In browser-based environments, prevent resetting scroll after this - * navigation when using the component + * Indicate a specific fetcherKey to use when using navigate=false */ - preventScrollReset?: boolean; + fetcherKey?: string; /** - * Enable flushSync for this navigation's state updates + * navigate=false will use a fetcher instead of a navigation */ - unstable_flushSync?: boolean; + navigate?: boolean; /** * Enable view transitions on this submission navigation diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 1f2e515f75..364d7e9c5b 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -72,6 +72,7 @@ import type { ParamKeyValuePair, URLSearchParamsInit, SubmitTarget, + FetcherSubmitOptions, } from "./dom"; import { createSearchParams, @@ -1523,7 +1524,7 @@ export interface FetcherSubmitFunction { ( target: SubmitTarget, // Fetchers cannot replace or set state because they are not navigation events - options?: Omit + options?: FetcherSubmitOptions ): void; } From 4120ae8fd6cc1bc3be4d9e8769eb32a8ee0d7554 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 13 Jun 2024 17:25:13 -0400 Subject: [PATCH 2/3] Add Shared types --- packages/react-router-dom/dom.ts | 13 ++++++++++++- packages/react-router-dom/index.tsx | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/react-router-dom/dom.ts b/packages/react-router-dom/dom.ts index 7cdecccf76..ca2ac9a767 100644 --- a/packages/react-router-dom/dom.ts +++ b/packages/react-router-dom/dom.ts @@ -150,7 +150,10 @@ function isFormDataSubmitterSupported() { return _formDataSupportsSubmitter; } -export interface FetcherSubmitOptions { +/** + * Submit options shared by both navigations and fetchers + */ +interface SharedSubmitOptions { /** * The HTTP method used to submit the form. Overrides ``. * Defaults to "GET". @@ -188,6 +191,14 @@ export interface FetcherSubmitOptions { unstable_flushSync?: boolean; } +/** + * Submit options available to fetchers + */ +export interface FetcherSubmitOptions extends SharedSubmitOptions {} + +/** + * Submit options available to navigations + */ export interface SubmitOptions extends FetcherSubmitOptions { /** * Set `true` to replace the current entry in the browser's history stack diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 364d7e9c5b..1229fcb453 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -1159,8 +1159,10 @@ if (__DEV__) { NavLink.displayName = "NavLink"; } -export interface FetcherFormProps - extends React.FormHTMLAttributes { +/** + * Form props shared by navigations and fetchers + */ +interface SharedFormProps extends React.FormHTMLAttributes { /** * The HTTP verb to use when the form is submit. Supports "get", "post", * "put", "delete", "patch". @@ -1201,7 +1203,15 @@ export interface FetcherFormProps onSubmit?: React.FormEventHandler; } -export interface FormProps extends FetcherFormProps { +/** + * Form props available to fetchers + */ +export interface FetcherFormProps extends SharedFormProps {} + +/** + * Form props available to navigations + */ +export interface FormProps extends SharedFormProps { /** * Indicate a specific fetcherKey to use when using navigate=false */ From d207bb1b4d95efbb00a03398ccdb21c7c48ea53d Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 13 Jun 2024 17:25:17 -0400 Subject: [PATCH 3/3] fix test --- packages/router/__tests__/navigation-test.ts | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/router/__tests__/navigation-test.ts b/packages/router/__tests__/navigation-test.ts index 894da06535..e6ea50c5b1 100644 --- a/packages/router/__tests__/navigation-test.ts +++ b/packages/router/__tests__/navigation-test.ts @@ -169,11 +169,13 @@ describe("navigations", () => { }) ); expect(t.router.state.loaderData).toEqual({}); - expect(t.router.state.errors).toMatchInlineSnapshot(` - { - "foo": [SyntaxError: Unexpected token } in JSON at position 15], - } - `); + + // Node 16/18 versus 20 output different errors here :/ + let expected = + process.version.startsWith("v16") || process.version.startsWith("v18") + ? "Unexpected token } in JSON at position 15" + : "Unexpected non-whitespace character after JSON at position 15"; + expect(t.router.state.errors?.foo).toEqual(new SyntaxError(expected)); }); it("bubbles errors when unwrapping Responses", async () => { @@ -204,11 +206,13 @@ describe("navigations", () => { }) ); expect(t.router.state.loaderData).toEqual({}); - expect(t.router.state.errors).toMatchInlineSnapshot(` - { - "root": [SyntaxError: Unexpected token } in JSON at position 15], - } - `); + + // Node 16/18 versus 20 output different errors here :/ + let expected = + process.version.startsWith("v16") || process.version.startsWith("v18") + ? "Unexpected token } in JSON at position 15" + : "Unexpected non-whitespace character after JSON at position 15"; + expect(t.router.state.errors?.root).toEqual(new SyntaxError(expected)); }); it("does not fetch unchanging layout data", async () => {