envoc-form 2.0.1-9 → 2.0.1

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 (141) hide show
  1. package/README.md +7 -7
  2. package/dist/css/envoc-form-styles.css +7 -6
  3. package/dist/css/envoc-form-styles.css.map +1 -1
  4. package/es/AddressInput/AddressInput.js +7 -6
  5. package/es/ConfirmBaseForm/ConfirmBaseForm.js +3 -2
  6. package/es/ConfirmDeleteForm/ConfirmDeleteForm.js +2 -1
  7. package/es/DatePickerInput/DatePickerInput.js +22 -5
  8. package/es/FileInput/DefaultFileList.js +3 -2
  9. package/es/FileInput/DropzoneFileInput.js +15 -12
  10. package/es/FileInput/FileInput.js +31 -9
  11. package/es/Form/Form.js +2 -1
  12. package/es/FormGroupWrapper.js +2 -1
  13. package/es/FormInput/FormInput.js +12 -6
  14. package/es/FormInputArray/FormInputArray.js +39 -24
  15. package/es/IconInput.js +2 -1
  16. package/es/ReactSelectField/ReactSelectField.js +6 -3
  17. package/es/SubmitFormButton.js +2 -1
  18. package/es/__Tests__/FormTestBase.js +5 -2
  19. package/es/normalizers.js +10 -5
  20. package/es/useStandardFormInput.js +4 -2
  21. package/lib/AddressInput/AddressInput.js +14 -8
  22. package/lib/ConfirmBaseForm/ConfirmBaseForm.js +4 -2
  23. package/lib/ConfirmDeleteForm/ConfirmDeleteForm.js +3 -1
  24. package/lib/DatePickerInput/DatePickerInput.js +25 -5
  25. package/lib/FileInput/DefaultFileList.js +3 -2
  26. package/lib/FileInput/DropzoneFileInput.js +17 -12
  27. package/lib/FileInput/FileInput.js +39 -10
  28. package/lib/Form/Form.js +9 -3
  29. package/lib/Form/FormBasedPreventNavigation.js +5 -1
  30. package/lib/FormGroupWrapper.js +3 -1
  31. package/lib/FormInput/FormInput.js +13 -6
  32. package/lib/FormInputArray/FormInputArray.js +47 -26
  33. package/lib/FormSection.js +5 -1
  34. package/lib/IconInput.js +3 -1
  35. package/lib/ReactSelectField/ReactSelectField.js +13 -5
  36. package/lib/ReactSelectField/index.js +6 -2
  37. package/lib/SubmitFormButton.js +3 -1
  38. package/lib/__Tests__/FormTestBase.js +6 -2
  39. package/lib/index.js +7 -3
  40. package/lib/normalizers.js +10 -5
  41. package/lib/useStandardFormInput.js +5 -2
  42. package/lib/validators/index.js +5 -1
  43. package/package.json +99 -93
  44. package/src/AddressInput/AddesssInput.test.js +23 -23
  45. package/src/AddressInput/AddressInput.js +73 -73
  46. package/src/AddressInput/UsStates.js +53 -53
  47. package/src/AddressInput/__snapshots__/AddesssInput.test.js.snap +207 -207
  48. package/src/AddressInput/index.js +2 -2
  49. package/src/BoolInput/BoolInput.js +7 -7
  50. package/src/BoolInput/BoolInput.test.js +23 -23
  51. package/src/BoolInput/InlineBoolInput.js +7 -7
  52. package/src/BoolInput/__snapshots__/BoolInput.test.js.snap +89 -89
  53. package/src/BoolInput/boolOptions.js +6 -6
  54. package/src/BoolInput/index.js +4 -4
  55. package/src/ConfirmBaseForm/ConfirmBaseForm.js +37 -37
  56. package/src/ConfirmBaseForm/ConfirmBaseForm.test.js +14 -14
  57. package/src/ConfirmBaseForm/__snapshots__/ConfirmBaseForm.test.js.snap +23 -23
  58. package/src/ConfirmBaseForm/index.js +1 -1
  59. package/src/ConfirmDeleteForm/ConfirmDeleteForm.js +39 -39
  60. package/src/ConfirmDeleteForm/ConfirmDeleteForm.test.js +24 -24
  61. package/src/ConfirmDeleteForm/__snapshots__/ConfirmDeleteForm.test.js.snap +25 -25
  62. package/src/ConfirmDeleteForm/index.js +1 -1
  63. package/src/DatePickerInput/DatePickerInput.js +58 -46
  64. package/src/DatePickerInput/DatePickerInput.test.js +74 -74
  65. package/src/DatePickerInput/__snapshots__/DatePickerInput.test.js.snap +134 -134
  66. package/src/DatePickerInput/date-picker-input.scss +42 -42
  67. package/src/DatePickerInput/index.js +3 -3
  68. package/src/ErrorScrollTarget.js +6 -6
  69. package/src/FileInput/DefaultFileList.js +39 -39
  70. package/src/FileInput/DropzoneFileInput.js +56 -55
  71. package/src/FileInput/DropzoneFileInput.test.js +24 -15
  72. package/src/FileInput/FileInput.js +77 -49
  73. package/src/FileInput/FileInput.test.js +24 -15
  74. package/src/FileInput/__snapshots__/DropzoneFileInput.test.js.snap +57 -28
  75. package/src/FileInput/__snapshots__/FileInput.test.js.snap +58 -22
  76. package/src/FileInput/file-input.scss +57 -57
  77. package/src/FileInput/index.js +4 -4
  78. package/src/Form/FocusError.js +48 -48
  79. package/src/Form/Form.js +139 -139
  80. package/src/Form/Form.test.js +23 -23
  81. package/src/Form/FormBasedPreventNavigation.js +25 -25
  82. package/src/Form/ServerErrorContext.js +7 -7
  83. package/src/Form/__snapshots__/Form.test.js.snap +9 -9
  84. package/src/Form/index.js +3 -3
  85. package/src/FormGroup.js +30 -30
  86. package/src/FormGroupWrapper.js +28 -28
  87. package/src/FormInput/FormInput.js +144 -144
  88. package/src/FormInput/FormInput.test.js +66 -66
  89. package/src/FormInput/__snapshots__/FormInput.test.js.snap +323 -316
  90. package/src/FormInput/form-input.scss +9 -9
  91. package/src/FormInput/index.js +2 -2
  92. package/src/FormInputArray/FormInputArray.js +224 -210
  93. package/src/FormInputArray/FormInputArray.test.js +108 -59
  94. package/src/FormInputArray/__snapshots__/FormInputArray.test.js.snap +52 -40
  95. package/src/FormInputArray/form-input-array.scss +13 -8
  96. package/src/FormInputArray/index.js +2 -2
  97. package/src/FormSection.js +13 -13
  98. package/src/IconInput.js +31 -31
  99. package/src/InlineFormInput/InlineFormInput.js +6 -6
  100. package/src/InlineFormInput/InlineFormInput.test.js +23 -23
  101. package/src/InlineFormInput/__snapshots__/InlineFormInput.test.js.snap +26 -26
  102. package/src/InlineFormInput/index.js +3 -3
  103. package/src/InlineFormInput/inline-form-input.scss +3 -3
  104. package/src/MoneyInput/InlineMoneyInput.js +7 -7
  105. package/src/MoneyInput/MoneyInput.js +7 -7
  106. package/src/MoneyInput/MoneyInputs.test.js +43 -43
  107. package/src/MoneyInput/__snapshots__/MoneyInputs.test.js.snap +81 -81
  108. package/src/MoneyInput/index.js +4 -4
  109. package/src/MoneyInput/money-input.scss +3 -3
  110. package/src/MoneyInput/moneyInputProps.js +12 -12
  111. package/src/NestedFormFieldContext.js +6 -6
  112. package/src/ReactSelectField/ReactSelectField.js +122 -120
  113. package/src/ReactSelectField/index.js +6 -6
  114. package/src/ReactSelectField/react-select-field.scss +5 -5
  115. package/src/StandardFormActions.js +27 -27
  116. package/src/SubmitFormButton.js +28 -28
  117. package/src/__Tests__/FormTestBase.js +14 -11
  118. package/src/__Tests__/IconInput.test.js +23 -23
  119. package/src/__Tests__/StandardFormActions.test.js +23 -23
  120. package/src/__Tests__/SubmitFormButton.test.js +23 -23
  121. package/src/__Tests__/__snapshots__/IconInput.test.js.snap +38 -38
  122. package/src/__Tests__/__snapshots__/StandardFormActions.test.js.snap +25 -25
  123. package/src/__Tests__/__snapshots__/SubmitFormButton.test.js.snap +18 -18
  124. package/src/__Tests__/index.js +2 -2
  125. package/src/_variables.scss +11 -11
  126. package/src/index.js +33 -33
  127. package/src/normalizers.js +42 -32
  128. package/src/selectors.js +3 -3
  129. package/src/styles.scss +7 -7
  130. package/src/useStandardFormInput.js +118 -118
  131. package/src/utils/index.js +3 -3
  132. package/src/utils/objectContainsNonSerializableProperty.js +15 -15
  133. package/src/utils/objectContainsNonSerializableProperty.test.js +49 -49
  134. package/src/utils/objectToFormData.js +89 -89
  135. package/src/utils/objectToFormData.test.js +76 -76
  136. package/src/utils/typeChecks.js +18 -18
  137. package/src/validators/index.js +2 -2
  138. package/src/validators/validators.js +93 -93
  139. package/src/validators/validators.test.js +79 -79
  140. package/CHANGELOG.json +0 -95
  141. package/CHANGELOG.md +0 -58
@@ -1,48 +1,48 @@
1
- import { useEffect } from 'react';
2
- import { useFormikContext } from 'formik';
3
- import smoothscroll from 'smoothscroll-polyfill';
4
-
5
- export default function FocusError(props) {
6
- const { errors, isSubmitting, isValidating } = useFormikContext();
7
- smoothscroll.polyfill();
8
- useEffect(() => {
9
- if (!isSubmitting || isValidating) {
10
- return;
11
- }
12
- //This block handles any front-end input validation errors
13
- //e.g. required fields, max characters, etc
14
- const keys = Object.keys(errors);
15
- if (keys.length > 0) {
16
- return scrollToErrorElement(keys);
17
- }
18
- //This block handles any input-specific server-side errors
19
- //e.g. improper email formatting, invalid phone number, etc.
20
- if (
21
- props.serverErrors.errors &&
22
- Object.values(props.serverErrors.errors).some((x) => !!x)
23
- ) {
24
- const names = Object.keys(props.serverErrors.errors);
25
- return scrollToErrorElement(names);
26
- }
27
- }, [errors, isSubmitting, isValidating, props]);
28
- return null;
29
- }
30
-
31
- const scrollToErrorElement = (keys) => {
32
- let firstErrorElement = document.getElementById(
33
- `${keys[0].toLowerCase()}-error-scroll-target`
34
- );
35
- if (firstErrorElement == null || firstErrorElement.parentNode == null) {
36
- return;
37
- }
38
- firstErrorElement = firstErrorElement.parentNode;
39
- const headerOffset = -110;
40
- const y =
41
- firstErrorElement.getBoundingClientRect().top +
42
- window.pageYOffset +
43
- headerOffset;
44
- window.scrollTo({ top: y, behavior: 'smooth' });
45
- setTimeout(() => {
46
- firstErrorElement.focus();
47
- }, 500);
48
- };
1
+ import { useEffect } from 'react';
2
+ import { useFormikContext } from 'formik';
3
+ import smoothscroll from 'smoothscroll-polyfill';
4
+
5
+ export default function FocusError(props) {
6
+ const { errors, isSubmitting, isValidating } = useFormikContext();
7
+ smoothscroll.polyfill();
8
+ useEffect(() => {
9
+ if (!isSubmitting || isValidating) {
10
+ return;
11
+ }
12
+ //This block handles any front-end input validation errors
13
+ //e.g. required fields, max characters, etc
14
+ const keys = Object.keys(errors);
15
+ if (keys.length > 0) {
16
+ return scrollToErrorElement(keys);
17
+ }
18
+ //This block handles any input-specific server-side errors
19
+ //e.g. improper email formatting, invalid phone number, etc.
20
+ if (
21
+ props.serverErrors.errors &&
22
+ Object.values(props.serverErrors.errors).some((x) => !!x)
23
+ ) {
24
+ const names = Object.keys(props.serverErrors.errors);
25
+ return scrollToErrorElement(names);
26
+ }
27
+ }, [errors, isSubmitting, isValidating, props]);
28
+ return null;
29
+ }
30
+
31
+ const scrollToErrorElement = (keys) => {
32
+ let firstErrorElement = document.getElementById(
33
+ `${keys[0].toLowerCase()}-error-scroll-target`
34
+ );
35
+ if (firstErrorElement == null || firstErrorElement.parentNode == null) {
36
+ return;
37
+ }
38
+ firstErrorElement = firstErrorElement.parentNode;
39
+ const headerOffset = -110;
40
+ const y =
41
+ firstErrorElement.getBoundingClientRect().top +
42
+ window.pageYOffset +
43
+ headerOffset;
44
+ window.scrollTo({ top: y, behavior: 'smooth' });
45
+ setTimeout(() => {
46
+ firstErrorElement.focus();
47
+ }, 500);
48
+ };
package/src/Form/Form.js CHANGED
@@ -1,139 +1,139 @@
1
- import React, { useState, useMemo, useContext } from 'react';
2
- import PropTypes from 'prop-types';
3
- import FocusError from './FocusError';
4
- import { Formik, Form as FormikFormWrapper, useFormikContext } from 'formik';
5
- import FormBasedPreventNavigation from './FormBasedPreventNavigation';
6
- import ServerErrorContext from './ServerErrorContext';
7
- import {
8
- objectToFormData,
9
- objectContainsNonSerializableProperty,
10
- } from '../utils';
11
-
12
- export default function Form({
13
- children,
14
- className,
15
- style,
16
- ignoreLostChanges,
17
- onSubmit,
18
- initialValues,
19
- ...props
20
- }) {
21
- // formik resets all error on each blur (with our settings)
22
- // this means that ALL errors from the server disappear when any one field is blurred
23
- // So, we have to store server errors ourselves
24
- // Since we only use useStandardFormInput, that means there is only one consumer
25
- const [serverErrors, setServerErrors] = useState(null);
26
- const serverErrorContextValue = useMemo(
27
- () => ({
28
- errors: serverErrors,
29
- getError: (path) => {
30
- const lowered = path.toLowerCase();
31
- return serverErrors && serverErrors[lowered];
32
- },
33
- setError: (path, errorMessage) => {
34
- const lowered = path.toLowerCase();
35
- setServerErrors(
36
- Object.assign({}, serverErrors, {
37
- [lowered]: !errorMessage ? undefined : errorMessage,
38
- })
39
- );
40
- },
41
- }),
42
- [serverErrors]
43
- );
44
-
45
- return (
46
- <Formik
47
- validateOnChange={false}
48
- validateOnBlur={true}
49
- validateOnMount={false}
50
- initialValues={initialValues || {}}
51
- onSubmit={handleSubmit}
52
- {...props}>
53
- <ServerErrorContext.Provider value={serverErrorContextValue}>
54
- <FormikFormWrapper className={className} style={style}>
55
- <FocusError serverErrors={serverErrorContextValue} />
56
- <FormBasedPreventNavigation ignoreLostChanges={ignoreLostChanges} />
57
- {typeof children === 'function' ? children(props) : children}
58
- </FormikFormWrapper>
59
- </ServerErrorContext.Provider>
60
- </Formik>
61
- );
62
-
63
- function handleSubmit(values, formikBag) {
64
- let formData = null;
65
- if (objectContainsNonSerializableProperty(values)) {
66
- formData = objectToFormData(values, {
67
- indices: true,
68
- dotNotation: true,
69
- allowEmptyArrays: true,
70
- noFileListBrackets: true,
71
- });
72
- }
73
-
74
- return Promise.resolve(onSubmit(formData || values))
75
- .then((response) => {
76
- return response;
77
- })
78
- .catch((err) => {
79
- //this is an http error
80
- if (
81
- err &&
82
- err.response &&
83
- err.response.data &&
84
- err.response.data.validationFailures
85
- ) {
86
- try {
87
- const serverErrors = err.response.data.validationFailures
88
- .map((error) => ({
89
- // case insensitive path
90
- path: error.propertyName.toLowerCase(),
91
- errorMessage: error.errorMessage,
92
- }))
93
- .reduce((acc, value) => {
94
- // for simplicity, just keep it to one server error at a time per path
95
- acc[value.path] = value.errorMessage;
96
- return acc;
97
- }, {});
98
- setServerErrors(serverErrors);
99
- } catch (err) {
100
- console.error('Failure to getErrorObject');
101
- console.error(err);
102
- throw err;
103
- }
104
- }
105
- throw err;
106
- });
107
- }
108
- }
109
-
110
- Form.DisplayFormState = DisplayFormState;
111
- function DisplayFormState() {
112
- const formState = useFormikContext();
113
- const serverErrorContext = useContext(ServerErrorContext);
114
- return (
115
- <div style={{ margin: '1rem 0' }}>
116
- <pre
117
- style={{
118
- background: '#f6f8fa',
119
- fontSize: '.65rem',
120
- padding: '.5rem',
121
- }}>
122
- {serverErrorContext && serverErrorContext.errors && (
123
- <div>
124
- <strong>serverErrors = </strong>
125
- {JSON.stringify(serverErrorContext.errors, null, 2)}
126
- </div>
127
- )}
128
- <strong>formState = </strong>
129
- {JSON.stringify(formState, null, 2)}
130
- </pre>
131
- </div>
132
- );
133
- }
134
-
135
- Form.propTypes = {
136
- ignoreLostChanges: PropTypes.bool,
137
- onSubmit: PropTypes.func.isRequired,
138
- initialValues: PropTypes.object,
139
- };
1
+ import React, { useState, useMemo, useContext } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import FocusError from './FocusError';
4
+ import { Formik, Form as FormikFormWrapper, useFormikContext } from 'formik';
5
+ import FormBasedPreventNavigation from './FormBasedPreventNavigation';
6
+ import ServerErrorContext from './ServerErrorContext';
7
+ import {
8
+ objectToFormData,
9
+ objectContainsNonSerializableProperty,
10
+ } from '../utils';
11
+
12
+ export default function Form({
13
+ children,
14
+ className,
15
+ style,
16
+ ignoreLostChanges,
17
+ onSubmit,
18
+ initialValues,
19
+ ...props
20
+ }) {
21
+ // formik resets all error on each blur (with our settings)
22
+ // this means that ALL errors from the server disappear when any one field is blurred
23
+ // So, we have to store server errors ourselves
24
+ // Since we only use useStandardFormInput, that means there is only one consumer
25
+ const [serverErrors, setServerErrors] = useState(null);
26
+ const serverErrorContextValue = useMemo(
27
+ () => ({
28
+ errors: serverErrors,
29
+ getError: (path) => {
30
+ const lowered = path.toLowerCase();
31
+ return serverErrors && serverErrors[lowered];
32
+ },
33
+ setError: (path, errorMessage) => {
34
+ const lowered = path.toLowerCase();
35
+ setServerErrors(
36
+ Object.assign({}, serverErrors, {
37
+ [lowered]: !errorMessage ? undefined : errorMessage,
38
+ })
39
+ );
40
+ },
41
+ }),
42
+ [serverErrors]
43
+ );
44
+
45
+ return (
46
+ <Formik
47
+ validateOnChange={false}
48
+ validateOnBlur={true}
49
+ validateOnMount={false}
50
+ initialValues={initialValues || {}}
51
+ onSubmit={handleSubmit}
52
+ {...props}>
53
+ <ServerErrorContext.Provider value={serverErrorContextValue}>
54
+ <FormikFormWrapper className={className} style={style}>
55
+ <FocusError serverErrors={serverErrorContextValue} />
56
+ <FormBasedPreventNavigation ignoreLostChanges={ignoreLostChanges} />
57
+ {typeof children === 'function' ? children(props) : children}
58
+ </FormikFormWrapper>
59
+ </ServerErrorContext.Provider>
60
+ </Formik>
61
+ );
62
+
63
+ function handleSubmit(values, formikBag) {
64
+ let formData = null;
65
+ if (objectContainsNonSerializableProperty(values)) {
66
+ formData = objectToFormData(values, {
67
+ indices: true,
68
+ dotNotation: true,
69
+ allowEmptyArrays: true,
70
+ noFileListBrackets: true,
71
+ });
72
+ }
73
+
74
+ return Promise.resolve(onSubmit(formData || values))
75
+ .then((response) => {
76
+ return response;
77
+ })
78
+ .catch((err) => {
79
+ //this is an http error
80
+ if (
81
+ err &&
82
+ err.response &&
83
+ err.response.data &&
84
+ err.response.data.validationFailures
85
+ ) {
86
+ try {
87
+ const serverErrors = err.response.data.validationFailures
88
+ .map((error) => ({
89
+ // case insensitive path
90
+ path: error.propertyName.toLowerCase(),
91
+ errorMessage: error.errorMessage,
92
+ }))
93
+ .reduce((acc, value) => {
94
+ // for simplicity, just keep it to one server error at a time per path
95
+ acc[value.path] = value.errorMessage;
96
+ return acc;
97
+ }, {});
98
+ setServerErrors(serverErrors);
99
+ } catch (err) {
100
+ console.error('Failure to getErrorObject');
101
+ console.error(err);
102
+ throw err;
103
+ }
104
+ }
105
+ throw err;
106
+ });
107
+ }
108
+ }
109
+
110
+ Form.DisplayFormState = DisplayFormState;
111
+ function DisplayFormState() {
112
+ const formState = useFormikContext();
113
+ const serverErrorContext = useContext(ServerErrorContext);
114
+ return (
115
+ <div style={{ margin: '1rem 0' }}>
116
+ <pre
117
+ style={{
118
+ background: '#f6f8fa',
119
+ fontSize: '.65rem',
120
+ padding: '.5rem',
121
+ }}>
122
+ {serverErrorContext && serverErrorContext.errors && (
123
+ <div>
124
+ <strong>serverErrors = </strong>
125
+ {JSON.stringify(serverErrorContext.errors, null, 2)}
126
+ </div>
127
+ )}
128
+ <strong>formState = </strong>
129
+ {JSON.stringify(formState, null, 2)}
130
+ </pre>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ Form.propTypes = {
136
+ ignoreLostChanges: PropTypes.bool,
137
+ onSubmit: PropTypes.func.isRequired,
138
+ initialValues: PropTypes.object,
139
+ };
@@ -1,23 +1,23 @@
1
- import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import { HashRouter } from 'react-router-dom';
4
- import Form from './Form';
5
-
6
- describe('MoneyInput', () => {
7
- it('renders without crashing', () => {
8
- render(
9
- <HashRouter>
10
- <Form onSubmit={() => {}} />
11
- </HashRouter>
12
- );
13
- });
14
-
15
- it('has matching snapshot', () => {
16
- const renderResult = render(
17
- <HashRouter>
18
- <Form onSubmit={() => {}} />
19
- </HashRouter>
20
- );
21
- expect(renderResult.asFragment()).toMatchSnapshot();
22
- });
23
- });
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { HashRouter } from 'react-router-dom';
4
+ import Form from './Form';
5
+
6
+ describe('MoneyInput', () => {
7
+ it('renders without crashing', () => {
8
+ render(
9
+ <HashRouter>
10
+ <Form onSubmit={() => {}} />
11
+ </HashRouter>
12
+ );
13
+ });
14
+
15
+ it('has matching snapshot', () => {
16
+ const renderResult = render(
17
+ <HashRouter>
18
+ <Form onSubmit={() => {}} />
19
+ </HashRouter>
20
+ );
21
+ expect(renderResult.asFragment()).toMatchSnapshot();
22
+ });
23
+ });
@@ -1,25 +1,25 @@
1
- import React, { useEffect } from 'react';
2
- import { Prompt } from 'react-router-dom';
3
- import { useFormikContext } from 'formik';
4
-
5
- export default function FormBasedPreventNavigation({
6
- ignoreLostChanges,
7
- promptMessage = 'Changes you made may not be saved.',
8
- }) {
9
- const { dirty, isSubmitting } = useFormikContext();
10
- const preventNavigate = !ignoreLostChanges && dirty && !isSubmitting;
11
- useEffect(() => {
12
- if (!preventNavigate) {
13
- return;
14
- }
15
- window.addEventListener('beforeunload', beforeUnload);
16
- return () => {
17
- window.removeEventListener('beforeunload', beforeUnload);
18
- };
19
- function beforeUnload(e) {
20
- e.preventDefault();
21
- e.returnValue = promptMessage;
22
- }
23
- }, [preventNavigate, promptMessage]);
24
- return <Prompt when={preventNavigate} message={promptMessage} />;
25
- }
1
+ import React, { useEffect } from 'react';
2
+ import { Prompt } from 'react-router-dom';
3
+ import { useFormikContext } from 'formik';
4
+
5
+ export default function FormBasedPreventNavigation({
6
+ ignoreLostChanges,
7
+ promptMessage = 'Changes you made may not be saved.',
8
+ }) {
9
+ const { dirty, isSubmitting } = useFormikContext();
10
+ const preventNavigate = !ignoreLostChanges && dirty && !isSubmitting;
11
+ useEffect(() => {
12
+ if (!preventNavigate) {
13
+ return;
14
+ }
15
+ window.addEventListener('beforeunload', beforeUnload);
16
+ return () => {
17
+ window.removeEventListener('beforeunload', beforeUnload);
18
+ };
19
+ function beforeUnload(e) {
20
+ e.preventDefault();
21
+ e.returnValue = promptMessage;
22
+ }
23
+ }, [preventNavigate, promptMessage]);
24
+ return <Prompt when={preventNavigate} message={promptMessage} />;
25
+ }
@@ -1,7 +1,7 @@
1
- import React from 'react';
2
-
3
- const ServerErrorContext = React.createContext({
4
- getError: (path) => {},
5
- setError: (path, errorMessage) => {},
6
- });
7
- export default ServerErrorContext;
1
+ import React from 'react';
2
+
3
+ const ServerErrorContext = React.createContext({
4
+ getError: (path) => {},
5
+ setError: (path, errorMessage) => {},
6
+ });
7
+ export default ServerErrorContext;
@@ -1,9 +1,9 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`MoneyInput has matching snapshot 1`] = `
4
- <DocumentFragment>
5
- <form
6
- action="#"
7
- />
8
- </DocumentFragment>
9
- `;
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`MoneyInput has matching snapshot 1`] = `
4
+ <DocumentFragment>
5
+ <form
6
+ action="#"
7
+ />
8
+ </DocumentFragment>
9
+ `;
package/src/Form/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import Form from './Form';
2
- import ServerErrorContext from './ServerErrorContext';
3
- export { Form as default, ServerErrorContext };
1
+ import Form from './Form';
2
+ import ServerErrorContext from './ServerErrorContext';
3
+ export { Form as default, ServerErrorContext };
package/src/FormGroup.js CHANGED
@@ -1,30 +1,30 @@
1
- import React from 'react';
2
- import {
3
- FormGroup as BootstrapFormGroup,
4
- Label,
5
- FormFeedback,
6
- FormText,
7
- Alert,
8
- } from 'reactstrap';
9
-
10
- const FormGroup = ({
11
- label,
12
- id,
13
- helpText,
14
- className,
15
- style,
16
- children,
17
- meta,
18
- }) => {
19
- return (
20
- <BootstrapFormGroup className={className} style={style}>
21
- {!!meta.warning && <Alert color="warning">{meta.warning}</Alert>}
22
- {label && <Label htmlFor={id}>{label}</Label>}
23
- {children}
24
- {meta.error && <FormFeedback>{meta.error}</FormFeedback>}
25
- {helpText && <FormText>{helpText}</FormText>}
26
- </BootstrapFormGroup>
27
- );
28
- };
29
-
30
- export default FormGroup;
1
+ import React from 'react';
2
+ import {
3
+ FormGroup as BootstrapFormGroup,
4
+ Label,
5
+ FormFeedback,
6
+ FormText,
7
+ Alert,
8
+ } from 'reactstrap';
9
+
10
+ const FormGroup = ({
11
+ label,
12
+ id,
13
+ helpText,
14
+ className,
15
+ style,
16
+ children,
17
+ meta,
18
+ }) => {
19
+ return (
20
+ <BootstrapFormGroup className={className} style={style}>
21
+ {!!meta.warning && <Alert color="warning">{meta.warning}</Alert>}
22
+ {label && <Label htmlFor={id}>{label}</Label>}
23
+ {children}
24
+ {meta.error && <FormFeedback>{meta.error}</FormFeedback>}
25
+ {helpText && <FormText>{helpText}</FormText>}
26
+ </BootstrapFormGroup>
27
+ );
28
+ };
29
+
30
+ export default FormGroup;
@@ -1,28 +1,28 @@
1
- import React from 'react';
2
- import { InputGroup } from 'reactstrap';
3
- import FormGroup from './FormGroup';
4
- import ErrorScrollTarget from './ErrorScrollTarget';
5
-
6
- export default function FormGroupWrapper({
7
- prepend,
8
- append,
9
- Component,
10
- helpText,
11
- ...props
12
- }) {
13
- const { meta } = props;
14
- return (
15
- <FormGroup meta={meta} helpText={helpText} {...props}>
16
- <ErrorScrollTarget name={props.name} />
17
- {prepend || append ? (
18
- <InputGroup>
19
- {prepend}
20
- <Component {...props} />
21
- {append}
22
- </InputGroup>
23
- ) : (
24
- <Component {...props} />
25
- )}
26
- </FormGroup>
27
- );
28
- }
1
+ import React from 'react';
2
+ import { InputGroup } from 'reactstrap';
3
+ import FormGroup from './FormGroup';
4
+ import ErrorScrollTarget from './ErrorScrollTarget';
5
+
6
+ export default function FormGroupWrapper({
7
+ prepend,
8
+ append,
9
+ Component,
10
+ helpText,
11
+ ...props
12
+ }) {
13
+ const { meta } = props;
14
+ return (
15
+ <FormGroup meta={meta} helpText={helpText} {...props}>
16
+ <ErrorScrollTarget name={props.name} />
17
+ {prepend || append ? (
18
+ <InputGroup>
19
+ {prepend}
20
+ <Component {...props} />
21
+ {append}
22
+ </InputGroup>
23
+ ) : (
24
+ <Component {...props} />
25
+ )}
26
+ </FormGroup>
27
+ );
28
+ }