remix-validated-form 4.5.2 → 4.5.5

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.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Ponyfill of the HTMLFormElement.requestSubmit() method.
3
+ * Based on polyfill from: https://github.com/javan/form-request-submit-polyfill/blob/main/form-request-submit-polyfill.js
4
+ */
5
+ export declare const requestSubmit: (element: HTMLFormElement, submitter?: HTMLElement | undefined) => void;
@@ -1,5 +1,5 @@
1
1
  import { FORM_DEFAULTS_FIELD } from "./internal/constants";
2
- import { ValidatorError } from "./validation/types";
2
+ import { ValidatorError, ValidationErrorResponseData } from "./validation/types";
3
3
  /**
4
4
  * Takes the errors from a `Validator` and returns a `Response`.
5
5
  * When you return this from your action, `ValidatedForm` on the frontend will automatically
@@ -14,7 +14,7 @@ import { ValidatorError } from "./validation/types";
14
14
  * if (result.error) return validationError(result.error, result.submittedData);
15
15
  * ```
16
16
  */
17
- export declare function validationError(error: ValidatorError, repopulateFields?: unknown, init?: ResponseInit): Response;
17
+ export declare function validationError(error: ValidatorError, repopulateFields?: unknown, init?: ResponseInit): import("@remix-run/server-runtime").TypedResponse<ValidationErrorResponseData>;
18
18
  export declare type FormDefaults = {
19
19
  [formDefaultsKey: `${typeof FORM_DEFAULTS_FIELD}_${string}`]: any;
20
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remix-validated-form",
3
- "version": "4.5.2",
3
+ "version": "4.5.5",
4
4
  "description": "Form component and utils for easy form validation in remix",
5
5
  "browser": "./dist/remix-validated-form.cjs.js",
6
6
  "main": "./dist/remix-validated-form.umd.js",
@@ -34,12 +34,11 @@
34
34
  ],
35
35
  "peerDependencies": {
36
36
  "@remix-run/react": "1.x",
37
- "@remix-run/server-runtime": "1.x",
38
37
  "react": "^17.0.2 || ^18.0.0"
39
38
  },
40
39
  "devDependencies": {
41
40
  "@remix-run/react": "^1.6.5",
42
- "@remix-run/server-runtime": "^1.6.5",
41
+ "@testing-library/react": "^13.3.0",
43
42
  "@types/lodash": "^4.14.178",
44
43
  "@types/react": "^18.0.9",
45
44
  "fetch-blob": "^3.1.3",
@@ -0,0 +1,24 @@
1
+ import { render } from "@testing-library/react";
2
+ import React, { createRef } from "react";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { requestSubmit } from "./requestSubmit";
5
+
6
+ describe("requestSubmit polyfill", () => {
7
+ it("should polyfill requestSubmit", () => {
8
+ const submit = vi.fn();
9
+ const ref = createRef<HTMLFormElement>();
10
+ render(
11
+ <form
12
+ onSubmit={(event) => {
13
+ event.preventDefault();
14
+ submit();
15
+ }}
16
+ ref={ref}
17
+ >
18
+ <input name="test" value="testing" />
19
+ </form>
20
+ );
21
+ requestSubmit(ref.current!);
22
+ expect(submit).toHaveBeenCalledTimes(1);
23
+ });
24
+ });
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Ponyfill of the HTMLFormElement.requestSubmit() method.
3
+ * Based on polyfill from: https://github.com/javan/form-request-submit-polyfill/blob/main/form-request-submit-polyfill.js
4
+ */
5
+ export const requestSubmit = (
6
+ element: HTMLFormElement,
7
+ submitter?: HTMLElement
8
+ ) => {
9
+ // In vitest, let's test the polyfill.
10
+ // Cypress will test the native implementation by nature of using chrome.
11
+ if (
12
+ typeof Object.getPrototypeOf(element).requestSubmit === "function" &&
13
+ !import.meta.vitest
14
+ ) {
15
+ element.requestSubmit(submitter);
16
+ return;
17
+ }
18
+
19
+ if (submitter) {
20
+ validateSubmitter(element, submitter);
21
+ submitter.click();
22
+ return;
23
+ }
24
+
25
+ const dummySubmitter = document.createElement("input");
26
+ dummySubmitter.type = "submit";
27
+ dummySubmitter.hidden = true;
28
+ element.appendChild(dummySubmitter);
29
+ dummySubmitter.click();
30
+ element.removeChild(dummySubmitter);
31
+ };
32
+
33
+ function validateSubmitter(element: HTMLFormElement, submitter: HTMLElement) {
34
+ // Should be redundant, but here for completeness
35
+ const isHtmlElement = submitter instanceof HTMLElement;
36
+ if (!isHtmlElement) {
37
+ raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
38
+ }
39
+
40
+ const hasSubmitType =
41
+ "type" in submitter && (submitter as HTMLInputElement).type === "submit";
42
+ if (!hasSubmitType)
43
+ raise(TypeError, "The specified element is not a submit button");
44
+
45
+ const isForCorrectForm =
46
+ "form" in submitter && (submitter as HTMLInputElement).form === element;
47
+ if (!isForCorrectForm)
48
+ raise(
49
+ DOMException,
50
+ "The specified element is not owned by this form element",
51
+ "NotFoundError"
52
+ );
53
+ }
54
+
55
+ interface ErrorConstructor {
56
+ new (message: string, name?: string): Error;
57
+ }
58
+
59
+ function raise(
60
+ errorConstructor: ErrorConstructor,
61
+ message: string,
62
+ name?: string
63
+ ): never {
64
+ throw new errorConstructor(
65
+ "Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".",
66
+ name
67
+ );
68
+ }
69
+
70
+ if (import.meta.vitest) {
71
+ const { it, expect } = import.meta.vitest;
72
+ it("should validate the submitter", () => {
73
+ const form = document.createElement("form");
74
+ document.body.appendChild(form);
75
+
76
+ const submitter = document.createElement("input");
77
+ expect(() => validateSubmitter(null as any, null as any)).toThrow();
78
+ expect(() => validateSubmitter(form, null as any)).toThrow();
79
+ expect(() => validateSubmitter(form, submitter)).toThrow();
80
+ expect(() =>
81
+ validateSubmitter(form, document.createElement("div"))
82
+ ).toThrow();
83
+
84
+ submitter.type = "submit";
85
+ expect(() => validateSubmitter(form, submitter)).toThrow();
86
+
87
+ form.appendChild(submitter);
88
+ expect(() => validateSubmitter(form, submitter)).not.toThrow();
89
+
90
+ form.removeChild(submitter);
91
+ expect(() => validateSubmitter(form, submitter)).toThrow();
92
+
93
+ document.body.appendChild(submitter);
94
+ form.id = "test-form";
95
+ submitter.setAttribute("form", "test-form");
96
+ expect(() => validateSubmitter(form, submitter)).not.toThrow();
97
+
98
+ const button = document.createElement("button");
99
+ button.type = "submit";
100
+ form.appendChild(button);
101
+ expect(() => validateSubmitter(form, button)).not.toThrow();
102
+ });
103
+ }
@@ -8,6 +8,7 @@ import {
8
8
  ValidationResult,
9
9
  Validator,
10
10
  } from "../../validation/types";
11
+ import { requestSubmit } from "../logic/requestSubmit";
11
12
  import { useControlledFieldStore } from "./controlledFieldStore";
12
13
  import { InternalFormId } from "./types";
13
14
 
@@ -206,18 +207,10 @@ const createFormState = (
206
207
  "Cannot find reference to form. This is probably a bug in remix-validated-form."
207
208
  );
208
209
 
209
- formElement.submit();
210
+ requestSubmit(formElement);
210
211
  },
211
212
 
212
- getValues: () => {
213
- const formElement = get().formElement;
214
- invariant(
215
- formElement,
216
- "Cannot find reference to form. This is probably a bug in remix-validated-form."
217
- );
218
-
219
- return new FormData(formElement);
220
- },
213
+ getValues: () => new FormData(get().formElement ?? undefined),
221
214
 
222
215
  resetFormElement: () => get().formElement?.reset(),
223
216
  });
package/src/server.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { json } from "@remix-run/server-runtime";
1
+ import { json } from "remix";
2
2
  import {
3
3
  formDefaultValuesKey,
4
4
  FORM_DEFAULTS_FIELD,
package/vite.config.ts CHANGED
@@ -2,6 +2,6 @@ import { makeConfig } from "vite-config";
2
2
 
3
3
  export default makeConfig({
4
4
  lib: "remix-validated-form",
5
- external: ["react", "@remix-run/react", "@remix-run/server-runtime"],
5
+ external: ["react", "@remix-run/react"],
6
6
  dir: __dirname,
7
7
  });