@conform-to/react 0.3.0 → 0.4.0-pre.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.
- package/README.md +99 -48
- package/helpers.js +20 -3
- package/hooks.d.ts +36 -12
- package/hooks.js +342 -160
- package/index.d.ts +1 -1
- package/index.js +12 -4
- package/module/helpers.js +20 -3
- package/module/hooks.js +343 -161
- package/module/index.js +1 -1
- package/package.json +2 -2
package/module/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
-
import { isFieldElement,
|
|
2
|
+
import { getSubmissionType, reportValidity, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom';
|
|
3
3
|
import { useRef, useState, useEffect } from 'react';
|
|
4
4
|
import { input } from './helpers.js';
|
|
5
5
|
|
|
@@ -7,64 +7,107 @@ import { input } from './helpers.js';
|
|
|
7
7
|
* Returns properties required to hook into form events.
|
|
8
8
|
* Applied custom validation and define when error should be reported.
|
|
9
9
|
*
|
|
10
|
-
* @see https://github.com/edmundhung/conform/tree/v0.
|
|
10
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#useform
|
|
11
11
|
*/
|
|
12
12
|
function useForm() {
|
|
13
13
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
14
|
-
var
|
|
15
|
-
validate
|
|
16
|
-
} = config;
|
|
14
|
+
var configRef = useRef(config);
|
|
17
15
|
var ref = useRef(null);
|
|
16
|
+
var [error, setError] = useState(() => {
|
|
17
|
+
var _config$state$error$f, _config$state, _config$state$error;
|
|
18
|
+
|
|
19
|
+
var [, message] = (_config$state$error$f = (_config$state = config.state) === null || _config$state === void 0 ? void 0 : (_config$state$error = _config$state.error) === null || _config$state$error === void 0 ? void 0 : _config$state$error.find(_ref => {
|
|
20
|
+
var [key] = _ref;
|
|
21
|
+
return key === '';
|
|
22
|
+
})) !== null && _config$state$error$f !== void 0 ? _config$state$error$f : [];
|
|
23
|
+
return message !== null && message !== void 0 ? message : '';
|
|
24
|
+
});
|
|
25
|
+
var [fieldsetConfig, setFieldsetConfig] = useState(() => {
|
|
26
|
+
var _config$state$error2, _config$state2, _config$state3, _config$state$value, _config$state4;
|
|
27
|
+
|
|
28
|
+
var error = (_config$state$error2 = (_config$state2 = config.state) === null || _config$state2 === void 0 ? void 0 : _config$state2.error) !== null && _config$state$error2 !== void 0 ? _config$state$error2 : [];
|
|
29
|
+
var scope = (_config$state3 = config.state) === null || _config$state3 === void 0 ? void 0 : _config$state3.scope;
|
|
30
|
+
return {
|
|
31
|
+
defaultValue: (_config$state$value = (_config$state4 = config.state) === null || _config$state4 === void 0 ? void 0 : _config$state4.value) !== null && _config$state$value !== void 0 ? _config$state$value : config.defaultValue,
|
|
32
|
+
initialError: error.filter(_ref2 => {
|
|
33
|
+
var [name] = _ref2;
|
|
34
|
+
return name !== '' && getSubmissionType(name) === null && (!scope || scope.includes(name));
|
|
35
|
+
})
|
|
36
|
+
};
|
|
37
|
+
});
|
|
18
38
|
var [noValidate, setNoValidate] = useState(config.noValidate || !config.fallbackNative);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
configRef.current = config;
|
|
41
|
+
});
|
|
19
42
|
useEffect(() => {
|
|
20
43
|
setNoValidate(true);
|
|
21
44
|
}, []);
|
|
22
45
|
useEffect(() => {
|
|
23
|
-
|
|
24
|
-
if (ref.current) {
|
|
25
|
-
validate === null || validate === void 0 ? void 0 : validate(ref.current);
|
|
26
|
-
} // Revalidate the form when input value is changed
|
|
46
|
+
var form = ref.current;
|
|
27
47
|
|
|
48
|
+
if (!form || !config.state) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!reportValidity(form, config.state)) {
|
|
53
|
+
focusFirstInvalidField(form, config.state.scope);
|
|
54
|
+
}
|
|
28
55
|
|
|
56
|
+
requestSubmit(form);
|
|
57
|
+
}, [config.state]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
// Revalidate the form when input value is changed
|
|
29
60
|
var handleInput = event => {
|
|
30
61
|
var field = event.target;
|
|
31
62
|
var form = ref.current;
|
|
63
|
+
var formConfig = configRef.current;
|
|
32
64
|
|
|
33
65
|
if (!form || !isFieldElement(field) || field.form !== form) {
|
|
34
66
|
return;
|
|
35
67
|
}
|
|
36
68
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (config.initialReport === 'onChange') {
|
|
41
|
-
field.dataset.conformTouched = 'true';
|
|
42
|
-
} // Field validity might be changed due to cross reference
|
|
43
|
-
|
|
69
|
+
if (formConfig.initialReport === 'onChange') {
|
|
70
|
+
field.dataset.conformTouched = 'true';
|
|
71
|
+
}
|
|
44
72
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Report latest error for all touched fields
|
|
48
|
-
_field.checkValidity();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
73
|
+
if (field.dataset.conformTouched) {
|
|
74
|
+
requestValidate(form, field.name);
|
|
51
75
|
}
|
|
52
76
|
};
|
|
53
77
|
|
|
54
78
|
var handleBlur = event => {
|
|
55
79
|
var field = event.target;
|
|
56
80
|
var form = ref.current;
|
|
81
|
+
var formConfig = configRef.current;
|
|
57
82
|
|
|
58
|
-
if (!form || !isFieldElement(field) || field.form !== form
|
|
83
|
+
if (!form || !isFieldElement(field) || field.form !== form) {
|
|
59
84
|
return;
|
|
60
85
|
}
|
|
61
86
|
|
|
62
|
-
field.dataset.conformTouched
|
|
63
|
-
|
|
87
|
+
if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) {
|
|
88
|
+
field.dataset.conformTouched = 'true';
|
|
89
|
+
requestValidate(form, field.name);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
var handleInvalid = event => {
|
|
94
|
+
var form = getFormElement(ref.current);
|
|
95
|
+
var field = event.target;
|
|
96
|
+
|
|
97
|
+
if (!form || !isFieldElement(field) || field.form !== form || field.name !== '') {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
|
|
103
|
+
if (field.dataset.conformTouched) {
|
|
104
|
+
setError(field.validationMessage);
|
|
105
|
+
}
|
|
64
106
|
};
|
|
65
107
|
|
|
66
108
|
var handleReset = event => {
|
|
67
109
|
var form = ref.current;
|
|
110
|
+
var formConfig = configRef.current;
|
|
68
111
|
|
|
69
112
|
if (!form || event.target !== form) {
|
|
70
113
|
return;
|
|
@@ -74,17 +117,15 @@ function useForm() {
|
|
|
74
117
|
for (var field of form.elements) {
|
|
75
118
|
if (isFieldElement(field)) {
|
|
76
119
|
delete field.dataset.conformTouched;
|
|
120
|
+
field.setCustomValidity('');
|
|
77
121
|
}
|
|
78
122
|
}
|
|
79
|
-
/**
|
|
80
|
-
* The reset event is triggered before form reset happens.
|
|
81
|
-
* This make sure the form to be revalidated with initial values.
|
|
82
|
-
*/
|
|
83
123
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
124
|
+
setError('');
|
|
125
|
+
setFieldsetConfig({
|
|
126
|
+
defaultValue: formConfig.defaultValue,
|
|
127
|
+
initialError: []
|
|
128
|
+
});
|
|
88
129
|
};
|
|
89
130
|
/**
|
|
90
131
|
* The input event handler will be triggered in capturing phase in order to
|
|
@@ -96,51 +137,83 @@ function useForm() {
|
|
|
96
137
|
|
|
97
138
|
document.addEventListener('input', handleInput, true);
|
|
98
139
|
document.addEventListener('blur', handleBlur, true);
|
|
140
|
+
document.addEventListener('invalid', handleInvalid, true);
|
|
99
141
|
document.addEventListener('reset', handleReset);
|
|
100
142
|
return () => {
|
|
101
143
|
document.removeEventListener('input', handleInput, true);
|
|
102
144
|
document.removeEventListener('blur', handleBlur, true);
|
|
145
|
+
document.removeEventListener('invalid', handleInvalid, true);
|
|
103
146
|
document.removeEventListener('reset', handleReset);
|
|
104
147
|
};
|
|
105
|
-
}, [
|
|
148
|
+
}, []);
|
|
106
149
|
return {
|
|
107
150
|
ref,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
|
|
124
|
-
// Mark all fields as touched
|
|
125
|
-
for (var field of form.elements) {
|
|
126
|
-
if (isFieldElement(field)) {
|
|
127
|
-
field.dataset.conformTouched = 'true';
|
|
151
|
+
error,
|
|
152
|
+
props: {
|
|
153
|
+
ref,
|
|
154
|
+
noValidate,
|
|
155
|
+
|
|
156
|
+
onSubmit(event) {
|
|
157
|
+
var form = event.currentTarget;
|
|
158
|
+
var nativeEvent = event.nativeEvent;
|
|
159
|
+
var submitter = nativeEvent.submitter;
|
|
160
|
+
|
|
161
|
+
for (var element of form.elements) {
|
|
162
|
+
if (isFieldElement(element) && element.name === '') {
|
|
163
|
+
setError(element.validationMessage);
|
|
164
|
+
break;
|
|
128
165
|
}
|
|
129
|
-
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* It checks defaultPrevented to confirm if the submission is intentional
|
|
169
|
+
* This is utilized by `useFieldList` to modify the list state when the submit
|
|
170
|
+
* event is captured and revalidate the form with new fields without triggering
|
|
171
|
+
* a form submission at the same time.
|
|
172
|
+
*/
|
|
130
173
|
|
|
131
174
|
|
|
132
|
-
if (!event.
|
|
175
|
+
if (!submitter || event.defaultPrevented) {
|
|
133
176
|
event.preventDefault();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
var formData = getFormData(form, submitter);
|
|
181
|
+
var submission = parse(formData);
|
|
182
|
+
var context = {
|
|
183
|
+
form,
|
|
184
|
+
formData,
|
|
185
|
+
submission
|
|
186
|
+
}; // Touch all fields only if the submitter is not a command button
|
|
187
|
+
|
|
188
|
+
if (!submission.type) {
|
|
189
|
+
for (var field of form.elements) {
|
|
190
|
+
if (isFieldElement(field)) {
|
|
191
|
+
// Mark the field as touched
|
|
192
|
+
field.dataset.conformTouched = 'true';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (typeof config.onValidate === 'function' && !config.noValidate && !submitter.formNoValidate) {
|
|
198
|
+
try {
|
|
199
|
+
if (!config.onValidate(context)) {
|
|
200
|
+
focusFirstInvalidField(form);
|
|
201
|
+
event.preventDefault();
|
|
202
|
+
}
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.warn(e);
|
|
205
|
+
}
|
|
134
206
|
}
|
|
135
|
-
}
|
|
136
207
|
|
|
137
|
-
|
|
138
|
-
|
|
208
|
+
if (!event.defaultPrevented) {
|
|
209
|
+
var _config$onSubmit;
|
|
139
210
|
|
|
140
|
-
|
|
211
|
+
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, context);
|
|
212
|
+
}
|
|
141
213
|
}
|
|
142
|
-
}
|
|
143
214
|
|
|
215
|
+
},
|
|
216
|
+
config: fieldsetConfig
|
|
144
217
|
};
|
|
145
218
|
}
|
|
146
219
|
/**
|
|
@@ -148,19 +221,55 @@ function useForm() {
|
|
|
148
221
|
*/
|
|
149
222
|
|
|
150
223
|
function useFieldset(ref, config) {
|
|
224
|
+
var configRef = useRef(config);
|
|
225
|
+
var [uncontrolledState, setUncontrolledState] = useState( // @ts-expect-error
|
|
226
|
+
() => {
|
|
227
|
+
var _config$defaultValue;
|
|
228
|
+
|
|
229
|
+
var initialError = {};
|
|
230
|
+
|
|
231
|
+
for (var [name, message] of (_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : []) {
|
|
232
|
+
var _config$initialError;
|
|
233
|
+
|
|
234
|
+
var [key, ...paths] = getPaths(name);
|
|
235
|
+
|
|
236
|
+
if (typeof key === 'string') {
|
|
237
|
+
var _initialError$key;
|
|
238
|
+
|
|
239
|
+
var scopedName = getName(paths);
|
|
240
|
+
var entries = (_initialError$key = initialError[key]) !== null && _initialError$key !== void 0 ? _initialError$key : [];
|
|
241
|
+
|
|
242
|
+
if (scopedName === '' && entries.length > 0 && entries[0][0] !== '') {
|
|
243
|
+
initialError[key] = [[scopedName, message], ...entries];
|
|
244
|
+
} else {
|
|
245
|
+
initialError[key] = [...entries, [scopedName, message]];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
defaultValue: (_config$defaultValue = config === null || config === void 0 ? void 0 : config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : {},
|
|
252
|
+
initialError
|
|
253
|
+
};
|
|
254
|
+
});
|
|
151
255
|
var [error, setError] = useState(() => {
|
|
152
256
|
var result = {};
|
|
153
257
|
|
|
154
|
-
for (var [key,
|
|
155
|
-
var
|
|
258
|
+
for (var [key, entries] of Object.entries(uncontrolledState.initialError)) {
|
|
259
|
+
var _entries$;
|
|
156
260
|
|
|
157
|
-
|
|
158
|
-
|
|
261
|
+
var [name, message] = (_entries$ = entries === null || entries === void 0 ? void 0 : entries[0]) !== null && _entries$ !== void 0 ? _entries$ : [];
|
|
262
|
+
|
|
263
|
+
if (name === '') {
|
|
264
|
+
result[key] = message !== null && message !== void 0 ? message : '';
|
|
159
265
|
}
|
|
160
266
|
}
|
|
161
267
|
|
|
162
268
|
return result;
|
|
163
269
|
});
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
configRef.current = config;
|
|
272
|
+
});
|
|
164
273
|
useEffect(() => {
|
|
165
274
|
/**
|
|
166
275
|
* Reset the error state of each field if its validity is changed.
|
|
@@ -170,13 +279,16 @@ function useFieldset(ref, config) {
|
|
|
170
279
|
*/
|
|
171
280
|
var resetError = form => {
|
|
172
281
|
setError(prev => {
|
|
282
|
+
var _configRef$current$na, _configRef$current;
|
|
283
|
+
|
|
173
284
|
var next = prev;
|
|
285
|
+
var fieldsetName = (_configRef$current$na = (_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : '';
|
|
174
286
|
|
|
175
287
|
for (var field of form.elements) {
|
|
176
|
-
if (isFieldElement(field)) {
|
|
177
|
-
var key =
|
|
288
|
+
if (isFieldElement(field) && field.name.startsWith(fieldsetName)) {
|
|
289
|
+
var [key, ...paths] = getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name);
|
|
178
290
|
|
|
179
|
-
if (key) {
|
|
291
|
+
if (typeof key === 'string' && paths.length === 0) {
|
|
180
292
|
var _next$key, _next;
|
|
181
293
|
|
|
182
294
|
var prevMessage = (_next$key = (_next = next) === null || _next === void 0 ? void 0 : _next[key]) !== null && _next$key !== void 0 ? _next$key : '';
|
|
@@ -212,29 +324,35 @@ function useFieldset(ref, config) {
|
|
|
212
324
|
};
|
|
213
325
|
|
|
214
326
|
var invalidHandler = event => {
|
|
327
|
+
var _configRef$current$na2, _configRef$current2;
|
|
328
|
+
|
|
215
329
|
var form = getFormElement(ref.current);
|
|
216
330
|
var field = event.target;
|
|
331
|
+
var fieldsetName = (_configRef$current$na2 = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : '';
|
|
217
332
|
|
|
218
|
-
if (!form || !isFieldElement(field) || field.form !== form) {
|
|
333
|
+
if (!form || !isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
|
|
219
334
|
return;
|
|
220
335
|
}
|
|
221
336
|
|
|
222
|
-
var key =
|
|
337
|
+
var [key, ...paths] = getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name); // Update the error only if the field belongs to the fieldset
|
|
223
338
|
|
|
224
|
-
if (key) {
|
|
225
|
-
|
|
226
|
-
|
|
339
|
+
if (typeof key === 'string' && paths.length === 0) {
|
|
340
|
+
if (field.dataset.conformTouched) {
|
|
341
|
+
setError(prev => {
|
|
342
|
+
var _prev$key;
|
|
227
343
|
|
|
228
|
-
|
|
344
|
+
var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
|
|
229
345
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
346
|
+
if (prevMessage === field.validationMessage) {
|
|
347
|
+
return prev;
|
|
348
|
+
}
|
|
233
349
|
|
|
234
|
-
|
|
235
|
-
|
|
350
|
+
return _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
351
|
+
[key]: field.validationMessage
|
|
352
|
+
});
|
|
236
353
|
});
|
|
237
|
-
}
|
|
354
|
+
}
|
|
355
|
+
|
|
238
356
|
event.preventDefault();
|
|
239
357
|
}
|
|
240
358
|
};
|
|
@@ -251,12 +369,20 @@ function useFieldset(ref, config) {
|
|
|
251
369
|
};
|
|
252
370
|
|
|
253
371
|
var resetHandler = event => {
|
|
372
|
+
var _fieldsetConfig$defau;
|
|
373
|
+
|
|
254
374
|
var form = getFormElement(ref.current);
|
|
255
375
|
|
|
256
376
|
if (!form || event.target !== form) {
|
|
257
377
|
return;
|
|
258
378
|
}
|
|
259
379
|
|
|
380
|
+
var fieldsetConfig = configRef.current;
|
|
381
|
+
setUncontrolledState({
|
|
382
|
+
// @ts-expect-error
|
|
383
|
+
defaultValue: (_fieldsetConfig$defau = fieldsetConfig === null || fieldsetConfig === void 0 ? void 0 : fieldsetConfig.defaultValue) !== null && _fieldsetConfig$defau !== void 0 ? _fieldsetConfig$defau : {},
|
|
384
|
+
initialError: {}
|
|
385
|
+
});
|
|
260
386
|
setError({});
|
|
261
387
|
};
|
|
262
388
|
|
|
@@ -271,26 +397,7 @@ function useFieldset(ref, config) {
|
|
|
271
397
|
document.removeEventListener('submit', submitHandler);
|
|
272
398
|
document.removeEventListener('reset', resetHandler);
|
|
273
399
|
};
|
|
274
|
-
}, [ref
|
|
275
|
-
useEffect(() => {
|
|
276
|
-
setError(prev => {
|
|
277
|
-
var next = prev;
|
|
278
|
-
|
|
279
|
-
for (var [key, _error2] of Object.entries((_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {})) {
|
|
280
|
-
var _config$initialError2;
|
|
281
|
-
|
|
282
|
-
if (next[key] !== (_error2 === null || _error2 === void 0 ? void 0 : _error2.message)) {
|
|
283
|
-
var _error2$message;
|
|
284
|
-
|
|
285
|
-
next = _objectSpread2(_objectSpread2({}, next), {}, {
|
|
286
|
-
[key]: (_error2$message = _error2 === null || _error2 === void 0 ? void 0 : _error2.message) !== null && _error2$message !== void 0 ? _error2$message : ''
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return next;
|
|
292
|
-
});
|
|
293
|
-
}, [config === null || config === void 0 ? void 0 : config.name, config === null || config === void 0 ? void 0 : config.initialError]);
|
|
400
|
+
}, [ref]);
|
|
294
401
|
/**
|
|
295
402
|
* This allows us constructing the field at runtime as we have no information
|
|
296
403
|
* about which fields would be available. The proxy will also help tracking
|
|
@@ -299,19 +406,20 @@ function useFieldset(ref, config) {
|
|
|
299
406
|
|
|
300
407
|
return new Proxy({}, {
|
|
301
408
|
get(_target, key) {
|
|
302
|
-
var
|
|
409
|
+
var _fieldsetConfig$const, _error$key;
|
|
303
410
|
|
|
304
411
|
if (typeof key !== 'string') {
|
|
305
412
|
return;
|
|
306
413
|
}
|
|
307
414
|
|
|
308
|
-
var
|
|
415
|
+
var fieldsetConfig = config !== null && config !== void 0 ? config : {};
|
|
416
|
+
var constraint = (_fieldsetConfig$const = fieldsetConfig.constraint) === null || _fieldsetConfig$const === void 0 ? void 0 : _fieldsetConfig$const[key];
|
|
309
417
|
var field = {
|
|
310
418
|
config: _objectSpread2({
|
|
311
|
-
name:
|
|
312
|
-
form:
|
|
313
|
-
defaultValue:
|
|
314
|
-
initialError:
|
|
419
|
+
name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
|
|
420
|
+
form: fieldsetConfig.form,
|
|
421
|
+
defaultValue: uncontrolledState.defaultValue[key],
|
|
422
|
+
initialError: uncontrolledState.initialError[key]
|
|
315
423
|
}, constraint),
|
|
316
424
|
error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''
|
|
317
425
|
};
|
|
@@ -325,25 +433,55 @@ function useFieldset(ref, config) {
|
|
|
325
433
|
* Returns a list of key and config, with a group of helpers
|
|
326
434
|
* configuring buttons for list manipulation
|
|
327
435
|
*
|
|
328
|
-
* @see https://github.com/edmundhung/conform/tree/v0.
|
|
436
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldlist
|
|
329
437
|
*/
|
|
330
438
|
function useFieldList(ref, config) {
|
|
331
|
-
var
|
|
439
|
+
var configRef = useRef(config);
|
|
440
|
+
var [uncontrolledState, setUncontrolledState] = useState(() => {
|
|
332
441
|
var _config$defaultValue2;
|
|
333
442
|
|
|
334
|
-
|
|
443
|
+
var initialError = [];
|
|
444
|
+
|
|
445
|
+
for (var [name, message] of (_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : []) {
|
|
446
|
+
var _config$initialError2;
|
|
447
|
+
|
|
448
|
+
var [index, ...paths] = getPaths(name);
|
|
449
|
+
|
|
450
|
+
if (typeof index === 'number') {
|
|
451
|
+
var _initialError$index;
|
|
452
|
+
|
|
453
|
+
var scopedName = getName(paths);
|
|
454
|
+
|
|
455
|
+
var _entries = (_initialError$index = initialError[index]) !== null && _initialError$index !== void 0 ? _initialError$index : [];
|
|
456
|
+
|
|
457
|
+
if (scopedName === '' && _entries.length > 0 && _entries[0][0] !== '') {
|
|
458
|
+
initialError[index] = [[scopedName, message], ..._entries];
|
|
459
|
+
} else {
|
|
460
|
+
initialError[index] = [..._entries, [scopedName, message]];
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
defaultValue: (_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [],
|
|
467
|
+
initialError
|
|
468
|
+
};
|
|
335
469
|
});
|
|
336
|
-
var
|
|
337
|
-
var _config$defaultValue3
|
|
470
|
+
var [entries, setEntries] = useState(() => {
|
|
471
|
+
var _config$defaultValue3;
|
|
338
472
|
|
|
339
|
-
|
|
473
|
+
return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]);
|
|
474
|
+
});
|
|
475
|
+
var list = entries.map((_ref3, index) => {
|
|
476
|
+
var [key, defaultValue] = _ref3;
|
|
340
477
|
return {
|
|
341
478
|
key,
|
|
342
|
-
config:
|
|
479
|
+
config: {
|
|
343
480
|
name: "".concat(config.name, "[").concat(index, "]"),
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
481
|
+
form: config.form,
|
|
482
|
+
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index],
|
|
483
|
+
initialError: uncontrolledState.initialError[index]
|
|
484
|
+
}
|
|
347
485
|
};
|
|
348
486
|
});
|
|
349
487
|
/***
|
|
@@ -356,9 +494,10 @@ function useFieldList(ref, config) {
|
|
|
356
494
|
return function () {
|
|
357
495
|
var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
358
496
|
return {
|
|
359
|
-
name:
|
|
360
|
-
value:
|
|
497
|
+
name: 'conform/list',
|
|
498
|
+
value: JSON.stringify({
|
|
361
499
|
type,
|
|
500
|
+
scope: config.name,
|
|
362
501
|
payload
|
|
363
502
|
}),
|
|
364
503
|
form: config.form,
|
|
@@ -369,56 +508,45 @@ function useFieldList(ref, config) {
|
|
|
369
508
|
|
|
370
509
|
});
|
|
371
510
|
useEffect(() => {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
var nextEntries = Object.entries((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : [undefined]);
|
|
376
|
-
|
|
377
|
-
if (prevEntries.length !== nextEntries.length) {
|
|
378
|
-
return nextEntries;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
for (var i = 0; i < prevEntries.length; i++) {
|
|
382
|
-
var [prevKey, prevValue] = prevEntries[i];
|
|
383
|
-
var [nextKey, nextValue] = nextEntries[i];
|
|
384
|
-
|
|
385
|
-
if (prevKey !== nextKey || prevValue !== nextValue) {
|
|
386
|
-
return nextEntries;
|
|
387
|
-
}
|
|
388
|
-
} // No need to rerender in this case
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
return prevEntries;
|
|
392
|
-
});
|
|
393
|
-
|
|
511
|
+
configRef.current = config;
|
|
512
|
+
});
|
|
513
|
+
useEffect(() => {
|
|
394
514
|
var submitHandler = event => {
|
|
395
515
|
var form = getFormElement(ref.current);
|
|
396
516
|
|
|
397
|
-
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !==
|
|
517
|
+
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') {
|
|
398
518
|
return;
|
|
399
519
|
}
|
|
400
520
|
|
|
401
|
-
var
|
|
521
|
+
var command = parseListCommand(event.submitter.value);
|
|
402
522
|
|
|
403
|
-
if (
|
|
523
|
+
if (command.scope !== configRef.current.name) {
|
|
404
524
|
// Ensure the scope of the listener are limited to specific field name
|
|
405
525
|
return;
|
|
406
526
|
}
|
|
407
527
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
528
|
+
setEntries(entries => {
|
|
529
|
+
switch (command.type) {
|
|
530
|
+
case 'append':
|
|
531
|
+
case 'prepend':
|
|
532
|
+
case 'replace':
|
|
533
|
+
return updateList([...(entries !== null && entries !== void 0 ? entries : [])], _objectSpread2(_objectSpread2({}, command), {}, {
|
|
534
|
+
payload: _objectSpread2(_objectSpread2({}, command.payload), {}, {
|
|
535
|
+
defaultValue: ["".concat(Date.now()), command.payload.defaultValue]
|
|
536
|
+
})
|
|
537
|
+
}));
|
|
538
|
+
|
|
539
|
+
default:
|
|
540
|
+
{
|
|
541
|
+
return updateList([...(entries !== null && entries !== void 0 ? entries : [])], command);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
});
|
|
417
545
|
event.preventDefault();
|
|
418
546
|
};
|
|
419
547
|
|
|
420
548
|
var resetHandler = event => {
|
|
421
|
-
var
|
|
549
|
+
var _fieldConfig$defaultV, _fieldConfig$defaultV2;
|
|
422
550
|
|
|
423
551
|
var form = getFormElement(ref.current);
|
|
424
552
|
|
|
@@ -426,7 +554,12 @@ function useFieldList(ref, config) {
|
|
|
426
554
|
return;
|
|
427
555
|
}
|
|
428
556
|
|
|
429
|
-
|
|
557
|
+
var fieldConfig = configRef.current;
|
|
558
|
+
setUncontrolledState({
|
|
559
|
+
defaultValue: (_fieldConfig$defaultV = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV !== void 0 ? _fieldConfig$defaultV : [],
|
|
560
|
+
initialError: []
|
|
561
|
+
});
|
|
562
|
+
setEntries(Object.entries((_fieldConfig$defaultV2 = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV2 !== void 0 ? _fieldConfig$defaultV2 : [undefined]));
|
|
430
563
|
};
|
|
431
564
|
|
|
432
565
|
document.addEventListener('submit', submitHandler, true);
|
|
@@ -435,7 +568,7 @@ function useFieldList(ref, config) {
|
|
|
435
568
|
document.removeEventListener('submit', submitHandler, true);
|
|
436
569
|
document.removeEventListener('reset', resetHandler);
|
|
437
570
|
};
|
|
438
|
-
}, [ref
|
|
571
|
+
}, [ref]);
|
|
439
572
|
return [list, control];
|
|
440
573
|
}
|
|
441
574
|
|
|
@@ -444,13 +577,19 @@ function useFieldList(ref, config) {
|
|
|
444
577
|
* This is particular useful when integrating dropdown and datepicker whichs
|
|
445
578
|
* introduces custom input mode.
|
|
446
579
|
*
|
|
447
|
-
* @see https://github.com/edmundhung/conform/tree/v0.
|
|
580
|
+
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usecontrolledinput
|
|
448
581
|
*/
|
|
449
|
-
function useControlledInput(
|
|
450
|
-
var
|
|
582
|
+
function useControlledInput(config) {
|
|
583
|
+
var _config$defaultValue4;
|
|
451
584
|
|
|
452
585
|
var ref = useRef(null);
|
|
453
|
-
var
|
|
586
|
+
var inputRef = useRef(null);
|
|
587
|
+
var configRef = useRef(config);
|
|
588
|
+
var [uncontrolledState, setUncontrolledState] = useState({
|
|
589
|
+
defaultValue: config.defaultValue,
|
|
590
|
+
initialError: config.initialError
|
|
591
|
+
});
|
|
592
|
+
var [value, setValue] = useState("".concat((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : ''));
|
|
454
593
|
|
|
455
594
|
var handleChange = eventOrValue => {
|
|
456
595
|
if (!ref.current) {
|
|
@@ -477,12 +616,55 @@ function useControlledInput(field) {
|
|
|
477
616
|
event.preventDefault();
|
|
478
617
|
};
|
|
479
618
|
|
|
619
|
+
useEffect(() => {
|
|
620
|
+
configRef.current = config;
|
|
621
|
+
});
|
|
622
|
+
useEffect(() => {
|
|
623
|
+
var resetHandler = event => {
|
|
624
|
+
var _configRef$current$de;
|
|
625
|
+
|
|
626
|
+
var form = getFormElement(ref.current);
|
|
627
|
+
|
|
628
|
+
if (!form || event.target !== form) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
setUncontrolledState({
|
|
633
|
+
defaultValue: configRef.current.defaultValue,
|
|
634
|
+
initialError: configRef.current.initialError
|
|
635
|
+
});
|
|
636
|
+
setValue("".concat((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : ''));
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
document.addEventListener('reset', resetHandler);
|
|
640
|
+
return () => {
|
|
641
|
+
document.removeEventListener('reset', resetHandler);
|
|
642
|
+
};
|
|
643
|
+
}, []);
|
|
480
644
|
return [_objectSpread2({
|
|
481
645
|
ref,
|
|
482
|
-
|
|
483
|
-
|
|
646
|
+
style: {
|
|
647
|
+
position: 'absolute',
|
|
648
|
+
width: '1px',
|
|
649
|
+
height: '1px',
|
|
650
|
+
padding: 0,
|
|
651
|
+
margin: '-1px',
|
|
652
|
+
overflow: 'hidden',
|
|
653
|
+
clip: 'rect(0,0,0,0)',
|
|
654
|
+
whiteSpace: 'nowrap',
|
|
655
|
+
borderWidth: 0
|
|
656
|
+
},
|
|
657
|
+
|
|
658
|
+
onFocus() {
|
|
659
|
+
var _inputRef$current;
|
|
660
|
+
|
|
661
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
}, input(_objectSpread2(_objectSpread2({}, config), uncontrolledState), {
|
|
484
665
|
type: 'text'
|
|
485
666
|
})), {
|
|
667
|
+
ref: inputRef,
|
|
486
668
|
value,
|
|
487
669
|
onChange: handleChange,
|
|
488
670
|
onBlur: handleBlur,
|