@paragrav/rhf-utils 0.0.20 → 0.0.21

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.
@@ -14,3 +14,11 @@ export type FlatFieldErrors = Record<string, FieldError>;
14
14
  */
15
15
  declare const getFlatFieldErrors: (errors: FieldErrors) => FlatFieldErrors;
16
16
  export default getFlatFieldErrors;
17
+ /**
18
+ * Regular expression to maybe match the end of a leaf node path.
19
+ *
20
+ * i.e., `name.type`, `address.street.message`
21
+ *
22
+ * iow: dot [?: non-capturing]("type" | "message")[\b word boundary][$ end of string]
23
+ */
24
+ export declare const regexMaybeFieldErrorLeafNode: RegExp;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.regexMaybeFieldErrorLeafNode = void 0;
6
7
  const react_hook_form_1 = require("react-hook-form");
7
8
  const flattenFieldErrors_1 = __importDefault(require("./flattenFieldErrors"));
8
9
  /**
@@ -23,7 +24,7 @@ const getFlatFieldErrors = (errors) => {
23
24
  return Object.fromEntries(keys.reduce((entries, key) => {
24
25
  // look for leaf node, which would have required `type` prop (e.g., `name.type`, `address.street.type`)
25
26
  // remove `regexEndsWithType` suffix to get flat field path (e.g., `name`, `address.street`)
26
- const path = key.replace(regexEndsWithType, '');
27
+ const path = key.replace(exports.regexMaybeFieldErrorLeafNode, '');
27
28
  // if nothing replaced, then it's not a leaf node
28
29
  if (path === key)
29
30
  return entries;
@@ -37,4 +38,12 @@ const getFlatFieldErrors = (errors) => {
37
38
  }, []));
38
39
  };
39
40
  exports.default = getFlatFieldErrors;
40
- const regexEndsWithType = /\.type$/;
41
+ //
42
+ /**
43
+ * Regular expression to maybe match the end of a leaf node path.
44
+ *
45
+ * i.e., `name.type`, `address.street.message`
46
+ *
47
+ * iow: dot [?: non-capturing]("type" | "message")[\b word boundary][$ end of string]
48
+ */
49
+ exports.regexMaybeFieldErrorLeafNode = /\.(?:type|message)\b$/;
@@ -4,7 +4,7 @@ type Props = {
4
4
  path: string;
5
5
  };
6
6
  /**
7
- * Empty, hidden marker to indicate a non-field error is presented to user.
7
+ * Empty, hidden marker to indicate a non-field/non-root error is being displayed to user.
8
8
  */
9
9
  declare const FormNonFieldErrorMarker: React.FC<Props>;
10
10
  export default FormNonFieldErrorMarker;
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const FormNonFieldErrorMarker_utils_1 = __importDefault(require("./FormNonFieldErrorMarker.utils"));
8
8
  /**
9
- * Empty, hidden marker to indicate a non-field error is presented to user.
9
+ * Empty, hidden marker to indicate a non-field/non-root error is being displayed to user.
10
10
  */
11
11
  const FormNonFieldErrorMarker = ({ path }) => {
12
12
  const dataAttribute = {
@@ -10,7 +10,7 @@ const useFormErrorsHasOnlyOrphans = (formRef) => {
10
10
  // get flat field errors of orphans and all errors
11
11
  const orphans = (0, useOrphanFormErrors_1.default)(formRef);
12
12
  const errors = (0, useFormFlatFieldErrors_1.default)();
13
- // if no orphans, or no errors
13
+ // if either empty, early return
14
14
  if ([orphans, errors].some(utils_1.isEmptyObject))
15
15
  return false;
16
16
  // equal length
@@ -9,3 +9,6 @@ export { default as useFormErrorsEffect } from './errors/useFormErrorsEffect';
9
9
  export { default as useFormErrorsIfAny } from './errors/useFormErrorsIfAny';
10
10
  export { default as useFormErrorsOnChange } from './errors/useFormErrorsOnChange';
11
11
  export { default as useFormRequestSubmit } from './errors/useFormRequestSubmit';
12
+ export { default as useFormOnSubmitSuccessful } from './submit/useFormOnSubmitSuccessful';
13
+ export { default as useFormOnSubmitSuccessfulAndReset } from './submit/useFormOnSubmitSuccessfulAndReset';
14
+ export { default as useResetFormAfterSubmitSuccessful } from './submit/useResetFormOnSubmitSuccessful';
package/dist/cjs/main.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.useFormRequestSubmit = exports.useFormErrorsOnChange = exports.useFormErrorsIfAny = exports.useFormErrorsEffect = exports.useFormErrorConsoleDebug = exports.useRootFormFieldErrors = exports.useOrphanFormErrorsToConsoleError = exports.useOrphanFormErrors = exports.useFormErrorsHasOnlyOrphans = exports.FormNonFieldErrorMarkerHtmlAttribute = exports.FormNonFieldErrorMarker = void 0;
6
+ exports.useResetFormAfterSubmitSuccessful = exports.useFormOnSubmitSuccessfulAndReset = exports.useFormOnSubmitSuccessful = exports.useFormRequestSubmit = exports.useFormErrorsOnChange = exports.useFormErrorsIfAny = exports.useFormErrorsEffect = exports.useFormErrorConsoleDebug = exports.useRootFormFieldErrors = exports.useOrphanFormErrorsToConsoleError = exports.useOrphanFormErrors = exports.useFormErrorsHasOnlyOrphans = exports.FormNonFieldErrorMarkerHtmlAttribute = exports.FormNonFieldErrorMarker = void 0;
7
7
  var FormNonFieldErrorMarker_1 = require("./errors/nonfield/FormNonFieldErrorMarker");
8
8
  Object.defineProperty(exports, "FormNonFieldErrorMarker", { enumerable: true, get: function () { return __importDefault(FormNonFieldErrorMarker_1).default; } });
9
9
  var FormNonFieldErrorMarker_utils_1 = require("./errors/nonfield/FormNonFieldErrorMarker.utils");
@@ -26,3 +26,9 @@ var useFormErrorsOnChange_1 = require("./errors/useFormErrorsOnChange");
26
26
  Object.defineProperty(exports, "useFormErrorsOnChange", { enumerable: true, get: function () { return __importDefault(useFormErrorsOnChange_1).default; } });
27
27
  var useFormRequestSubmit_1 = require("./errors/useFormRequestSubmit");
28
28
  Object.defineProperty(exports, "useFormRequestSubmit", { enumerable: true, get: function () { return __importDefault(useFormRequestSubmit_1).default; } });
29
+ var useFormOnSubmitSuccessful_1 = require("./submit/useFormOnSubmitSuccessful");
30
+ Object.defineProperty(exports, "useFormOnSubmitSuccessful", { enumerable: true, get: function () { return __importDefault(useFormOnSubmitSuccessful_1).default; } });
31
+ var useFormOnSubmitSuccessfulAndReset_1 = require("./submit/useFormOnSubmitSuccessfulAndReset");
32
+ Object.defineProperty(exports, "useFormOnSubmitSuccessfulAndReset", { enumerable: true, get: function () { return __importDefault(useFormOnSubmitSuccessfulAndReset_1).default; } });
33
+ var useResetFormOnSubmitSuccessful_1 = require("./submit/useResetFormOnSubmitSuccessful");
34
+ Object.defineProperty(exports, "useResetFormAfterSubmitSuccessful", { enumerable: true, get: function () { return __importDefault(useResetFormOnSubmitSuccessful_1).default; } });
@@ -0,0 +1,2 @@
1
+ declare const useFormOnSubmitSuccessful: (callback?: () => void) => void;
2
+ export default useFormOnSubmitSuccessful;
@@ -0,0 +1,17 @@
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
+ const react_1 = __importDefault(require("react"));
7
+ const react_hook_form_1 = require("react-hook-form");
8
+ const useFormOnSubmitSuccessful = (callback) => {
9
+ const { isSubmitSuccessful } = (0, react_hook_form_1.useFormState)();
10
+ react_1.default.useEffect(() => {
11
+ if (!callback)
12
+ return;
13
+ if (isSubmitSuccessful)
14
+ callback();
15
+ }, [callback, isSubmitSuccessful]);
16
+ };
17
+ exports.default = useFormOnSubmitSuccessful;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Calls a callback after a successful submit and after a form reset.
3
+ *
4
+ * Using RHF and following its rules, we are not able to get the state `isSubmitSuccessful=true` and `isDirty=false`.
5
+ * So, this has to keep track of previous state.
6
+ *
7
+ * SubmitSuccessfulAndReset = was `isSubmitSuccessful` and now `!isSubmitSuccessful && !isDirty`
8
+ */
9
+ declare const useFormOnSubmitSuccessfulAndReset: (callback?: () => void) => void;
10
+ export default useFormOnSubmitSuccessfulAndReset;
@@ -0,0 +1,39 @@
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
+ const react_1 = __importDefault(require("react"));
7
+ const react_hook_form_1 = require("react-hook-form");
8
+ const useFormOnSubmitSuccessful_1 = __importDefault(require("./useFormOnSubmitSuccessful"));
9
+ /**
10
+ * Calls a callback after a successful submit and after a form reset.
11
+ *
12
+ * Using RHF and following its rules, we are not able to get the state `isSubmitSuccessful=true` and `isDirty=false`.
13
+ * So, this has to keep track of previous state.
14
+ *
15
+ * SubmitSuccessfulAndReset = was `isSubmitSuccessful` and now `!isSubmitSuccessful && !isDirty`
16
+ */
17
+ const useFormOnSubmitSuccessfulAndReset = (callback) => {
18
+ const { isSubmitSuccessful, isDirty } = (0, react_hook_form_1.useFormState)();
19
+ /** Tracks whether form has been successfully submitted. (Ref as it should not trigger re-render.) */
20
+ const wasSubmittedSuccessfully = react_1.default.useRef(false);
21
+ // mark as submitted successfully
22
+ (0, useFormOnSubmitSuccessful_1.default)(() => {
23
+ wasSubmittedSuccessfully.current = true;
24
+ });
25
+ react_1.default.useEffect(() => {
26
+ if (!callback)
27
+ return;
28
+ // if hasn't been submitted successfully (to distinguish from initial load)
29
+ if (!wasSubmittedSuccessfully.current)
30
+ return;
31
+ // after resetting (and on initial load), both state vars are `false`
32
+ if (!isSubmitSuccessful && !isDirty) {
33
+ callback();
34
+ // reset ref
35
+ wasSubmittedSuccessfully.current = false;
36
+ }
37
+ }, [isSubmitSuccessful, isDirty]); // eslint-disable-line react-hooks/exhaustive-deps
38
+ };
39
+ exports.default = useFormOnSubmitSuccessfulAndReset;
@@ -0,0 +1,11 @@
1
+ import type { KeepStateOptions } from 'react-hook-form';
2
+ type Options = {
3
+ enabled?: boolean;
4
+ } & KeepStateOptions;
5
+ /**
6
+ * Handle resetting after successful submit with no server validation errors.
7
+ * See `Rules` section: https://react-hook-form.com/api/useform/reset/
8
+ * Specifically: "- It's recommended to reset inside useEffect after submission."
9
+ */
10
+ declare const useResetFormAfterSubmitSuccessful: (options?: Options) => void;
11
+ export default useResetFormAfterSubmitSuccessful;
@@ -0,0 +1,21 @@
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
+ const react_hook_form_1 = require("react-hook-form");
7
+ const useFormOnSubmitSuccessful_1 = __importDefault(require("./useFormOnSubmitSuccessful"));
8
+ /**
9
+ * Handle resetting after successful submit with no server validation errors.
10
+ * See `Rules` section: https://react-hook-form.com/api/useform/reset/
11
+ * Specifically: "- It's recommended to reset inside useEffect after submission."
12
+ */
13
+ const useResetFormAfterSubmitSuccessful = (options) => {
14
+ const { reset } = (0, react_hook_form_1.useFormContext)();
15
+ (0, useFormOnSubmitSuccessful_1.default)(() => {
16
+ if (!(options === null || options === void 0 ? void 0 : options.enabled))
17
+ return;
18
+ reset(undefined, options);
19
+ });
20
+ };
21
+ exports.default = useResetFormAfterSubmitSuccessful;
@@ -1,21 +1,22 @@
1
1
  import { get as l } from "react-hook-form";
2
- import d from "./flattenFieldErrors.mjs";
3
- const f = (e) => {
4
- const s = d(e), c = Object.keys(s);
2
+ import n from "./flattenFieldErrors.mjs";
3
+ const d = (t) => {
4
+ const a = n(t), c = Object.keys(a);
5
5
  return Object.fromEntries(
6
6
  c.reduce(
7
- (t, o) => {
8
- const r = o.replace(a, "");
9
- if (r === o)
10
- return t;
11
- const n = l(e, r, void 0);
12
- return n && t.push([r, n]), t;
7
+ (r, o) => {
8
+ const e = o.replace(f, "");
9
+ if (e === o)
10
+ return r;
11
+ const s = l(t, e, void 0);
12
+ return s && r.push([e, s]), r;
13
13
  },
14
14
  []
15
15
  // entries
16
16
  )
17
17
  );
18
- }, u = f, a = /\.type$/;
18
+ }, u = d, f = /\.(?:type|message)\b$/;
19
19
  export {
20
- u as default
20
+ u as default,
21
+ f as regexMaybeFieldErrorLeafNode
21
22
  };
package/dist/esm/main.mjs CHANGED
@@ -1,24 +1,30 @@
1
1
  import { default as e } from "./errors/nonfield/FormNonFieldErrorMarker.mjs";
2
2
  import { default as t } from "./errors/nonfield/FormNonFieldErrorMarker.utils.mjs";
3
- import { default as f } from "./errors/orphan/useFormErrorsHasOnlyOrphans.mjs";
4
- import { default as u } from "./errors/orphan/useOrphanFormErrors.mjs";
3
+ import { default as a } from "./errors/orphan/useFormErrorsHasOnlyOrphans.mjs";
4
+ import { default as m } from "./errors/orphan/useOrphanFormErrors.mjs";
5
5
  import { default as d } from "./errors/orphan/useOrphanFormErrorsToConsoleError.mjs";
6
6
  import { default as F } from "./errors/root/useRootFormFieldErrors.mjs";
7
- import { default as n } from "./errors/useFormErrorConsoleDebug.mjs";
7
+ import { default as x } from "./errors/useFormErrorConsoleDebug.mjs";
8
8
  import { default as i } from "./errors/useFormErrorsEffect.mjs";
9
- import { default as h } from "./errors/useFormErrorsIfAny.mjs";
10
- import { default as C } from "./errors/useFormErrorsOnChange.mjs";
11
- import { default as k } from "./errors/useFormRequestSubmit.mjs";
9
+ import { default as O } from "./errors/useFormErrorsIfAny.mjs";
10
+ import { default as b } from "./errors/useFormErrorsOnChange.mjs";
11
+ import { default as A } from "./errors/useFormRequestSubmit.mjs";
12
+ import { default as C } from "./submit/useFormOnSubmitSuccessful.mjs";
13
+ import { default as k } from "./submit/useFormOnSubmitSuccessfulAndReset.mjs";
14
+ import { default as H } from "./submit/useResetFormOnSubmitSuccessful.mjs";
12
15
  export {
13
16
  e as FormNonFieldErrorMarker,
14
17
  t as FormNonFieldErrorMarkerHtmlAttribute,
15
- n as useFormErrorConsoleDebug,
18
+ x as useFormErrorConsoleDebug,
16
19
  i as useFormErrorsEffect,
17
- f as useFormErrorsHasOnlyOrphans,
18
- h as useFormErrorsIfAny,
19
- C as useFormErrorsOnChange,
20
- k as useFormRequestSubmit,
21
- u as useOrphanFormErrors,
20
+ a as useFormErrorsHasOnlyOrphans,
21
+ O as useFormErrorsIfAny,
22
+ b as useFormErrorsOnChange,
23
+ C as useFormOnSubmitSuccessful,
24
+ k as useFormOnSubmitSuccessfulAndReset,
25
+ A as useFormRequestSubmit,
26
+ m as useOrphanFormErrors,
22
27
  d as useOrphanFormErrorsToConsoleError,
28
+ H as useResetFormAfterSubmitSuccessful,
23
29
  F as useRootFormFieldErrors
24
30
  };
@@ -0,0 +1,11 @@
1
+ import u from "react";
2
+ import { useFormState as e } from "react-hook-form";
3
+ const o = (s) => {
4
+ const { isSubmitSuccessful: t } = e();
5
+ u.useEffect(() => {
6
+ s && t && s();
7
+ }, [s, t]);
8
+ }, r = o;
9
+ export {
10
+ r as default
11
+ };
@@ -0,0 +1,14 @@
1
+ import r from "react";
2
+ import { useFormState as c } from "react-hook-form";
3
+ import f from "./useFormOnSubmitSuccessful.mjs";
4
+ const m = (s) => {
5
+ const { isSubmitSuccessful: t, isDirty: u } = c(), e = r.useRef(!1);
6
+ f(() => {
7
+ e.current = !0;
8
+ }), r.useEffect(() => {
9
+ s && e.current && !t && !u && (s(), e.current = !1);
10
+ }, [t, u]);
11
+ }, S = m;
12
+ export {
13
+ S as default
14
+ };
@@ -0,0 +1,11 @@
1
+ import { useFormContext as r } from "react-hook-form";
2
+ import t from "./useFormOnSubmitSuccessful.mjs";
3
+ const s = (e) => {
4
+ const { reset: u } = r();
5
+ t(() => {
6
+ e != null && e.enabled && u(void 0, e);
7
+ });
8
+ }, f = s;
9
+ export {
10
+ f as default
11
+ };
@@ -15,3 +15,11 @@ export type FlatFieldErrors = Record<string, FieldError>;
15
15
  */
16
16
  declare const getFlatFieldErrors: (errors: FieldErrors) => FlatFieldErrors;
17
17
  export default getFlatFieldErrors;
18
+ /**
19
+ * Regular expression to maybe match the end of a leaf node path.
20
+ *
21
+ * i.e., `name.type`, `address.street.message`
22
+ *
23
+ * iow: dot [?: non-capturing]("type" | "message")[\b word boundary][$ end of string]
24
+ */
25
+ export declare const regexMaybeFieldErrorLeafNode: RegExp;
@@ -4,7 +4,7 @@ type Props = {
4
4
  path: string;
5
5
  };
6
6
  /**
7
- * Empty, hidden marker to indicate a non-field error is presented to user.
7
+ * Empty, hidden marker to indicate a non-field/non-root error is being displayed to user.
8
8
  */
9
9
  declare const FormNonFieldErrorMarker: React.FC<Props>;
10
10
  export default FormNonFieldErrorMarker;
@@ -9,3 +9,6 @@ export { default as useFormErrorsEffect } from './errors/useFormErrorsEffect';
9
9
  export { default as useFormErrorsIfAny } from './errors/useFormErrorsIfAny';
10
10
  export { default as useFormErrorsOnChange } from './errors/useFormErrorsOnChange';
11
11
  export { default as useFormRequestSubmit } from './errors/useFormRequestSubmit';
12
+ export { default as useFormOnSubmitSuccessful } from './submit/useFormOnSubmitSuccessful';
13
+ export { default as useFormOnSubmitSuccessfulAndReset } from './submit/useFormOnSubmitSuccessfulAndReset';
14
+ export { default as useResetFormAfterSubmitSuccessful } from './submit/useResetFormOnSubmitSuccessful';
@@ -0,0 +1,2 @@
1
+ declare const useFormOnSubmitSuccessful: (callback?: () => void) => void;
2
+ export default useFormOnSubmitSuccessful;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Calls a callback after a successful submit and after a form reset.
3
+ *
4
+ * Using RHF and following its rules, we are not able to get the state `isSubmitSuccessful=true` and `isDirty=false`.
5
+ * So, this has to keep track of previous state.
6
+ *
7
+ * SubmitSuccessfulAndReset = was `isSubmitSuccessful` and now `!isSubmitSuccessful && !isDirty`
8
+ */
9
+ declare const useFormOnSubmitSuccessfulAndReset: (callback?: () => void) => void;
10
+ export default useFormOnSubmitSuccessfulAndReset;
@@ -0,0 +1,12 @@
1
+ import { KeepStateOptions } from 'react-hook-form';
2
+
3
+ type Options = {
4
+ enabled?: boolean;
5
+ } & KeepStateOptions;
6
+ /**
7
+ * Handle resetting after successful submit with no server validation errors.
8
+ * See `Rules` section: https://react-hook-form.com/api/useform/reset/
9
+ * Specifically: "- It's recommended to reset inside useEffect after submission."
10
+ */
11
+ declare const useResetFormAfterSubmitSuccessful: (options?: Options) => void;
12
+ export default useResetFormAfterSubmitSuccessful;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@paragrav/rhf-utils",
3
3
  "author": "paragrav.dev",
4
4
  "license": "MIT",
5
- "version": "0.0.20",
5
+ "version": "0.0.21",
6
6
  "description": "Integration utilities for react-hook-form.",
7
7
  "type": "module",
8
8
  "sideEffects": false,
@@ -71,6 +71,21 @@
71
71
  "import": "./dist/esm/errors/root/useRootFormFieldErrors.mjs",
72
72
  "require": "./dist/cjs/errors/root/useRootFormFieldErrors.cjs",
73
73
  "types": "./dist/types/errors/root/useRootFormFieldErrors.d.ts"
74
+ },
75
+ "./submit/useFormOnSubmitSuccessful": {
76
+ "import": "./dist/esm/submit/useFormOnSubmitSuccessful.mjs",
77
+ "require": "./dist/cjs/submit/useFormOnSubmitSuccessful.cjs",
78
+ "types": "./dist/types/submit/useFormOnSubmitSuccessful.d.ts"
79
+ },
80
+ "./submit/useFormOnSubmitSuccessfulAndReset": {
81
+ "import": "./dist/esm/submit/useFormOnSubmitSuccessfulAndReset.mjs",
82
+ "require": "./dist/cjs/submit/useFormOnSubmitSuccessfulAndReset.cjs",
83
+ "types": "./dist/types/submit/useFormOnSubmitSuccessfulAndReset.d.ts"
84
+ },
85
+ "./submit/useResetFormAfterSubmitSuccessful": {
86
+ "import": "./dist/esm/submit/useResetFormAfterSubmitSuccessful.mjs",
87
+ "require": "./dist/cjs/submit/useResetFormAfterSubmitSuccessful.cjs",
88
+ "types": "./dist/types/submit/useResetFormAfterSubmitSuccessful.d.ts"
74
89
  }
75
90
  },
76
91
  "scripts": {