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