remix-validated-form 4.1.1 → 4.1.4

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.
Files changed (55) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/browser/ValidatedForm.js +9 -4
  3. package/browser/internal/hooks-valtio.d.ts +18 -0
  4. package/browser/internal/hooks-valtio.js +110 -0
  5. package/browser/internal/hooks-zustand.d.ts +16 -0
  6. package/browser/internal/hooks-zustand.js +100 -0
  7. package/browser/internal/hydratable.d.ts +14 -0
  8. package/browser/internal/hydratable.js +14 -0
  9. package/browser/internal/immerMiddleware.d.ts +6 -0
  10. package/browser/internal/immerMiddleware.js +7 -0
  11. package/browser/internal/logic/getCheckboxChecked.js +1 -1
  12. package/browser/internal/logic/setInputValueInForm.d.ts +1 -0
  13. package/browser/internal/logic/setInputValueInForm.js +120 -0
  14. package/browser/internal/setFieldValue.d.ts +20 -0
  15. package/browser/internal/setFieldValue.js +83 -0
  16. package/browser/internal/setFormValues.d.ts +2 -0
  17. package/browser/internal/setFormValues.js +26 -0
  18. package/browser/internal/state/atomUtils.d.ts +38 -0
  19. package/browser/internal/state/atomUtils.js +5 -0
  20. package/browser/internal/state/controlledFields.d.ts +66 -0
  21. package/browser/internal/state/controlledFields.js +93 -0
  22. package/browser/internal/state/setFieldValue.d.ts +0 -0
  23. package/browser/internal/state/setFieldValue.js +1 -0
  24. package/browser/internal/state-valtio.d.ts +62 -0
  25. package/browser/internal/state-valtio.js +69 -0
  26. package/browser/internal/state-zustand.d.ts +47 -0
  27. package/browser/internal/state-zustand.js +85 -0
  28. package/browser/internal/util.js +1 -1
  29. package/build/ValidatedForm.js +9 -4
  30. package/build/internal/hooks-valtio.d.ts +18 -0
  31. package/build/internal/hooks-valtio.js +128 -0
  32. package/build/internal/hooks-zustand.d.ts +16 -0
  33. package/build/internal/hooks-zustand.js +117 -0
  34. package/build/internal/hydratable.d.ts +14 -0
  35. package/build/internal/hydratable.js +17 -0
  36. package/build/internal/immerMiddleware.d.ts +6 -0
  37. package/build/internal/immerMiddleware.js +14 -0
  38. package/build/internal/logic/getCheckboxChecked.js +1 -1
  39. package/build/internal/logic/setFieldValue.js +3 -3
  40. package/build/internal/logic/setInputValueInForm.d.ts +1 -0
  41. package/build/internal/logic/setInputValueInForm.js +127 -0
  42. package/build/internal/setFormValues.d.ts +2 -0
  43. package/build/internal/setFormValues.js +33 -0
  44. package/build/internal/state/atomUtils.d.ts +38 -0
  45. package/build/internal/state/atomUtils.js +13 -0
  46. package/build/internal/state/controlledFields.d.ts +66 -0
  47. package/build/internal/state/controlledFields.js +95 -0
  48. package/build/internal/state-valtio.d.ts +62 -0
  49. package/build/internal/state-valtio.js +83 -0
  50. package/build/internal/state-zustand.d.ts +47 -0
  51. package/build/internal/state-zustand.js +91 -0
  52. package/build/internal/util.js +5 -2
  53. package/package.json +5 -5
  54. package/src/ValidatedForm.tsx +10 -4
  55. package/src/internal/util.ts +1 -1
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setFieldErrors = exports.reset = exports.setTouched = exports.addError = exports.clearError = exports.sync = exports.endSubmit = exports.startSubmit = exports.useFormData = exports.unregisterFormSlice = exports.registerFormSlice = exports.state = void 0;
4
+ const valtio_1 = require("valtio");
5
+ exports.state = (0, valtio_1.proxy)({ forms: {} });
6
+ const registerFormSlice = (formId, { registerReceiveFocus, setFieldValueForForm, validateField, action, defaultValues, subaction, }) => {
7
+ exports.state.forms[formId] = {
8
+ hydrated: true,
9
+ defaultValues: defaultValues !== null && defaultValues !== void 0 ? defaultValues : {},
10
+ fieldErrors: {},
11
+ hasBeenSubmitted: false,
12
+ isSubmitting: false,
13
+ touchedFields: {},
14
+ registerReceiveFocus,
15
+ setFieldValue: setFieldValueForForm,
16
+ validateField,
17
+ action,
18
+ subaction,
19
+ };
20
+ };
21
+ exports.registerFormSlice = registerFormSlice;
22
+ const unregisterFormSlice = (formId) => {
23
+ delete exports.state.forms[formId];
24
+ };
25
+ exports.unregisterFormSlice = unregisterFormSlice;
26
+ const unhydratedFormState = {
27
+ hydrated: false,
28
+ fieldErrors: {},
29
+ isSubmitting: false,
30
+ hasBeenSubmitted: false,
31
+ touchedFields: {},
32
+ defaultValues: {},
33
+ validateField: () => Promise.resolve(null),
34
+ registerReceiveFocus: () => () => { },
35
+ setFieldValue: () => { },
36
+ };
37
+ const useFormData = (formId) => {
38
+ var _a;
39
+ const snapshot = (0, valtio_1.useSnapshot)(exports.state);
40
+ return (_a = snapshot.forms[formId]) !== null && _a !== void 0 ? _a : unhydratedFormState;
41
+ };
42
+ exports.useFormData = useFormData;
43
+ const startSubmit = (formId) => {
44
+ exports.state.forms[formId].isSubmitting = true;
45
+ exports.state.forms[formId].hasBeenSubmitted = true;
46
+ };
47
+ exports.startSubmit = startSubmit;
48
+ const endSubmit = (formId) => {
49
+ exports.state.forms[formId].isSubmitting = false;
50
+ };
51
+ exports.endSubmit = endSubmit;
52
+ const sync = (formId, { defaultValues, action, subaction, registerReceiveFocus, validateField, setFieldValueForForm, }) => {
53
+ exports.state.forms[formId].defaultValues = defaultValues !== null && defaultValues !== void 0 ? defaultValues : {};
54
+ exports.state.forms[formId].action = action;
55
+ exports.state.forms[formId].subaction = subaction;
56
+ exports.state.forms[formId].registerReceiveFocus = registerReceiveFocus;
57
+ exports.state.forms[formId].validateField = validateField;
58
+ exports.state.forms[formId].hydrated = true;
59
+ exports.state.forms[formId].setFieldValue = setFieldValueForForm;
60
+ };
61
+ exports.sync = sync;
62
+ const clearError = (formId, fieldName) => {
63
+ delete exports.state.forms[formId].fieldErrors[fieldName];
64
+ };
65
+ exports.clearError = clearError;
66
+ const addError = (formId, fieldName, error) => {
67
+ exports.state.forms[formId].fieldErrors[fieldName] = error;
68
+ };
69
+ exports.addError = addError;
70
+ const setTouched = (formId, fieldName, touched) => {
71
+ exports.state.forms[formId].touchedFields[fieldName] = touched;
72
+ };
73
+ exports.setTouched = setTouched;
74
+ const reset = (formId) => {
75
+ exports.state.forms[formId].fieldErrors = {};
76
+ exports.state.forms[formId].touchedFields = {};
77
+ exports.state.forms[formId].hasBeenSubmitted = false;
78
+ };
79
+ exports.reset = reset;
80
+ const setFieldErrors = (formId, fieldErrors) => {
81
+ exports.state.forms[formId].fieldErrors = fieldErrors;
82
+ };
83
+ exports.setFieldErrors = setFieldErrors;
@@ -0,0 +1,47 @@
1
+ import { FieldErrors, TouchedFields } from "..";
2
+ export declare type InternalFormState = {
3
+ hydrated: boolean;
4
+ fieldErrors: FieldErrors;
5
+ isSubmitting: boolean;
6
+ hasBeenSubmitted: boolean;
7
+ touchedFields: TouchedFields;
8
+ action?: string;
9
+ subaction?: string;
10
+ defaultValues: {
11
+ [fieldName: string]: any;
12
+ };
13
+ validateField: (fieldName: string) => Promise<string | null>;
14
+ registerReceiveFocus: (fieldName: string, handler: () => void) => () => void;
15
+ setFieldValue: (fieldName: string, value: unknown) => void;
16
+ };
17
+ declare type Helpers = {
18
+ startSubmit: () => void;
19
+ endSubmit: () => void;
20
+ sync: (args: SyncFormArgs) => void;
21
+ clearError: (name: string) => void;
22
+ addError: (name: string, error: string) => void;
23
+ setTouched: (name: string, touched: boolean) => void;
24
+ reset: () => void;
25
+ setFieldErrors: (fieldErrors: FieldErrors) => void;
26
+ register: (init: SyncFormArgs) => void;
27
+ unregister: () => void;
28
+ };
29
+ declare type SyncFormArgs = {
30
+ defaultValues?: {
31
+ [fieldName: string]: any;
32
+ };
33
+ action?: string;
34
+ subaction?: string;
35
+ validateField: InternalFormState["validateField"];
36
+ registerReceiveFocus: InternalFormState["registerReceiveFocus"];
37
+ setFieldValueForForm: InternalFormState["setFieldValue"];
38
+ };
39
+ declare type StoreState = {
40
+ forms: {
41
+ [formId: string | symbol]: InternalFormState;
42
+ };
43
+ form: (formId: string | symbol) => InternalFormState;
44
+ helpers: (formId: string | symbol) => Helpers;
45
+ };
46
+ export declare const useStore: import("zustand").UseBoundStore<StoreState, import("zustand").StoreApi<StoreState>>;
47
+ export {};
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useStore = void 0;
7
+ const zustand_1 = __importDefault(require("zustand"));
8
+ const immerMiddleware_1 = require("./immerMiddleware");
9
+ const unhydratedFormState = {
10
+ hydrated: false,
11
+ fieldErrors: {},
12
+ isSubmitting: false,
13
+ hasBeenSubmitted: false,
14
+ touchedFields: {},
15
+ defaultValues: {},
16
+ validateField: () => Promise.resolve(null),
17
+ registerReceiveFocus: () => () => { },
18
+ setFieldValue: () => { },
19
+ // clearError: () => {},
20
+ // addError: () => {},
21
+ // setTouched: () => {},
22
+ // reset: () => {},
23
+ // startSubmit: () => {},
24
+ // endSubmit: () => {},
25
+ // sync: () => {},
26
+ // setFieldErrors: () => {},
27
+ };
28
+ exports.useStore = (0, zustand_1.default)((0, immerMiddleware_1.immer)((set, get) => ({
29
+ forms: {},
30
+ form: (formId) => { var _a; return (_a = get().forms[formId]) !== null && _a !== void 0 ? _a : unhydratedFormState; },
31
+ helpers: (formId) => ({
32
+ clearError: (name) => set((state) => {
33
+ delete state.forms[formId].fieldErrors[name];
34
+ }),
35
+ addError: (name, error) => set((state) => {
36
+ state.forms[formId].fieldErrors[name] = error;
37
+ }),
38
+ setTouched: (name, touched) => set((state) => {
39
+ state.forms[formId].touchedFields[name] = touched;
40
+ }),
41
+ reset: () => set((state) => {
42
+ state.forms[formId].fieldErrors = {};
43
+ state.forms[formId].touchedFields = {};
44
+ state.forms[formId].hasBeenSubmitted = false;
45
+ }),
46
+ startSubmit: () => set((state) => {
47
+ state.forms[formId].hasBeenSubmitted = true;
48
+ state.forms[formId].isSubmitting = true;
49
+ }),
50
+ endSubmit: () => set((state) => {
51
+ state.forms[formId].isSubmitting = false;
52
+ }),
53
+ setFieldErrors: (fieldErrors) => {
54
+ set((state) => {
55
+ state.forms[formId].fieldErrors = fieldErrors;
56
+ });
57
+ },
58
+ sync: ({ defaultValues, action, subaction, validateField, registerReceiveFocus, setFieldValueForForm, }) => set((state) => {
59
+ state.forms[formId].defaultValues = defaultValues !== null && defaultValues !== void 0 ? defaultValues : {};
60
+ state.forms[formId].action = action;
61
+ state.forms[formId].subaction = subaction;
62
+ state.forms[formId].registerReceiveFocus = registerReceiveFocus;
63
+ state.forms[formId].validateField = validateField;
64
+ state.forms[formId].hydrated = true;
65
+ state.forms[formId].setFieldValue = setFieldValueForForm;
66
+ }),
67
+ unregister: () => {
68
+ set((state) => {
69
+ delete state.forms[formId];
70
+ });
71
+ },
72
+ register: ({ defaultValues, action, subaction, validateField, registerReceiveFocus, setFieldValueForForm, }) => {
73
+ set((state) => {
74
+ state.forms[formId] = {
75
+ defaultValues: defaultValues !== null && defaultValues !== void 0 ? defaultValues : {},
76
+ setFieldValue: setFieldValueForForm,
77
+ registerReceiveFocus,
78
+ validateField,
79
+ action,
80
+ subaction,
81
+ hydrated: true,
82
+ fieldErrors: {},
83
+ isSubmitting: false,
84
+ hasBeenSubmitted: false,
85
+ touchedFields: {},
86
+ // helpers
87
+ };
88
+ });
89
+ },
90
+ }),
91
+ })));
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.useDeepEqualsMemo = exports.useIsomorphicLayoutEffect = exports.mergeRefs = exports.omit = void 0;
4
- const lodash_1 = require("lodash");
7
+ const isEqual_1 = __importDefault(require("lodash/isEqual"));
5
8
  const react_1 = require("react");
6
9
  const omit = (obj, ...keys) => {
7
10
  const result = { ...obj };
@@ -27,7 +30,7 @@ exports.mergeRefs = mergeRefs;
27
30
  exports.useIsomorphicLayoutEffect = typeof window !== "undefined" ? react_1.useLayoutEffect : react_1.useEffect;
28
31
  const useDeepEqualsMemo = (item) => {
29
32
  const ref = (0, react_1.useRef)(item);
30
- const areEqual = ref.current === item || (0, lodash_1.isEqual)(ref.current, item);
33
+ const areEqual = ref.current === item || (0, isEqual_1.default)(ref.current, item);
31
34
  (0, react_1.useEffect)(() => {
32
35
  if (!areEqual) {
33
36
  ref.current = item;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remix-validated-form",
3
- "version": "4.1.1",
3
+ "version": "4.1.4",
4
4
  "description": "Form component and utils for easy form validation in remix",
5
5
  "browser": "./browser/index.js",
6
6
  "main": "./build/index.js",
@@ -33,13 +33,13 @@
33
33
  "validation"
34
34
  ],
35
35
  "peerDependencies": {
36
- "@remix-run/react": "^1.0.6",
37
- "@remix-run/server-runtime": "^1.0.6",
36
+ "@remix-run/react": "1.x",
37
+ "@remix-run/server-runtime": "1.x",
38
38
  "react": "^17.0.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@remix-run/react": "^1.0.6",
42
- "@remix-run/server-runtime": "^1.0.6",
41
+ "@remix-run/react": "^1.2.1",
42
+ "@remix-run/server-runtime": "^1.2.1",
43
43
  "@types/lodash": "^4.14.178",
44
44
  "@types/react": "^17.0.37",
45
45
  "fetch-blob": "^3.1.3",
@@ -327,9 +327,9 @@ export function ValidatedForm<DataType>({
327
327
  }
328
328
  }
329
329
 
330
- window.addEventListener("click", handleClick);
330
+ window.addEventListener("click", handleClick, { capture: true });
331
331
  return () => {
332
- window.removeEventListener("click", handleClick);
332
+ window.removeEventListener("click", handleClick, { capture: true });
333
333
  };
334
334
  }, []);
335
335
 
@@ -354,12 +354,18 @@ export function ValidatedForm<DataType>({
354
354
  return;
355
355
  }
356
356
 
357
- if (fetcher) fetcher.submit(clickedButtonRef.current || e.currentTarget);
357
+ // We deviate from the remix code here a bit because of our async submit.
358
+ // In remix's `FormImpl`, they use `event.currentTarget` to get the form,
359
+ // but we already have the form in `formRef.current` so we can just use that.
360
+ // If we use `event.currentTarget` here, it will break because `currentTarget`
361
+ // will have changed since the start of the submission.
362
+ if (fetcher) fetcher.submit(clickedButtonRef.current || formRef.current);
358
363
  else
359
- submit(clickedButtonRef.current || e.currentTarget, {
364
+ submit(clickedButtonRef.current || formRef.current, {
360
365
  method,
361
366
  replace,
362
367
  });
368
+
363
369
  clickedButtonRef.current = null;
364
370
  }
365
371
  };
@@ -1,4 +1,4 @@
1
- import { isEqual } from "lodash";
1
+ import isEqual from "lodash/isEqual";
2
2
  import type React from "react";
3
3
  import { useEffect, useLayoutEffect, useRef } from "react";
4
4