@homecode/ui 4.25.3 → 4.26.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.
- package/dist/esm/src/components/Form/Form.helpers.js +2 -2
- package/dist/esm/src/components/Form/Form.js +215 -222
- package/dist/esm/src/components/Input/Input.js +3 -4
- package/dist/esm/types/src/components/Form/Form.d.ts +1 -29
- package/dist/esm/types/src/components/Form/Form.helpers.d.ts +1 -1
- package/dist/esm/types/src/components/Form/Form.test.d.ts +1 -0
- package/dist/esm/types/src/components/Form/Form.types.d.ts +1 -1
- package/dist/esm/types/src/components/Icon/Icon.d.ts +1 -0
- package/package.json +3 -2
|
@@ -17,7 +17,7 @@ function dropFocusFromSubmit() {
|
|
|
17
17
|
function getInitialTouched(initialValues) {
|
|
18
18
|
return Object.keys(initialValues).reduce((acc, name) => ({ ...acc, [name]: false }), {});
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function getChanged(_defaultValues, values) {
|
|
21
21
|
const defaultValues = _defaultValues || values;
|
|
22
22
|
return Object.entries(values).reduce((acc, [field, val]) => compare(defaultValues[field], val) ? acc : { ...acc, [field]: true }, {});
|
|
23
23
|
}
|
|
@@ -39,4 +39,4 @@ function cloneValues(values) {
|
|
|
39
39
|
return Object.entries(values).reduce((acc, [name, val]) => ({ ...acc, [name]: cloneValue(val) }), {});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export { cloneValues, dropFocusFromSubmit,
|
|
42
|
+
export { cloneValues, dropFocusFromSubmit, getChanged, getInitialTouched, getVal, patchWithCustomMessages };
|
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
3
|
-
import { createStore } from 'justorm/react';
|
|
2
|
+
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
4
3
|
import cn from 'classnames';
|
|
5
4
|
import compare from 'compareq';
|
|
6
|
-
import pick from 'lodash.pick';
|
|
7
|
-
import omit from 'lodash.omit';
|
|
8
5
|
import { Input } from '../Input/Input.js';
|
|
9
6
|
import S from './Form.styl.js';
|
|
10
|
-
import { cloneValues,
|
|
7
|
+
import { cloneValues, getInitialTouched, getChanged, patchWithCustomMessages, dropFocusFromSubmit, getVal } from './Form.helpers.js';
|
|
11
8
|
import { Validator } from './Validator.js';
|
|
12
9
|
import '../Spinner/Spinner.styl.js';
|
|
13
10
|
import '../Button/Button.styl.js';
|
|
14
11
|
import './SubmitButtons/SubmitButtons.styl.js';
|
|
15
12
|
|
|
16
|
-
const
|
|
17
|
-
'isDirty',
|
|
18
|
-
'isEmpty',
|
|
19
|
-
'isValid',
|
|
20
|
-
'isLoading',
|
|
21
|
-
'values',
|
|
22
|
-
'errors',
|
|
23
|
-
'touched',
|
|
24
|
-
'changed',
|
|
25
|
-
'disabled',
|
|
26
|
-
];
|
|
27
|
-
function Field(props) {
|
|
13
|
+
const Field = function Field(props) {
|
|
28
14
|
const { value, error, markEdited, isChanged, isTouched, clearMargins, component: Control = Input, className, onChange, onBlur, handleChange, handleBlur, children, ...controlProps } = props;
|
|
29
15
|
const { name, isHidden } = controlProps;
|
|
30
16
|
const valField = typeof value === 'boolean' ? 'checked' : 'value';
|
|
@@ -48,239 +34,246 @@ function Field(props) {
|
|
|
48
34
|
error: isTouched && error?.message,
|
|
49
35
|
});
|
|
50
36
|
return (jsxs("div", { className: classes, children: [jsx(Control, { ...controlProps }), children] }));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
validationSchema;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const {
|
|
59
|
-
|
|
60
|
-
this.validationSchema = validationSchema;
|
|
61
|
-
const values = cloneValues(initialValues);
|
|
62
|
-
const notEmpty = getNotEmpty(this.defaultValues, initialValues);
|
|
63
|
-
const disabled = Object(defaultDisabled);
|
|
64
|
-
this.store = createStore(this, {
|
|
65
|
-
values,
|
|
66
|
-
touched: getInitialTouched(initialValues),
|
|
67
|
-
changed: {},
|
|
68
|
-
notEmpty,
|
|
69
|
-
disabled,
|
|
70
|
-
isLoading: false,
|
|
71
|
-
isDirty: false,
|
|
72
|
-
// TODO: do not validate here (only when Field is mounted)
|
|
73
|
-
...this.getValidationState({ values, disabled }),
|
|
74
|
-
isEmpty: Object.keys(notEmpty).length === 0,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
componentDidMount() {
|
|
78
|
-
this.calcChangedAll();
|
|
79
|
-
this.validate();
|
|
80
|
-
this.onInit();
|
|
81
|
-
}
|
|
82
|
-
shouldComponentUpdate({ defaultValues, initialValues, validationSchema, }) {
|
|
83
|
-
const validationChanged = !compare(validationSchema, this.props.validationSchema);
|
|
84
|
-
const initialValsChanged = !compare(initialValues, this.props.initialValues);
|
|
85
|
-
const defaultValsChanged = !compare(defaultValues, this.props.defaultValues);
|
|
86
|
-
this.validationSchema = validationSchema;
|
|
87
|
-
if (initialValsChanged) {
|
|
88
|
-
this.setInitialVals(initialValues);
|
|
89
|
-
}
|
|
90
|
-
if (defaultValsChanged)
|
|
91
|
-
this.updateDefaultValues();
|
|
92
|
-
if (initialValsChanged || defaultValsChanged) {
|
|
93
|
-
this.calcChangedAll(initialValues);
|
|
94
|
-
}
|
|
95
|
-
if (initialValsChanged || validationChanged) {
|
|
96
|
-
this.validate();
|
|
97
|
-
}
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
updateDefaultValues(props = this.props) {
|
|
101
|
-
const { defaultValues, initialValues } = props;
|
|
102
|
-
return defaultValues || cloneValues(initialValues);
|
|
103
|
-
}
|
|
104
|
-
setInitialVals(initialValues = {}) {
|
|
105
|
-
this.store.values = cloneValues(initialValues);
|
|
106
|
-
this.validate();
|
|
107
|
-
this.onInit();
|
|
108
|
-
}
|
|
109
|
-
setValue = (field, val) => {
|
|
110
|
-
const { values } = this.store;
|
|
111
|
-
values[field] = val;
|
|
112
|
-
this.calcChanged(field, val);
|
|
113
|
-
this.validate();
|
|
37
|
+
};
|
|
38
|
+
function Form(props) {
|
|
39
|
+
const { className, children, initialValues = {}, validationSchema, defaultDisabled = {}, defaultValues, markEdited, onInit, onChange, onSubmit, ...restProps } = props;
|
|
40
|
+
const validationSchemaRef = useRef(validationSchema);
|
|
41
|
+
const defaultValuesRef = useRef({});
|
|
42
|
+
// Update default values helper
|
|
43
|
+
const updateDefaultValues = (propsToUse = props) => {
|
|
44
|
+
const { defaultValues: dv, initialValues: iv } = propsToUse;
|
|
45
|
+
return dv || cloneValues(iv);
|
|
114
46
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
47
|
+
// Initialize default values
|
|
48
|
+
defaultValuesRef.current = updateDefaultValues();
|
|
49
|
+
// Separate states
|
|
50
|
+
const [values, _setValues] = useState(() => cloneValues(initialValues));
|
|
51
|
+
const [touched, _setTouched] = useState(() => getInitialTouched(initialValues));
|
|
52
|
+
const [changed, _setChanged] = useState({});
|
|
53
|
+
const [disabled, setDisabled] = useState(() => ({ ...defaultDisabled }));
|
|
54
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
55
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
56
|
+
const [isValid, setIsValid] = useState(true);
|
|
57
|
+
const [errors, _setErrors] = useState({});
|
|
58
|
+
const [isEmpty, setIsEmpty] = useState(() => Object.keys(getChanged(defaultValuesRef.current, initialValues))
|
|
59
|
+
.length === 0);
|
|
60
|
+
// Refs for stable handlers
|
|
61
|
+
const valuesRef = useRef(values);
|
|
62
|
+
const changedRef = useRef(changed);
|
|
63
|
+
const touchedRef = useRef(touched);
|
|
64
|
+
const errorsRef = useRef(errors);
|
|
65
|
+
const onChangeRef = useRef(onChange);
|
|
66
|
+
const setValues = (newValues) => {
|
|
67
|
+
_setValues(newValues);
|
|
68
|
+
valuesRef.current = newValues;
|
|
121
69
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (typeof name === 'object') {
|
|
125
|
-
Object.assign(disabled, name);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (isDisabled) {
|
|
129
|
-
disabled[name] = true;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
delete disabled[name];
|
|
133
|
-
}
|
|
70
|
+
const setValue = (field, val) => {
|
|
71
|
+
setValues({ ...valuesRef.current, [field]: val });
|
|
134
72
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
this.store.touched = getInitialTouched(initialValues);
|
|
73
|
+
const setErrors = (newErrors) => {
|
|
74
|
+
_setErrors(newErrors);
|
|
75
|
+
errorsRef.current = newErrors;
|
|
139
76
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
setValues: this.setValues,
|
|
165
|
-
setDisabled: this.setDisabled,
|
|
166
|
-
reset: this.reset,
|
|
167
|
-
submit: this.onSubmit,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
getValidationState(store) {
|
|
171
|
-
const errors = this.getValidationErrors(store);
|
|
172
|
-
const isValid = Object.keys(errors).length === 0;
|
|
173
|
-
return { isValid, errors };
|
|
174
|
-
}
|
|
175
|
-
getValidationErrors(store = this.store.originalObject) {
|
|
176
|
-
const { values, disabled } = store;
|
|
177
|
-
if (!this.validationSchema)
|
|
77
|
+
const setTouched = (newTouched) => {
|
|
78
|
+
_setTouched(newTouched);
|
|
79
|
+
touchedRef.current = newTouched;
|
|
80
|
+
};
|
|
81
|
+
const setFieldTouched = (field, isTouched) => {
|
|
82
|
+
setTouched({ ...touchedRef.current, [field]: isTouched });
|
|
83
|
+
};
|
|
84
|
+
const setChanged = (newChanged) => {
|
|
85
|
+
_setChanged(newChanged);
|
|
86
|
+
changedRef.current = newChanged;
|
|
87
|
+
};
|
|
88
|
+
// Update refs
|
|
89
|
+
onChangeRef.current = onChange;
|
|
90
|
+
const updateIsDirty = () => {
|
|
91
|
+
const newIsDirty = Object.keys(changedRef.current).length > 0;
|
|
92
|
+
setIsDirty(newIsDirty);
|
|
93
|
+
};
|
|
94
|
+
const updateIsEmpty = () => {
|
|
95
|
+
const newNotEmpty = getChanged(defaultValuesRef.current, valuesRef.current);
|
|
96
|
+
setIsEmpty(Object.keys(newNotEmpty).length === 0);
|
|
97
|
+
};
|
|
98
|
+
// Validation functions
|
|
99
|
+
const getValidationErrors = useCallback((valuesData = valuesRef.current, disabledData = disabled) => {
|
|
100
|
+
if (!validationSchemaRef.current)
|
|
178
101
|
return {};
|
|
179
|
-
|
|
180
|
-
const schema = Object.entries(this.validationSchema).reduce((acc, [field, { ...rule }]) => {
|
|
102
|
+
const schema = Object.entries(validationSchemaRef.current).reduce((acc, [field, { ...rule }]) => {
|
|
181
103
|
const { type, check } = rule;
|
|
182
|
-
if (
|
|
104
|
+
if (disabledData[field])
|
|
183
105
|
return acc;
|
|
184
106
|
if (type === 'custom') {
|
|
185
|
-
// NOTE: pass all `values` to custom checker function
|
|
186
|
-
// to allow create validator for dependent fields
|
|
187
|
-
// @ts-ignore
|
|
188
107
|
rule.check = function checkWrap(...args) {
|
|
189
|
-
|
|
190
|
-
return check.call(this, ...args, values);
|
|
108
|
+
return check.call(this, ...args, valuesData);
|
|
191
109
|
};
|
|
192
110
|
}
|
|
193
111
|
return { ...acc, [field]: rule };
|
|
194
112
|
}, {});
|
|
195
|
-
const res = Validator.validate(
|
|
113
|
+
const res = Validator.validate(valuesData, schema);
|
|
196
114
|
if (typeof res === 'object')
|
|
197
115
|
return patchWithCustomMessages(res, schema);
|
|
198
116
|
return {};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
const
|
|
117
|
+
}, [values, disabled]);
|
|
118
|
+
const validate = useCallback(() => {
|
|
119
|
+
const newErrors = getValidationErrors();
|
|
120
|
+
const newIsValid = Object.keys(newErrors).length === 0;
|
|
121
|
+
setErrors(newErrors);
|
|
122
|
+
setIsValid(newIsValid);
|
|
123
|
+
}, [getValidationErrors]);
|
|
124
|
+
const calcChanged = useCallback((field, val) => {
|
|
125
|
+
const newChanged = { ...changedRef.current };
|
|
203
126
|
if (compare(val, initialValues[field])) {
|
|
204
|
-
delete
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
changed[field] = true;
|
|
208
|
-
}
|
|
209
|
-
if (compare(val, this.defaultValues[field])) {
|
|
210
|
-
delete notEmpty[field];
|
|
127
|
+
delete newChanged[field];
|
|
211
128
|
}
|
|
212
129
|
else {
|
|
213
|
-
|
|
130
|
+
newChanged[field] = true;
|
|
214
131
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
132
|
+
setChanged(newChanged);
|
|
133
|
+
updateIsDirty();
|
|
134
|
+
updateIsEmpty();
|
|
135
|
+
}, [initialValues]);
|
|
136
|
+
const calcChangedAll = (initValues = initialValues) => {
|
|
137
|
+
const newChanged = Object.entries(values).reduce((acc, [field, val]) => compare(initValues[field], val) ? acc : { ...acc, [field]: true }, {});
|
|
138
|
+
setChanged(newChanged);
|
|
139
|
+
updateIsDirty();
|
|
140
|
+
updateIsEmpty();
|
|
141
|
+
};
|
|
142
|
+
// Form API methods
|
|
143
|
+
const setValueAPI = (field, val) => {
|
|
144
|
+
setValue(field, val);
|
|
145
|
+
calcChanged(field, val);
|
|
146
|
+
validate();
|
|
147
|
+
};
|
|
148
|
+
const setValuesAPI = vals => {
|
|
149
|
+
const newValues = { ...valuesRef.current, ...vals };
|
|
150
|
+
setValues(newValues);
|
|
151
|
+
calcChangedAll();
|
|
152
|
+
validate();
|
|
153
|
+
return values;
|
|
154
|
+
};
|
|
155
|
+
const setDisabledAPI = useCallback((name, isDisabledFlag) => {
|
|
156
|
+
setDisabled(prev => {
|
|
157
|
+
const newDisabled = { ...prev };
|
|
158
|
+
if (typeof name === 'object') {
|
|
159
|
+
Object.assign(newDisabled, name);
|
|
160
|
+
}
|
|
161
|
+
else if (isDisabledFlag) {
|
|
162
|
+
newDisabled[name] = true;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
delete newDisabled[name];
|
|
166
|
+
}
|
|
167
|
+
return newDisabled;
|
|
228
168
|
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
169
|
+
}, []);
|
|
170
|
+
const reset = useCallback(() => {
|
|
171
|
+
setValues(cloneValues(initialValues));
|
|
172
|
+
setTouched({});
|
|
173
|
+
setChanged({});
|
|
174
|
+
updateIsDirty();
|
|
175
|
+
updateIsEmpty();
|
|
176
|
+
validate();
|
|
177
|
+
}, [initialValues]);
|
|
178
|
+
// Event handlers - memoized to prevent field recreation
|
|
179
|
+
const onChangeHandler = useCallback((field, val) => {
|
|
180
|
+
if (valuesRef.current[field] === val)
|
|
181
|
+
return;
|
|
182
|
+
const newValues = { ...valuesRef.current, [field]: val };
|
|
183
|
+
if (onChangeRef.current && !onChangeRef.current(newValues))
|
|
184
|
+
return;
|
|
185
|
+
setValue(field, val);
|
|
186
|
+
setFieldTouched(field, true);
|
|
187
|
+
calcChanged(field, val);
|
|
188
|
+
validate();
|
|
189
|
+
}, [calcChanged, validate]);
|
|
190
|
+
const onBlurHandler = useCallback((name) => {
|
|
191
|
+
setFieldTouched(name, true);
|
|
192
|
+
}, []);
|
|
193
|
+
const onSubmitHandler = async (e) => {
|
|
241
194
|
e?.preventDefault();
|
|
242
195
|
dropFocusFromSubmit();
|
|
243
196
|
if (!onSubmit)
|
|
244
197
|
return;
|
|
245
|
-
|
|
198
|
+
setIsLoading(true);
|
|
246
199
|
await onSubmit({ ...values });
|
|
247
|
-
|
|
248
|
-
};
|
|
249
|
-
onChange = (field, val) => {
|
|
250
|
-
const { onChange } = this.props;
|
|
251
|
-
const { values, touched } = this.store;
|
|
252
|
-
if (values[field] === val)
|
|
253
|
-
return;
|
|
254
|
-
const newValues = { ...values.originalObject, [field]: val };
|
|
255
|
-
// @ts-ignore
|
|
256
|
-
if (onChange && onChange(newValues) === false)
|
|
257
|
-
return;
|
|
258
|
-
values[field] = val;
|
|
259
|
-
touched[field] = true;
|
|
260
|
-
this.handleChange(field, val);
|
|
200
|
+
setIsLoading(false);
|
|
261
201
|
};
|
|
262
|
-
|
|
263
|
-
|
|
202
|
+
// Simple field component - let memo on Field handle optimization
|
|
203
|
+
const FieldComponent = useRef((fieldProps) => {
|
|
204
|
+
const { name } = fieldProps;
|
|
205
|
+
const fullProps = {
|
|
206
|
+
...fieldProps,
|
|
207
|
+
value: valuesRef.current[name],
|
|
208
|
+
error: errorsRef.current[name],
|
|
209
|
+
markEdited,
|
|
210
|
+
isChanged: changedRef.current[name],
|
|
211
|
+
isTouched: touchedRef.current[name],
|
|
212
|
+
handleChange: onChangeHandler,
|
|
213
|
+
handleBlur: onBlurHandler,
|
|
214
|
+
};
|
|
215
|
+
if (validationSchemaRef.current?.[name]?.empty === false) {
|
|
216
|
+
fullProps.required = true;
|
|
217
|
+
}
|
|
218
|
+
return jsx(Field, { ...fullProps });
|
|
219
|
+
});
|
|
220
|
+
const formAPI = {
|
|
221
|
+
values,
|
|
222
|
+
touched,
|
|
223
|
+
changed,
|
|
224
|
+
disabled,
|
|
225
|
+
isLoading,
|
|
226
|
+
isDirty,
|
|
227
|
+
isValid,
|
|
228
|
+
isEmpty,
|
|
229
|
+
errors,
|
|
230
|
+
Field: FieldComponent.current,
|
|
231
|
+
setValue: setValueAPI,
|
|
232
|
+
setValues: setValuesAPI,
|
|
233
|
+
setDisabled: setDisabledAPI,
|
|
234
|
+
reset,
|
|
235
|
+
submit: onSubmitHandler,
|
|
264
236
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
237
|
+
// Effects
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
validationSchemaRef.current = validationSchema;
|
|
240
|
+
}, [validationSchema]);
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
calcChangedAll();
|
|
243
|
+
validate();
|
|
244
|
+
if (onInit)
|
|
245
|
+
onInit(formAPI);
|
|
246
|
+
}, []);
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
const validationChanged = !compare(validationSchema, validationSchemaRef.current);
|
|
249
|
+
const initialValsChanged = !compare(initialValues, props.initialValues);
|
|
250
|
+
const defaultValsChanged = !compare(defaultValues, props.defaultValues);
|
|
251
|
+
if (initialValsChanged) {
|
|
252
|
+
setValues(cloneValues(initialValues));
|
|
253
|
+
validate();
|
|
254
|
+
if (onInit)
|
|
255
|
+
onInit(formAPI);
|
|
256
|
+
}
|
|
257
|
+
if (defaultValsChanged) {
|
|
258
|
+
defaultValuesRef.current = updateDefaultValues();
|
|
259
|
+
}
|
|
260
|
+
if (initialValsChanged || defaultValsChanged) {
|
|
261
|
+
calcChangedAll(initialValues);
|
|
262
|
+
}
|
|
263
|
+
if (initialValsChanged || validationChanged) {
|
|
264
|
+
validate();
|
|
265
|
+
}
|
|
266
|
+
}, [
|
|
267
|
+
initialValues,
|
|
268
|
+
validationSchema,
|
|
269
|
+
defaultValues,
|
|
270
|
+
onInit,
|
|
271
|
+
formAPI,
|
|
272
|
+
calcChangedAll,
|
|
273
|
+
validate,
|
|
274
|
+
]);
|
|
275
|
+
const classes = cn(S.root, className, isLoading && S.isLoading);
|
|
276
|
+
return (jsx("form", { className: classes, ...restProps, onSubmit: onSubmitHandler, children: children(formAPI) }));
|
|
284
277
|
}
|
|
285
278
|
|
|
286
279
|
export { Form };
|
|
@@ -51,7 +51,7 @@ const Input = forwardRef((props, ref) => {
|
|
|
51
51
|
const [inputValue, setInputValue] = useState((value ?? defaultValue ?? ''));
|
|
52
52
|
const [labelClipPath, setLabelClipPath] = useState('');
|
|
53
53
|
const [autoComplete, setAutoComplete] = useState('');
|
|
54
|
-
const uid = generateUID();
|
|
54
|
+
const uid = useRef(generateUID());
|
|
55
55
|
const isTextArea = type === 'textarea';
|
|
56
56
|
const isNumber = type === 'number';
|
|
57
57
|
const hasValue = isNumber || Boolean(value || inputValue || defaultValue);
|
|
@@ -171,7 +171,7 @@ const Input = forwardRef((props, ref) => {
|
|
|
171
171
|
}
|
|
172
172
|
if (!autoComplete) {
|
|
173
173
|
controlProps.suppressHydrationWarning = true;
|
|
174
|
-
controlProps.autoComplete = uid;
|
|
174
|
+
controlProps.autoComplete = uid.current;
|
|
175
175
|
delete controlProps.name;
|
|
176
176
|
}
|
|
177
177
|
if (controlProps.value === undefined)
|
|
@@ -196,7 +196,6 @@ const Input = forwardRef((props, ref) => {
|
|
|
196
196
|
label,
|
|
197
197
|
isLabelOnTop,
|
|
198
198
|
autoComplete,
|
|
199
|
-
uid,
|
|
200
199
|
]);
|
|
201
200
|
const wrapControl = control => {
|
|
202
201
|
if (isTextArea) {
|
|
@@ -254,7 +253,7 @@ const Input = forwardRef((props, ref) => {
|
|
|
254
253
|
}, []);
|
|
255
254
|
const Control = isTextArea ? 'span' : 'input';
|
|
256
255
|
const classes = cn(S.root, isTextArea && S.isTextArea, S[`size-${size}`], S[`variant-${variant}`], isFocused && S.isFocused, error && S.hasError, hasClear && S.hasClear, disabled && S.isDisabled, round && S.round, className);
|
|
257
|
-
return (jsxs("div", { className: classes,
|
|
256
|
+
return (jsxs("div", { className: classes, children: [jsxs("label", { className: cn(S.main, clearPaddingLeft && S.clearPaddingLeft, clearPaddingRight && S.clearPaddingRight), children: [jsx("div", { className: S.border, suppressHydrationWarning: true, style: { clipPath: labelClipPath } }, "border"), renderAddon('left'), wrapControl(jsxs(Fragment, { children: [createElement(Control, { ...controlProps, className: cn(S.control, controlProps?.className), ref: setRef, key: "control" }), isTextArea &&
|
|
258
257
|
controlProps.placeholder &&
|
|
259
258
|
!controlProps.value && (jsx("span", { className: S.placeholder, spellCheck: false, children: controlProps.placeholder }))] })), isNumber && (jsxs("div", { className: S.numberArrows, children: [jsx(Button, { variant: "clear", onClick: () => onNumberWheel(1), tabIndex: -1, children: jsx(Icon, { type: "chevronUp", size: size }) }), jsx(Button, { variant: "clear", onClick: () => onNumberWheel(-1), tabIndex: -1, children: jsx(Icon, { type: "chevronDown", size: size }) })] })), jsx(Label, { className: S.label, size: size, isOnTop: isLabelOnTop, isError: Boolean(error), onClipPathChange: onLabelClipPathChange, children: label }, "label"), hasClear && !disabled && hasValue && (jsx(Button, { className: S.clearButton, variant: "clear", size: size, square: true, round: round, onClick: onClearPress, title: "", children: jsx(Icon, { className: S.clearIcon, size: size, type: "close" }) }, "clear")), renderAddon('right'), required && !hideRequiredStar && (jsx(RequiredStar, { size: size }, "required-star"))] }, "main"), !disabled && typeof error === 'string' && (jsx(AssistiveText, { variant: "danger", size: size, children: error }, "assistive-text"))] }));
|
|
260
259
|
});
|
|
@@ -1,32 +1,4 @@
|
|
|
1
|
-
import { Component } from 'react';
|
|
2
1
|
import * as T from './Form.types';
|
|
3
|
-
export declare
|
|
4
|
-
store: any;
|
|
5
|
-
validationSchema: T.FormValidationSchema;
|
|
6
|
-
defaultValues: T.FormValues;
|
|
7
|
-
constructor(props: T.Props);
|
|
8
|
-
componentDidMount(): void;
|
|
9
|
-
shouldComponentUpdate({ defaultValues, initialValues, validationSchema, }: T.Props): boolean;
|
|
10
|
-
updateDefaultValues(props?: Readonly<T.Props>): T.FormValues;
|
|
11
|
-
setInitialVals(initialValues?: {}): void;
|
|
12
|
-
setValue: (field: any, val: any) => void;
|
|
13
|
-
setValues: (vals: any) => any;
|
|
14
|
-
setDisabled: (name: string | object, isDisabled?: any) => void;
|
|
15
|
-
reset: () => void;
|
|
16
|
-
field: (props: T.FieldProps) => JSX.Element;
|
|
17
|
-
getFieldProps(props: any): T.FormFieldProps;
|
|
18
|
-
getFormAPI(): T.FormAPI;
|
|
19
|
-
getValidationState(store?: any): T.ValidationState;
|
|
20
|
-
getValidationErrors(store?: T.ValidationStateParams): any;
|
|
21
|
-
calcChanged(field: string, val: any): void;
|
|
22
|
-
calcChangedAll(initialValues?: T.FormValues): void;
|
|
23
|
-
validate(): void;
|
|
24
|
-
onInit(): void;
|
|
25
|
-
onSubmit: (e: any) => Promise<void>;
|
|
26
|
-
onChange: (field: string, val: any) => void;
|
|
27
|
-
onBlur: (name: string) => void;
|
|
28
|
-
handleChange(field: string, val: any): void;
|
|
29
|
-
render(): JSX.Element;
|
|
30
|
-
}
|
|
2
|
+
export declare function Form(props: T.Props): JSX.Element;
|
|
31
3
|
export * from './SubmitButtons/SubmitButtons';
|
|
32
4
|
export * as FormTypes from './Form.types';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function patchWithCustomMessages(checkRes: any, validationSchema: any): any;
|
|
2
2
|
export declare function dropFocusFromSubmit(): void;
|
|
3
3
|
export declare function getInitialTouched(initialValues: any): {};
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function getChanged(_defaultValues: any, values: any): {};
|
|
5
5
|
export declare function getVal(e: any, val: any, valField: any): any;
|
|
6
6
|
export declare function cloneValues(values: any): {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -45,7 +45,7 @@ export type Props = ComponentType & {
|
|
|
45
45
|
markEdited?: boolean;
|
|
46
46
|
children: (api: FormAPI) => ReactNode | ReactNode[];
|
|
47
47
|
onInit?: (api: FormAPI) => boolean | void;
|
|
48
|
-
onChange?: (values: FormValues) => void;
|
|
48
|
+
onChange?: (values: FormValues) => void | boolean;
|
|
49
49
|
onSubmit?: (values: FormValues) => Promise<void>;
|
|
50
50
|
};
|
|
51
51
|
export type FieldProps = {
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homecode/ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.26.1",
|
|
4
4
|
"description": "React UI components library",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"
|
|
6
|
+
"tests": "jest",
|
|
7
|
+
"tests:watch": "jest --watch",
|
|
7
8
|
"ts": "tsc --noUnusedLocals",
|
|
8
9
|
"dev": "NODE_OPTIONS='--loader ts-node/esm' NODE_ENV=development webpack-dev-server --mode=development --config ./src/docs/config/webpack.config.js --progress",
|
|
9
10
|
"build": "rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript",
|