@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/module/hooks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
2
- import { isFieldElement, listCommandKey, serializeListCommand, getFormElement, getKey, parseListCommand, updateList } from '@conform-to/dom';
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.3.1/packages/conform-react/README.md#useform
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
- // Initialize form validation messages
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
- validate === null || validate === void 0 ? void 0 : validate(form);
38
-
39
- if (!config.noValidate) {
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
- for (var _field of form.elements) {
46
- if (isFieldElement(_field) && _field.dataset.conformTouched) {
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;
82
+
83
+ if (!form || !isFieldElement(field) || field.form !== form) {
84
+ return;
85
+ }
86
+
87
+ if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) {
88
+ field.dataset.conformTouched = 'true';
89
+ requestValidate(form, field.name);
90
+ }
91
+ };
57
92
 
58
- if (!form || !isFieldElement(field) || field.form !== form || config.noValidate || config.initialReport !== 'onBlur') {
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 !== '') {
59
98
  return;
60
99
  }
61
100
 
62
- field.dataset.conformTouched = 'true';
63
- field.reportValidity();
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
-
84
123
 
85
- setTimeout(() => {
86
- validate === null || validate === void 0 ? void 0 : validate(form);
87
- }, 0);
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,58 +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
- }, [validate, config.initialReport, config.noValidate]);
148
+ }, []);
106
149
  return {
107
150
  ref,
108
- noValidate,
109
-
110
- onSubmit(event) {
111
- var form = event.currentTarget;
112
- var nativeEvent = event.nativeEvent;
113
- var submitter = nativeEvent.submitter instanceof HTMLButtonElement || nativeEvent.submitter instanceof HTMLInputElement ? nativeEvent.submitter : null; // Validating the form with the submitter value
114
-
115
- validate === null || validate === void 0 ? void 0 : validate(form, submitter);
116
- /**
117
- * It checks defaultPrevented to confirm if the submission is intentional
118
- * This is utilized by `useFieldList` to modify the list state when the submit
119
- * event is captured and revalidate the form with new fields without triggering
120
- * a form submission at the same time.
121
- */
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;
165
+ }
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
+ */
122
173
 
123
- if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
124
- var focused = false;
125
174
 
126
- for (var field of form.elements) {
127
- if (isFieldElement(field)) {
128
- // Mark the field as touched
129
- field.dataset.conformTouched = 'true'; // Focus on the first invalid field
175
+ if (!submitter || event.defaultPrevented) {
176
+ event.preventDefault();
177
+ return;
178
+ }
130
179
 
131
- if (!focused && !field.validity.valid && field.tagName !== 'BUTTON') {
132
- field.focus();
133
- focused = true;
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';
134
193
  }
135
194
  }
136
- } // Check the validity of the form
137
-
195
+ }
138
196
 
139
- if (!event.currentTarget.reportValidity()) {
140
- event.preventDefault();
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
+ }
141
206
  }
142
- }
143
207
 
144
- if (!event.defaultPrevented) {
145
- var _config$onSubmit;
208
+ if (!event.defaultPrevented) {
209
+ var _config$onSubmit;
146
210
 
147
- (_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event);
211
+ (_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, context);
212
+ }
148
213
  }
149
- }
150
214
 
215
+ },
216
+ config: fieldsetConfig
151
217
  };
152
218
  }
153
219
  /**
@@ -155,19 +221,55 @@ function useForm() {
155
221
  */
156
222
 
157
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
+ });
158
255
  var [error, setError] = useState(() => {
159
256
  var result = {};
160
257
 
161
- 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 : {})) {
162
- var _config$initialError;
258
+ for (var [key, entries] of Object.entries(uncontrolledState.initialError)) {
259
+ var _entries$;
163
260
 
164
- if (_error !== null && _error !== void 0 && _error.message) {
165
- result[key] = _error.message;
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 : '';
166
265
  }
167
266
  }
168
267
 
169
268
  return result;
170
269
  });
270
+ useEffect(() => {
271
+ configRef.current = config;
272
+ });
171
273
  useEffect(() => {
172
274
  /**
173
275
  * Reset the error state of each field if its validity is changed.
@@ -177,13 +279,16 @@ function useFieldset(ref, config) {
177
279
  */
178
280
  var resetError = form => {
179
281
  setError(prev => {
282
+ var _configRef$current$na, _configRef$current;
283
+
180
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 : '';
181
286
 
182
287
  for (var field of form.elements) {
183
- if (isFieldElement(field)) {
184
- var key = getKey(field.name, config === null || config === void 0 ? void 0 : config.name);
288
+ if (isFieldElement(field) && field.name.startsWith(fieldsetName)) {
289
+ var [key, ...paths] = getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name);
185
290
 
186
- if (key) {
291
+ if (typeof key === 'string' && paths.length === 0) {
187
292
  var _next$key, _next;
188
293
 
189
294
  var prevMessage = (_next$key = (_next = next) === null || _next === void 0 ? void 0 : _next[key]) !== null && _next$key !== void 0 ? _next$key : '';
@@ -219,29 +324,35 @@ function useFieldset(ref, config) {
219
324
  };
220
325
 
221
326
  var invalidHandler = event => {
327
+ var _configRef$current$na2, _configRef$current2;
328
+
222
329
  var form = getFormElement(ref.current);
223
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 : '';
224
332
 
225
- if (!form || !isFieldElement(field) || field.form !== form) {
333
+ if (!form || !isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
226
334
  return;
227
335
  }
228
336
 
229
- var key = getKey(field.name, config === null || config === void 0 ? void 0 : config.name); // Update the error only if the field belongs to the fieldset
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
230
338
 
231
- if (key) {
232
- setError(prev => {
233
- var _prev$key;
339
+ if (typeof key === 'string' && paths.length === 0) {
340
+ if (field.dataset.conformTouched) {
341
+ setError(prev => {
342
+ var _prev$key;
234
343
 
235
- var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
344
+ var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
236
345
 
237
- if (prevMessage === field.validationMessage) {
238
- return prev;
239
- }
346
+ if (prevMessage === field.validationMessage) {
347
+ return prev;
348
+ }
240
349
 
241
- return _objectSpread2(_objectSpread2({}, prev), {}, {
242
- [key]: field.validationMessage
350
+ return _objectSpread2(_objectSpread2({}, prev), {}, {
351
+ [key]: field.validationMessage
352
+ });
243
353
  });
244
- });
354
+ }
355
+
245
356
  event.preventDefault();
246
357
  }
247
358
  };
@@ -258,12 +369,20 @@ function useFieldset(ref, config) {
258
369
  };
259
370
 
260
371
  var resetHandler = event => {
372
+ var _fieldsetConfig$defau;
373
+
261
374
  var form = getFormElement(ref.current);
262
375
 
263
376
  if (!form || event.target !== form) {
264
377
  return;
265
378
  }
266
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
+ });
267
386
  setError({});
268
387
  };
269
388
 
@@ -278,26 +397,7 @@ function useFieldset(ref, config) {
278
397
  document.removeEventListener('submit', submitHandler);
279
398
  document.removeEventListener('reset', resetHandler);
280
399
  };
281
- }, [ref, config === null || config === void 0 ? void 0 : config.name]);
282
- useEffect(() => {
283
- setError(prev => {
284
- var next = prev;
285
-
286
- 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 : {})) {
287
- var _config$initialError2;
288
-
289
- if (next[key] !== (_error2 === null || _error2 === void 0 ? void 0 : _error2.message)) {
290
- var _error2$message;
291
-
292
- next = _objectSpread2(_objectSpread2({}, next), {}, {
293
- [key]: (_error2$message = _error2 === null || _error2 === void 0 ? void 0 : _error2.message) !== null && _error2$message !== void 0 ? _error2$message : ''
294
- });
295
- }
296
- }
297
-
298
- return next;
299
- });
300
- }, [config === null || config === void 0 ? void 0 : config.name, config === null || config === void 0 ? void 0 : config.initialError]);
400
+ }, [ref]);
301
401
  /**
302
402
  * This allows us constructing the field at runtime as we have no information
303
403
  * about which fields would be available. The proxy will also help tracking
@@ -306,19 +406,20 @@ function useFieldset(ref, config) {
306
406
 
307
407
  return new Proxy({}, {
308
408
  get(_target, key) {
309
- var _constraint, _config$defaultValue, _config$initialError$, _config$initialError3, _config$initialError4, _config$initialError5, _config$initialError6, _error$key;
409
+ var _fieldsetConfig$const, _error$key;
310
410
 
311
411
  if (typeof key !== 'string') {
312
412
  return;
313
413
  }
314
414
 
315
- var constraint = config === null || config === void 0 ? void 0 : (_constraint = config.constraint) === null || _constraint === void 0 ? void 0 : _constraint[key];
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];
316
417
  var field = {
317
418
  config: _objectSpread2({
318
- name: config !== null && config !== void 0 && config.name ? "".concat(config.name, ".").concat(key) : key,
319
- form: config === null || config === void 0 ? void 0 : config.form,
320
- defaultValue: config === null || config === void 0 ? void 0 : (_config$defaultValue = config.defaultValue) === null || _config$defaultValue === void 0 ? void 0 : _config$defaultValue[key],
321
- 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
419
+ name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
420
+ form: fieldsetConfig.form,
421
+ defaultValue: uncontrolledState.defaultValue[key],
422
+ initialError: uncontrolledState.initialError[key]
322
423
  }, constraint),
323
424
  error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''
324
425
  };
@@ -332,25 +433,55 @@ function useFieldset(ref, config) {
332
433
  * Returns a list of key and config, with a group of helpers
333
434
  * configuring buttons for list manipulation
334
435
  *
335
- * @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
436
+ * @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldlist
336
437
  */
337
438
  function useFieldList(ref, config) {
338
- var [entries, setEntries] = useState(() => {
439
+ var configRef = useRef(config);
440
+ var [uncontrolledState, setUncontrolledState] = useState(() => {
339
441
  var _config$defaultValue2;
340
442
 
341
- return Object.entries((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [undefined]);
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
+ };
342
469
  });
343
- var list = entries.map((_ref, index) => {
344
- var _config$defaultValue3, _config$initialError7, _config$initialError8;
470
+ var [entries, setEntries] = useState(() => {
471
+ var _config$defaultValue3;
345
472
 
346
- var [key, defaultValue] = _ref;
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;
347
477
  return {
348
478
  key,
349
- config: _objectSpread2(_objectSpread2({}, config), {}, {
479
+ config: {
350
480
  name: "".concat(config.name, "[").concat(index, "]"),
351
- defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue3 = config.defaultValue) === null || _config$defaultValue3 === void 0 ? void 0 : _config$defaultValue3[index],
352
- 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
353
- })
481
+ form: config.form,
482
+ defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index],
483
+ initialError: uncontrolledState.initialError[index]
484
+ }
354
485
  };
355
486
  });
356
487
  /***
@@ -363,9 +494,10 @@ function useFieldList(ref, config) {
363
494
  return function () {
364
495
  var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
365
496
  return {
366
- name: listCommandKey,
367
- value: serializeListCommand(config.name, {
497
+ name: 'conform/list',
498
+ value: JSON.stringify({
368
499
  type,
500
+ scope: config.name,
369
501
  payload
370
502
  }),
371
503
  form: config.form,
@@ -376,56 +508,45 @@ function useFieldList(ref, config) {
376
508
 
377
509
  });
378
510
  useEffect(() => {
379
- setEntries(prevEntries => {
380
- var _config$defaultValue4;
381
-
382
- var nextEntries = Object.entries((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : [undefined]);
383
-
384
- if (prevEntries.length !== nextEntries.length) {
385
- return nextEntries;
386
- }
387
-
388
- for (var i = 0; i < prevEntries.length; i++) {
389
- var [prevKey, prevValue] = prevEntries[i];
390
- var [nextKey, nextValue] = nextEntries[i];
391
-
392
- if (prevKey !== nextKey || prevValue !== nextValue) {
393
- return nextEntries;
394
- }
395
- } // No need to rerender in this case
396
-
397
-
398
- return prevEntries;
399
- });
400
-
511
+ configRef.current = config;
512
+ });
513
+ useEffect(() => {
401
514
  var submitHandler = event => {
402
515
  var form = getFormElement(ref.current);
403
516
 
404
- if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== listCommandKey) {
517
+ if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') {
405
518
  return;
406
519
  }
407
520
 
408
- var [name, command] = parseListCommand(event.submitter.value);
521
+ var command = parseListCommand(event.submitter.value);
409
522
 
410
- if (name !== config.name) {
523
+ if (command.scope !== configRef.current.name) {
411
524
  // Ensure the scope of the listener are limited to specific field name
412
525
  return;
413
526
  }
414
527
 
415
- switch (command.type) {
416
- case 'append':
417
- case 'prepend':
418
- case 'replace':
419
- command.payload.defaultValue = ["".concat(Date.now()), command.payload.defaultValue];
420
- break;
421
- }
422
-
423
- setEntries(entries => updateList([...(entries !== null && entries !== void 0 ? entries : [])], command));
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
+ });
424
545
  event.preventDefault();
425
546
  };
426
547
 
427
548
  var resetHandler = event => {
428
- var _config$defaultValue5;
549
+ var _fieldConfig$defaultV, _fieldConfig$defaultV2;
429
550
 
430
551
  var form = getFormElement(ref.current);
431
552
 
@@ -433,7 +554,12 @@ function useFieldList(ref, config) {
433
554
  return;
434
555
  }
435
556
 
436
- setEntries(Object.entries((_config$defaultValue5 = config.defaultValue) !== null && _config$defaultValue5 !== void 0 ? _config$defaultValue5 : []));
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]));
437
563
  };
438
564
 
439
565
  document.addEventListener('submit', submitHandler, true);
@@ -442,7 +568,7 @@ function useFieldList(ref, config) {
442
568
  document.removeEventListener('submit', submitHandler, true);
443
569
  document.removeEventListener('reset', resetHandler);
444
570
  };
445
- }, [ref, config.name, config.defaultValue]);
571
+ }, [ref]);
446
572
  return [list, control];
447
573
  }
448
574
 
@@ -451,14 +577,19 @@ function useFieldList(ref, config) {
451
577
  * This is particular useful when integrating dropdown and datepicker whichs
452
578
  * introduces custom input mode.
453
579
  *
454
- * @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
580
+ * @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usecontrolledinput
455
581
  */
456
- function useControlledInput(field) {
457
- var _field$defaultValue;
582
+ function useControlledInput(config) {
583
+ var _config$defaultValue4;
458
584
 
459
585
  var ref = useRef(null);
460
586
  var inputRef = useRef(null);
461
- var [value, setValue] = useState("".concat((_field$defaultValue = field.defaultValue) !== null && _field$defaultValue !== void 0 ? _field$defaultValue : ''));
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 : ''));
462
593
 
463
594
  var handleChange = eventOrValue => {
464
595
  if (!ref.current) {
@@ -485,6 +616,31 @@ function useControlledInput(field) {
485
616
  event.preventDefault();
486
617
  };
487
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
+ }, []);
488
644
  return [_objectSpread2({
489
645
  ref,
490
646
  style: {
@@ -505,7 +661,7 @@ function useControlledInput(field) {
505
661
  (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
506
662
  }
507
663
 
508
- }, input(field, {
664
+ }, input(_objectSpread2(_objectSpread2({}, config), uncontrolledState), {
509
665
  type: 'text'
510
666
  })), {
511
667
  ref: inputRef,