@conform-to/dom 0.9.0 → 1.0.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/dom.d.ts CHANGED
@@ -1,51 +1,43 @@
1
- export type FormControl = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement;
2
- export type Submitter = HTMLInputElement | HTMLButtonElement;
3
1
  /**
4
- * A type guard to check if the provided reference is a form control element, including
5
- * `input`, `select`, `textarea` or `button`
2
+ * Element that user can interact with,
3
+ * includes `<input>`, `<select>` and `<textarea>`.
6
4
  */
7
- export declare function isFormControl(element: unknown): element is FormControl;
5
+ export type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
8
6
  /**
9
- * A type guard to check if the provided reference is a focusable form control element.
7
+ * HTML Element that can be used as a form control,
8
+ * includes `<input>`, `<select>`, `<textarea>` and `<button>`.
10
9
  */
11
- export declare function isFocusableFormControl(element: unknown): element is FormControl;
12
- /**
13
- * Resolves the form action based on the submit event
14
- */
15
- export declare function getFormAction(event: SubmitEvent): string;
10
+ export type FormControl = FieldElement | HTMLButtonElement;
16
11
  /**
17
- * Resolves the form encoding type based on the submit event
12
+ * Form Control element. It can either be a submit button or a submit input.
18
13
  */
19
- export declare function getFormEncType(event: SubmitEvent): 'application/x-www-form-urlencoded' | 'multipart/form-data';
14
+ export type Submitter = HTMLInputElement | HTMLButtonElement;
20
15
  /**
21
- * Resolves the form method based on the submit event
16
+ * A type guard to check if the provided element is a form control
22
17
  */
23
- export declare function getFormMethod(event: SubmitEvent): 'get' | 'post' | 'put' | 'patch' | 'delete';
18
+ export declare function isFormControl(element: unknown): element is FormControl;
24
19
  /**
25
- * Resolve the form element
20
+ * A type guard to check if the provided element is a field element, which
21
+ * is a form control excluding submit, button and reset type.
26
22
  */
27
- export declare function getFormElement(element: HTMLFormElement | HTMLFieldSetElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement | null): HTMLFormElement | null;
23
+ export declare function isFieldElement(element: unknown): element is FieldElement;
28
24
  /**
29
- * Returns a list of form control elements in the form
25
+ * Resolves the action from the submit event
26
+ * with respect to the submitter `formaction` attribute.
30
27
  */
31
- export declare function getFormControls(form: HTMLFormElement): FormControl[];
28
+ export declare function getFormAction(event: SubmitEvent): string;
32
29
  /**
33
- * A function to create a submitter button element
30
+ * Resolves the encoding type from the submit event
31
+ * with respect to the submitter `formenctype` attribute.
34
32
  */
35
- export declare function createSubmitter(config: {
36
- name: string;
37
- value: string;
38
- hidden?: boolean;
39
- formAction?: string;
40
- formEnctype?: ReturnType<typeof getFormEncType>;
41
- formMethod?: ReturnType<typeof getFormMethod>;
42
- formNoValidate?: boolean;
43
- }): HTMLButtonElement;
33
+ export declare function getFormEncType(event: SubmitEvent): 'application/x-www-form-urlencoded' | 'multipart/form-data';
44
34
  /**
45
- * Trigger form submission with a submitter.
35
+ * Resolves the method from the submit event
36
+ * with respect to the submitter `formmethod` attribute.
46
37
  */
47
- export declare function requestSubmit(form: HTMLFormElement, submitter: Submitter | null): void;
38
+ export declare function getFormMethod(event: SubmitEvent): 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
48
39
  /**
49
- * Focus on the first invalid form control in the form
40
+ * Trigger a form submit event with an optional submitter.
41
+ * If the submitter is not mounted, it will be appended to the form and removed after submission.
50
42
  */
51
- export declare function focusFirstInvalidControl(form: HTMLFormElement): void;
43
+ export declare function requestSubmit(form: HTMLFormElement | null | undefined, submitter: Submitter | null): void;
package/dom.js CHANGED
@@ -2,23 +2,40 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var util = require('./util.js');
6
+
7
+ /**
8
+ * Element that user can interact with,
9
+ * includes `<input>`, `<select>` and `<textarea>`.
10
+ */
11
+
12
+ /**
13
+ * HTML Element that can be used as a form control,
14
+ * includes `<input>`, `<select>`, `<textarea>` and `<button>`.
15
+ */
16
+
17
+ /**
18
+ * Form Control element. It can either be a submit button or a submit input.
19
+ */
20
+
5
21
  /**
6
- * A type guard to check if the provided reference is a form control element, including
7
- * `input`, `select`, `textarea` or `button`
22
+ * A type guard to check if the provided element is a form control
8
23
  */
9
24
  function isFormControl(element) {
10
25
  return element instanceof Element && (element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA' || element.tagName === 'BUTTON');
11
26
  }
12
27
 
13
28
  /**
14
- * A type guard to check if the provided reference is a focusable form control element.
29
+ * A type guard to check if the provided element is a field element, which
30
+ * is a form control excluding submit, button and reset type.
15
31
  */
16
- function isFocusableFormControl(element) {
17
- return isFormControl(element) && element.willValidate && element.type !== 'submit';
32
+ function isFieldElement(element) {
33
+ return isFormControl(element) && element.type !== 'submit' && element.type !== 'button' && element.type !== 'reset';
18
34
  }
19
35
 
20
36
  /**
21
- * Resolves the form action based on the submit event
37
+ * Resolves the action from the submit event
38
+ * with respect to the submitter `formaction` attribute.
22
39
  */
23
40
  function getFormAction(event) {
24
41
  var _ref, _submitter$getAttribu;
@@ -28,7 +45,8 @@ function getFormAction(event) {
28
45
  }
29
46
 
30
47
  /**
31
- * Resolves the form encoding type based on the submit event
48
+ * Resolves the encoding type from the submit event
49
+ * with respect to the submitter `formenctype` attribute.
32
50
  */
33
51
  function getFormEncType(event) {
34
52
  var _submitter$getAttribu2;
@@ -42,67 +60,30 @@ function getFormEncType(event) {
42
60
  }
43
61
 
44
62
  /**
45
- * Resolves the form method based on the submit event
63
+ * Resolves the method from the submit event
64
+ * with respect to the submitter `formmethod` attribute.
46
65
  */
47
66
  function getFormMethod(event) {
48
- var _submitter$getAttribu3;
67
+ var _ref2, _submitter$getAttribu3;
49
68
  var form = event.target;
50
69
  var submitter = event.submitter;
51
- var method = (_submitter$getAttribu3 = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute('formmethod')) !== null && _submitter$getAttribu3 !== void 0 ? _submitter$getAttribu3 : form.getAttribute('method');
70
+ var method = (_ref2 = (_submitter$getAttribu3 = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute('formmethod')) !== null && _submitter$getAttribu3 !== void 0 ? _submitter$getAttribu3 : form.getAttribute('method')) === null || _ref2 === void 0 ? void 0 : _ref2.toUpperCase();
52
71
  switch (method) {
53
- case 'post':
54
- case 'put':
55
- case 'patch':
56
- case 'delete':
72
+ case 'POST':
73
+ case 'PUT':
74
+ case 'PATCH':
75
+ case 'DELETE':
57
76
  return method;
58
77
  }
59
- return 'get';
60
- }
61
-
62
- /**
63
- * Resolve the form element
64
- */
65
- function getFormElement(element) {
66
- var _element$form;
67
- return element instanceof HTMLFormElement ? element : (_element$form = element === null || element === void 0 ? void 0 : element.form) !== null && _element$form !== void 0 ? _element$form : null;
68
- }
69
-
70
- /**
71
- * Returns a list of form control elements in the form
72
- */
73
- function getFormControls(form) {
74
- return Array.from(form.elements).filter(isFormControl);
75
- }
76
-
77
- /**
78
- * A function to create a submitter button element
79
- */
80
- function createSubmitter(config) {
81
- var button = document.createElement('button');
82
- button.name = config.name;
83
- button.value = config.value;
84
- if (config.hidden) {
85
- button.hidden = true;
86
- }
87
- if (config.formAction) {
88
- button.formAction = config.formAction;
89
- }
90
- if (config.formEnctype) {
91
- button.formEnctype = config.formEnctype;
92
- }
93
- if (config.formMethod) {
94
- button.formMethod = config.formMethod;
95
- }
96
- if (config.formNoValidate) {
97
- button.formNoValidate = true;
98
- }
99
- return button;
78
+ return 'GET';
100
79
  }
101
80
 
102
81
  /**
103
- * Trigger form submission with a submitter.
82
+ * Trigger a form submit event with an optional submitter.
83
+ * If the submitter is not mounted, it will be appended to the form and removed after submission.
104
84
  */
105
85
  function requestSubmit(form, submitter) {
86
+ util.invariant(!!form, 'Failed to submit the form. The element provided is null or undefined.');
106
87
  var shouldRemoveSubmitter = false;
107
88
  if (submitter && !submitter.isConnected) {
108
89
  shouldRemoveSubmitter = true;
@@ -123,25 +104,9 @@ function requestSubmit(form, submitter) {
123
104
  }
124
105
  }
125
106
 
126
- /**
127
- * Focus on the first invalid form control in the form
128
- */
129
- function focusFirstInvalidControl(form) {
130
- for (var element of form.elements) {
131
- if (isFocusableFormControl(element) && !element.validity.valid) {
132
- element.focus();
133
- break;
134
- }
135
- }
136
- }
137
-
138
- exports.createSubmitter = createSubmitter;
139
- exports.focusFirstInvalidControl = focusFirstInvalidControl;
140
107
  exports.getFormAction = getFormAction;
141
- exports.getFormControls = getFormControls;
142
- exports.getFormElement = getFormElement;
143
108
  exports.getFormEncType = getFormEncType;
144
109
  exports.getFormMethod = getFormMethod;
145
- exports.isFocusableFormControl = isFocusableFormControl;
110
+ exports.isFieldElement = isFieldElement;
146
111
  exports.isFormControl = isFormControl;
147
112
  exports.requestSubmit = requestSubmit;
package/dom.mjs CHANGED
@@ -1,20 +1,37 @@
1
+ import { invariant } from './util.mjs';
2
+
3
+ /**
4
+ * Element that user can interact with,
5
+ * includes `<input>`, `<select>` and `<textarea>`.
6
+ */
7
+
8
+ /**
9
+ * HTML Element that can be used as a form control,
10
+ * includes `<input>`, `<select>`, `<textarea>` and `<button>`.
11
+ */
12
+
13
+ /**
14
+ * Form Control element. It can either be a submit button or a submit input.
15
+ */
16
+
1
17
  /**
2
- * A type guard to check if the provided reference is a form control element, including
3
- * `input`, `select`, `textarea` or `button`
18
+ * A type guard to check if the provided element is a form control
4
19
  */
5
20
  function isFormControl(element) {
6
21
  return element instanceof Element && (element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA' || element.tagName === 'BUTTON');
7
22
  }
8
23
 
9
24
  /**
10
- * A type guard to check if the provided reference is a focusable form control element.
25
+ * A type guard to check if the provided element is a field element, which
26
+ * is a form control excluding submit, button and reset type.
11
27
  */
12
- function isFocusableFormControl(element) {
13
- return isFormControl(element) && element.willValidate && element.type !== 'submit';
28
+ function isFieldElement(element) {
29
+ return isFormControl(element) && element.type !== 'submit' && element.type !== 'button' && element.type !== 'reset';
14
30
  }
15
31
 
16
32
  /**
17
- * Resolves the form action based on the submit event
33
+ * Resolves the action from the submit event
34
+ * with respect to the submitter `formaction` attribute.
18
35
  */
19
36
  function getFormAction(event) {
20
37
  var _ref, _submitter$getAttribu;
@@ -24,7 +41,8 @@ function getFormAction(event) {
24
41
  }
25
42
 
26
43
  /**
27
- * Resolves the form encoding type based on the submit event
44
+ * Resolves the encoding type from the submit event
45
+ * with respect to the submitter `formenctype` attribute.
28
46
  */
29
47
  function getFormEncType(event) {
30
48
  var _submitter$getAttribu2;
@@ -38,67 +56,30 @@ function getFormEncType(event) {
38
56
  }
39
57
 
40
58
  /**
41
- * Resolves the form method based on the submit event
59
+ * Resolves the method from the submit event
60
+ * with respect to the submitter `formmethod` attribute.
42
61
  */
43
62
  function getFormMethod(event) {
44
- var _submitter$getAttribu3;
63
+ var _ref2, _submitter$getAttribu3;
45
64
  var form = event.target;
46
65
  var submitter = event.submitter;
47
- var method = (_submitter$getAttribu3 = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute('formmethod')) !== null && _submitter$getAttribu3 !== void 0 ? _submitter$getAttribu3 : form.getAttribute('method');
66
+ var method = (_ref2 = (_submitter$getAttribu3 = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute('formmethod')) !== null && _submitter$getAttribu3 !== void 0 ? _submitter$getAttribu3 : form.getAttribute('method')) === null || _ref2 === void 0 ? void 0 : _ref2.toUpperCase();
48
67
  switch (method) {
49
- case 'post':
50
- case 'put':
51
- case 'patch':
52
- case 'delete':
68
+ case 'POST':
69
+ case 'PUT':
70
+ case 'PATCH':
71
+ case 'DELETE':
53
72
  return method;
54
73
  }
55
- return 'get';
56
- }
57
-
58
- /**
59
- * Resolve the form element
60
- */
61
- function getFormElement(element) {
62
- var _element$form;
63
- return element instanceof HTMLFormElement ? element : (_element$form = element === null || element === void 0 ? void 0 : element.form) !== null && _element$form !== void 0 ? _element$form : null;
64
- }
65
-
66
- /**
67
- * Returns a list of form control elements in the form
68
- */
69
- function getFormControls(form) {
70
- return Array.from(form.elements).filter(isFormControl);
71
- }
72
-
73
- /**
74
- * A function to create a submitter button element
75
- */
76
- function createSubmitter(config) {
77
- var button = document.createElement('button');
78
- button.name = config.name;
79
- button.value = config.value;
80
- if (config.hidden) {
81
- button.hidden = true;
82
- }
83
- if (config.formAction) {
84
- button.formAction = config.formAction;
85
- }
86
- if (config.formEnctype) {
87
- button.formEnctype = config.formEnctype;
88
- }
89
- if (config.formMethod) {
90
- button.formMethod = config.formMethod;
91
- }
92
- if (config.formNoValidate) {
93
- button.formNoValidate = true;
94
- }
95
- return button;
74
+ return 'GET';
96
75
  }
97
76
 
98
77
  /**
99
- * Trigger form submission with a submitter.
78
+ * Trigger a form submit event with an optional submitter.
79
+ * If the submitter is not mounted, it will be appended to the form and removed after submission.
100
80
  */
101
81
  function requestSubmit(form, submitter) {
82
+ invariant(!!form, 'Failed to submit the form. The element provided is null or undefined.');
102
83
  var shouldRemoveSubmitter = false;
103
84
  if (submitter && !submitter.isConnected) {
104
85
  shouldRemoveSubmitter = true;
@@ -119,16 +100,4 @@ function requestSubmit(form, submitter) {
119
100
  }
120
101
  }
121
102
 
122
- /**
123
- * Focus on the first invalid form control in the form
124
- */
125
- function focusFirstInvalidControl(form) {
126
- for (var element of form.elements) {
127
- if (isFocusableFormControl(element) && !element.validity.valid) {
128
- element.focus();
129
- break;
130
- }
131
- }
132
- }
133
-
134
- export { createSubmitter, focusFirstInvalidControl, getFormAction, getFormControls, getFormElement, getFormEncType, getFormMethod, isFocusableFormControl, isFormControl, requestSubmit };
103
+ export { getFormAction, getFormEncType, getFormMethod, isFieldElement, isFormControl, requestSubmit };
package/form.d.ts ADDED
@@ -0,0 +1,101 @@
1
+ import { getFormAction, getFormEncType, getFormMethod } from './dom';
2
+ import { 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;
7
+ export type FormValue<Schema> = Schema extends string | number | boolean | Date | null | undefined ? Schema | string : Schema extends File ? undefined : Schema extends Array<infer InnerType> ? Array<FormValue<InnerType>> : Schema extends Record<string, any> ? {
8
+ [Key in UnionKeyof<Schema>]?: FormValue<UnionKeyType<Schema, Key>>;
9
+ } : any;
10
+ export type FieldName<Schema> = string & {
11
+ __type?: Schema;
12
+ };
13
+ export type Constraint = {
14
+ required?: boolean;
15
+ minLength?: number;
16
+ maxLength?: number;
17
+ min?: string | number;
18
+ max?: string | number;
19
+ step?: string | number;
20
+ multiple?: boolean;
21
+ pattern?: string;
22
+ };
23
+ export type FormState = {
24
+ key: Record<string, string>;
25
+ validated: Record<string, boolean>;
26
+ valid: Record<string, boolean>;
27
+ dirty: Record<string, boolean>;
28
+ };
29
+ export type FormContext = {
30
+ defaultValue: Record<string, unknown>;
31
+ initialValue: Record<string, unknown>;
32
+ value: Record<string, unknown>;
33
+ error: Record<string, string[]>;
34
+ constraint: Record<string, Constraint>;
35
+ state: FormState;
36
+ };
37
+ export type FormOptions<Schema> = {
38
+ /**
39
+ * An object representing the initial value of the form.
40
+ */
41
+ defaultValue?: FormValue<Schema>;
42
+ /**
43
+ * An object describing the constraint of each field
44
+ */
45
+ constraint?: Record<string, Constraint>;
46
+ /**
47
+ * An object describing the result of the last submission
48
+ */
49
+ lastResult?: SubmissionResult;
50
+ /**
51
+ * Define when conform should start validation.
52
+ * Support "onSubmit", "onInput", "onBlur".
53
+ *
54
+ * @default "onSubmit"
55
+ */
56
+ shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput';
57
+ /**
58
+ * Define when conform should revalidate again.
59
+ * Support "onSubmit", "onInput", "onBlur".
60
+ *
61
+ * @default Same as shouldValidate, or "onSubmit" if shouldValidate is not provided.
62
+ */
63
+ shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput';
64
+ /**
65
+ * A function to be called when the form should be (re)validated.
66
+ */
67
+ onValidate?: (context: {
68
+ form: HTMLFormElement;
69
+ submitter: HTMLInputElement | HTMLButtonElement | null;
70
+ formData: FormData;
71
+ }) => Submission<Schema>;
72
+ };
73
+ export type SubscriptionSubject = {
74
+ [key in 'error' | 'initialValue' | 'value' | 'key' | 'validated' | 'valid' | 'dirty']?: SubscriptionScope;
75
+ };
76
+ export type SubscriptionScope = {
77
+ prefix?: string[];
78
+ name?: string[];
79
+ };
80
+ export type Form<Schema extends Record<string, any> = any> = {
81
+ id: string;
82
+ submit(event: SubmitEvent): {
83
+ formData: FormData;
84
+ action: ReturnType<typeof getFormAction>;
85
+ encType: ReturnType<typeof getFormEncType>;
86
+ method: ReturnType<typeof getFormMethod>;
87
+ submission?: Submission<Schema>;
88
+ };
89
+ reset(event: Event): void;
90
+ input(event: Event): void;
91
+ blur(event: Event): void;
92
+ initialize(): void;
93
+ report(result: SubmissionResult): void;
94
+ update(options: Omit<FormOptions<Schema>, 'lastResult'>): void;
95
+ subscribe(callback: () => void, getSubject?: () => SubscriptionSubject | undefined): () => void;
96
+ getContext(): FormContext;
97
+ getSerializedState(): string;
98
+ };
99
+ export declare const VALIDATION_UNDEFINED = "__undefined__";
100
+ export declare const VALIDATION_SKIPPED = "__skipped__";
101
+ export declare function createForm<Schema extends Record<string, any> = any>(formId: string, options: FormOptions<Schema>): Form<Schema>;