ember-headless-form 0.0.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.
Files changed (48) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +26 -0
  3. package/addon-main.js +5 -0
  4. package/dist/_app_/components/headless-form.js +1 -0
  5. package/dist/components/-private/capture-events.d.ts +21 -0
  6. package/dist/components/-private/capture-events.d.ts.map +1 -0
  7. package/dist/components/-private/capture-events.js +16 -0
  8. package/dist/components/-private/capture-events.js.map +1 -0
  9. package/dist/components/-private/control/checkbox.d.ts +16 -0
  10. package/dist/components/-private/control/checkbox.js +18 -0
  11. package/dist/components/-private/control/checkbox.js.map +1 -0
  12. package/dist/components/-private/control/input.d.ts +20 -0
  13. package/dist/components/-private/control/input.js +32 -0
  14. package/dist/components/-private/control/input.js.map +1 -0
  15. package/dist/components/-private/control/radio/input.d.ts +12 -0
  16. package/dist/components/-private/control/radio/input.js +10 -0
  17. package/dist/components/-private/control/radio/input.js.map +1 -0
  18. package/dist/components/-private/control/radio.d.ts +28 -0
  19. package/dist/components/-private/control/radio.js +23 -0
  20. package/dist/components/-private/control/radio.js.map +1 -0
  21. package/dist/components/-private/control/textarea.d.ts +16 -0
  22. package/dist/components/-private/control/textarea.js +18 -0
  23. package/dist/components/-private/control/textarea.js.map +1 -0
  24. package/dist/components/-private/errors.d.ts +15 -0
  25. package/dist/components/-private/errors.js +12 -0
  26. package/dist/components/-private/errors.js.map +1 -0
  27. package/dist/components/-private/field.d.ts +76 -0
  28. package/dist/components/-private/field.js +61 -0
  29. package/dist/components/-private/field.js.map +1 -0
  30. package/dist/components/-private/label.d.ts +11 -0
  31. package/dist/components/-private/label.js +10 -0
  32. package/dist/components/-private/label.js.map +1 -0
  33. package/dist/components/-private/types.d.ts +48 -0
  34. package/dist/components/-private/types.js +2 -0
  35. package/dist/components/-private/types.js.map +1 -0
  36. package/dist/components/-private/utils.d.ts +3 -0
  37. package/dist/components/-private/utils.js +16 -0
  38. package/dist/components/-private/utils.js.map +1 -0
  39. package/dist/components/headless-form.d.ts +123 -0
  40. package/dist/components/headless-form.js +258 -0
  41. package/dist/components/headless-form.js.map +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +2 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/template-registry.d.ts +5 -0
  46. package/dist/template-registry.js +2 -0
  47. package/dist/template-registry.js.map +1 -0
  48. package/package.json +120 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * What the user can pass as @data
3
+ */
4
+ type UserData = object;
5
+ /**
6
+ * The subset of properties of DATA, whose keys are strings (and not number or symbol)
7
+ * Only this data is useable in the form
8
+ */
9
+ type FormData<DATA extends UserData = UserData> = OnlyStringKeys<DATA>;
10
+ /**
11
+ * Returns the type of all keys of DATA, that are also strings. Only strings can be used as field @name
12
+ */
13
+ type FormKey<DATA extends UserData> = keyof DATA & string;
14
+ /**
15
+ * Generic interface for all validation errors
16
+ */
17
+ interface ValidationError<T = unknown> {
18
+ type: string;
19
+ value: T;
20
+ message?: string;
21
+ }
22
+ type ErrorRecord<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> = Partial<Record<KEY, ValidationError<DATA[KEY]>[]>>;
23
+ /**
24
+ * Callback used for form level validation
25
+ */
26
+ type FormValidateCallback<DATA extends FormData> = (formData: DATA) => undefined | ErrorRecord<DATA> | Promise<undefined | ErrorRecord<DATA>>;
27
+ /**
28
+ * Callback used for field level validation
29
+ */
30
+ type FieldValidateCallback<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> = (fieldValue: DATA[KEY], fieldName: KEY, formData: DATA) => undefined | ValidationError<DATA[KEY]>[] | Promise<undefined | ValidationError<DATA[KEY]>[]>;
31
+ /**
32
+ * Internal structure to track used fields
33
+ * @private
34
+ */
35
+ interface FieldRegistrationData<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> {
36
+ validate?: FieldValidateCallback<DATA, KEY>;
37
+ }
38
+ /**
39
+ * For internal field registration
40
+ * @private
41
+ */
42
+ type RegisterFieldCallback<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> = (name: KEY, field: FieldRegistrationData<DATA, KEY>) => void;
43
+ type UnregisterFieldCallback<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> = (name: KEY) => void;
44
+ /**
45
+ * Mapper type to construct subset of objects, whose keys are only strings (and not number or symbol)
46
+ */
47
+ type OnlyStringKeys<T extends object> = Pick<T, keyof T & string>;
48
+ export { UserData, FormData, FormKey, ValidationError, ErrorRecord, FormValidateCallback, FieldValidateCallback, FieldRegistrationData, RegisterFieldCallback, UnregisterFieldCallback, OnlyStringKeys };
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { ErrorRecord, FormData, FormKey } from "./types.js";
2
+ declare function mergeErrorRecord<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>>(...records: Array<ErrorRecord<DATA, KEY> | undefined>): ErrorRecord<DATA, KEY>;
3
+ export { mergeErrorRecord };
@@ -0,0 +1,16 @@
1
+ function mergeErrorRecord(...records) {
2
+ const errors = {};
3
+ for (const record of records) {
4
+ if (!record) {
5
+ continue;
6
+ }
7
+ for (const [name, fieldErrors] of Object.entries(record)) {
8
+ const existingFieldErrors = errors[name];
9
+ errors[name] = existingFieldErrors ? [...existingFieldErrors, ...fieldErrors] : fieldErrors;
10
+ }
11
+ }
12
+ return errors;
13
+ }
14
+
15
+ export { mergeErrorRecord };
16
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../../src/components/-private/utils.ts"],"sourcesContent":["import type { ErrorRecord, FormData, FormKey, ValidationError } from './types';\n\nexport function mergeErrorRecord<\n DATA extends FormData,\n KEY extends FormKey<DATA> = FormKey<DATA>\n>(\n ...records: Array<ErrorRecord<DATA, KEY> | undefined>\n): ErrorRecord<DATA, KEY> {\n const errors: ErrorRecord<DATA, KEY> = {};\n\n for (const record of records) {\n if (!record) {\n continue;\n }\n\n for (const [name, fieldErrors] of Object.entries(record) as [\n // TS does not infer the types correctly here, fieldErrors would be unknown, not sure why\n KEY,\n ValidationError<DATA[KEY]>[]\n ][]) {\n const existingFieldErrors = errors[name];\n\n errors[name] = existingFieldErrors\n ? [...existingFieldErrors, ...fieldErrors]\n : fieldErrors;\n }\n }\n\n return errors;\n}\n"],"names":["mergeErrorRecord","records","errors","record","name","fieldErrors","Object","entries","existingFieldErrors"],"mappings":"AAEO,SAASA,gBAAgB,CAI9B,GAAGC,OAAkD,EAC7B;EACxB,MAAMC,MAA8B,GAAG,EAAE,CAAA;AAEzC,EAAA,KAAK,MAAMC,MAAM,IAAIF,OAAO,EAAE;IAC5B,IAAI,CAACE,MAAM,EAAE;AACX,MAAA,SAAA;AACF,KAAA;AAEA,IAAA,KAAK,MAAM,CAACC,IAAI,EAAEC,WAAW,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACJ,MAAM,CAAC,EAInD;AACH,MAAA,MAAMK,mBAAmB,GAAGN,MAAM,CAACE,IAAI,CAAC,CAAA;AAExCF,MAAAA,MAAM,CAACE,IAAI,CAAC,GAAGI,mBAAmB,GAC9B,CAAC,GAAGA,mBAAmB,EAAE,GAAGH,WAAW,CAAC,GACxCA,WAAW,CAAA;AACjB,KAAA;AACF,GAAA;AAEA,EAAA,OAAOH,MAAM,CAAA;AACf;;;;"}
@@ -0,0 +1,123 @@
1
+ import Component from '@glimmer/component';
2
+ import FieldComponent from "./-private/field.js";
3
+ import { HeadlessFormFieldComponentSignature } from "./-private/field.js";
4
+ import { ErrorRecord, FieldRegistrationData, FieldValidateCallback, FormData, FormKey, FormValidateCallback, UserData } from "./-private/types.js";
5
+ import { ComponentLike, ModifierLike, WithBoundArgs } from '@glint/template';
6
+ type ValidateOn = 'change' | 'focusout' | 'submit' | 'input';
7
+ interface HeadlessFormComponentSignature<DATA extends UserData> {
8
+ Element: HTMLFormElement;
9
+ Args: {
10
+ data?: DATA;
11
+ validateOn?: ValidateOn;
12
+ revalidateOn?: ValidateOn;
13
+ validate?: FormValidateCallback<FormData<DATA>>;
14
+ onSubmit?: (data: FormData<DATA>) => void;
15
+ onInvalid?: (data: FormData<DATA>, errors: ErrorRecord<FormData<DATA>>) => void;
16
+ };
17
+ Blocks: {
18
+ default: [
19
+ {
20
+ field: WithBoundArgs<typeof FieldComponent<DATA>, 'data' | 'set' | 'errors' | 'registerField' | 'unregisterField' | 'triggerValidationFor' | 'fieldValidationEvent' | 'fieldRevalidationEvent'>;
21
+ }
22
+ ];
23
+ };
24
+ }
25
+ /**
26
+ * This internal data structure maintains information about each field that is registered to the form by `registerField`.
27
+ */
28
+ declare class FieldData<DATA extends FormData, KEY extends FormKey<DATA> = FormKey<DATA>> {
29
+ constructor(fieldRegistration: FieldRegistrationData<DATA, KEY>);
30
+ /**
31
+ * tracked state that enabled a dynamic validation of a field *before* the whole form is submitted, e.g. by `@validateOn="blur" and the blur event being triggered for that particular field.
32
+ */
33
+ validationEnabled: boolean;
34
+ /**
35
+ * The *field* level validation callback passed to the field as in `<form.field @name="foo" @validate={{this.validateCallback}}>`
36
+ */
37
+ validate?: FieldValidateCallback<DATA, KEY>;
38
+ }
39
+ declare class HeadlessFormComponent<DATA extends UserData> extends Component<HeadlessFormComponentSignature<DATA>> {
40
+ FieldComponent: ComponentLike<HeadlessFormFieldComponentSignature<DATA>>;
41
+ on: import("@ember/modifier").OnModifier;
42
+ formElement?: HTMLFormElement;
43
+ registerForm: ModifierLike<unknown>;
44
+ /**
45
+ * A copy of the passed `@data` stored internally, which is only passed back to the component consumer after a (successful) form submission.
46
+ */
47
+ internalData: DATA;
48
+ fields: Map<FormKey<FormData<DATA>>, FieldData<FormData<DATA>, FormKey<FormData<DATA>>>>;
49
+ /**
50
+ * The last result of calling `this.validate()`.
51
+ */
52
+ lastValidationResult?: ErrorRecord<FormData<DATA>>;
53
+ /**
54
+ * When this is set to true by submitting the form, eventual validation errors are show for *all* field, regardless of their individual dynamic validation status in `FieldData#validationEnabled`
55
+ */
56
+ showAllValidations: boolean;
57
+ get validateOn(): ValidateOn;
58
+ get revalidateOn(): ValidateOn;
59
+ /**
60
+ * Return the event type that will be listened on for dynamic validation (i.e. *before* submitting)
61
+ */
62
+ get fieldValidationEvent(): 'focusout' | 'change' | 'input' | undefined;
63
+ /**
64
+ * Return the event type that will be listened on for dynamic *re*validation, i.e. updating the validation status of a field that has been previously marked as invalid
65
+ */
66
+ get fieldRevalidationEvent(): 'focusout' | 'change' | 'input' | undefined;
67
+ /**
68
+ * Return true if validation has happened (by submitting or by an `@validateOn` event being triggered) and at least one field is invalid
69
+ */
70
+ get hasValidationErrors(): boolean;
71
+ /**
72
+ * Call the passed validation callbacks, defined both on the whole form as well as on field level, and return the merged result for all fields.
73
+ */
74
+ /**
75
+ * Call the passed validation callbacks, defined both on the whole form as well as on field level, and return the merged result for all fields.
76
+ */
77
+ validate(): Promise<ErrorRecord<FormData<DATA>>>;
78
+ validateNative(): ErrorRecord<FormData<DATA>> | undefined;
79
+ /**
80
+ * Return a mapping of field to validation errors, for all fields that are invalid *and* for which validation errors should be visible.
81
+ * Validation errors will be visible for a certain field, if validation errors for *all* fields are visible, which is the case when trying to submit the form,
82
+ * or when that field has triggered the event given by `@validateOn` for showing validation errors before submitting, e.g. on blur.
83
+ */
84
+ get visibleErrors(): ErrorRecord<FormData<DATA>> | undefined;
85
+ /**
86
+ * Given a field name, return if eventual errors for the field should be visible. See `visibleErrors` for further details.
87
+ */
88
+ /**
89
+ * Given a field name, return if eventual errors for the field should be visible. See `visibleErrors` for further details.
90
+ */
91
+ showErrorsFor(field: FormKey<FormData<DATA>>): boolean;
92
+ onSubmit(e: Event): Promise<void>;
93
+ registerField(name: FormKey<FormData<DATA>>, field: FieldRegistrationData<FormData<DATA>>): void;
94
+ unregisterField(name: FormKey<FormData<DATA>>): void;
95
+ set<KEY extends FormKey<FormData<DATA>>>(key: KEY, value: DATA[KEY]): void;
96
+ /**
97
+ * Handle the `@validateOn` event for a certain field, e.g. "blur".
98
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
99
+ * Validation will be triggered, and the particular field will be marked to show eventual validation errors.
100
+ */
101
+ /**
102
+ * Handle the `@validateOn` event for a certain field, e.g. "blur".
103
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
104
+ * Validation will be triggered, and the particular field will be marked to show eventual validation errors.
105
+ */
106
+ handleFieldValidation(e: Event | string): Promise<void>;
107
+ /**
108
+ * Handle the `@revalidateOn` event for a certain field, e.g. "blur".
109
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
110
+ * When a field has been already marked to show validation errors by `@validateOn`, then for revalidation another validation will be triggered.
111
+ *
112
+ * The use case here is to allow this to happen more frequently than the initial validation, e.g. `@validateOn="blur" @revalidateOn="change"`.
113
+ */
114
+ /**
115
+ * Handle the `@revalidateOn` event for a certain field, e.g. "blur".
116
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
117
+ * When a field has been already marked to show validation errors by `@validateOn`, then for revalidation another validation will be triggered.
118
+ *
119
+ * The use case here is to allow this to happen more frequently than the initial validation, e.g. `@validateOn="blur" @revalidateOn="change"`.
120
+ */
121
+ handleFieldRevalidation(e: Event): Promise<void>;
122
+ }
123
+ export { HeadlessFormComponentSignature, HeadlessFormComponent as default };
@@ -0,0 +1,258 @@
1
+ import _initializerDefineProperty from '@babel/runtime/helpers/esm/initializerDefineProperty';
2
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
3
+ import _applyDecoratedDescriptor from '@babel/runtime/helpers/esm/applyDecoratedDescriptor';
4
+ import '@babel/runtime/helpers/esm/initializerWarningHelper';
5
+ import { setComponentTemplate } from '@ember/component';
6
+ import { precompileTemplate } from '@ember/template-compilation';
7
+ import Component from '@glimmer/component';
8
+ import { tracked } from '@glimmer/tracking';
9
+ import { assert, warn } from '@ember/debug';
10
+ import { on } from '@ember/modifier';
11
+ import { action } from '@ember/object';
12
+ import { waitFor } from '@ember/test-waiters';
13
+ import { modifier } from 'ember-modifier';
14
+ import { TrackedObject } from 'tracked-built-ins';
15
+ import HeadlessFormFieldComponent from './-private/field.js';
16
+ import { mergeErrorRecord } from './-private/utils.js';
17
+
18
+ var TEMPLATE = precompileTemplate("<form\n novalidate\n ...attributes\n {{this.registerForm}}\n {{on \'submit\' this.onSubmit}}\n {{(if\n this.fieldValidationEvent\n (modifier this.on this.fieldValidationEvent this.handleFieldValidation)\n )}}\n {{(if\n this.fieldRevalidationEvent\n (modifier this.on this.fieldRevalidationEvent this.handleFieldRevalidation)\n )}}\n>\n {{yield\n (hash\n field=(component\n (ensure-safe-component this.FieldComponent)\n data=this.internalData\n set=this.set\n errors=this.visibleErrors\n registerField=this.registerField\n unregisterField=this.unregisterField\n triggerValidationFor=this.handleFieldValidation\n fieldValidationEvent=this.fieldValidationEvent\n fieldRevalidationEvent=this.fieldRevalidationEvent\n )\n )\n }}\n</form>");
19
+
20
+ var _class, _descriptor, _class3, _descriptor2, _descriptor3;
21
+ /**
22
+ * This internal data structure maintains information about each field that is registered to the form by `registerField`.
23
+ */
24
+ let FieldData = (_class = class FieldData {
25
+ constructor(fieldRegistration) {
26
+ _initializerDefineProperty(this, "validationEnabled", _descriptor, this);
27
+ _defineProperty(this, "validate", void 0);
28
+ this.validate = fieldRegistration.validate;
29
+ }
30
+
31
+ /**
32
+ * tracked state that enabled a dynamic validation of a field *before* the whole form is submitted, e.g. by `@validateOn="blur" and the blur event being triggered for that particular field.
33
+ */
34
+ }, (_descriptor = _applyDecoratedDescriptor(_class.prototype, "validationEnabled", [tracked], {
35
+ configurable: true,
36
+ enumerable: true,
37
+ writable: true,
38
+ initializer: function () {
39
+ return false;
40
+ }
41
+ })), _class);
42
+ let HeadlessFormComponent = (_class3 = class HeadlessFormComponent extends Component {
43
+ constructor(...args) {
44
+ super(...args);
45
+ _defineProperty(this, "FieldComponent", HeadlessFormFieldComponent);
46
+ _defineProperty(this, "on", on);
47
+ _defineProperty(this, "formElement", void 0);
48
+ _defineProperty(this, "registerForm", modifier((el, _p) => {
49
+ this.formElement = el;
50
+ }));
51
+ _defineProperty(this, "internalData", new TrackedObject(this.args.data ?? {}));
52
+ _defineProperty(this, "fields", new Map());
53
+ _initializerDefineProperty(this, "lastValidationResult", _descriptor2, this);
54
+ _initializerDefineProperty(this, "showAllValidations", _descriptor3, this);
55
+ }
56
+ get validateOn() {
57
+ return this.args.validateOn ?? 'submit';
58
+ }
59
+ get revalidateOn() {
60
+ return this.args.revalidateOn ?? 'change';
61
+ }
62
+
63
+ /**
64
+ * Return the event type that will be listened on for dynamic validation (i.e. *before* submitting)
65
+ */
66
+ get fieldValidationEvent() {
67
+ const {
68
+ validateOn
69
+ } = this;
70
+ return validateOn === 'submit' ?
71
+ // no need for dynamic validation, as validation always happens on submit
72
+ undefined : validateOn;
73
+ }
74
+
75
+ /**
76
+ * Return the event type that will be listened on for dynamic *re*validation, i.e. updating the validation status of a field that has been previously marked as invalid
77
+ */
78
+ get fieldRevalidationEvent() {
79
+ const {
80
+ validateOn,
81
+ revalidateOn
82
+ } = this;
83
+ return revalidateOn === 'submit' ?
84
+ // no need for dynamic validation, as validation always happens on submit
85
+ undefined :
86
+ // when validation happens more frequently than revalidation, then we can ignore revalidation, because the validation handler will already cover us
87
+ validateOn === 'input' || validateOn === 'change' && revalidateOn === 'focusout' || validateOn === revalidateOn ? undefined : revalidateOn;
88
+ }
89
+
90
+ /**
91
+ * Return true if validation has happened (by submitting or by an `@validateOn` event being triggered) and at least one field is invalid
92
+ */
93
+ get hasValidationErrors() {
94
+ // Only consider validation errors for which we actually have a field rendered
95
+ return this.lastValidationResult ? Object.keys(this.lastValidationResult).some(name => this.fields.has(name)) : false;
96
+ }
97
+
98
+ /**
99
+ * Call the passed validation callbacks, defined both on the whole form as well as on field level, and return the merged result for all fields.
100
+ */
101
+ async validate() {
102
+ const nativeValidation = this.validateNative();
103
+ const customFormValidation = await this.args.validate?.(this.internalData);
104
+ const customFieldValidations = [];
105
+ for (const [name, field] of this.fields) {
106
+ const fieldValidationResult = await field.validate?.(this.internalData[name], name, this.internalData);
107
+ if (fieldValidationResult) {
108
+ customFieldValidations.push({
109
+ [name]: fieldValidationResult
110
+ });
111
+ }
112
+ }
113
+ return mergeErrorRecord(nativeValidation, customFormValidation, ...customFieldValidations);
114
+ }
115
+ validateNative() {
116
+ const form = this.formElement;
117
+ assert('Form element expected to be present. If you see this, please report it as a bug to ember-headless-form!', form);
118
+ if (form.checkValidity()) {
119
+ return;
120
+ }
121
+ const errors = {};
122
+ for (const el of form.elements) {
123
+ // This is just to make TS happy, as we need to access properties on el that only form elements have, but elements in `form.elements` are just typed as plain `Element`. Should never occur in reality.
124
+ assert('Unexpected form element. If you see this, please report it as a bug to ember-headless-form!', el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement || el instanceof HTMLButtonElement || el instanceof HTMLFieldSetElement || el instanceof HTMLObjectElement || el instanceof HTMLOutputElement);
125
+ if (el.validity.valid) {
126
+ continue;
127
+ }
128
+ const name = el.name;
129
+ if (this.fields.has(name)) {
130
+ errors[name] = [{
131
+ type: 'native',
132
+ value: this.internalData[name],
133
+ message: el.validationMessage
134
+ }];
135
+ } else {
136
+ warn(`An invalid form element with name "${name}" was detected, but this name is not used as a form field. It will be ignored for validation. Make sure to apply the correct name to custom form elements that participate in form validation!`, {
137
+ id: 'headless-form.invalid-control-for-unknown-field'
138
+ });
139
+ }
140
+ }
141
+ return errors;
142
+ }
143
+
144
+ /**
145
+ * Return a mapping of field to validation errors, for all fields that are invalid *and* for which validation errors should be visible.
146
+ * Validation errors will be visible for a certain field, if validation errors for *all* fields are visible, which is the case when trying to submit the form,
147
+ * or when that field has triggered the event given by `@validateOn` for showing validation errors before submitting, e.g. on blur.
148
+ */
149
+ get visibleErrors() {
150
+ if (!this.lastValidationResult) {
151
+ return undefined;
152
+ }
153
+ const visibleErrors = {};
154
+ for (const [field, errors] of Object.entries(this.lastValidationResult)) {
155
+ if (this.showErrorsFor(field)) {
156
+ visibleErrors[field] = errors;
157
+ }
158
+ }
159
+ return visibleErrors;
160
+ }
161
+
162
+ /**
163
+ * Given a field name, return if eventual errors for the field should be visible. See `visibleErrors` for further details.
164
+ */
165
+ showErrorsFor(field) {
166
+ return this.showAllValidations || (this.fields.get(field)?.validationEnabled ?? false);
167
+ }
168
+ async onSubmit(e) {
169
+ e.preventDefault();
170
+ this.lastValidationResult = await this.validate();
171
+ this.showAllValidations = true;
172
+ if (!this.hasValidationErrors) {
173
+ this.args.onSubmit?.(this.internalData);
174
+ } else {
175
+ assert('Validation errors expected to be present. If you see this, please report it as a bug to ember-headless-form!', this.lastValidationResult);
176
+ this.args.onInvalid?.(this.internalData, this.lastValidationResult);
177
+ }
178
+ }
179
+ registerField(name, field) {
180
+ assert(`You passed @name="${String(name)}" to the form field, but this is already in use. Names of form fields must be unique!`, !this.fields.has(name));
181
+ this.fields.set(name, new FieldData(field));
182
+ }
183
+ unregisterField(name) {
184
+ this.fields.delete(name);
185
+ }
186
+ set(key, value) {
187
+ this.internalData[key] = value;
188
+ }
189
+
190
+ /**
191
+ * Handle the `@validateOn` event for a certain field, e.g. "blur".
192
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
193
+ * Validation will be triggered, and the particular field will be marked to show eventual validation errors.
194
+ */
195
+ async handleFieldValidation(e) {
196
+ let name;
197
+ if (typeof e === 'string') {
198
+ name = e;
199
+ } else {
200
+ const {
201
+ target
202
+ } = e;
203
+ name = target.name;
204
+ }
205
+ if (name) {
206
+ const field = this.fields.get(name);
207
+ if (field) {
208
+ this.lastValidationResult = await this.validate();
209
+ field.validationEnabled = true;
210
+ }
211
+ } else if (e instanceof Event) {
212
+ warn(`An event of type "${e.type}" was received by headless-form, which is supposed to trigger validations for a certain field. But the name of that field could not be determined. Make sure that your control element has a \`name\` attribute matching the field, or use the yielded \`{{field.captureEvents}}\` to capture the events.`, {
213
+ id: 'headless-form.validation-event-for-unknown-field'
214
+ });
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Handle the `@revalidateOn` event for a certain field, e.g. "blur".
220
+ * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name="...">` invocations by the user's template.
221
+ * When a field has been already marked to show validation errors by `@validateOn`, then for revalidation another validation will be triggered.
222
+ *
223
+ * The use case here is to allow this to happen more frequently than the initial validation, e.g. `@validateOn="blur" @revalidateOn="change"`.
224
+ */
225
+ async handleFieldRevalidation(e) {
226
+ const {
227
+ target
228
+ } = e;
229
+ const {
230
+ name
231
+ } = target;
232
+ if (name) {
233
+ if (this.showErrorsFor(name)) {
234
+ this.lastValidationResult = await this.validate();
235
+ }
236
+ } else {
237
+ warn(`An event of type "${e.type}" was received by headless-form, which is supposed to trigger validations for a certain field. But the name of that field could not be determined. Make sure that your control element has a \`name\` attribute matching the field, or use the yielded \`{{field.captureEvents}}\` to capture the events.`, {
238
+ id: 'headless-form.validation-event-for-unknown-field'
239
+ });
240
+ }
241
+ }
242
+ }, (_descriptor2 = _applyDecoratedDescriptor(_class3.prototype, "lastValidationResult", [tracked], {
243
+ configurable: true,
244
+ enumerable: true,
245
+ writable: true,
246
+ initializer: null
247
+ }), _descriptor3 = _applyDecoratedDescriptor(_class3.prototype, "showAllValidations", [tracked], {
248
+ configurable: true,
249
+ enumerable: true,
250
+ writable: true,
251
+ initializer: function () {
252
+ return false;
253
+ }
254
+ }), _applyDecoratedDescriptor(_class3.prototype, "validate", [waitFor], Object.getOwnPropertyDescriptor(_class3.prototype, "validate"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "onSubmit", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "onSubmit"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "registerField", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "registerField"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "unregisterField", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "unregisterField"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "set", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "set"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "handleFieldValidation", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "handleFieldValidation"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "handleFieldRevalidation", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "handleFieldRevalidation"), _class3.prototype)), _class3);
255
+ setComponentTemplate(TEMPLATE, HeadlessFormComponent);
256
+
257
+ export { HeadlessFormComponent as default };
258
+ //# sourceMappingURL=headless-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-form.js","sources":["../../src/components/headless-form.hbs.js","../../src/components/headless-form.ts"],"sourcesContent":["import { precompileTemplate } from \"@ember/template-compilation\";\nexport default precompileTemplate(\"<form\\n novalidate\\n ...attributes\\n {{this.registerForm}}\\n {{on \\'submit\\' this.onSubmit}}\\n {{(if\\n this.fieldValidationEvent\\n (modifier this.on this.fieldValidationEvent this.handleFieldValidation)\\n )}}\\n {{(if\\n this.fieldRevalidationEvent\\n (modifier this.on this.fieldRevalidationEvent this.handleFieldRevalidation)\\n )}}\\n>\\n {{yield\\n (hash\\n field=(component\\n (ensure-safe-component this.FieldComponent)\\n data=this.internalData\\n set=this.set\\n errors=this.visibleErrors\\n registerField=this.registerField\\n unregisterField=this.unregisterField\\n triggerValidationFor=this.handleFieldValidation\\n fieldValidationEvent=this.fieldValidationEvent\\n fieldRevalidationEvent=this.fieldRevalidationEvent\\n )\\n )\\n }}\\n</form>\")","import Component from '@glimmer/component';\nimport { tracked } from '@glimmer/tracking';\nimport { assert, warn } from '@ember/debug';\nimport { on } from '@ember/modifier';\nimport { action } from '@ember/object';\nimport { waitFor } from '@ember/test-waiters';\n\nimport { modifier } from 'ember-modifier';\nimport { TrackedObject } from 'tracked-built-ins';\n\nimport FieldComponent from './-private/field';\nimport { mergeErrorRecord } from './-private/utils';\n\nimport type { HeadlessFormFieldComponentSignature } from './-private/field';\nimport type {\n ErrorRecord,\n FieldRegistrationData,\n FieldValidateCallback,\n FormData,\n FormKey,\n FormValidateCallback,\n UserData,\n ValidationError,\n} from './-private/types';\nimport type {\n ComponentLike,\n ModifierLike,\n WithBoundArgs,\n} from '@glint/template';\n\ntype ValidateOn = 'change' | 'focusout' | 'submit' | 'input';\n\nexport interface HeadlessFormComponentSignature<DATA extends UserData> {\n Element: HTMLFormElement;\n Args: {\n data?: DATA;\n validateOn?: ValidateOn;\n revalidateOn?: ValidateOn;\n validate?: FormValidateCallback<FormData<DATA>>;\n onSubmit?: (data: FormData<DATA>) => void;\n onInvalid?: (\n data: FormData<DATA>,\n errors: ErrorRecord<FormData<DATA>>\n ) => void;\n };\n Blocks: {\n default: [\n {\n field: WithBoundArgs<\n typeof FieldComponent<DATA>,\n | 'data'\n | 'set'\n | 'errors'\n | 'registerField'\n | 'unregisterField'\n | 'triggerValidationFor'\n | 'fieldValidationEvent'\n | 'fieldRevalidationEvent'\n >;\n }\n ];\n };\n}\n\n/**\n * This internal data structure maintains information about each field that is registered to the form by `registerField`.\n */\nclass FieldData<\n DATA extends FormData,\n KEY extends FormKey<DATA> = FormKey<DATA>\n> {\n constructor(fieldRegistration: FieldRegistrationData<DATA, KEY>) {\n this.validate = fieldRegistration.validate;\n }\n\n /**\n * tracked state that enabled a dynamic validation of a field *before* the whole form is submitted, e.g. by `@validateOn=\"blur\" and the blur event being triggered for that particular field.\n */\n @tracked validationEnabled = false;\n\n /**\n * The *field* level validation callback passed to the field as in `<form.field @name=\"foo\" @validate={{this.validateCallback}}>`\n */\n validate?: FieldValidateCallback<DATA, KEY>;\n}\n\nexport default class HeadlessFormComponent<\n DATA extends UserData\n> extends Component<HeadlessFormComponentSignature<DATA>> {\n FieldComponent: ComponentLike<HeadlessFormFieldComponentSignature<DATA>> =\n FieldComponent;\n\n // we cannot use (modifier \"on\") directly in the template due to https://github.com/emberjs/ember.js/issues/19869\n on = on;\n\n formElement?: HTMLFormElement;\n\n registerForm = modifier((el: HTMLFormElement, _p: []) => {\n this.formElement = el;\n }) as unknown as ModifierLike<unknown>; // @todo getting Glint errors without this. Try again with Glint 1.0 (beta)!\n\n /**\n * A copy of the passed `@data` stored internally, which is only passed back to the component consumer after a (successful) form submission.\n */\n internalData: DATA = new TrackedObject(this.args.data ?? {}) as DATA;\n\n fields = new Map<FormKey<FormData<DATA>>, FieldData<FormData<DATA>>>();\n\n /**\n * The last result of calling `this.validate()`.\n */\n @tracked lastValidationResult?: ErrorRecord<FormData<DATA>>;\n\n /**\n * When this is set to true by submitting the form, eventual validation errors are show for *all* field, regardless of their individual dynamic validation status in `FieldData#validationEnabled`\n */\n @tracked showAllValidations = false;\n\n get validateOn(): ValidateOn {\n return this.args.validateOn ?? 'submit';\n }\n\n get revalidateOn(): ValidateOn {\n return this.args.revalidateOn ?? 'change';\n }\n\n /**\n * Return the event type that will be listened on for dynamic validation (i.e. *before* submitting)\n */\n get fieldValidationEvent(): 'focusout' | 'change' | 'input' | undefined {\n const { validateOn } = this;\n\n return validateOn === 'submit'\n ? // no need for dynamic validation, as validation always happens on submit\n undefined\n : validateOn;\n }\n\n /**\n * Return the event type that will be listened on for dynamic *re*validation, i.e. updating the validation status of a field that has been previously marked as invalid\n */\n get fieldRevalidationEvent(): 'focusout' | 'change' | 'input' | undefined {\n const { validateOn, revalidateOn } = this;\n\n return revalidateOn === 'submit'\n ? // no need for dynamic validation, as validation always happens on submit\n undefined\n : // when validation happens more frequently than revalidation, then we can ignore revalidation, because the validation handler will already cover us\n validateOn === 'input' ||\n (validateOn === 'change' && revalidateOn === 'focusout') ||\n validateOn === revalidateOn\n ? undefined\n : revalidateOn;\n }\n\n /**\n * Return true if validation has happened (by submitting or by an `@validateOn` event being triggered) and at least one field is invalid\n */\n get hasValidationErrors(): boolean {\n // Only consider validation errors for which we actually have a field rendered\n return this.lastValidationResult\n ? Object.keys(this.lastValidationResult).some((name) =>\n this.fields.has(name as FormKey<FormData<DATA>>)\n )\n : false;\n }\n\n /**\n * Call the passed validation callbacks, defined both on the whole form as well as on field level, and return the merged result for all fields.\n */\n @waitFor\n async validate(): Promise<ErrorRecord<FormData<DATA>>> {\n const nativeValidation = this.validateNative();\n const customFormValidation = await this.args.validate?.(this.internalData);\n const customFieldValidations: ErrorRecord<FormData<DATA>>[] = [];\n\n for (const [name, field] of this.fields) {\n const fieldValidationResult = await field.validate?.(\n this.internalData[name],\n name,\n this.internalData\n );\n\n if (fieldValidationResult) {\n customFieldValidations.push({\n [name]: fieldValidationResult,\n } as ErrorRecord<FormData<DATA>>);\n }\n }\n\n return mergeErrorRecord(\n nativeValidation,\n customFormValidation,\n ...customFieldValidations\n );\n }\n\n validateNative(): ErrorRecord<FormData<DATA>> | undefined {\n const form = this.formElement;\n\n assert(\n 'Form element expected to be present. If you see this, please report it as a bug to ember-headless-form!',\n form\n );\n\n if (form.checkValidity()) {\n return;\n }\n\n const errors: ErrorRecord<FormData<DATA>> = {};\n\n for (const el of form.elements) {\n // This is just to make TS happy, as we need to access properties on el that only form elements have, but elements in `form.elements` are just typed as plain `Element`. Should never occur in reality.\n assert(\n 'Unexpected form element. If you see this, please report it as a bug to ember-headless-form!',\n el instanceof HTMLInputElement ||\n el instanceof HTMLTextAreaElement ||\n el instanceof HTMLSelectElement ||\n el instanceof HTMLButtonElement ||\n el instanceof HTMLFieldSetElement ||\n el instanceof HTMLObjectElement ||\n el instanceof HTMLOutputElement\n );\n\n if (el.validity.valid) {\n continue;\n }\n\n const name = el.name as FormKey<FormData<DATA>>;\n\n if (this.fields.has(name)) {\n errors[name] = [\n {\n type: 'native',\n value: this.internalData[name],\n message: el.validationMessage,\n },\n ];\n } else {\n warn(\n `An invalid form element with name \"${name}\" was detected, but this name is not used as a form field. It will be ignored for validation. Make sure to apply the correct name to custom form elements that participate in form validation!`,\n { id: 'headless-form.invalid-control-for-unknown-field' }\n );\n }\n }\n\n return errors;\n }\n\n /**\n * Return a mapping of field to validation errors, for all fields that are invalid *and* for which validation errors should be visible.\n * Validation errors will be visible for a certain field, if validation errors for *all* fields are visible, which is the case when trying to submit the form,\n * or when that field has triggered the event given by `@validateOn` for showing validation errors before submitting, e.g. on blur.\n */\n get visibleErrors(): ErrorRecord<FormData<DATA>> | undefined {\n if (!this.lastValidationResult) {\n return undefined;\n }\n\n const visibleErrors: ErrorRecord<FormData<DATA>> = {};\n\n for (const [field, errors] of Object.entries(this.lastValidationResult) as [\n FormKey<FormData<DATA>>,\n ValidationError<FormData<DATA>[FormKey<FormData<DATA>>]>[]\n ][]) {\n if (this.showErrorsFor(field)) {\n visibleErrors[field] = errors;\n }\n }\n\n return visibleErrors;\n }\n\n /**\n * Given a field name, return if eventual errors for the field should be visible. See `visibleErrors` for further details.\n */\n showErrorsFor(field: FormKey<FormData<DATA>>): boolean {\n return (\n this.showAllValidations ||\n (this.fields.get(field)?.validationEnabled ?? false)\n );\n }\n\n @action\n async onSubmit(e: Event): Promise<void> {\n e.preventDefault();\n\n this.lastValidationResult = await this.validate();\n this.showAllValidations = true;\n\n if (!this.hasValidationErrors) {\n this.args.onSubmit?.(this.internalData);\n } else {\n assert(\n 'Validation errors expected to be present. If you see this, please report it as a bug to ember-headless-form!',\n this.lastValidationResult\n );\n this.args.onInvalid?.(this.internalData, this.lastValidationResult);\n }\n }\n\n @action\n registerField(\n name: FormKey<FormData<DATA>>,\n field: FieldRegistrationData<FormData<DATA>>\n ): void {\n assert(\n `You passed @name=\"${String(\n name\n )}\" to the form field, but this is already in use. Names of form fields must be unique!`,\n !this.fields.has(name)\n );\n this.fields.set(name, new FieldData(field));\n }\n\n @action\n unregisterField(name: FormKey<FormData<DATA>>): void {\n this.fields.delete(name);\n }\n\n @action\n set<KEY extends FormKey<FormData<DATA>>>(key: KEY, value: DATA[KEY]): void {\n this.internalData[key] = value;\n }\n\n /**\n * Handle the `@validateOn` event for a certain field, e.g. \"blur\".\n * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name=\"...\">` invocations by the user's template.\n * Validation will be triggered, and the particular field will be marked to show eventual validation errors.\n */\n @action\n async handleFieldValidation(e: Event | string): Promise<void> {\n let name: string;\n\n if (typeof e === 'string') {\n name = e;\n } else {\n const { target } = e;\n\n name = (target as HTMLInputElement).name;\n }\n\n if (name) {\n const field = this.fields.get(name as FormKey<FormData<DATA>>);\n\n if (field) {\n this.lastValidationResult = await this.validate();\n field.validationEnabled = true;\n }\n } else if (e instanceof Event) {\n warn(\n `An event of type \"${e.type}\" was received by headless-form, which is supposed to trigger validations for a certain field. But the name of that field could not be determined. Make sure that your control element has a \\`name\\` attribute matching the field, or use the yielded \\`{{field.captureEvents}}\\` to capture the events.`,\n { id: 'headless-form.validation-event-for-unknown-field' }\n );\n }\n }\n\n /**\n * Handle the `@revalidateOn` event for a certain field, e.g. \"blur\".\n * Associating the event with a field is done by looking at the event target's `name` attribute, which must match one of the `<form.field @name=\"...\">` invocations by the user's template.\n * When a field has been already marked to show validation errors by `@validateOn`, then for revalidation another validation will be triggered.\n *\n * The use case here is to allow this to happen more frequently than the initial validation, e.g. `@validateOn=\"blur\" @revalidateOn=\"change\"`.\n */\n @action\n async handleFieldRevalidation(e: Event): Promise<void> {\n const { target } = e;\n const { name } = target as HTMLInputElement;\n\n if (name) {\n if (this.showErrorsFor(name as FormKey<FormData<DATA>>)) {\n this.lastValidationResult = await this.validate();\n }\n } else {\n warn(\n `An event of type \"${e.type}\" was received by headless-form, which is supposed to trigger validations for a certain field. But the name of that field could not be determined. Make sure that your control element has a \\`name\\` attribute matching the field, or use the yielded \\`{{field.captureEvents}}\\` to capture the events.`,\n { id: 'headless-form.validation-event-for-unknown-field' }\n );\n }\n }\n}\n"],"names":["precompileTemplate","FieldData","constructor","fieldRegistration","validate","tracked","HeadlessFormComponent","Component","FieldComponent","on","modifier","el","_p","formElement","TrackedObject","args","data","Map","validateOn","revalidateOn","fieldValidationEvent","undefined","fieldRevalidationEvent","hasValidationErrors","lastValidationResult","Object","keys","some","name","fields","has","nativeValidation","validateNative","customFormValidation","internalData","customFieldValidations","field","fieldValidationResult","push","mergeErrorRecord","form","assert","checkValidity","errors","elements","HTMLInputElement","HTMLTextAreaElement","HTMLSelectElement","HTMLButtonElement","HTMLFieldSetElement","HTMLObjectElement","HTMLOutputElement","validity","valid","type","value","message","validationMessage","warn","id","visibleErrors","entries","showErrorsFor","showAllValidations","get","validationEnabled","onSubmit","e","preventDefault","onInvalid","registerField","String","set","unregisterField","delete","key","handleFieldValidation","target","Event","handleFieldRevalidation","waitFor","action"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export type { InputType } from "./components/-private/control/input.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import HeadlessFormComponent from "./components/headless-form.js";
2
+ interface Registry {
3
+ HeadlessForm: typeof HeadlessFormComponent;
4
+ }
5
+ export { Registry as default };
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=template-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-registry.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}