@conform-to/dom 0.4.0 → 0.5.0-pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1,26 +1,26 @@
1
1
  export declare type Primitive = null | undefined | string | number | boolean | Date;
2
2
  export declare type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement;
3
- export interface FieldConfig<Schema = unknown> extends FieldConstraint {
3
+ export interface FieldConfig<Schema = unknown> extends FieldConstraint<Schema> {
4
4
  name: string;
5
5
  defaultValue?: FieldValue<Schema>;
6
6
  initialError?: Array<[string, string]>;
7
7
  form?: string;
8
8
  }
9
- export declare type FieldValue<Schema> = Schema extends Primitive | File ? string : Schema extends Array<infer InnerType> ? Array<FieldValue<InnerType>> : Schema extends Record<string, any> ? {
9
+ export declare type FieldValue<Schema> = Schema extends Primitive ? string : Schema extends File ? File : Schema extends Array<infer InnerType> ? Array<FieldValue<InnerType>> : Schema extends Record<string, any> ? {
10
10
  [Key in keyof Schema]?: FieldValue<Schema[Key]>;
11
11
  } : unknown;
12
- export declare type FieldConstraint = {
12
+ export declare type FieldConstraint<Schema = any> = {
13
13
  required?: boolean;
14
14
  minLength?: number;
15
15
  maxLength?: number;
16
- min?: string | number;
17
- max?: string | number;
18
- step?: string;
16
+ min?: Schema extends number ? number : string;
17
+ max?: Schema extends number ? number : string;
18
+ step?: Schema extends number ? number : string;
19
19
  multiple?: boolean;
20
20
  pattern?: string;
21
21
  };
22
22
  export declare type FieldsetConstraint<Schema extends Record<string, any>> = {
23
- [Key in keyof Schema]?: FieldConstraint;
23
+ [Key in keyof Schema]?: FieldConstraint<Schema[Key]>;
24
24
  };
25
25
  export declare type Submission<Schema = unknown> = {
26
26
  type: string;
@@ -35,7 +35,7 @@ export declare function getFormData(form: HTMLFormElement, submitter?: HTMLInput
35
35
  export declare function getName(paths: Array<string | number>): string;
36
36
  export declare function shouldValidate(submission: Submission, name?: string): boolean;
37
37
  export declare function hasError(error: Array<[string, string]>, name?: string): boolean;
38
- export declare function setFormError(form: HTMLFormElement, submission: Submission): void;
38
+ export declare function reportSubmission(form: HTMLFormElement, submission: Submission): void;
39
39
  export declare function setValue<T>(target: any, paths: Array<string | number>, valueFn: (prev?: T) => T): void;
40
40
  export declare function requestSubmit(form: HTMLFormElement, submitter?: HTMLButtonElement | HTMLInputElement): void;
41
41
  export declare function requestValidate(form: HTMLFormElement, field?: string): void;
package/index.js CHANGED
@@ -53,16 +53,48 @@ function hasError(error, name) {
53
53
  return (typeof name === 'undefined' || name === fieldName) && message !== '';
54
54
  }) !== 'undefined';
55
55
  }
56
- function setFormError(form, submission) {
57
- var firstErrorByName = Object.fromEntries([...submission.error].reverse());
56
+ function reportSubmission(form, submission) {
57
+ var messageByName = new Map();
58
+ var nameByInput = new Map();
59
+ for (var [name, message] of submission.error) {
60
+ if (!messageByName.has(name)) {
61
+ // Only keep the first error message (for now)
62
+ messageByName.set(name, message);
63
+
64
+ // We can't use empty string as button name
65
+ // As `form.element.namedItem('')` will always returns null
66
+ var elementName = name ? name : '__form__';
67
+ var item = form.elements.namedItem(elementName);
68
+ if (item instanceof RadioNodeList) {
69
+ throw new Error('Repeated field name is not supported');
70
+ }
71
+ if (item === null) {
72
+ // Create placeholder button to keep the error without contributing to the form data
73
+ var button = document.createElement('button');
74
+ button.name = elementName;
75
+ button.hidden = true;
76
+ button.dataset.conformTouched = 'true';
77
+ item = button;
78
+ form.appendChild(button);
79
+ }
80
+ nameByInput.set(item, name);
81
+ }
82
+ }
58
83
  for (var element of form.elements) {
59
- if (isFieldElement(element)) {
60
- var error = firstErrorByName[element.name];
61
- if (typeof error !== 'undefined' || shouldValidate(submission, element.name)) {
62
- element.setCustomValidity(error !== null && error !== void 0 ? error : '');
84
+ if (isFieldElement(element) && element.willValidate) {
85
+ var _nameByInput$get;
86
+ var _name = (_nameByInput$get = nameByInput.get(element)) !== null && _nameByInput$get !== void 0 ? _nameByInput$get : element.name;
87
+ var _message = messageByName.get(_name);
88
+ if (typeof _message !== 'undefined' || shouldValidate(submission, _name)) {
89
+ var invalidEvent = new Event('invalid', {
90
+ cancelable: true
91
+ });
92
+ element.setCustomValidity(_message !== null && _message !== void 0 ? _message : '');
93
+ element.dispatchEvent(invalidEvent);
63
94
  }
64
95
  }
65
96
  }
97
+ focusFirstInvalidField(form);
66
98
  }
67
99
  function setValue(target, paths, valueFn) {
68
100
  var length = paths.length;
@@ -150,10 +182,13 @@ function parse(payload) {
150
182
  } else {
151
183
  var paths = getPaths(name);
152
184
  setValue(submission.value, paths, prev => {
153
- if (prev) {
154
- throw new Error('Entry with the same name is not supported');
185
+ if (!prev) {
186
+ return value;
187
+ } else if (Array.isArray(prev)) {
188
+ return prev.concat(value);
189
+ } else {
190
+ return [prev, value];
155
191
  }
156
- return value;
157
192
  });
158
193
  }
159
194
  };
@@ -237,9 +272,9 @@ exports.hasError = hasError;
237
272
  exports.isFieldElement = isFieldElement;
238
273
  exports.parse = parse;
239
274
  exports.parseListCommand = parseListCommand;
275
+ exports.reportSubmission = reportSubmission;
240
276
  exports.requestSubmit = requestSubmit;
241
277
  exports.requestValidate = requestValidate;
242
- exports.setFormError = setFormError;
243
278
  exports.setValue = setValue;
244
279
  exports.shouldValidate = shouldValidate;
245
280
  exports.updateList = updateList;
package/module/index.js CHANGED
@@ -49,16 +49,48 @@ function hasError(error, name) {
49
49
  return (typeof name === 'undefined' || name === fieldName) && message !== '';
50
50
  }) !== 'undefined';
51
51
  }
52
- function setFormError(form, submission) {
53
- var firstErrorByName = Object.fromEntries([...submission.error].reverse());
52
+ function reportSubmission(form, submission) {
53
+ var messageByName = new Map();
54
+ var nameByInput = new Map();
55
+ for (var [name, message] of submission.error) {
56
+ if (!messageByName.has(name)) {
57
+ // Only keep the first error message (for now)
58
+ messageByName.set(name, message);
59
+
60
+ // We can't use empty string as button name
61
+ // As `form.element.namedItem('')` will always returns null
62
+ var elementName = name ? name : '__form__';
63
+ var item = form.elements.namedItem(elementName);
64
+ if (item instanceof RadioNodeList) {
65
+ throw new Error('Repeated field name is not supported');
66
+ }
67
+ if (item === null) {
68
+ // Create placeholder button to keep the error without contributing to the form data
69
+ var button = document.createElement('button');
70
+ button.name = elementName;
71
+ button.hidden = true;
72
+ button.dataset.conformTouched = 'true';
73
+ item = button;
74
+ form.appendChild(button);
75
+ }
76
+ nameByInput.set(item, name);
77
+ }
78
+ }
54
79
  for (var element of form.elements) {
55
- if (isFieldElement(element)) {
56
- var error = firstErrorByName[element.name];
57
- if (typeof error !== 'undefined' || shouldValidate(submission, element.name)) {
58
- element.setCustomValidity(error !== null && error !== void 0 ? error : '');
80
+ if (isFieldElement(element) && element.willValidate) {
81
+ var _nameByInput$get;
82
+ var _name = (_nameByInput$get = nameByInput.get(element)) !== null && _nameByInput$get !== void 0 ? _nameByInput$get : element.name;
83
+ var _message = messageByName.get(_name);
84
+ if (typeof _message !== 'undefined' || shouldValidate(submission, _name)) {
85
+ var invalidEvent = new Event('invalid', {
86
+ cancelable: true
87
+ });
88
+ element.setCustomValidity(_message !== null && _message !== void 0 ? _message : '');
89
+ element.dispatchEvent(invalidEvent);
59
90
  }
60
91
  }
61
92
  }
93
+ focusFirstInvalidField(form);
62
94
  }
63
95
  function setValue(target, paths, valueFn) {
64
96
  var length = paths.length;
@@ -146,10 +178,13 @@ function parse(payload) {
146
178
  } else {
147
179
  var paths = getPaths(name);
148
180
  setValue(submission.value, paths, prev => {
149
- if (prev) {
150
- throw new Error('Entry with the same name is not supported');
181
+ if (!prev) {
182
+ return value;
183
+ } else if (Array.isArray(prev)) {
184
+ return prev.concat(value);
185
+ } else {
186
+ return [prev, value];
151
187
  }
152
- return value;
153
188
  });
154
189
  }
155
190
  };
@@ -221,4 +256,4 @@ function handleList(submission) {
221
256
  return submission;
222
257
  }
223
258
 
224
- export { focusFirstInvalidField, getFormData, getFormElement, getFormElements, getName, getPaths, getSubmissionType, handleList, hasError, isFieldElement, parse, parseListCommand, requestSubmit, requestValidate, setFormError, setValue, shouldValidate, updateList };
259
+ export { focusFirstInvalidField, getFormData, getFormElement, getFormElements, getName, getPaths, getSubmissionType, handleList, hasError, isFieldElement, parse, parseListCommand, reportSubmission, requestSubmit, requestValidate, setValue, shouldValidate, updateList };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@conform-to/dom",
3
3
  "description": "A set of opinionated helpers built on top of the Constraint Validation API",
4
4
  "license": "MIT",
5
- "version": "0.4.0",
5
+ "version": "0.5.0-pre.0",
6
6
  "main": "index.js",
7
7
  "module": "module/index.js",
8
8
  "repository": {