@conform-to/dom 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README CHANGED
@@ -8,7 +8,7 @@
8
8
  ╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
9
9
 
10
10
 
11
- Version 1.0.1 / License MIT / Copyright (c) 2024 Edmund Hung
11
+ Version 1.0.3 / License MIT / Copyright (c) 2024 Edmund Hung
12
12
 
13
13
  A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.
14
14
 
package/form.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { getFormAction, getFormEncType, getFormMethod } from './dom';
2
2
  import { type Intent, type Submission, type SubmissionResult } from './submission';
3
- export type UnionKeyof<T> = T extends any ? keyof T : never;
4
- export type UnionKeyType<T, K extends UnionKeyof<T>> = T extends {
5
- [k in K]?: any;
6
- } ? T[K] : undefined;
3
+ type BaseCombine<T, K extends PropertyKey = T extends unknown ? keyof T : never> = T extends unknown ? T & Partial<Record<Exclude<K, keyof T>, never>> : never;
4
+ export type Combine<T> = {
5
+ [K in keyof BaseCombine<T>]: BaseCombine<T>[K];
6
+ };
7
7
  export type DefaultValue<Schema> = Schema extends string | number | boolean | Date | bigint | null | undefined ? Schema | string | null | undefined : Schema extends File ? null | undefined : Schema extends Array<infer Item> ? Array<DefaultValue<Item>> | null | undefined : Schema extends Record<string, any> ? {
8
- [Key in UnionKeyof<Schema>]?: DefaultValue<UnionKeyType<Schema, Key>>;
8
+ [Key in keyof Schema]?: DefaultValue<Schema[Key]>;
9
9
  } | null | undefined : string | null | undefined;
10
- export type FormValue<Schema> = Schema extends string | number | boolean | Date | bigint | null | undefined ? string | undefined : Schema extends File ? File | undefined : Schema extends Array<infer Item> ? string | Array<FormValue<Item>> | undefined : Schema extends Record<string, any> ? {
11
- [Key in UnionKeyof<Schema>]?: FormValue<UnionKeyType<Schema, Key>>;
12
- } | undefined : unknown;
10
+ export type FormValue<Schema> = Schema extends string | number | boolean | Date | bigint | null | undefined ? string | undefined : Schema extends File ? File | undefined : Schema extends File[] ? File | Array<File> | undefined : Schema extends Array<infer Item> ? string | Array<FormValue<Item>> | undefined : Schema extends Record<string, any> ? {
11
+ [Key in keyof Schema]?: FormValue<Schema[Key]>;
12
+ } | null | undefined : unknown;
13
13
  declare const error: unique symbol;
14
14
  declare const field: unique symbol;
15
15
  declare const form: unique symbol;
@@ -90,6 +90,10 @@ export type FormOptions<Schema, FormError = string[], FormValue = Schema> = {
90
90
  submitter: HTMLInputElement | HTMLButtonElement | null;
91
91
  formData: FormData;
92
92
  }) => Submission<Schema, FormError, FormValue>;
93
+ /**
94
+ * To schedule when an intent should be dispatched.
95
+ */
96
+ onSchedule?: (callback: () => void) => void;
93
97
  };
94
98
  export type SubscriptionSubject = {
95
99
  [key in 'error' | 'initialValue' | 'value' | 'key' | 'valid' | 'dirty']?: SubscriptionScope;
package/form.js CHANGED
@@ -27,9 +27,7 @@ function createFormMeta(options, initialized) {
27
27
  // We can consider adding a warning if it happens
28
28
  error: (_ref = lastResult === null || lastResult === void 0 ? void 0 : lastResult.error) !== null && _ref !== void 0 ? _ref : {}
29
29
  };
30
- if (lastResult !== null && lastResult !== void 0 && lastResult.intent) {
31
- handleIntent(result, lastResult.intent);
32
- }
30
+ handleIntent(result, lastResult === null || lastResult === void 0 ? void 0 : lastResult.intent, lastResult === null || lastResult === void 0 ? void 0 : lastResult.fields);
33
31
  return result;
34
32
  }
35
33
  function getDefaultKey(defaultValue, prefix) {
@@ -45,24 +43,71 @@ function getDefaultKey(defaultValue, prefix) {
45
43
  return result;
46
44
  }, {});
47
45
  }
48
- function handleIntent(meta, intent, initialized) {
46
+ function setFieldsValidated(meta, fields) {
47
+ for (var _name of Object.keys(meta.error).concat(fields !== null && fields !== void 0 ? fields : [])) {
48
+ meta.validated[_name] = true;
49
+ }
50
+ }
51
+ function handleIntent(meta, intent, fields, initialized) {
52
+ if (!intent) {
53
+ setFieldsValidated(meta, fields);
54
+ return;
55
+ }
49
56
  switch (intent.type) {
57
+ case 'validate':
58
+ {
59
+ if (intent.payload.name) {
60
+ meta.validated[intent.payload.name] = true;
61
+ } else {
62
+ setFieldsValidated(meta, fields);
63
+ }
64
+ break;
65
+ }
50
66
  case 'update':
51
67
  {
52
- if (typeof intent.payload.value !== 'undefined') {
53
- var _intent$payload$name;
54
- var _name = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
55
- var value = submission.serialize(intent.payload.value);
56
- updateValue(meta, _name, value);
68
+ var {
69
+ name: _name2,
70
+ validated,
71
+ value
72
+ } = intent.payload;
73
+ if (typeof value !== 'undefined') {
74
+ updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', submission.serialize(value));
75
+ }
76
+ if (typeof validated !== 'undefined') {
77
+ // Clean up previous validated state
78
+ if (_name2) {
79
+ submission.setState(meta.validated, _name2, () => undefined);
80
+ } else {
81
+ meta.validated = {};
82
+ }
83
+ if (validated) {
84
+ if (formdata.isPlainObject(value) || Array.isArray(value)) {
85
+ Object.assign(meta.validated, formdata.flatten(value, {
86
+ resolve() {
87
+ return true;
88
+ },
89
+ prefix: _name2
90
+ }));
91
+ }
92
+ meta.validated[_name2 !== null && _name2 !== void 0 ? _name2 : ''] = true;
93
+ } else if (_name2) {
94
+ delete meta.validated[_name2];
95
+ }
57
96
  }
58
97
  break;
59
98
  }
60
99
  case 'reset':
61
100
  {
62
- var _intent$payload$name2;
63
- var _name2 = (_intent$payload$name2 = intent.payload.name) !== null && _intent$payload$name2 !== void 0 ? _intent$payload$name2 : '';
64
- var _value = formdata.getValue(meta.defaultValue, _name2);
65
- updateValue(meta, _name2, _value);
101
+ var _intent$payload$name;
102
+ var _name3 = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
103
+ var _value = formdata.getValue(meta.defaultValue, _name3);
104
+ updateValue(meta, _name3, _value);
105
+ if (_name3) {
106
+ submission.setState(meta.validated, _name3, () => undefined);
107
+ delete meta.validated[_name3];
108
+ } else {
109
+ meta.validated = {};
110
+ }
66
111
  break;
67
112
  }
68
113
  case 'insert':
@@ -75,9 +120,18 @@ function handleIntent(meta, intent, initialized) {
75
120
  submission.setListState(meta.key, intent, util.generateId);
76
121
  submission.setListValue(meta.initialValue, intent);
77
122
  }
123
+ submission.setListState(meta.validated, intent);
124
+ meta.validated[intent.payload.name] = true;
78
125
  break;
79
126
  }
80
127
  }
128
+ meta.error = Object.entries(meta.error).reduce((result, _ref3) => {
129
+ var [name, error] = _ref3;
130
+ if (meta.validated[name]) {
131
+ result[name] = error;
132
+ }
133
+ return result;
134
+ }, {});
81
135
  }
82
136
  function updateValue(meta, name, value) {
83
137
  meta.initialValue = util.clone(meta.initialValue);
@@ -96,6 +150,9 @@ function createStateProxy(fn) {
96
150
  return new Proxy(cache, {
97
151
  get(_, name, receiver) {
98
152
  var _cache$name;
153
+ if (typeof name !== 'string') {
154
+ return;
155
+ }
99
156
  return (_cache$name = cache[name]) !== null && _cache$name !== void 0 ? _cache$name : cache[name] = fn(name, receiver);
100
157
  }
101
158
  });
@@ -165,8 +222,8 @@ function createValidProxy(error) {
165
222
  function createDirtyProxy(defaultValue, value, shouldDirtyConsider) {
166
223
  return createStateProxy(name => JSON.stringify(defaultValue[name]) !== JSON.stringify(value[name], (key, value) => {
167
224
  if (name === '' && key === '' && value) {
168
- return Object.entries(value).reduce((result, _ref3) => {
169
- var [name, value] = _ref3;
225
+ return Object.entries(value).reduce((result, _ref4) => {
226
+ var [name, value] = _ref4;
170
227
  if (!shouldDirtyConsider(name)) {
171
228
  return result;
172
229
  }
@@ -185,11 +242,11 @@ function shouldNotify(prev, next, cache, scope) {
185
242
  var prefixes = (_scope$prefix = scope.prefix) !== null && _scope$prefix !== void 0 ? _scope$prefix : [];
186
243
  var names = (_scope$name = scope.name) !== null && _scope$name !== void 0 ? _scope$name : [];
187
244
  var list = prefixes.length === 0 ? names : Array.from(new Set([...Object.keys(prev), ...Object.keys(next)]));
188
- var _loop = function _loop(_name3) {
189
- if (prefixes.length === 0 || names.includes(_name3) || prefixes.some(prefix => formdata.isPrefix(_name3, prefix))) {
245
+ var _loop = function _loop(_name4) {
246
+ if (prefixes.length === 0 || names.includes(_name4) || prefixes.some(prefix => formdata.isPrefix(_name4, prefix))) {
190
247
  var _cache$_name;
191
- (_cache$_name = cache[_name3]) !== null && _cache$_name !== void 0 ? _cache$_name : cache[_name3] = compareFn(prev[_name3], next[_name3]);
192
- if (cache[_name3]) {
248
+ (_cache$_name = cache[_name4]) !== null && _cache$_name !== void 0 ? _cache$_name : cache[_name4] = compareFn(prev[_name4], next[_name4]);
249
+ if (cache[_name4]) {
193
250
  return {
194
251
  v: true
195
252
  };
@@ -197,8 +254,8 @@ function shouldNotify(prev, next, cache, scope) {
197
254
  }
198
255
  },
199
256
  _ret;
200
- for (var _name3 of list) {
201
- _ret = _loop(_name3);
257
+ for (var _name4 of list) {
258
+ _ret = _loop(_name4);
202
259
  if (_ret) return _ret.v;
203
260
  }
204
261
  }
@@ -263,19 +320,6 @@ function createFormContext(options) {
263
320
  var next = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
264
321
  return prev !== next;
265
322
  }
266
- function getStateInput(form) {
267
- var element = form.elements.namedItem(submission.STATE);
268
- util.invariant(element === null || dom.isFieldElement(element), "The input name \"".concat(submission.STATE, "\" is reserved by Conform. Please use another name."));
269
- if (!element) {
270
- var input = document.createElement('input');
271
- input.type = 'hidden';
272
- input.name = submission.STATE;
273
- input.value = '';
274
- form.append(input);
275
- return input;
276
- }
277
- return element;
278
- }
279
323
  function getSerializedState() {
280
324
  return JSON.stringify({
281
325
  validated: meta.validated
@@ -285,10 +329,6 @@ function createFormContext(options) {
285
329
  var form = event.target;
286
330
  var submitter = event.submitter;
287
331
  util.invariant(form === getFormElement(), "The submit event is dispatched by form#".concat(form.id, " instead of form#").concat(latestOptions.formId));
288
- var input = getStateInput(form);
289
-
290
- // To ensure it capturing latest state before parsing
291
- input.value = getSerializedState();
292
332
  var formData = formdata.getFormData(form, submitter);
293
333
  var result = {
294
334
  formData,
@@ -367,14 +407,14 @@ function createFormContext(options) {
367
407
  updateFormMeta(createFormMeta(latestOptions, true));
368
408
  }
369
409
  function report(result) {
370
- var _result$error, _result$state$validat, _result$state;
410
+ var _result$error, _result$state;
371
411
  var formElement = getFormElement();
372
412
  if (!result.initialValue) {
373
413
  formElement === null || formElement === void 0 || formElement.reset();
374
414
  return;
375
415
  }
376
- var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref4) => {
377
- var [name, newError] = _ref4;
416
+ var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
417
+ var [name, newError] = _ref5;
378
418
  var error = newError === null ? meta.error[name] : newError;
379
419
  if (error) {
380
420
  result[name] = error;
@@ -384,16 +424,14 @@ function createFormContext(options) {
384
424
  var update = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
385
425
  submissionStatus: result.status,
386
426
  value: result.initialValue,
387
- error,
388
- validated: (_result$state$validat = (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated) !== null && _result$state$validat !== void 0 ? _result$state$validat : {}
427
+ validated: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
428
+ error
389
429
  });
390
- if (result.intent) {
391
- handleIntent(update, result.intent, true);
392
- }
430
+ handleIntent(update, result.intent, result.fields, true);
393
431
  updateFormMeta(update);
394
432
  if (formElement && result.status === 'error') {
395
433
  for (var element of formElement.elements) {
396
- if (dom.isFieldElement(element) && error[element.name]) {
434
+ if (dom.isFieldElement(element) && meta.error[element.name]) {
397
435
  element.focus();
398
436
  break;
399
437
  }
@@ -447,12 +485,14 @@ function createFormContext(options) {
447
485
  };
448
486
  }
449
487
  function createFormControl(type) {
488
+ var _latestOptions$onSche;
489
+ var schedule = (_latestOptions$onSche = latestOptions.onSchedule) !== null && _latestOptions$onSche !== void 0 ? _latestOptions$onSche : callback => callback();
450
490
  var control = function control() {
451
491
  var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
452
- return dispatch({
492
+ return schedule(() => dispatch({
453
493
  type,
454
494
  payload
455
- });
495
+ }));
456
496
  };
457
497
  return Object.assign(control, {
458
498
  getButtonProps() {
package/form.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
- import { flatten, formatPaths, getPaths, getValue, setValue, isPlainObject, normalize, getFormData, isPrefix } from './formdata.mjs';
2
+ import { flatten, formatPaths, getPaths, getValue, isPlainObject, setValue, normalize, getFormData, isPrefix } from './formdata.mjs';
3
3
  import { getFormAction, getFormEncType, getFormMethod, isFieldElement, requestSubmit } from './dom.mjs';
4
4
  import { generateId, clone, invariant } from './util.mjs';
5
- import { serialize, setListState, setListValue, setState, getSubmissionContext, INTENT, serializeIntent, STATE } from './submission.mjs';
5
+ import { serialize, setListState, setListValue, setState, getSubmissionContext, INTENT, serializeIntent } from './submission.mjs';
6
6
 
7
7
  function createFormMeta(options, initialized) {
8
8
  var _lastResult$initialVa, _options$constraint, _lastResult$state$val, _lastResult$state, _ref;
@@ -23,9 +23,7 @@ function createFormMeta(options, initialized) {
23
23
  // We can consider adding a warning if it happens
24
24
  error: (_ref = lastResult === null || lastResult === void 0 ? void 0 : lastResult.error) !== null && _ref !== void 0 ? _ref : {}
25
25
  };
26
- if (lastResult !== null && lastResult !== void 0 && lastResult.intent) {
27
- handleIntent(result, lastResult.intent);
28
- }
26
+ handleIntent(result, lastResult === null || lastResult === void 0 ? void 0 : lastResult.intent, lastResult === null || lastResult === void 0 ? void 0 : lastResult.fields);
29
27
  return result;
30
28
  }
31
29
  function getDefaultKey(defaultValue, prefix) {
@@ -41,24 +39,71 @@ function getDefaultKey(defaultValue, prefix) {
41
39
  return result;
42
40
  }, {});
43
41
  }
44
- function handleIntent(meta, intent, initialized) {
42
+ function setFieldsValidated(meta, fields) {
43
+ for (var _name of Object.keys(meta.error).concat(fields !== null && fields !== void 0 ? fields : [])) {
44
+ meta.validated[_name] = true;
45
+ }
46
+ }
47
+ function handleIntent(meta, intent, fields, initialized) {
48
+ if (!intent) {
49
+ setFieldsValidated(meta, fields);
50
+ return;
51
+ }
45
52
  switch (intent.type) {
53
+ case 'validate':
54
+ {
55
+ if (intent.payload.name) {
56
+ meta.validated[intent.payload.name] = true;
57
+ } else {
58
+ setFieldsValidated(meta, fields);
59
+ }
60
+ break;
61
+ }
46
62
  case 'update':
47
63
  {
48
- if (typeof intent.payload.value !== 'undefined') {
49
- var _intent$payload$name;
50
- var _name = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
51
- var value = serialize(intent.payload.value);
52
- updateValue(meta, _name, value);
64
+ var {
65
+ name: _name2,
66
+ validated,
67
+ value
68
+ } = intent.payload;
69
+ if (typeof value !== 'undefined') {
70
+ updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', serialize(value));
71
+ }
72
+ if (typeof validated !== 'undefined') {
73
+ // Clean up previous validated state
74
+ if (_name2) {
75
+ setState(meta.validated, _name2, () => undefined);
76
+ } else {
77
+ meta.validated = {};
78
+ }
79
+ if (validated) {
80
+ if (isPlainObject(value) || Array.isArray(value)) {
81
+ Object.assign(meta.validated, flatten(value, {
82
+ resolve() {
83
+ return true;
84
+ },
85
+ prefix: _name2
86
+ }));
87
+ }
88
+ meta.validated[_name2 !== null && _name2 !== void 0 ? _name2 : ''] = true;
89
+ } else if (_name2) {
90
+ delete meta.validated[_name2];
91
+ }
53
92
  }
54
93
  break;
55
94
  }
56
95
  case 'reset':
57
96
  {
58
- var _intent$payload$name2;
59
- var _name2 = (_intent$payload$name2 = intent.payload.name) !== null && _intent$payload$name2 !== void 0 ? _intent$payload$name2 : '';
60
- var _value = getValue(meta.defaultValue, _name2);
61
- updateValue(meta, _name2, _value);
97
+ var _intent$payload$name;
98
+ var _name3 = (_intent$payload$name = intent.payload.name) !== null && _intent$payload$name !== void 0 ? _intent$payload$name : '';
99
+ var _value = getValue(meta.defaultValue, _name3);
100
+ updateValue(meta, _name3, _value);
101
+ if (_name3) {
102
+ setState(meta.validated, _name3, () => undefined);
103
+ delete meta.validated[_name3];
104
+ } else {
105
+ meta.validated = {};
106
+ }
62
107
  break;
63
108
  }
64
109
  case 'insert':
@@ -71,9 +116,18 @@ function handleIntent(meta, intent, initialized) {
71
116
  setListState(meta.key, intent, generateId);
72
117
  setListValue(meta.initialValue, intent);
73
118
  }
119
+ setListState(meta.validated, intent);
120
+ meta.validated[intent.payload.name] = true;
74
121
  break;
75
122
  }
76
123
  }
124
+ meta.error = Object.entries(meta.error).reduce((result, _ref3) => {
125
+ var [name, error] = _ref3;
126
+ if (meta.validated[name]) {
127
+ result[name] = error;
128
+ }
129
+ return result;
130
+ }, {});
77
131
  }
78
132
  function updateValue(meta, name, value) {
79
133
  meta.initialValue = clone(meta.initialValue);
@@ -92,6 +146,9 @@ function createStateProxy(fn) {
92
146
  return new Proxy(cache, {
93
147
  get(_, name, receiver) {
94
148
  var _cache$name;
149
+ if (typeof name !== 'string') {
150
+ return;
151
+ }
95
152
  return (_cache$name = cache[name]) !== null && _cache$name !== void 0 ? _cache$name : cache[name] = fn(name, receiver);
96
153
  }
97
154
  });
@@ -161,8 +218,8 @@ function createValidProxy(error) {
161
218
  function createDirtyProxy(defaultValue, value, shouldDirtyConsider) {
162
219
  return createStateProxy(name => JSON.stringify(defaultValue[name]) !== JSON.stringify(value[name], (key, value) => {
163
220
  if (name === '' && key === '' && value) {
164
- return Object.entries(value).reduce((result, _ref3) => {
165
- var [name, value] = _ref3;
221
+ return Object.entries(value).reduce((result, _ref4) => {
222
+ var [name, value] = _ref4;
166
223
  if (!shouldDirtyConsider(name)) {
167
224
  return result;
168
225
  }
@@ -181,11 +238,11 @@ function shouldNotify(prev, next, cache, scope) {
181
238
  var prefixes = (_scope$prefix = scope.prefix) !== null && _scope$prefix !== void 0 ? _scope$prefix : [];
182
239
  var names = (_scope$name = scope.name) !== null && _scope$name !== void 0 ? _scope$name : [];
183
240
  var list = prefixes.length === 0 ? names : Array.from(new Set([...Object.keys(prev), ...Object.keys(next)]));
184
- var _loop = function _loop(_name3) {
185
- if (prefixes.length === 0 || names.includes(_name3) || prefixes.some(prefix => isPrefix(_name3, prefix))) {
241
+ var _loop = function _loop(_name4) {
242
+ if (prefixes.length === 0 || names.includes(_name4) || prefixes.some(prefix => isPrefix(_name4, prefix))) {
186
243
  var _cache$_name;
187
- (_cache$_name = cache[_name3]) !== null && _cache$_name !== void 0 ? _cache$_name : cache[_name3] = compareFn(prev[_name3], next[_name3]);
188
- if (cache[_name3]) {
244
+ (_cache$_name = cache[_name4]) !== null && _cache$_name !== void 0 ? _cache$_name : cache[_name4] = compareFn(prev[_name4], next[_name4]);
245
+ if (cache[_name4]) {
189
246
  return {
190
247
  v: true
191
248
  };
@@ -193,8 +250,8 @@ function shouldNotify(prev, next, cache, scope) {
193
250
  }
194
251
  },
195
252
  _ret;
196
- for (var _name3 of list) {
197
- _ret = _loop(_name3);
253
+ for (var _name4 of list) {
254
+ _ret = _loop(_name4);
198
255
  if (_ret) return _ret.v;
199
256
  }
200
257
  }
@@ -259,19 +316,6 @@ function createFormContext(options) {
259
316
  var next = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
260
317
  return prev !== next;
261
318
  }
262
- function getStateInput(form) {
263
- var element = form.elements.namedItem(STATE);
264
- invariant(element === null || isFieldElement(element), "The input name \"".concat(STATE, "\" is reserved by Conform. Please use another name."));
265
- if (!element) {
266
- var input = document.createElement('input');
267
- input.type = 'hidden';
268
- input.name = STATE;
269
- input.value = '';
270
- form.append(input);
271
- return input;
272
- }
273
- return element;
274
- }
275
319
  function getSerializedState() {
276
320
  return JSON.stringify({
277
321
  validated: meta.validated
@@ -281,10 +325,6 @@ function createFormContext(options) {
281
325
  var form = event.target;
282
326
  var submitter = event.submitter;
283
327
  invariant(form === getFormElement(), "The submit event is dispatched by form#".concat(form.id, " instead of form#").concat(latestOptions.formId));
284
- var input = getStateInput(form);
285
-
286
- // To ensure it capturing latest state before parsing
287
- input.value = getSerializedState();
288
328
  var formData = getFormData(form, submitter);
289
329
  var result = {
290
330
  formData,
@@ -363,14 +403,14 @@ function createFormContext(options) {
363
403
  updateFormMeta(createFormMeta(latestOptions, true));
364
404
  }
365
405
  function report(result) {
366
- var _result$error, _result$state$validat, _result$state;
406
+ var _result$error, _result$state;
367
407
  var formElement = getFormElement();
368
408
  if (!result.initialValue) {
369
409
  formElement === null || formElement === void 0 || formElement.reset();
370
410
  return;
371
411
  }
372
- var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref4) => {
373
- var [name, newError] = _ref4;
412
+ var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
413
+ var [name, newError] = _ref5;
374
414
  var error = newError === null ? meta.error[name] : newError;
375
415
  if (error) {
376
416
  result[name] = error;
@@ -380,16 +420,14 @@ function createFormContext(options) {
380
420
  var update = _objectSpread2(_objectSpread2({}, meta), {}, {
381
421
  submissionStatus: result.status,
382
422
  value: result.initialValue,
383
- error,
384
- validated: (_result$state$validat = (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated) !== null && _result$state$validat !== void 0 ? _result$state$validat : {}
423
+ validated: _objectSpread2(_objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
424
+ error
385
425
  });
386
- if (result.intent) {
387
- handleIntent(update, result.intent, true);
388
- }
426
+ handleIntent(update, result.intent, result.fields, true);
389
427
  updateFormMeta(update);
390
428
  if (formElement && result.status === 'error') {
391
429
  for (var element of formElement.elements) {
392
- if (isFieldElement(element) && error[element.name]) {
430
+ if (isFieldElement(element) && meta.error[element.name]) {
393
431
  element.focus();
394
432
  break;
395
433
  }
@@ -443,12 +481,14 @@ function createFormContext(options) {
443
481
  };
444
482
  }
445
483
  function createFormControl(type) {
484
+ var _latestOptions$onSche;
485
+ var schedule = (_latestOptions$onSche = latestOptions.onSchedule) !== null && _latestOptions$onSche !== void 0 ? _latestOptions$onSche : callback => callback();
446
486
  var control = function control() {
447
487
  var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
448
- return dispatch({
488
+ return schedule(() => dispatch({
449
489
  type,
450
490
  payload
451
- });
491
+ }));
452
492
  };
453
493
  return Object.assign(control, {
454
494
  getButtonProps() {
package/formdata.d.ts CHANGED
@@ -45,9 +45,9 @@ export declare function isFile(obj: unknown): obj is File;
45
45
  /**
46
46
  * Normalize value by removing empty object or array, empty string and null values
47
47
  */
48
- export declare function normalize<Type extends Record<string, unknown>>(value: Type | null): Type | null | undefined;
49
- export declare function normalize<Type extends Array<unknown>>(value: Type | null): Type | null | undefined;
50
- export declare function normalize(value: unknown): unknown | undefined;
48
+ export declare function normalize<Type extends Record<string, unknown>>(value: Type, acceptFile?: boolean): Type | undefined;
49
+ export declare function normalize<Type extends Array<unknown>>(value: Type, acceptFile?: boolean): Type | undefined;
50
+ export declare function normalize(value: unknown, acceptFile?: boolean): unknown | undefined;
51
51
  /**
52
52
  * Flatten a tree into a dictionary
53
53
  */
package/formdata.js CHANGED
@@ -136,9 +136,10 @@ function isFile(obj) {
136
136
  */
137
137
 
138
138
  function normalize(value) {
139
+ var acceptFile = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
139
140
  if (isPlainObject(value)) {
140
141
  var obj = Object.keys(value).sort().reduce((result, key) => {
141
- var data = normalize(value[key]);
142
+ var data = normalize(value[key], acceptFile);
142
143
  if (typeof data !== 'undefined') {
143
144
  result[key] = data;
144
145
  }
@@ -153,9 +154,9 @@ function normalize(value) {
153
154
  if (value.length === 0) {
154
155
  return undefined;
155
156
  }
156
- return value.map(normalize);
157
+ return value.map(item => normalize(item, acceptFile));
157
158
  }
158
- if (typeof value === 'string' && value === '' || value === null || isFile(value)) {
159
+ if (typeof value === 'string' && value === '' || value === null || isFile(value) && (!acceptFile || value.size === 0)) {
159
160
  return;
160
161
  }
161
162
  return value;
package/formdata.mjs CHANGED
@@ -132,9 +132,10 @@ function isFile(obj) {
132
132
  */
133
133
 
134
134
  function normalize(value) {
135
+ var acceptFile = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
135
136
  if (isPlainObject(value)) {
136
137
  var obj = Object.keys(value).sort().reduce((result, key) => {
137
- var data = normalize(value[key]);
138
+ var data = normalize(value[key], acceptFile);
138
139
  if (typeof data !== 'undefined') {
139
140
  result[key] = data;
140
141
  }
@@ -149,9 +150,9 @@ function normalize(value) {
149
150
  if (value.length === 0) {
150
151
  return undefined;
151
152
  }
152
- return value.map(normalize);
153
+ return value.map(item => normalize(item, acceptFile));
153
154
  }
154
- if (typeof value === 'string' && value === '' || value === null || isFile(value)) {
155
+ if (typeof value === 'string' && value === '' || value === null || isFile(value) && (!acceptFile || value.size === 0)) {
155
156
  return;
156
157
  }
157
158
  return value;
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type UnionKeyof, type UnionKeyType, type Constraint, type ControlButtonProps, type FormId, type FieldName, type DefaultValue, type FormValue, type FormOptions, type FormState, type FormContext, type SubscriptionSubject, type SubscriptionScope, createFormContext as unstable_createFormContext, } from './form';
1
+ export { type Combine, type Constraint, type ControlButtonProps, type FormId, type FieldName, type DefaultValue, type FormValue, type FormOptions, type FormState, type FormContext, type SubscriptionSubject, type SubscriptionScope, createFormContext as unstable_createFormContext, } from './form';
2
2
  export { type FieldElement, isFieldElement } from './dom';
3
3
  export { type Submission, type SubmissionResult, type Intent, INTENT, STATE, serializeIntent, parse, } from './submission';
4
4
  export { getPaths, formatPaths, isPrefix } from './formdata';
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A set of opinionated helpers built on top of the Constraint Validation API",
4
4
  "homepage": "https://conform.guide",
5
5
  "license": "MIT",
6
- "version": "1.0.1",
6
+ "version": "1.0.3",
7
7
  "main": "index.js",
8
8
  "module": "index.mjs",
9
9
  "types": "index.d.ts",
package/submission.d.ts CHANGED
@@ -5,10 +5,10 @@ export type SubmissionState = {
5
5
  export type SubmissionContext<Value = null, FormError = string[]> = {
6
6
  intent: Intent | null;
7
7
  payload: Record<string, unknown>;
8
- fields: string[];
8
+ fields: Set<string>;
9
9
  value?: Value;
10
10
  error?: Record<string, FormError | null> | null;
11
- state: SubmissionState;
11
+ state?: SubmissionState;
12
12
  };
13
13
  export type Submission<Schema, FormError = string[], FormValue = Schema> = {
14
14
  status: 'success';
@@ -25,6 +25,7 @@ export type SubmissionResult<FormError = string[]> = {
25
25
  status?: 'error' | 'success';
26
26
  intent?: Intent;
27
27
  initialValue?: Record<string, unknown> | null;
28
+ fields?: string[];
28
29
  error?: Record<string, FormError | null>;
29
30
  state?: SubmissionState;
30
31
  };
package/submission.js CHANGED
@@ -18,15 +18,21 @@ var STATE = '__state__';
18
18
  function getSubmissionContext(body) {
19
19
  var intent = body.get(INTENT);
20
20
  var state = body.get(STATE);
21
- var payload = {};
22
- var fields = [];
23
21
  util.invariant((typeof intent === 'string' || intent === null) && (typeof state === 'string' || state === null), "The input name \"".concat(INTENT, "\" and \"").concat(STATE, "\" are reserved by Conform. Please use another name for your input."));
22
+ var context = {
23
+ payload: {},
24
+ fields: new Set(),
25
+ intent: getIntent(intent)
26
+ };
27
+ if (state) {
28
+ context.state = JSON.parse(state);
29
+ }
24
30
  var _loop = function _loop(next) {
25
31
  if (name === INTENT || name === STATE) {
26
32
  return 1; // continue
27
33
  }
28
- fields.push(name);
29
- formdata.setValue(payload, name, prev => {
34
+ context.fields.add(name);
35
+ formdata.setValue(context.payload, name, prev => {
30
36
  if (!prev) {
31
37
  return next;
32
38
  } else if (Array.isArray(prev)) {
@@ -39,30 +45,17 @@ function getSubmissionContext(body) {
39
45
  for (var [name, next] of body.entries()) {
40
46
  if (_loop(next)) continue;
41
47
  }
42
- return {
43
- payload,
44
- intent: getIntent(intent),
45
- state: state ? JSON.parse(state) : {
46
- validated: {}
47
- },
48
- fields
49
- };
48
+ return context;
50
49
  }
51
50
  function parse(payload, options) {
52
51
  var context = getSubmissionContext(payload);
53
52
  var intent = context.intent;
54
53
  if (intent) {
55
54
  switch (intent.type) {
56
- case 'validate':
57
- if (intent.payload.name) {
58
- context.state.validated[intent.payload.name] = true;
59
- }
60
- break;
61
55
  case 'update':
62
56
  {
63
57
  var {
64
- name,
65
- validated
58
+ name
66
59
  } = intent.payload;
67
60
  var _value = serialize(intent.payload.value);
68
61
  if (typeof _value !== 'undefined') {
@@ -73,27 +66,6 @@ function parse(payload, options) {
73
66
  context.payload = _value;
74
67
  }
75
68
  }
76
- if (typeof validated !== 'undefined') {
77
- // Clean up previous validated state
78
- if (name) {
79
- setState(context.state.validated, name, () => undefined);
80
- } else {
81
- context.state.validated = {};
82
- }
83
- if (validated) {
84
- if (formdata.isPlainObject(_value) || Array.isArray(_value)) {
85
- Object.assign(context.state.validated, formdata.flatten(_value, {
86
- resolve() {
87
- return true;
88
- },
89
- prefix: name
90
- }));
91
- }
92
- context.state.validated[name !== null && name !== void 0 ? name : ''] = true;
93
- } else if (name) {
94
- delete context.state.validated[name];
95
- }
96
- }
97
69
  break;
98
70
  }
99
71
  case 'reset':
@@ -103,11 +75,8 @@ function parse(payload, options) {
103
75
  } = intent.payload;
104
76
  if (_name) {
105
77
  formdata.setValue(context.payload, _name, () => undefined);
106
- setState(context.state.validated, _name, () => undefined);
107
- delete context.state.validated[_name];
108
78
  } else {
109
79
  context.payload = {};
110
- context.state.validated = {};
111
80
  }
112
81
  break;
113
82
  }
@@ -116,25 +85,15 @@ function parse(payload, options) {
116
85
  case 'reorder':
117
86
  {
118
87
  setListValue(context.payload, intent);
119
- setListState(context.state.validated, intent);
120
- context.state.validated[intent.payload.name] = true;
121
88
  break;
122
89
  }
123
90
  }
124
91
  }
125
92
  var result = options.resolve(context.payload, intent);
126
- var mergeResolveResult = resolved => {
127
- var error = typeof resolved.error !== 'undefined' ? resolved.error : {};
128
- if (!intent || intent.type === 'validate' && !intent.payload.name) {
129
- for (var _name2 of [...context.fields, ...Object.keys(error !== null && error !== void 0 ? error : {})]) {
130
- context.state.validated[_name2] = true;
131
- }
132
- }
133
- return createSubmission(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, context), {}, {
134
- value: resolved.value,
135
- error: resolved.error
136
- }));
137
- };
93
+ var mergeResolveResult = resolved => createSubmission(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, context), {}, {
94
+ value: resolved.value,
95
+ error: resolved.error
96
+ }));
138
97
  if (result instanceof Promise) {
139
98
  return result.then(mergeResolveResult);
140
99
  }
@@ -161,50 +120,34 @@ function createSubmission(context) {
161
120
  };
162
121
  }
163
122
  function replySubmission(context) {
164
- var _context$intent, _options$formErrors, _normalize;
123
+ var _context$intent, _context$intent$paylo, _options$formErrors, _normalize;
165
124
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
166
- switch ((_context$intent = context.intent) === null || _context$intent === void 0 ? void 0 : _context$intent.type) {
167
- case 'reset':
168
- {
169
- var _context$intent$paylo;
170
- var name = (_context$intent$paylo = context.intent.payload.name) !== null && _context$intent$paylo !== void 0 ? _context$intent$paylo : '';
171
- if (name === '') {
172
- return {
173
- initialValue: null
174
- };
175
- }
176
- }
177
- }
178
- if ('resetForm' in options && options.resetForm) {
125
+ if ('resetForm' in options && options.resetForm || ((_context$intent = context.intent) === null || _context$intent === void 0 ? void 0 : _context$intent.type) === 'reset' && ((_context$intent$paylo = context.intent.payload.name) !== null && _context$intent$paylo !== void 0 ? _context$intent$paylo : '') === '') {
179
126
  return {
180
127
  initialValue: null
181
128
  };
182
129
  }
183
130
  if ('hideFields' in options && options.hideFields) {
184
- for (var _name3 of options.hideFields) {
185
- var _value2 = formdata.getValue(context.payload, _name3);
131
+ for (var name of options.hideFields) {
132
+ var _value2 = formdata.getValue(context.payload, name);
186
133
  if (typeof _value2 !== 'undefined') {
187
- formdata.setValue(context.payload, _name3, () => undefined);
134
+ formdata.setValue(context.payload, name, () => undefined);
188
135
  }
189
136
  }
190
137
  }
191
- var submissionError = context.error ? Object.entries(context.error).reduce((result, _ref) => {
192
- var [name, error] = _ref;
193
- if (context.state.validated[name]) {
194
- result[name] = error;
195
- }
196
- return result;
197
- }, {}) : undefined;
198
138
  var extraError = 'formErrors' in options || 'fieldErrors' in options ? formdata.normalize(_rollupPluginBabelHelpers.objectSpread2({
199
139
  '': (_options$formErrors = options.formErrors) !== null && _options$formErrors !== void 0 ? _options$formErrors : null
200
140
  }, options.fieldErrors)) : null;
201
- var error = submissionError || extraError ? _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, submissionError), extraError) : undefined;
141
+ var error = context.error || extraError ? _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, context.error), extraError) : undefined;
202
142
  return {
203
143
  status: context.intent ? undefined : error ? 'error' : 'success',
204
144
  intent: context.intent ? context.intent : undefined,
205
- initialValue: (_normalize = formdata.normalize(context.payload)) !== null && _normalize !== void 0 ? _normalize : {},
145
+ initialValue: (_normalize = formdata.normalize(context.payload,
146
+ // We can't serialize the file and send it back from the server, but we can preserve it in the client
147
+ typeof document !== 'undefined')) !== null && _normalize !== void 0 ? _normalize : {},
206
148
  error,
207
- state: context.state
149
+ state: context.state,
150
+ fields: Array.from(context.fields)
208
151
  };
209
152
  }
210
153
  function getIntent(serializedIntent) {
@@ -310,8 +253,8 @@ function setListState(state, intent, getDefaultValue) {
310
253
  function serialize(defaultValue) {
311
254
  if (formdata.isPlainObject(defaultValue)) {
312
255
  // @ts-expect-error FIXME
313
- return Object.entries(defaultValue).reduce((result, _ref2) => {
314
- var [key, value] = _ref2;
256
+ return Object.entries(defaultValue).reduce((result, _ref) => {
257
+ var [key, value] = _ref;
315
258
  // @ts-ignore-error FIXME
316
259
  result[key] = serialize(value);
317
260
  return result;
package/submission.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
- import { setValue, isPlainObject, flatten, getValue, normalize, isPrefix } from './formdata.mjs';
2
+ import { setValue, isPlainObject, getValue, normalize, flatten, isPrefix } from './formdata.mjs';
3
3
  import { invariant } from './util.mjs';
4
4
 
5
5
  /**
@@ -14,15 +14,21 @@ var STATE = '__state__';
14
14
  function getSubmissionContext(body) {
15
15
  var intent = body.get(INTENT);
16
16
  var state = body.get(STATE);
17
- var payload = {};
18
- var fields = [];
19
17
  invariant((typeof intent === 'string' || intent === null) && (typeof state === 'string' || state === null), "The input name \"".concat(INTENT, "\" and \"").concat(STATE, "\" are reserved by Conform. Please use another name for your input."));
18
+ var context = {
19
+ payload: {},
20
+ fields: new Set(),
21
+ intent: getIntent(intent)
22
+ };
23
+ if (state) {
24
+ context.state = JSON.parse(state);
25
+ }
20
26
  var _loop = function _loop(next) {
21
27
  if (name === INTENT || name === STATE) {
22
28
  return 1; // continue
23
29
  }
24
- fields.push(name);
25
- setValue(payload, name, prev => {
30
+ context.fields.add(name);
31
+ setValue(context.payload, name, prev => {
26
32
  if (!prev) {
27
33
  return next;
28
34
  } else if (Array.isArray(prev)) {
@@ -35,30 +41,17 @@ function getSubmissionContext(body) {
35
41
  for (var [name, next] of body.entries()) {
36
42
  if (_loop(next)) continue;
37
43
  }
38
- return {
39
- payload,
40
- intent: getIntent(intent),
41
- state: state ? JSON.parse(state) : {
42
- validated: {}
43
- },
44
- fields
45
- };
44
+ return context;
46
45
  }
47
46
  function parse(payload, options) {
48
47
  var context = getSubmissionContext(payload);
49
48
  var intent = context.intent;
50
49
  if (intent) {
51
50
  switch (intent.type) {
52
- case 'validate':
53
- if (intent.payload.name) {
54
- context.state.validated[intent.payload.name] = true;
55
- }
56
- break;
57
51
  case 'update':
58
52
  {
59
53
  var {
60
- name,
61
- validated
54
+ name
62
55
  } = intent.payload;
63
56
  var _value = serialize(intent.payload.value);
64
57
  if (typeof _value !== 'undefined') {
@@ -69,27 +62,6 @@ function parse(payload, options) {
69
62
  context.payload = _value;
70
63
  }
71
64
  }
72
- if (typeof validated !== 'undefined') {
73
- // Clean up previous validated state
74
- if (name) {
75
- setState(context.state.validated, name, () => undefined);
76
- } else {
77
- context.state.validated = {};
78
- }
79
- if (validated) {
80
- if (isPlainObject(_value) || Array.isArray(_value)) {
81
- Object.assign(context.state.validated, flatten(_value, {
82
- resolve() {
83
- return true;
84
- },
85
- prefix: name
86
- }));
87
- }
88
- context.state.validated[name !== null && name !== void 0 ? name : ''] = true;
89
- } else if (name) {
90
- delete context.state.validated[name];
91
- }
92
- }
93
65
  break;
94
66
  }
95
67
  case 'reset':
@@ -99,11 +71,8 @@ function parse(payload, options) {
99
71
  } = intent.payload;
100
72
  if (_name) {
101
73
  setValue(context.payload, _name, () => undefined);
102
- setState(context.state.validated, _name, () => undefined);
103
- delete context.state.validated[_name];
104
74
  } else {
105
75
  context.payload = {};
106
- context.state.validated = {};
107
76
  }
108
77
  break;
109
78
  }
@@ -112,25 +81,15 @@ function parse(payload, options) {
112
81
  case 'reorder':
113
82
  {
114
83
  setListValue(context.payload, intent);
115
- setListState(context.state.validated, intent);
116
- context.state.validated[intent.payload.name] = true;
117
84
  break;
118
85
  }
119
86
  }
120
87
  }
121
88
  var result = options.resolve(context.payload, intent);
122
- var mergeResolveResult = resolved => {
123
- var error = typeof resolved.error !== 'undefined' ? resolved.error : {};
124
- if (!intent || intent.type === 'validate' && !intent.payload.name) {
125
- for (var _name2 of [...context.fields, ...Object.keys(error !== null && error !== void 0 ? error : {})]) {
126
- context.state.validated[_name2] = true;
127
- }
128
- }
129
- return createSubmission(_objectSpread2(_objectSpread2({}, context), {}, {
130
- value: resolved.value,
131
- error: resolved.error
132
- }));
133
- };
89
+ var mergeResolveResult = resolved => createSubmission(_objectSpread2(_objectSpread2({}, context), {}, {
90
+ value: resolved.value,
91
+ error: resolved.error
92
+ }));
134
93
  if (result instanceof Promise) {
135
94
  return result.then(mergeResolveResult);
136
95
  }
@@ -157,50 +116,34 @@ function createSubmission(context) {
157
116
  };
158
117
  }
159
118
  function replySubmission(context) {
160
- var _context$intent, _options$formErrors, _normalize;
119
+ var _context$intent, _context$intent$paylo, _options$formErrors, _normalize;
161
120
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
162
- switch ((_context$intent = context.intent) === null || _context$intent === void 0 ? void 0 : _context$intent.type) {
163
- case 'reset':
164
- {
165
- var _context$intent$paylo;
166
- var name = (_context$intent$paylo = context.intent.payload.name) !== null && _context$intent$paylo !== void 0 ? _context$intent$paylo : '';
167
- if (name === '') {
168
- return {
169
- initialValue: null
170
- };
171
- }
172
- }
173
- }
174
- if ('resetForm' in options && options.resetForm) {
121
+ if ('resetForm' in options && options.resetForm || ((_context$intent = context.intent) === null || _context$intent === void 0 ? void 0 : _context$intent.type) === 'reset' && ((_context$intent$paylo = context.intent.payload.name) !== null && _context$intent$paylo !== void 0 ? _context$intent$paylo : '') === '') {
175
122
  return {
176
123
  initialValue: null
177
124
  };
178
125
  }
179
126
  if ('hideFields' in options && options.hideFields) {
180
- for (var _name3 of options.hideFields) {
181
- var _value2 = getValue(context.payload, _name3);
127
+ for (var name of options.hideFields) {
128
+ var _value2 = getValue(context.payload, name);
182
129
  if (typeof _value2 !== 'undefined') {
183
- setValue(context.payload, _name3, () => undefined);
130
+ setValue(context.payload, name, () => undefined);
184
131
  }
185
132
  }
186
133
  }
187
- var submissionError = context.error ? Object.entries(context.error).reduce((result, _ref) => {
188
- var [name, error] = _ref;
189
- if (context.state.validated[name]) {
190
- result[name] = error;
191
- }
192
- return result;
193
- }, {}) : undefined;
194
134
  var extraError = 'formErrors' in options || 'fieldErrors' in options ? normalize(_objectSpread2({
195
135
  '': (_options$formErrors = options.formErrors) !== null && _options$formErrors !== void 0 ? _options$formErrors : null
196
136
  }, options.fieldErrors)) : null;
197
- var error = submissionError || extraError ? _objectSpread2(_objectSpread2({}, submissionError), extraError) : undefined;
137
+ var error = context.error || extraError ? _objectSpread2(_objectSpread2({}, context.error), extraError) : undefined;
198
138
  return {
199
139
  status: context.intent ? undefined : error ? 'error' : 'success',
200
140
  intent: context.intent ? context.intent : undefined,
201
- initialValue: (_normalize = normalize(context.payload)) !== null && _normalize !== void 0 ? _normalize : {},
141
+ initialValue: (_normalize = normalize(context.payload,
142
+ // We can't serialize the file and send it back from the server, but we can preserve it in the client
143
+ typeof document !== 'undefined')) !== null && _normalize !== void 0 ? _normalize : {},
202
144
  error,
203
- state: context.state
145
+ state: context.state,
146
+ fields: Array.from(context.fields)
204
147
  };
205
148
  }
206
149
  function getIntent(serializedIntent) {
@@ -306,8 +249,8 @@ function setListState(state, intent, getDefaultValue) {
306
249
  function serialize(defaultValue) {
307
250
  if (isPlainObject(defaultValue)) {
308
251
  // @ts-expect-error FIXME
309
- return Object.entries(defaultValue).reduce((result, _ref2) => {
310
- var [key, value] = _ref2;
252
+ return Object.entries(defaultValue).reduce((result, _ref) => {
253
+ var [key, value] = _ref;
311
254
  // @ts-ignore-error FIXME
312
255
  result[key] = serialize(value);
313
256
  return result;