@conform-to/dom 0.6.0-pre.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,10 +2,16 @@
2
2
 
3
3
  > This package is a transitive dependency for the rest of the conform packages with no intention to be used directly at the moment. Use at your own risk.
4
4
 
5
- Conform is a form validation library built on top of the [Constraint Validation](https://caniuse.com/constraint-validation) API.
5
+ Conform is a progressive enhancement first form validation library for [Remix](https://remix.run)
6
6
 
7
- - **Progressive Enhancement**: It is designed based on the [HTML specification](https://html.spec.whatwg.org/dev/form-control-infrastructure.html#the-constraint-validation-api). From validating the form to reporting error messages for each field, if you don't like part of the solution, just replace it with your own.
8
- - **Framework Agnostic**: The DOM is the only dependency. Conform makes use of native [Web APIs](https://developer.mozilla.org/en-US/docs/Web/API) exclusively. You don't have to use React / Vue / Svelte to utilise this library.
9
- - **Flexible Setup**: It can validates fields anywhere in the dom with the help of [form attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form). Also enables CSS pseudo-classes like `:valid` and `:invalid`, allowing flexible styling across your form without the need to manipulate the class names.
7
+ ### Highlights
8
+
9
+ - Focused on progressive enhancment by default
10
+ - Simplifed intergration through event delegation
11
+ - Server first validation with Zod / Yup schema support
12
+ - Field name inference with type checking
13
+ - Focus management
14
+ - Accessibility support
15
+ - About 5kb compressed
10
16
 
11
17
  Checkout the [repository](https://github.com/edmundhung/conform) if you want to know more!
package/index.d.ts CHANGED
@@ -6,7 +6,16 @@ export interface FieldConfig<Schema = unknown> extends FieldConstraint<Schema> {
6
6
  defaultValue?: FieldValue<Schema>;
7
7
  initialError?: Record<string, string | string[]>;
8
8
  form?: string;
9
+ descriptionId?: string;
9
10
  errorId?: string;
11
+ /**
12
+ * The frist error of the field
13
+ */
14
+ error?: string;
15
+ /**
16
+ * All of the field errors
17
+ */
18
+ errors?: string[];
10
19
  }
11
20
  export type FieldValue<Schema> = Schema extends Primitive ? string : Schema extends File ? File : Schema extends Array<infer InnerType> ? Array<FieldValue<InnerType>> : Schema extends Record<string, any> ? {
12
21
  [Key in keyof Schema]?: FieldValue<Schema[Key]>;
@@ -36,12 +45,19 @@ export type Submission<Schema extends Record<string, any> | unknown = unknown> =
36
45
  toJSON(): Submission;
37
46
  };
38
47
  export interface IntentButtonProps {
39
- name: '__intent__';
48
+ name: typeof INTENT;
40
49
  value: string;
41
50
  formNoValidate?: boolean;
42
51
  }
52
+ /**
53
+ * Check if the provided reference is a form element (_input_ / _select_ / _textarea_ or _button_)
54
+ */
43
55
  export declare function isFieldElement(element: unknown): element is FieldElement;
44
- export declare function getFormElements(form: HTMLFormElement): FieldElement[];
56
+ /**
57
+ * Find the corresponding paths based on the formatted name
58
+ * @param name formatted name
59
+ * @returns paths
60
+ */
45
61
  export declare function getPaths(name: string): Array<string | number>;
46
62
  export declare function getFormData(form: HTMLFormElement, submitter?: HTMLInputElement | HTMLButtonElement | null): FormData;
47
63
  export type FormMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
@@ -52,19 +68,16 @@ export declare function getFormAttributes(form: HTMLFormElement, submitter?: HTM
52
68
  method: FormMethod;
53
69
  };
54
70
  export declare function getName(paths: Array<string | number>): string;
55
- export declare function shouldValidate(intent: string, name: string): boolean;
71
+ export declare function getScope(intent: string): string | null;
72
+ export declare function isFocusedOnIntentButton(form: HTMLFormElement, intent: string): boolean;
56
73
  export declare function getValidationMessage(errors?: string | string[]): string;
57
74
  export declare function getErrors(message: string | undefined): string[];
75
+ export declare const FORM_ERROR_ELEMENT_NAME = "__form__";
76
+ export declare const INTENT = "__intent__";
58
77
  export declare const VALIDATION_UNDEFINED = "__undefined__";
59
78
  export declare const VALIDATION_SKIPPED = "__skipped__";
60
79
  export declare function reportSubmission(form: HTMLFormElement, submission: Submission): void;
61
80
  export declare function setValue<T>(target: any, paths: Array<string | number>, valueFn: (prev?: T) => T): void;
62
- /**
63
- * The ponyfill of `HTMLFormElement.requestSubmit()`
64
- * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
65
- * @see https://caniuse.com/?search=requestSubmit
66
- */
67
- export declare function requestSubmit(form: HTMLFormElement, submitter?: HTMLButtonElement | HTMLInputElement): void;
68
81
  /**
69
82
  * Creates an intent button on demand and trigger a form submit by clicking it.
70
83
  */
@@ -73,13 +86,12 @@ export declare function requestIntent(form: HTMLFormElement | undefined, buttonP
73
86
  formNoValidate?: boolean;
74
87
  }): void;
75
88
  /**
76
- * Returns the properties required to configure a command button for validation
89
+ * Returns the properties required to configure an intent button for validation
77
90
  *
78
91
  * @see https://conform.guide/api/react#validate
79
92
  */
80
93
  export declare function validate(field?: string): IntentButtonProps;
81
94
  export declare function getFormElement(element: HTMLFormElement | HTMLFieldSetElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement | null): HTMLFormElement | null;
82
- export declare function focus(field: FieldElement): void;
83
95
  export declare function parse(payload: FormData | URLSearchParams): Submission;
84
96
  export declare function parse<Schema>(payload: FormData | URLSearchParams, options?: {
85
97
  resolve?: (payload: Record<string, any>, intent: string) => {
@@ -161,7 +173,7 @@ export interface ListCommandButtonBuilder {
161
173
  }): IntentButtonProps;
162
174
  }
163
175
  /**
164
- * Helpers to configure a command button for modifying a list
176
+ * Helpers to configure an intent button for modifying a list
165
177
  *
166
178
  * @see https://conform.guide/api/react#list
167
179
  */
package/index.js CHANGED
@@ -4,27 +4,18 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
6
6
 
7
- // type Join<K, P> = P extends string | number ?
8
- // K extends string | number ?
9
- // `${K}${"" extends P ? "" : "."}${P}`
10
- // : never : never;
11
-
12
- // type DottedPaths<T> = T extends object ?
13
- // { [K in keyof T]-?: K extends string | number ?
14
- // `${K}` | Join<K, DottedPaths<T[K]>>
15
- // : never
16
- // }[keyof T] : ""
17
-
18
- // type Pathfix<T> = T extends `${infer Prefix}.${number}${infer Postfix}` ? `${Prefix}[${number}]${Pathfix<Postfix>}` : T;
19
-
20
- // type Path<Schema> = Pathfix<DottedPaths<Schema>> | '';
21
-
7
+ /**
8
+ * Check if the provided reference is a form element (_input_ / _select_ / _textarea_ or _button_)
9
+ */
22
10
  function isFieldElement(element) {
23
11
  return element instanceof Element && (element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA' || element.tagName === 'BUTTON');
24
12
  }
25
- function getFormElements(form) {
26
- return Array.from(form.elements).filter(isFieldElement);
27
- }
13
+
14
+ /**
15
+ * Find the corresponding paths based on the formatted name
16
+ * @param name formatted name
17
+ * @returns paths
18
+ */
28
19
  function getPaths(name) {
29
20
  var pattern = /(\w*)\[(\d+)\]/;
30
21
  if (!name) {
@@ -71,18 +62,22 @@ function getName(paths) {
71
62
  return [name, path].join('.');
72
63
  }, '');
73
64
  }
74
- function shouldValidate(intent, name) {
75
- var _parseListCommand;
76
- var [type] = intent.split('/', 1);
65
+ function getScope(intent) {
66
+ var _parseListCommand$sco, _parseListCommand;
67
+ var [type, ...rest] = intent.split('/');
77
68
  switch (type) {
78
69
  case 'validate':
79
- return intent === 'validate' || intent === "validate/".concat(name);
70
+ return rest.length > 0 ? rest.join('/') : null;
80
71
  case 'list':
81
- return ((_parseListCommand = parseListCommand(intent)) === null || _parseListCommand === void 0 ? void 0 : _parseListCommand.scope) === name;
72
+ return (_parseListCommand$sco = (_parseListCommand = parseListCommand(intent)) === null || _parseListCommand === void 0 ? void 0 : _parseListCommand.scope) !== null && _parseListCommand$sco !== void 0 ? _parseListCommand$sco : null;
82
73
  default:
83
- return true;
74
+ return null;
84
75
  }
85
76
  }
77
+ function isFocusedOnIntentButton(form, intent) {
78
+ var element = document.activeElement;
79
+ return isFieldElement(element) && element.tagName === 'BUTTON' && element.form === form && element.name === INTENT && element.value === intent;
80
+ }
86
81
  function getValidationMessage(errors) {
87
82
  return [].concat(errors !== null && errors !== void 0 ? errors : []).join(String.fromCharCode(31));
88
83
  }
@@ -92,6 +87,8 @@ function getErrors(message) {
92
87
  }
93
88
  return message.split(String.fromCharCode(31));
94
89
  }
90
+ var FORM_ERROR_ELEMENT_NAME = '__form__';
91
+ var INTENT = '__intent__';
95
92
  var VALIDATION_UNDEFINED = '__undefined__';
96
93
  var VALIDATION_SKIPPED = '__skipped__';
97
94
  function reportSubmission(form, submission) {
@@ -103,7 +100,7 @@ function reportSubmission(form, submission) {
103
100
 
104
101
  // We can't use empty string as button name
105
102
  // As `form.element.namedItem('')` will always returns null
106
- var elementName = _name ? _name : '__form__';
103
+ var elementName = _name ? _name : FORM_ERROR_ELEMENT_NAME;
107
104
  var item = form.elements.namedItem(elementName);
108
105
  if (item instanceof RadioNodeList) {
109
106
  for (var field of item) {
@@ -122,23 +119,28 @@ function reportSubmission(form, submission) {
122
119
  form.appendChild(button);
123
120
  }
124
121
  }
122
+ var focusedFirstInvalidField = false;
123
+ var scope = getScope(submission.intent);
124
+ var isSubmitting = submission.intent.slice(0, submission.intent.indexOf('/')) !== 'validate' && parseListCommand(submission.intent) === null;
125
125
  for (var element of form.elements) {
126
126
  if (isFieldElement(element) && element.willValidate) {
127
- var _elementName = element.name !== '__form__' ? element.name : '';
128
- var _message = submission.error[_elementName];
129
- var elementShouldValidate = shouldValidate(submission.intent, _elementName);
130
- if (elementShouldValidate) {
127
+ var _submission$error$_el;
128
+ var _elementName = element.name !== FORM_ERROR_ELEMENT_NAME ? element.name : '';
129
+ var messages = [].concat((_submission$error$_el = submission.error[_elementName]) !== null && _submission$error$_el !== void 0 ? _submission$error$_el : []);
130
+ var shouldValidate = scope === null || scope === _elementName;
131
+ if (shouldValidate) {
131
132
  element.dataset.conformTouched = 'true';
132
133
  }
133
- if (typeof _message === 'undefined' || ![].concat(_message).includes(VALIDATION_SKIPPED)) {
134
+ if (!messages.includes(VALIDATION_SKIPPED) && !messages.includes(VALIDATION_UNDEFINED)) {
134
135
  var invalidEvent = new Event('invalid', {
135
136
  cancelable: true
136
137
  });
137
- element.setCustomValidity(getValidationMessage(_message));
138
+ element.setCustomValidity(getValidationMessage(messages));
138
139
  element.dispatchEvent(invalidEvent);
139
140
  }
140
- if (elementShouldValidate && !element.validity.valid) {
141
- focus(element);
141
+ if (!focusedFirstInvalidField && (isSubmitting || isFocusedOnIntentButton(form, submission.intent)) && shouldValidate && element.tagName !== 'BUTTON' && !element.validity.valid) {
142
+ element.focus();
143
+ focusedFirstInvalidField = true;
142
144
  }
143
145
  }
144
146
  }
@@ -158,20 +160,6 @@ function setValue(target, paths, valueFn) {
158
160
  }
159
161
  }
160
162
 
161
- /**
162
- * The ponyfill of `HTMLFormElement.requestSubmit()`
163
- * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
164
- * @see https://caniuse.com/?search=requestSubmit
165
- */
166
- function requestSubmit(form, submitter) {
167
- var submitEvent = new SubmitEvent('submit', {
168
- bubbles: true,
169
- cancelable: true,
170
- submitter
171
- });
172
- form.dispatchEvent(submitEvent);
173
- }
174
-
175
163
  /**
176
164
  * Creates an intent button on demand and trigger a form submit by clicking it.
177
165
  */
@@ -181,7 +169,7 @@ function requestIntent(form, buttonProps) {
181
169
  return;
182
170
  }
183
171
  var button = document.createElement('button');
184
- button.name = '__intent__';
172
+ button.name = INTENT;
185
173
  button.value = buttonProps.value;
186
174
  button.hidden = true;
187
175
  if (buttonProps.formNoValidate) {
@@ -193,13 +181,13 @@ function requestIntent(form, buttonProps) {
193
181
  }
194
182
 
195
183
  /**
196
- * Returns the properties required to configure a command button for validation
184
+ * Returns the properties required to configure an intent button for validation
197
185
  *
198
186
  * @see https://conform.guide/api/react#validate
199
187
  */
200
188
  function validate(field) {
201
189
  return {
202
- name: '__intent__',
190
+ name: INTENT,
203
191
  value: field ? "validate/".concat(field) : 'validate',
204
192
  formNoValidate: true
205
193
  };
@@ -211,13 +199,6 @@ function getFormElement(element) {
211
199
  }
212
200
  return form;
213
201
  }
214
- function focus(field) {
215
- var currentFocus = document.activeElement;
216
- if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== field.form) {
217
- return;
218
- }
219
- field.focus();
220
- }
221
202
  function parse(payload, options) {
222
203
  var submission = {
223
204
  intent: 'submit',
@@ -225,7 +206,7 @@ function parse(payload, options) {
225
206
  error: {}
226
207
  };
227
208
  var _loop = function _loop(_value) {
228
- if (_name2 === '__intent__') {
209
+ if (_name2 === INTENT) {
229
210
  if (typeof _value !== 'string' || submission.intent !== 'submit') {
230
211
  throw new Error('The intent could only be set on a button');
231
212
  }
@@ -323,7 +304,7 @@ function updateList(list, command) {
323
304
  return list;
324
305
  }
325
306
  /**
326
- * Helpers to configure a command button for modifying a list
307
+ * Helpers to configure an intent button for modifying a list
327
308
  *
328
309
  * @see https://conform.guide/api/react#list
329
310
  */
@@ -338,7 +319,7 @@ var list = new Proxy({}, {
338
319
  return function (scope) {
339
320
  var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
340
321
  return {
341
- name: '__intent__',
322
+ name: INTENT,
342
323
  value: "list/".concat(type, "/").concat(scope, "/").concat(JSON.stringify(payload)),
343
324
  formNoValidate: true
344
325
  };
@@ -384,7 +365,7 @@ function validateConstraint(options) {
384
365
  var _loop2 = function _loop2(element) {
385
366
  if (isFieldElement(element)) {
386
367
  var _options$acceptMultip, _options$acceptMultip2;
387
- var _name3 = element.name === '__form__' ? '' : element.name;
368
+ var _name3 = element.name !== FORM_ERROR_ELEMENT_NAME ? element.name : '';
388
369
  var constraint = Object.entries(element.dataset).reduce((result, _ref4) => {
389
370
  var [name, attributeValue = ''] = _ref4;
390
371
  if (constraintPattern.test(name)) {
@@ -428,26 +409,26 @@ function validateConstraint(options) {
428
409
  });
429
410
  }
430
411
 
412
+ exports.FORM_ERROR_ELEMENT_NAME = FORM_ERROR_ELEMENT_NAME;
413
+ exports.INTENT = INTENT;
431
414
  exports.VALIDATION_SKIPPED = VALIDATION_SKIPPED;
432
415
  exports.VALIDATION_UNDEFINED = VALIDATION_UNDEFINED;
433
- exports.focus = focus;
434
416
  exports.getErrors = getErrors;
435
417
  exports.getFormAttributes = getFormAttributes;
436
418
  exports.getFormData = getFormData;
437
419
  exports.getFormElement = getFormElement;
438
- exports.getFormElements = getFormElements;
439
420
  exports.getName = getName;
440
421
  exports.getPaths = getPaths;
422
+ exports.getScope = getScope;
441
423
  exports.getValidationMessage = getValidationMessage;
442
424
  exports.isFieldElement = isFieldElement;
425
+ exports.isFocusedOnIntentButton = isFocusedOnIntentButton;
443
426
  exports.list = list;
444
427
  exports.parse = parse;
445
428
  exports.parseListCommand = parseListCommand;
446
429
  exports.reportSubmission = reportSubmission;
447
430
  exports.requestIntent = requestIntent;
448
- exports.requestSubmit = requestSubmit;
449
431
  exports.setValue = setValue;
450
- exports.shouldValidate = shouldValidate;
451
432
  exports.updateList = updateList;
452
433
  exports.validate = validate;
453
434
  exports.validateConstraint = validateConstraint;
package/module/index.js CHANGED
@@ -1,26 +1,17 @@
1
1
  import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
2
2
 
3
- // type Join<K, P> = P extends string | number ?
4
- // K extends string | number ?
5
- // `${K}${"" extends P ? "" : "."}${P}`
6
- // : never : never;
7
-
8
- // type DottedPaths<T> = T extends object ?
9
- // { [K in keyof T]-?: K extends string | number ?
10
- // `${K}` | Join<K, DottedPaths<T[K]>>
11
- // : never
12
- // }[keyof T] : ""
13
-
14
- // type Pathfix<T> = T extends `${infer Prefix}.${number}${infer Postfix}` ? `${Prefix}[${number}]${Pathfix<Postfix>}` : T;
15
-
16
- // type Path<Schema> = Pathfix<DottedPaths<Schema>> | '';
17
-
3
+ /**
4
+ * Check if the provided reference is a form element (_input_ / _select_ / _textarea_ or _button_)
5
+ */
18
6
  function isFieldElement(element) {
19
7
  return element instanceof Element && (element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA' || element.tagName === 'BUTTON');
20
8
  }
21
- function getFormElements(form) {
22
- return Array.from(form.elements).filter(isFieldElement);
23
- }
9
+
10
+ /**
11
+ * Find the corresponding paths based on the formatted name
12
+ * @param name formatted name
13
+ * @returns paths
14
+ */
24
15
  function getPaths(name) {
25
16
  var pattern = /(\w*)\[(\d+)\]/;
26
17
  if (!name) {
@@ -67,18 +58,22 @@ function getName(paths) {
67
58
  return [name, path].join('.');
68
59
  }, '');
69
60
  }
70
- function shouldValidate(intent, name) {
71
- var _parseListCommand;
72
- var [type] = intent.split('/', 1);
61
+ function getScope(intent) {
62
+ var _parseListCommand$sco, _parseListCommand;
63
+ var [type, ...rest] = intent.split('/');
73
64
  switch (type) {
74
65
  case 'validate':
75
- return intent === 'validate' || intent === "validate/".concat(name);
66
+ return rest.length > 0 ? rest.join('/') : null;
76
67
  case 'list':
77
- return ((_parseListCommand = parseListCommand(intent)) === null || _parseListCommand === void 0 ? void 0 : _parseListCommand.scope) === name;
68
+ return (_parseListCommand$sco = (_parseListCommand = parseListCommand(intent)) === null || _parseListCommand === void 0 ? void 0 : _parseListCommand.scope) !== null && _parseListCommand$sco !== void 0 ? _parseListCommand$sco : null;
78
69
  default:
79
- return true;
70
+ return null;
80
71
  }
81
72
  }
73
+ function isFocusedOnIntentButton(form, intent) {
74
+ var element = document.activeElement;
75
+ return isFieldElement(element) && element.tagName === 'BUTTON' && element.form === form && element.name === INTENT && element.value === intent;
76
+ }
82
77
  function getValidationMessage(errors) {
83
78
  return [].concat(errors !== null && errors !== void 0 ? errors : []).join(String.fromCharCode(31));
84
79
  }
@@ -88,6 +83,8 @@ function getErrors(message) {
88
83
  }
89
84
  return message.split(String.fromCharCode(31));
90
85
  }
86
+ var FORM_ERROR_ELEMENT_NAME = '__form__';
87
+ var INTENT = '__intent__';
91
88
  var VALIDATION_UNDEFINED = '__undefined__';
92
89
  var VALIDATION_SKIPPED = '__skipped__';
93
90
  function reportSubmission(form, submission) {
@@ -99,7 +96,7 @@ function reportSubmission(form, submission) {
99
96
 
100
97
  // We can't use empty string as button name
101
98
  // As `form.element.namedItem('')` will always returns null
102
- var elementName = _name ? _name : '__form__';
99
+ var elementName = _name ? _name : FORM_ERROR_ELEMENT_NAME;
103
100
  var item = form.elements.namedItem(elementName);
104
101
  if (item instanceof RadioNodeList) {
105
102
  for (var field of item) {
@@ -118,23 +115,28 @@ function reportSubmission(form, submission) {
118
115
  form.appendChild(button);
119
116
  }
120
117
  }
118
+ var focusedFirstInvalidField = false;
119
+ var scope = getScope(submission.intent);
120
+ var isSubmitting = submission.intent.slice(0, submission.intent.indexOf('/')) !== 'validate' && parseListCommand(submission.intent) === null;
121
121
  for (var element of form.elements) {
122
122
  if (isFieldElement(element) && element.willValidate) {
123
- var _elementName = element.name !== '__form__' ? element.name : '';
124
- var _message = submission.error[_elementName];
125
- var elementShouldValidate = shouldValidate(submission.intent, _elementName);
126
- if (elementShouldValidate) {
123
+ var _submission$error$_el;
124
+ var _elementName = element.name !== FORM_ERROR_ELEMENT_NAME ? element.name : '';
125
+ var messages = [].concat((_submission$error$_el = submission.error[_elementName]) !== null && _submission$error$_el !== void 0 ? _submission$error$_el : []);
126
+ var shouldValidate = scope === null || scope === _elementName;
127
+ if (shouldValidate) {
127
128
  element.dataset.conformTouched = 'true';
128
129
  }
129
- if (typeof _message === 'undefined' || ![].concat(_message).includes(VALIDATION_SKIPPED)) {
130
+ if (!messages.includes(VALIDATION_SKIPPED) && !messages.includes(VALIDATION_UNDEFINED)) {
130
131
  var invalidEvent = new Event('invalid', {
131
132
  cancelable: true
132
133
  });
133
- element.setCustomValidity(getValidationMessage(_message));
134
+ element.setCustomValidity(getValidationMessage(messages));
134
135
  element.dispatchEvent(invalidEvent);
135
136
  }
136
- if (elementShouldValidate && !element.validity.valid) {
137
- focus(element);
137
+ if (!focusedFirstInvalidField && (isSubmitting || isFocusedOnIntentButton(form, submission.intent)) && shouldValidate && element.tagName !== 'BUTTON' && !element.validity.valid) {
138
+ element.focus();
139
+ focusedFirstInvalidField = true;
138
140
  }
139
141
  }
140
142
  }
@@ -154,20 +156,6 @@ function setValue(target, paths, valueFn) {
154
156
  }
155
157
  }
156
158
 
157
- /**
158
- * The ponyfill of `HTMLFormElement.requestSubmit()`
159
- * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
160
- * @see https://caniuse.com/?search=requestSubmit
161
- */
162
- function requestSubmit(form, submitter) {
163
- var submitEvent = new SubmitEvent('submit', {
164
- bubbles: true,
165
- cancelable: true,
166
- submitter
167
- });
168
- form.dispatchEvent(submitEvent);
169
- }
170
-
171
159
  /**
172
160
  * Creates an intent button on demand and trigger a form submit by clicking it.
173
161
  */
@@ -177,7 +165,7 @@ function requestIntent(form, buttonProps) {
177
165
  return;
178
166
  }
179
167
  var button = document.createElement('button');
180
- button.name = '__intent__';
168
+ button.name = INTENT;
181
169
  button.value = buttonProps.value;
182
170
  button.hidden = true;
183
171
  if (buttonProps.formNoValidate) {
@@ -189,13 +177,13 @@ function requestIntent(form, buttonProps) {
189
177
  }
190
178
 
191
179
  /**
192
- * Returns the properties required to configure a command button for validation
180
+ * Returns the properties required to configure an intent button for validation
193
181
  *
194
182
  * @see https://conform.guide/api/react#validate
195
183
  */
196
184
  function validate(field) {
197
185
  return {
198
- name: '__intent__',
186
+ name: INTENT,
199
187
  value: field ? "validate/".concat(field) : 'validate',
200
188
  formNoValidate: true
201
189
  };
@@ -207,13 +195,6 @@ function getFormElement(element) {
207
195
  }
208
196
  return form;
209
197
  }
210
- function focus(field) {
211
- var currentFocus = document.activeElement;
212
- if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== field.form) {
213
- return;
214
- }
215
- field.focus();
216
- }
217
198
  function parse(payload, options) {
218
199
  var submission = {
219
200
  intent: 'submit',
@@ -221,7 +202,7 @@ function parse(payload, options) {
221
202
  error: {}
222
203
  };
223
204
  var _loop = function _loop(_value) {
224
- if (_name2 === '__intent__') {
205
+ if (_name2 === INTENT) {
225
206
  if (typeof _value !== 'string' || submission.intent !== 'submit') {
226
207
  throw new Error('The intent could only be set on a button');
227
208
  }
@@ -319,7 +300,7 @@ function updateList(list, command) {
319
300
  return list;
320
301
  }
321
302
  /**
322
- * Helpers to configure a command button for modifying a list
303
+ * Helpers to configure an intent button for modifying a list
323
304
  *
324
305
  * @see https://conform.guide/api/react#list
325
306
  */
@@ -334,7 +315,7 @@ var list = new Proxy({}, {
334
315
  return function (scope) {
335
316
  var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
336
317
  return {
337
- name: '__intent__',
318
+ name: INTENT,
338
319
  value: "list/".concat(type, "/").concat(scope, "/").concat(JSON.stringify(payload)),
339
320
  formNoValidate: true
340
321
  };
@@ -380,7 +361,7 @@ function validateConstraint(options) {
380
361
  var _loop2 = function _loop2(element) {
381
362
  if (isFieldElement(element)) {
382
363
  var _options$acceptMultip, _options$acceptMultip2;
383
- var _name3 = element.name === '__form__' ? '' : element.name;
364
+ var _name3 = element.name !== FORM_ERROR_ELEMENT_NAME ? element.name : '';
384
365
  var constraint = Object.entries(element.dataset).reduce((result, _ref4) => {
385
366
  var [name, attributeValue = ''] = _ref4;
386
367
  if (constraintPattern.test(name)) {
@@ -424,4 +405,4 @@ function validateConstraint(options) {
424
405
  });
425
406
  }
426
407
 
427
- export { VALIDATION_SKIPPED, VALIDATION_UNDEFINED, focus, getErrors, getFormAttributes, getFormData, getFormElement, getFormElements, getName, getPaths, getValidationMessage, isFieldElement, list, parse, parseListCommand, reportSubmission, requestIntent, requestSubmit, setValue, shouldValidate, updateList, validate, validateConstraint };
408
+ export { FORM_ERROR_ELEMENT_NAME, INTENT, VALIDATION_SKIPPED, VALIDATION_UNDEFINED, getErrors, getFormAttributes, getFormData, getFormElement, getName, getPaths, getScope, getValidationMessage, isFieldElement, isFocusedOnIntentButton, list, parse, parseListCommand, reportSubmission, requestIntent, setValue, updateList, validate, validateConstraint };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@conform-to/dom",
3
3
  "description": "A set of opinionated helpers built on top of the Constraint Validation API",
4
+ "homepage": "https://conform.guide",
4
5
  "license": "MIT",
5
- "version": "0.6.0-pre.0",
6
+ "version": "0.6.1",
6
7
  "main": "index.js",
7
8
  "module": "module/index.js",
8
9
  "repository": {
@@ -22,6 +23,8 @@
22
23
  "constraint-validation",
23
24
  "form",
24
25
  "form-validation",
26
+ "html",
27
+ "progressive-enhancement",
25
28
  "validation",
26
29
  "dom"
27
30
  ],