@conform-to/dom 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README CHANGED
@@ -8,7 +8,7 @@
8
8
  ╚══════╝ ╚═════╝ ╚═╝ ╚══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
9
9
 
10
10
 
11
- Version 1.0.6 / License MIT / Copyright (c) 2024 Edmund Hung
11
+ Version 1.1.0 / 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
@@ -33,6 +33,8 @@ export type Constraint = {
33
33
  pattern?: string;
34
34
  };
35
35
  export type FormMeta<FormError> = {
36
+ formId: string;
37
+ isValueUpdated: boolean;
36
38
  submissionStatus?: 'error' | 'success';
37
39
  defaultValue: Record<string, unknown>;
38
40
  initialValue: Record<string, unknown>;
@@ -42,7 +44,7 @@ export type FormMeta<FormError> = {
42
44
  key: Record<string, string | undefined>;
43
45
  validated: Record<string, boolean>;
44
46
  };
45
- export type FormState<FormError> = FormMeta<FormError> & {
47
+ export type FormState<FormError> = Omit<FormMeta<FormError>, 'formId' | 'isValueUpdated'> & {
46
48
  valid: Record<string, boolean>;
47
49
  dirty: Record<string, boolean>;
48
50
  };
@@ -94,6 +96,7 @@ export type FormOptions<Schema, FormError = string[], FormValue = Schema> = {
94
96
  export type SubscriptionSubject = {
95
97
  [key in 'error' | 'initialValue' | 'value' | 'key' | 'valid' | 'dirty']?: SubscriptionScope;
96
98
  } & {
99
+ formId?: boolean;
97
100
  status?: boolean;
98
101
  };
99
102
  export type SubscriptionScope = {
@@ -107,7 +110,7 @@ export type ControlButtonProps = {
107
110
  formNoValidate: boolean;
108
111
  };
109
112
  export type FormContext<Schema extends Record<string, any> = any, FormError = string[], FormValue = Schema> = {
110
- formId: string;
113
+ getFormId(): string;
111
114
  submit(event: SubmitEvent): {
112
115
  formData: FormData;
113
116
  action: ReturnType<typeof getFormAction>;
@@ -119,6 +122,7 @@ export type FormContext<Schema extends Record<string, any> = any, FormError = st
119
122
  onInput(event: Event): void;
120
123
  onBlur(event: Event): void;
121
124
  onUpdate(options: Partial<FormOptions<Schema, FormError, FormValue>>): void;
125
+ observe(): () => void;
122
126
  subscribe(callback: () => void, getSubject?: () => SubscriptionSubject | undefined): () => void;
123
127
  getState(): FormState<FormError>;
124
128
  getSerializedState(): string;
package/form.js CHANGED
@@ -14,6 +14,8 @@ function createFormMeta(options, initialized) {
14
14
  var defaultValue = options.defaultValue ? submission.serialize(options.defaultValue) : {};
15
15
  var initialValue = (_lastResult$initialVa = lastResult === null || lastResult === void 0 ? void 0 : lastResult.initialValue) !== null && _lastResult$initialVa !== void 0 ? _lastResult$initialVa : defaultValue;
16
16
  var result = {
17
+ formId: options.formId,
18
+ isValueUpdated: false,
17
19
  submissionStatus: lastResult === null || lastResult === void 0 ? void 0 : lastResult.status,
18
20
  defaultValue,
19
21
  initialValue,
@@ -37,7 +39,7 @@ function getDefaultKey(defaultValue, prefix) {
37
39
  var [key, value] = _ref2;
38
40
  if (Array.isArray(value)) {
39
41
  for (var i = 0; i < value.length; i++) {
40
- result[formdata.formatPaths([...formdata.getPaths(key), i])] = util.generateId();
42
+ result[formdata.formatName(key, i)] = util.generateId();
41
43
  }
42
44
  }
43
45
  return result;
@@ -66,10 +68,10 @@ function handleIntent(meta, intent, fields, initialized) {
66
68
  case 'update':
67
69
  {
68
70
  var {
69
- name: _name2,
70
71
  validated,
71
72
  value
72
73
  } = intent.payload;
74
+ var _name2 = formdata.formatName(intent.payload.name, intent.payload.index);
73
75
  if (typeof value !== 'undefined') {
74
76
  updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', submission.serialize(value));
75
77
  }
@@ -98,8 +100,7 @@ function handleIntent(meta, intent, fields, initialized) {
98
100
  }
99
101
  case 'reset':
100
102
  {
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 _name3 = formdata.formatName(intent.payload.name, intent.payload.index);
103
104
  var _value = formdata.getValue(meta.defaultValue, _name3);
104
105
  updateValue(meta, _name3, _value);
105
106
  if (_name3) {
@@ -323,7 +324,7 @@ function createFormContext(options) {
323
324
  for (var subscriber of subscribers) {
324
325
  var _subscriber$getSubjec;
325
326
  var subject = (_subscriber$getSubjec = subscriber.getSubject) === null || _subscriber$getSubjec === void 0 ? void 0 : _subscriber$getSubjec.call(subscriber);
326
- if (!subject || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
327
+ if (!subject || subject.formId && prevMeta.formId !== nextMeta.formId || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
327
328
  subscriber.callback();
328
329
  }
329
330
  }
@@ -357,8 +358,11 @@ function createFormContext(options) {
357
358
  formData,
358
359
  submitter
359
360
  });
360
- if (submission.status !== 'success' && submission.error !== null) {
361
- report(submission.reply());
361
+ if (submission.status === 'success' || submission.error !== null) {
362
+ var _result2 = submission.reply();
363
+ report(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _result2), {}, {
364
+ status: _result2.status !== 'success' ? _result2.status : undefined
365
+ }));
362
366
  }
363
367
  return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, result), {}, {
364
368
  submission
@@ -378,7 +382,15 @@ function createFormContext(options) {
378
382
  shouldRevalidate = shouldValidate
379
383
  } = latestOptions;
380
384
  var validated = meta.validated[element.name];
381
- return validated ? shouldRevalidate === eventName : shouldValidate === eventName;
385
+ return validated ? shouldRevalidate === eventName && (eventName === 'onInput' || meta.isValueUpdated) : shouldValidate === eventName;
386
+ }
387
+ function updateFormValue(form) {
388
+ var formData = new FormData(form);
389
+ var result = submission.getSubmissionContext(formData);
390
+ updateFormMeta(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
391
+ isValueUpdated: true,
392
+ value: result.payload
393
+ }));
382
394
  }
383
395
  function onInput(event) {
384
396
  var element = resolveTarget(event);
@@ -386,11 +398,7 @@ function createFormContext(options) {
386
398
  return;
387
399
  }
388
400
  if (event.defaultPrevented || !willValidate(element, 'onInput')) {
389
- var formData = new FormData(element.form);
390
- var result = submission.getSubmissionContext(formData);
391
- updateFormMeta(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
392
- value: result.payload
393
- }));
401
+ updateFormValue(element.form);
394
402
  } else {
395
403
  dispatch({
396
404
  type: 'validate',
@@ -412,18 +420,21 @@ function createFormContext(options) {
412
420
  }
413
421
  });
414
422
  }
423
+ function reset() {
424
+ updateFormMeta(createFormMeta(latestOptions, true));
425
+ }
415
426
  function onReset(event) {
416
427
  var element = getFormElement();
417
428
  if (event.type !== 'reset' || event.target !== element || event.defaultPrevented) {
418
429
  return;
419
430
  }
420
- updateFormMeta(createFormMeta(latestOptions, true));
431
+ reset();
421
432
  }
422
433
  function report(result) {
423
434
  var _result$error, _result$state;
424
435
  var formElement = getFormElement();
425
436
  if (!result.initialValue) {
426
- formElement === null || formElement === void 0 || formElement.reset();
437
+ reset();
427
438
  return;
428
439
  }
429
440
  var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
@@ -435,6 +446,7 @@ function createFormContext(options) {
435
446
  return result;
436
447
  }, {});
437
448
  var update = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta), {}, {
449
+ isValueUpdated: false,
438
450
  submissionStatus: result.status,
439
451
  value: result.initialValue,
440
452
  validated: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
@@ -458,8 +470,7 @@ function createFormContext(options) {
458
470
  // Merge new options with the latest options
459
471
  Object.assign(latestOptions, options);
460
472
  if (latestOptions.formId !== currentFormId) {
461
- var _getFormElement;
462
- (_getFormElement = getFormElement()) === null || _getFormElement === void 0 || _getFormElement.reset();
473
+ reset();
463
474
  } else if (options.lastResult && options.lastResult !== currentResult) {
464
475
  report(options.lastResult);
465
476
  }
@@ -515,9 +526,36 @@ function createFormContext(options) {
515
526
  }
516
527
  });
517
528
  }
529
+ function observe() {
530
+ var observer = new MutationObserver(mutations => {
531
+ var form = getFormElement();
532
+ if (!form) {
533
+ return;
534
+ }
535
+ for (var mutation of mutations) {
536
+ var nodes = mutation.type === 'childList' ? [...mutation.addedNodes, ...mutation.removedNodes] : [mutation.target];
537
+ for (var node of nodes) {
538
+ var element = dom.isFieldElement(node) ? node : node instanceof HTMLElement ? node.querySelector('input,select,textarea') : null;
539
+ if ((element === null || element === void 0 ? void 0 : element.form) === form) {
540
+ updateFormValue(form);
541
+ return;
542
+ }
543
+ }
544
+ }
545
+ });
546
+ observer.observe(document, {
547
+ subtree: true,
548
+ childList: true,
549
+ attributes: true,
550
+ attributeFilter: ['form', 'name']
551
+ });
552
+ return () => {
553
+ observer.disconnect();
554
+ };
555
+ }
518
556
  return {
519
- get formId() {
520
- return latestOptions.formId;
557
+ getFormId() {
558
+ return meta.formId;
521
559
  },
522
560
  submit,
523
561
  onReset,
@@ -532,7 +570,8 @@ function createFormContext(options) {
532
570
  reorder: createFormControl('reorder'),
533
571
  subscribe,
534
572
  getState,
535
- getSerializedState
573
+ getSerializedState,
574
+ observe
536
575
  };
537
576
  }
538
577
 
package/form.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
- import { flatten, formatPaths, getPaths, getValue, isPlainObject, setValue, normalize, getFormData, isPrefix } from './formdata.mjs';
2
+ import { flatten, formatName, getValue, isPlainObject, setValue, normalize, getFormData, getPaths, formatPaths, 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, root } from './submission.mjs';
5
+ import { serialize, setListState, setListValue, setState, INTENT, serializeIntent, root, getSubmissionContext } from './submission.mjs';
6
6
 
7
7
  function createFormMeta(options, initialized) {
8
8
  var _lastResult$initialVa, _options$constraint, _lastResult$state$val, _lastResult$state, _ref;
@@ -10,6 +10,8 @@ function createFormMeta(options, initialized) {
10
10
  var defaultValue = options.defaultValue ? serialize(options.defaultValue) : {};
11
11
  var initialValue = (_lastResult$initialVa = lastResult === null || lastResult === void 0 ? void 0 : lastResult.initialValue) !== null && _lastResult$initialVa !== void 0 ? _lastResult$initialVa : defaultValue;
12
12
  var result = {
13
+ formId: options.formId,
14
+ isValueUpdated: false,
13
15
  submissionStatus: lastResult === null || lastResult === void 0 ? void 0 : lastResult.status,
14
16
  defaultValue,
15
17
  initialValue,
@@ -33,7 +35,7 @@ function getDefaultKey(defaultValue, prefix) {
33
35
  var [key, value] = _ref2;
34
36
  if (Array.isArray(value)) {
35
37
  for (var i = 0; i < value.length; i++) {
36
- result[formatPaths([...getPaths(key), i])] = generateId();
38
+ result[formatName(key, i)] = generateId();
37
39
  }
38
40
  }
39
41
  return result;
@@ -62,10 +64,10 @@ function handleIntent(meta, intent, fields, initialized) {
62
64
  case 'update':
63
65
  {
64
66
  var {
65
- name: _name2,
66
67
  validated,
67
68
  value
68
69
  } = intent.payload;
70
+ var _name2 = formatName(intent.payload.name, intent.payload.index);
69
71
  if (typeof value !== 'undefined') {
70
72
  updateValue(meta, _name2 !== null && _name2 !== void 0 ? _name2 : '', serialize(value));
71
73
  }
@@ -94,8 +96,7 @@ function handleIntent(meta, intent, fields, initialized) {
94
96
  }
95
97
  case 'reset':
96
98
  {
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 _name3 = formatName(intent.payload.name, intent.payload.index);
99
100
  var _value = getValue(meta.defaultValue, _name3);
100
101
  updateValue(meta, _name3, _value);
101
102
  if (_name3) {
@@ -319,7 +320,7 @@ function createFormContext(options) {
319
320
  for (var subscriber of subscribers) {
320
321
  var _subscriber$getSubjec;
321
322
  var subject = (_subscriber$getSubjec = subscriber.getSubject) === null || _subscriber$getSubjec === void 0 ? void 0 : _subscriber$getSubjec.call(subscriber);
322
- if (!subject || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
323
+ if (!subject || subject.formId && prevMeta.formId !== nextMeta.formId || subject.status && prevState.submissionStatus !== nextState.submissionStatus || shouldNotify(prevState.error, nextState.error, cache.error, subject.error) || shouldNotify(prevState.initialValue, nextState.initialValue, cache.initialValue, subject.initialValue) || shouldNotify(prevState.key, nextState.key, cache.key, subject.key, (prev, next) => prev !== next) || shouldNotify(prevState.valid, nextState.valid, cache.valid, subject.valid, compareBoolean) || shouldNotify(prevState.dirty, nextState.dirty, cache.dirty, subject.dirty, compareBoolean) || shouldNotify(prevState.value, nextState.value, cache.value, subject.value)) {
323
324
  subscriber.callback();
324
325
  }
325
326
  }
@@ -353,8 +354,11 @@ function createFormContext(options) {
353
354
  formData,
354
355
  submitter
355
356
  });
356
- if (submission.status !== 'success' && submission.error !== null) {
357
- report(submission.reply());
357
+ if (submission.status === 'success' || submission.error !== null) {
358
+ var _result2 = submission.reply();
359
+ report(_objectSpread2(_objectSpread2({}, _result2), {}, {
360
+ status: _result2.status !== 'success' ? _result2.status : undefined
361
+ }));
358
362
  }
359
363
  return _objectSpread2(_objectSpread2({}, result), {}, {
360
364
  submission
@@ -374,7 +378,15 @@ function createFormContext(options) {
374
378
  shouldRevalidate = shouldValidate
375
379
  } = latestOptions;
376
380
  var validated = meta.validated[element.name];
377
- return validated ? shouldRevalidate === eventName : shouldValidate === eventName;
381
+ return validated ? shouldRevalidate === eventName && (eventName === 'onInput' || meta.isValueUpdated) : shouldValidate === eventName;
382
+ }
383
+ function updateFormValue(form) {
384
+ var formData = new FormData(form);
385
+ var result = getSubmissionContext(formData);
386
+ updateFormMeta(_objectSpread2(_objectSpread2({}, meta), {}, {
387
+ isValueUpdated: true,
388
+ value: result.payload
389
+ }));
378
390
  }
379
391
  function onInput(event) {
380
392
  var element = resolveTarget(event);
@@ -382,11 +394,7 @@ function createFormContext(options) {
382
394
  return;
383
395
  }
384
396
  if (event.defaultPrevented || !willValidate(element, 'onInput')) {
385
- var formData = new FormData(element.form);
386
- var result = getSubmissionContext(formData);
387
- updateFormMeta(_objectSpread2(_objectSpread2({}, meta), {}, {
388
- value: result.payload
389
- }));
397
+ updateFormValue(element.form);
390
398
  } else {
391
399
  dispatch({
392
400
  type: 'validate',
@@ -408,18 +416,21 @@ function createFormContext(options) {
408
416
  }
409
417
  });
410
418
  }
419
+ function reset() {
420
+ updateFormMeta(createFormMeta(latestOptions, true));
421
+ }
411
422
  function onReset(event) {
412
423
  var element = getFormElement();
413
424
  if (event.type !== 'reset' || event.target !== element || event.defaultPrevented) {
414
425
  return;
415
426
  }
416
- updateFormMeta(createFormMeta(latestOptions, true));
427
+ reset();
417
428
  }
418
429
  function report(result) {
419
430
  var _result$error, _result$state;
420
431
  var formElement = getFormElement();
421
432
  if (!result.initialValue) {
422
- formElement === null || formElement === void 0 || formElement.reset();
433
+ reset();
423
434
  return;
424
435
  }
425
436
  var error = Object.entries((_result$error = result.error) !== null && _result$error !== void 0 ? _result$error : {}).reduce((result, _ref5) => {
@@ -431,6 +442,7 @@ function createFormContext(options) {
431
442
  return result;
432
443
  }, {});
433
444
  var update = _objectSpread2(_objectSpread2({}, meta), {}, {
445
+ isValueUpdated: false,
434
446
  submissionStatus: result.status,
435
447
  value: result.initialValue,
436
448
  validated: _objectSpread2(_objectSpread2({}, meta.validated), (_result$state = result.state) === null || _result$state === void 0 ? void 0 : _result$state.validated),
@@ -454,8 +466,7 @@ function createFormContext(options) {
454
466
  // Merge new options with the latest options
455
467
  Object.assign(latestOptions, options);
456
468
  if (latestOptions.formId !== currentFormId) {
457
- var _getFormElement;
458
- (_getFormElement = getFormElement()) === null || _getFormElement === void 0 || _getFormElement.reset();
469
+ reset();
459
470
  } else if (options.lastResult && options.lastResult !== currentResult) {
460
471
  report(options.lastResult);
461
472
  }
@@ -511,9 +522,36 @@ function createFormContext(options) {
511
522
  }
512
523
  });
513
524
  }
525
+ function observe() {
526
+ var observer = new MutationObserver(mutations => {
527
+ var form = getFormElement();
528
+ if (!form) {
529
+ return;
530
+ }
531
+ for (var mutation of mutations) {
532
+ var nodes = mutation.type === 'childList' ? [...mutation.addedNodes, ...mutation.removedNodes] : [mutation.target];
533
+ for (var node of nodes) {
534
+ var element = isFieldElement(node) ? node : node instanceof HTMLElement ? node.querySelector('input,select,textarea') : null;
535
+ if ((element === null || element === void 0 ? void 0 : element.form) === form) {
536
+ updateFormValue(form);
537
+ return;
538
+ }
539
+ }
540
+ }
541
+ });
542
+ observer.observe(document, {
543
+ subtree: true,
544
+ childList: true,
545
+ attributes: true,
546
+ attributeFilter: ['form', 'name']
547
+ });
548
+ return () => {
549
+ observer.disconnect();
550
+ };
551
+ }
514
552
  return {
515
- get formId() {
516
- return latestOptions.formId;
553
+ getFormId() {
554
+ return meta.formId;
517
555
  },
518
556
  submit,
519
557
  onReset,
@@ -528,7 +566,8 @@ function createFormContext(options) {
528
566
  reorder: createFormControl('reorder'),
529
567
  subscribe,
530
568
  getState,
531
- getSerializedState
569
+ getSerializedState,
570
+ observe
532
571
  };
533
572
  }
534
573
 
package/formdata.d.ts CHANGED
@@ -13,7 +13,7 @@ export declare function getFormData(form: HTMLFormElement, submitter?: HTMLInput
13
13
  * const paths = getPaths('todos[0].content'); // ['todos', 0, 'content']
14
14
  * ```
15
15
  */
16
- export declare function getPaths(name: string): Array<string | number>;
16
+ export declare function getPaths(name: string | undefined): Array<string | number>;
17
17
  /**
18
18
  * Returns a formatted name from the paths based on the JS syntax convention
19
19
  * @example
@@ -22,6 +22,10 @@ export declare function getPaths(name: string): Array<string | number>;
22
22
  * ```
23
23
  */
24
24
  export declare function formatPaths(paths: Array<string | number>): string;
25
+ /**
26
+ * Format based on a prefix and a path
27
+ */
28
+ export declare function formatName(prefix: string | undefined, path?: string | number): string;
25
29
  /**
26
30
  * Check if a name match the prefix paths
27
31
  */
package/formdata.js CHANGED
@@ -65,6 +65,13 @@ function formatPaths(paths) {
65
65
  }, '');
66
66
  }
67
67
 
68
+ /**
69
+ * Format based on a prefix and a path
70
+ */
71
+ function formatName(prefix, path) {
72
+ return typeof path !== 'undefined' ? formatPaths([...getPaths(prefix), path]) : prefix !== null && prefix !== void 0 ? prefix : '';
73
+ }
74
+
68
75
  /**
69
76
  * Check if a name match the prefix paths
70
77
  */
@@ -215,6 +222,7 @@ function flatten(data, options) {
215
222
  }
216
223
 
217
224
  exports.flatten = flatten;
225
+ exports.formatName = formatName;
218
226
  exports.formatPaths = formatPaths;
219
227
  exports.getFormData = getFormData;
220
228
  exports.getPaths = getPaths;
package/formdata.mjs CHANGED
@@ -61,6 +61,13 @@ function formatPaths(paths) {
61
61
  }, '');
62
62
  }
63
63
 
64
+ /**
65
+ * Format based on a prefix and a path
66
+ */
67
+ function formatName(prefix, path) {
68
+ return typeof path !== 'undefined' ? formatPaths([...getPaths(prefix), path]) : prefix !== null && prefix !== void 0 ? prefix : '';
69
+ }
70
+
64
71
  /**
65
72
  * Check if a name match the prefix paths
66
73
  */
@@ -210,4 +217,4 @@ function flatten(data, options) {
210
217
  return result;
211
218
  }
212
219
 
213
- export { flatten, formatPaths, getFormData, getPaths, getValue, isFile, isPlainObject, isPrefix, normalize, setValue };
220
+ export { flatten, formatName, formatPaths, getFormData, getPaths, getValue, isFile, isPlainObject, isPrefix, normalize, setValue };
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.6",
6
+ "version": "1.1.0",
7
7
  "main": "index.js",
8
8
  "module": "index.mjs",
9
9
  "types": "index.d.ts",
package/submission.d.ts CHANGED
@@ -78,14 +78,24 @@ export type ResetIntent<Schema = any> = {
78
78
  type: 'reset';
79
79
  payload: {
80
80
  name?: FieldName<Schema>;
81
+ index?: never;
82
+ } | {
83
+ name: FieldName<Schema>;
84
+ index: Schema extends Array<unknown> ? number : never;
81
85
  };
82
86
  };
83
87
  export type UpdateIntent<Schema = unknown> = {
84
88
  type: 'update';
85
89
  payload: {
86
90
  name?: FieldName<Schema>;
91
+ index?: never;
87
92
  value?: NonNullable<DefaultValue<Schema>>;
88
93
  validated?: boolean;
94
+ } | {
95
+ name: FieldName<Schema>;
96
+ index: Schema extends Array<unknown> ? number : never;
97
+ value?: NonNullable<DefaultValue<Schema extends Array<infer Item> ? Item : unknown>>;
98
+ validated?: boolean;
89
99
  };
90
100
  };
91
101
  export type RemoveIntent<Schema extends Array<any> = any> = {
package/submission.js CHANGED
@@ -54,9 +54,7 @@ function parse(payload, options) {
54
54
  switch (intent.type) {
55
55
  case 'update':
56
56
  {
57
- var {
58
- name
59
- } = intent.payload;
57
+ var name = formdata.formatName(intent.payload.name, intent.payload.index);
60
58
  var _value = serialize(intent.payload.value);
61
59
  if (typeof _value !== 'undefined') {
62
60
  if (name) {
@@ -70,9 +68,7 @@ function parse(payload, options) {
70
68
  }
71
69
  case 'reset':
72
70
  {
73
- var {
74
- name: _name
75
- } = intent.payload;
71
+ var _name = formdata.formatName(intent.payload.name, intent.payload.index);
76
72
  if (_name) {
77
73
  formdata.setValue(context.payload, _name, () => undefined);
78
74
  } else {
package/submission.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
- import { setValue, isPlainObject, getValue, normalize, flatten, isPrefix } from './formdata.mjs';
2
+ import { formatName, setValue, isPlainObject, getValue, normalize, flatten, isPrefix } from './formdata.mjs';
3
3
  import { invariant } from './util.mjs';
4
4
 
5
5
  /**
@@ -50,9 +50,7 @@ function parse(payload, options) {
50
50
  switch (intent.type) {
51
51
  case 'update':
52
52
  {
53
- var {
54
- name
55
- } = intent.payload;
53
+ var name = formatName(intent.payload.name, intent.payload.index);
56
54
  var _value = serialize(intent.payload.value);
57
55
  if (typeof _value !== 'undefined') {
58
56
  if (name) {
@@ -66,9 +64,7 @@ function parse(payload, options) {
66
64
  }
67
65
  case 'reset':
68
66
  {
69
- var {
70
- name: _name
71
- } = intent.payload;
67
+ var _name = formatName(intent.payload.name, intent.payload.index);
72
68
  if (_name) {
73
69
  setValue(context.payload, _name, () => undefined);
74
70
  } else {