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