envoc-form 3.0.0 → 3.3.0

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 (34) hide show
  1. package/es/AddressInput/index.js +2 -1
  2. package/es/DatePickerInput/DatePickerInput.js +1 -1
  3. package/es/FileInput/index.js +2 -1
  4. package/es/Form/index.js +3 -1
  5. package/es/FormInput/FormInput.js +6 -0
  6. package/es/MoneyFormattedInput/MoneyFormattedInput.js +106 -0
  7. package/es/MoneyFormattedInput/index.js +2 -0
  8. package/es/ReactSelectField/ReactSelectField.js +36 -2
  9. package/es/index.js +20 -10
  10. package/es/validators/validators.js +2 -2
  11. package/lib/AddressInput/index.js +13 -3
  12. package/lib/DatePickerInput/DatePickerInput.js +2 -2
  13. package/lib/FileInput/index.js +9 -1
  14. package/lib/Form/index.js +16 -0
  15. package/lib/FormInput/FormInput.js +7 -0
  16. package/lib/MoneyFormattedInput/MoneyFormattedInput.js +126 -0
  17. package/lib/MoneyFormattedInput/index.js +15 -0
  18. package/lib/ReactSelectField/ReactSelectField.js +37 -2
  19. package/lib/index.js +166 -38
  20. package/lib/validators/validators.js +2 -2
  21. package/package.json +3 -2
  22. package/src/AddressInput/__snapshots__/AddesssInput.test.js.snap +1 -1
  23. package/src/AddressInput/index.js +2 -1
  24. package/src/BoolInput/__snapshots__/BoolInput.test.js.snap +1 -1
  25. package/src/DatePickerInput/DatePickerInput.js +1 -1
  26. package/src/FileInput/index.js +2 -1
  27. package/src/Form/index.js +9 -1
  28. package/src/FormInput/FormInput.js +3 -0
  29. package/src/FormInput/__snapshots__/FormInput.test.js.snap +1 -1
  30. package/src/MoneyFormattedInput/MoneyFormattedInput.js +115 -0
  31. package/src/MoneyFormattedInput/index.js +3 -0
  32. package/src/ReactSelectField/ReactSelectField.js +34 -1
  33. package/src/index.js +54 -17
  34. package/src/validators/validators.js +2 -2
package/lib/index.js CHANGED
@@ -7,22 +7,130 @@ var _typeof = require("@babel/runtime/helpers/typeof");
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
+ Object.defineProperty(exports, "BoolInput", {
11
+ enumerable: true,
12
+ get: function get() {
13
+ return _BoolInput.BoolInput;
14
+ }
15
+ });
16
+ Object.defineProperty(exports, "InlineBoolInput", {
17
+ enumerable: true,
18
+ get: function get() {
19
+ return _BoolInput.InlineBoolInput;
20
+ }
21
+ });
22
+ Object.defineProperty(exports, "InlineMoneyInput", {
23
+ enumerable: true,
24
+ get: function get() {
25
+ return _MoneyInput.InlineMoneyInput;
26
+ }
27
+ });
28
+ Object.defineProperty(exports, "MoneyInput", {
29
+ enumerable: true,
30
+ get: function get() {
31
+ return _MoneyInput.MoneyInput;
32
+ }
33
+ });
34
+ Object.defineProperty(exports, "MoneyFormattedInput", {
35
+ enumerable: true,
36
+ get: function get() {
37
+ return _MoneyFormattedInput.MoneyFormattedInput;
38
+ }
39
+ });
40
+ Object.defineProperty(exports, "AddressInput", {
41
+ enumerable: true,
42
+ get: function get() {
43
+ return _AddressInput["default"];
44
+ }
45
+ });
46
+ Object.defineProperty(exports, "UsStates", {
47
+ enumerable: true,
48
+ get: function get() {
49
+ return _AddressInput.UsStates;
50
+ }
51
+ });
52
+ Object.defineProperty(exports, "ConfirmBaseForm", {
53
+ enumerable: true,
54
+ get: function get() {
55
+ return _ConfirmBaseForm["default"];
56
+ }
57
+ });
58
+ Object.defineProperty(exports, "ConfirmDeleteForm", {
59
+ enumerable: true,
60
+ get: function get() {
61
+ return _ConfirmDeleteForm["default"];
62
+ }
63
+ });
64
+ Object.defineProperty(exports, "DatePickerInput", {
65
+ enumerable: true,
66
+ get: function get() {
67
+ return _DatePickerInput["default"];
68
+ }
69
+ });
70
+ Object.defineProperty(exports, "ErrorScrollTarget", {
71
+ enumerable: true,
72
+ get: function get() {
73
+ return _ErrorScrollTarget["default"];
74
+ }
75
+ });
76
+ Object.defineProperty(exports, "FileInput", {
77
+ enumerable: true,
78
+ get: function get() {
79
+ return _FileInput.FileInput;
80
+ }
81
+ });
82
+ Object.defineProperty(exports, "DropzoneFileInput", {
83
+ enumerable: true,
84
+ get: function get() {
85
+ return _FileInput.DropzoneFileInput;
86
+ }
87
+ });
88
+ Object.defineProperty(exports, "DefaultFileList", {
89
+ enumerable: true,
90
+ get: function get() {
91
+ return _FileInput.DefaultFileList;
92
+ }
93
+ });
10
94
  Object.defineProperty(exports, "Form", {
11
95
  enumerable: true,
12
96
  get: function get() {
13
97
  return _Form["default"];
14
98
  }
15
99
  });
16
- Object.defineProperty(exports, "FormInput", {
100
+ Object.defineProperty(exports, "ServerErrorContext", {
17
101
  enumerable: true,
18
102
  get: function get() {
19
- return _FormInput["default"];
103
+ return _Form.ServerErrorContext;
20
104
  }
21
105
  });
22
- Object.defineProperty(exports, "InlineFormInput", {
106
+ Object.defineProperty(exports, "FocusError", {
23
107
  enumerable: true,
24
108
  get: function get() {
25
- return _InlineFormInput["default"];
109
+ return _Form.FocusError;
110
+ }
111
+ });
112
+ Object.defineProperty(exports, "FormBasedPreventNavigation", {
113
+ enumerable: true,
114
+ get: function get() {
115
+ return _Form.FormBasedPreventNavigation;
116
+ }
117
+ });
118
+ Object.defineProperty(exports, "FormGroup", {
119
+ enumerable: true,
120
+ get: function get() {
121
+ return _FormGroup["default"];
122
+ }
123
+ });
124
+ Object.defineProperty(exports, "FormGroupWrapper", {
125
+ enumerable: true,
126
+ get: function get() {
127
+ return _FormGroupWrapper["default"];
128
+ }
129
+ });
130
+ Object.defineProperty(exports, "FormInput", {
131
+ enumerable: true,
132
+ get: function get() {
133
+ return _FormInput["default"];
26
134
  }
27
135
  });
28
136
  Object.defineProperty(exports, "FormInputArray", {
@@ -31,22 +139,22 @@ Object.defineProperty(exports, "FormInputArray", {
31
139
  return _FormInputArray["default"];
32
140
  }
33
141
  });
34
- Object.defineProperty(exports, "IconInput", {
142
+ Object.defineProperty(exports, "FormSection", {
35
143
  enumerable: true,
36
144
  get: function get() {
37
- return _IconInput["default"];
145
+ return _FormSection["default"];
38
146
  }
39
147
  });
40
- Object.defineProperty(exports, "BoolInput", {
148
+ Object.defineProperty(exports, "IconInput", {
41
149
  enumerable: true,
42
150
  get: function get() {
43
- return _BoolInput.BoolInput;
151
+ return _IconInput["default"];
44
152
  }
45
153
  });
46
- Object.defineProperty(exports, "InlineBoolInput", {
154
+ Object.defineProperty(exports, "InlineFormInput", {
47
155
  enumerable: true,
48
156
  get: function get() {
49
- return _BoolInput.InlineBoolInput;
157
+ return _InlineFormInput["default"];
50
158
  }
51
159
  });
52
160
  Object.defineProperty(exports, "StandardFormActions", {
@@ -55,79 +163,99 @@ Object.defineProperty(exports, "StandardFormActions", {
55
163
  return _StandardFormActions["default"];
56
164
  }
57
165
  });
58
- Object.defineProperty(exports, "validators", {
166
+ Object.defineProperty(exports, "SubmitFormButton", {
59
167
  enumerable: true,
60
168
  get: function get() {
61
- return _validators["default"];
169
+ return _SubmitFormButton["default"];
62
170
  }
63
171
  });
64
- Object.defineProperty(exports, "ConfirmBaseForm", {
172
+ Object.defineProperty(exports, "useStandardFormInput", {
65
173
  enumerable: true,
66
174
  get: function get() {
67
- return _ConfirmBaseForm["default"];
175
+ return _useStandardFormInput["default"];
68
176
  }
69
177
  });
70
- Object.defineProperty(exports, "ConfirmDeleteForm", {
178
+ Object.defineProperty(exports, "validators", {
71
179
  enumerable: true,
72
180
  get: function get() {
73
- return _ConfirmDeleteForm["default"];
181
+ return _validators["default"];
74
182
  }
75
183
  });
76
- Object.defineProperty(exports, "SubmitFormButton", {
184
+ Object.defineProperty(exports, "ReactSelectField", {
77
185
  enumerable: true,
78
186
  get: function get() {
79
- return _SubmitFormButton["default"];
187
+ return _ReactSelectField["default"];
80
188
  }
81
189
  });
82
- Object.defineProperty(exports, "AddressInput", {
190
+ Object.defineProperty(exports, "customReactSelectFieldStyles", {
83
191
  enumerable: true,
84
192
  get: function get() {
85
- return _AddressInput["default"];
193
+ return _ReactSelectField.customStyles;
86
194
  }
87
195
  });
88
- Object.defineProperty(exports, "MoneyInput", {
196
+ Object.defineProperty(exports, "overrideReactSelectFieldStyles", {
89
197
  enumerable: true,
90
198
  get: function get() {
91
- return _MoneyInput.MoneyInput;
199
+ return _ReactSelectField.overrideTheme;
92
200
  }
93
201
  });
94
- Object.defineProperty(exports, "InlineMoneyInput", {
202
+ Object.defineProperty(exports, "NestedFormFieldContext", {
95
203
  enumerable: true,
96
204
  get: function get() {
97
- return _MoneyInput.InlineMoneyInput;
205
+ return _NestedFormFieldContext["default"];
98
206
  }
99
207
  });
100
208
  exports.normalizers = void 0;
101
209
 
102
- var _Form = _interopRequireDefault(require("./Form"));
210
+ var normalizers = _interopRequireWildcard(require("./normalizers"));
103
211
 
104
- var _FormInput = _interopRequireDefault(require("./FormInput"));
212
+ exports.normalizers = normalizers;
105
213
 
106
- var _InlineFormInput = _interopRequireDefault(require("./InlineFormInput"));
214
+ var _BoolInput = require("./BoolInput");
107
215
 
108
- var _FormInputArray = _interopRequireDefault(require("./FormInputArray"));
216
+ var _MoneyInput = require("./MoneyInput");
109
217
 
110
- var _IconInput = _interopRequireDefault(require("./IconInput"));
218
+ var _MoneyFormattedInput = require("./MoneyFormattedInput");
111
219
 
112
- var _BoolInput = require("./BoolInput");
220
+ var _AddressInput = _interopRequireWildcard(require("./AddressInput"));
113
221
 
114
- var _StandardFormActions = _interopRequireDefault(require("./StandardFormActions"));
222
+ var _ConfirmBaseForm = _interopRequireDefault(require("./ConfirmBaseForm"));
115
223
 
116
- var _validators = _interopRequireDefault(require("./validators"));
224
+ var _ConfirmDeleteForm = _interopRequireDefault(require("./ConfirmDeleteForm"));
117
225
 
118
- var normalizers = _interopRequireWildcard(require("./normalizers"));
226
+ var _DatePickerInput = _interopRequireDefault(require("./DatePickerInput"));
119
227
 
120
- exports.normalizers = normalizers;
228
+ var _ErrorScrollTarget = _interopRequireDefault(require("./ErrorScrollTarget"));
121
229
 
122
- var _ConfirmBaseForm = _interopRequireDefault(require("./ConfirmBaseForm"));
230
+ var _FileInput = require("./FileInput");
123
231
 
124
- var _ConfirmDeleteForm = _interopRequireDefault(require("./ConfirmDeleteForm"));
232
+ var _Form = _interopRequireWildcard(require("./Form"));
233
+
234
+ var _FormGroup = _interopRequireDefault(require("./FormGroup"));
235
+
236
+ var _FormGroupWrapper = _interopRequireDefault(require("./FormGroupWrapper"));
237
+
238
+ var _FormInput = _interopRequireDefault(require("./FormInput"));
239
+
240
+ var _FormInputArray = _interopRequireDefault(require("./FormInputArray"));
241
+
242
+ var _FormSection = _interopRequireDefault(require("./FormSection"));
243
+
244
+ var _IconInput = _interopRequireDefault(require("./IconInput"));
245
+
246
+ var _InlineFormInput = _interopRequireDefault(require("./InlineFormInput"));
247
+
248
+ var _StandardFormActions = _interopRequireDefault(require("./StandardFormActions"));
125
249
 
126
250
  var _SubmitFormButton = _interopRequireDefault(require("./SubmitFormButton"));
127
251
 
128
- var _AddressInput = _interopRequireDefault(require("./AddressInput"));
252
+ var _useStandardFormInput = _interopRequireDefault(require("./useStandardFormInput"));
129
253
 
130
- var _MoneyInput = require("./MoneyInput");
254
+ var _validators = _interopRequireDefault(require("./validators"));
255
+
256
+ var _ReactSelectField = _interopRequireWildcard(require("./ReactSelectField"));
257
+
258
+ var _NestedFormFieldContext = _interopRequireDefault(require("./NestedFormFieldContext"));
131
259
 
132
260
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
133
261
 
@@ -82,7 +82,7 @@ function minCount(count) {
82
82
 
83
83
  var maxValue = function maxValue(value) {
84
84
  return function (inputValue) {
85
- if (inputValue && value) {
85
+ if (inputValue != null && value != null) {
86
86
  return inputValue <= value ? undefined : "Maximum value ".concat(value, " exceeded");
87
87
  } else {
88
88
  return undefined;
@@ -94,7 +94,7 @@ exports.maxValue = maxValue;
94
94
 
95
95
  var minValue = function minValue(value) {
96
96
  return function (inputValue) {
97
- if (inputValue && value) {
97
+ if (inputValue != null && value != null) {
98
98
  return inputValue >= value ? undefined : "Minimum value ".concat(value, " not met");
99
99
  } else {
100
100
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envoc-form",
3
- "version": "3.0.0",
3
+ "version": "3.3.0",
4
4
  "description": "Envoc form components",
5
5
  "keywords": [
6
6
  "react-component",
@@ -26,7 +26,8 @@
26
26
  "axios": "^0.21.1",
27
27
  "classnames": "^2.3.1",
28
28
  "date-fns": "^2.22.1",
29
- "envoc-request": "^3.0.0",
29
+ "envoc-request": "^3.3.0",
30
+ "lodash": "^4.17.21",
30
31
  "lru-cache": "^6.0.0",
31
32
  "prop-types": "^15.7.2",
32
33
  "react-date-picker": "^8.2.0",
@@ -110,7 +110,7 @@ exports[`AddressInput has matching snapshot 1`] = `
110
110
  class=" css-lbak6p-Component"
111
111
  >
112
112
  <div
113
- class=" css-1osw1h9-placeholder"
113
+ class=" css-1vk4ta-placeholder"
114
114
  >
115
115
  State
116
116
  </div>
@@ -1,2 +1,3 @@
1
1
  import AddressInput from './AddressInput';
2
- export default AddressInput;
2
+ import UsStates from './UsStates';
3
+ export { AddressInput as default, UsStates };
@@ -23,7 +23,7 @@ exports[`BoolInput has matching snapshot 1`] = `
23
23
  class=" css-lbak6p-Component"
24
24
  >
25
25
  <div
26
- class=" css-1osw1h9-placeholder"
26
+ class=" css-1vk4ta-placeholder"
27
27
  >
28
28
  Select...
29
29
  </div>
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import DatePicker from 'react-date-picker';
2
+ import DatePicker from 'react-date-picker/dist/entry.nostyle';
3
3
  import parseISO from 'date-fns/parseISO';
4
4
  import classnames from 'classnames';
5
5
 
@@ -1,4 +1,5 @@
1
1
  import FileInput from './FileInput';
2
2
  import DropzoneFileInput from './DropzoneFileInput';
3
+ import DefaultFileList from './DefaultFileList';
3
4
 
4
- export { FileInput, DropzoneFileInput };
5
+ export { FileInput, DropzoneFileInput, DefaultFileList };
package/src/Form/index.js CHANGED
@@ -1,3 +1,11 @@
1
+ import FocusError from './FocusError';
1
2
  import Form from './Form';
3
+ import FormBasedPreventNavigation from './FormBasedPreventNavigation';
2
4
  import ServerErrorContext from './ServerErrorContext';
3
- export { Form as default, ServerErrorContext };
5
+
6
+ export {
7
+ Form as default,
8
+ ServerErrorContext,
9
+ FocusError,
10
+ FormBasedPreventNavigation,
11
+ };
@@ -15,6 +15,7 @@ import FormGroupWrapper from '../FormGroupWrapper';
15
15
  import DatePickerInput from '../DatePickerInput';
16
16
  import ReactSelectField from '../ReactSelectField';
17
17
  import useStandardFormInput from '../useStandardFormInput';
18
+ import { MoneyFormattedInput } from '../MoneyFormattedInput';
18
19
  import { FileInput, DropzoneFileInput } from '../FileInput';
19
20
 
20
21
  export default function FormInput(props) {
@@ -57,6 +58,8 @@ function StandardFieldGroup(props) {
57
58
  return <FormGroupWrapper {...props} Component={FileInput} />;
58
59
  case 'textarea':
59
60
  return <FormGroupWrapper {...props} Component={TextAreaInput} />;
61
+ case 'moneyFormatted':
62
+ return <FormGroupWrapper {...props} Component={MoneyFormattedInput} />;
60
63
  default:
61
64
  return <FormGroupWrapper {...props} Component={DefaultInput} />;
62
65
  }
@@ -234,7 +234,7 @@ exports[`FormInput has matching select snapshot 1`] = `
234
234
  class=" css-lbak6p-Component"
235
235
  >
236
236
  <div
237
- class=" css-1osw1h9-placeholder"
237
+ class=" css-1vk4ta-placeholder"
238
238
  >
239
239
  Select...
240
240
  </div>
@@ -0,0 +1,115 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { useField } from 'formik';
3
+ import debounce from 'lodash/debounce';
4
+ import classNames from 'classnames';
5
+
6
+ // Money input that will format the value to always have commas, a single decimal, and
7
+ // exactly two digits after the decimal. This happens after a delay (using debounce).
8
+ export default function MoneyFormattedInput({
9
+ name,
10
+ onBlur,
11
+ onChange,
12
+ classname,
13
+ disabled = false,
14
+ debounceTimer = 1500,
15
+ meta,
16
+ }) {
17
+ // The displayed state and formik state are two seperate values that we handle
18
+ const [inputValue, setInputValue] = useState('');
19
+ const [{ value: formikValue }] = useField(name);
20
+
21
+ const handleChangeDebounce = useMemo(() => {
22
+ return debounce(debouncedUpdateInput, debounceTimer);
23
+
24
+ function debouncedUpdateInput(value) {
25
+ var result = formatToCurrency(value);
26
+
27
+ setInputValue(result ?? '');
28
+
29
+ // sets value in formik
30
+ onChange(result ?? '');
31
+ onBlur();
32
+ }
33
+ }, [onBlur, onChange]);
34
+
35
+ // Format first render
36
+ useEffect(() => {
37
+ var formattedFormikValue = formatToCurrency(formikValue);
38
+ setInputValue(formattedFormikValue ?? '');
39
+ }, [formikValue]);
40
+
41
+ function handleChange(e) {
42
+ const onlyNumbersDecimalComma = e.target.value
43
+ .toString()
44
+ .replace(/[^.,0-9]/g, '');
45
+
46
+ setInputValue(onlyNumbersDecimalComma);
47
+ handleChangeDebounce(onlyNumbersDecimalComma);
48
+ }
49
+
50
+ return (
51
+ <>
52
+ <div className="input-group">
53
+ <div className="input-group-prepend">
54
+ <span className="input-group-text">$</span>
55
+ </div>
56
+ <input
57
+ name={name}
58
+ type="text"
59
+ value={inputValue}
60
+ onChange={handleChange}
61
+ onBlur={onBlur}
62
+ disabled={disabled}
63
+ className={classNames(
64
+ classname,
65
+ meta.error === 'Required' ? 'is-invalid' : '',
66
+ 'react-select-input money-input form-control'
67
+ )}
68
+ />
69
+ </div>
70
+ </>
71
+ );
72
+ }
73
+
74
+ function formatToCurrency(value) {
75
+ if (value === null || value === undefined) {
76
+ return null;
77
+ }
78
+
79
+ // 'value' is sometimes a number on first render
80
+ const onlyNumbersDecimal = value.toString().replace(/[^.0-9]/g, '');
81
+
82
+ if (!onlyNumbersDecimal) {
83
+ return null;
84
+ }
85
+
86
+ var result = new Intl.NumberFormat('en-US', {
87
+ style: 'decimal',
88
+ minimumSignificantDigits: 2,
89
+ minimumFractionDigits: 2,
90
+ }).format(parseFloat(onlyNumbersDecimal));
91
+
92
+ result = formatTwoDecimalPlaces(result);
93
+ return result;
94
+ }
95
+
96
+ function formatTwoDecimalPlaces(value) {
97
+ const decimalIndex = value.indexOf('.');
98
+
99
+ // If the string doesn't contain a decimal OR
100
+ // the string contains a single '.' with nothing to the right of the decimal -> append '.00'
101
+ // Reason: parseFloat will remove '.00' from whole numbers (ex. 350.00 -> 350)
102
+ if (!value.includes('.')) {
103
+ return value.concat('.00');
104
+ }
105
+ // If 2 or more characters to the right of the decimal
106
+ else if (!!value.charAt(decimalIndex + 2)) {
107
+ return value.substring(0, decimalIndex + 3);
108
+ }
109
+ // If only 1 character to the right of the decimal
110
+ else if (!!value.charAt(decimalIndex + 1)) {
111
+ return value.substring(0, decimalIndex + 2).concat('0');
112
+ }
113
+
114
+ return value;
115
+ }
@@ -0,0 +1,3 @@
1
+ import MoneyFormattedInput from './MoneyFormattedInput';
2
+
3
+ export { MoneyFormattedInput };
@@ -1,3 +1,4 @@
1
+ import classNames from 'classnames';
1
2
  import React, { useEffect, useRef } from 'react';
2
3
  import { default as ReactSelect } from 'react-select';
3
4
 
@@ -17,6 +18,8 @@ const red = '#f86c6b';
17
18
  const inputBorderColor = '#c2cfd6';
18
19
  const inputBorderColorFocused = '#8ad4ee';
19
20
  const inputBoxShadowFocused = '0 0 0 0.2rem rgba(32, 168, 216, 0.25)';
21
+ const placeholderColor = '#9ca3af';
22
+ const disabledSingleValueColor = '#4b5563';
20
23
 
21
24
  export const customStyles = {
22
25
  control: (provided, { isFocused, selectProps }) => {
@@ -35,6 +38,13 @@ export const customStyles = {
35
38
  };
36
39
  },
37
40
  menu: (provided) => ({ ...provided, zIndex: 3 }),
41
+ singleValue: (provided, state) => {
42
+ const color = state.isDisabled ? disabledSingleValueColor : '';
43
+ return { ...provided, color };
44
+ },
45
+ placeholder: (defaultStyles) => {
46
+ return { ...defaultStyles, color: placeholderColor };
47
+ },
38
48
  };
39
49
 
40
50
  // internal to forms use only
@@ -59,6 +69,28 @@ export default function ReactSelectInput({
59
69
  onSelectedRef.current && onSelectedRef.current(selectedItems);
60
70
  }, [selectedItems]);
61
71
 
72
+ const onBlurRef = useRef(onBlur);
73
+ onBlurRef.current = onBlur;
74
+ const { touched } = meta;
75
+
76
+ useEffect(() => {
77
+ if (!touched) return;
78
+
79
+ // without the timer set to 0, if the empty option is selected the required message doesn't appear until clicked away from the select input
80
+ const timerRef = setTimeout(() => {
81
+ onBlurRef.current && onBlurRef.current();
82
+ }, 0);
83
+
84
+ return () => {
85
+ clearTimeout(timerRef);
86
+ };
87
+ }, [value, touched]);
88
+
89
+ const classes = classNames(className, 'react-select-input', {
90
+ 'is-invalid': !!meta.error,
91
+ disabled: disabled,
92
+ });
93
+
62
94
  return (
63
95
  <ReactSelect
64
96
  {...props}
@@ -69,7 +101,8 @@ export default function ReactSelectInput({
69
101
  getOptionValue={getOptionValue}
70
102
  value={selectedItems}
71
103
  onChange={handleChange}
72
- className="react-select-input"
104
+ onBlur={() => onBlur()}
105
+ className={classes}
73
106
  theme={overrideTheme}
74
107
  styles={customStyles}
75
108
  menuPortalTarget={document.body}