ember-headless-form 1.0.0-beta.2 → 1.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.
@@ -5,7 +5,7 @@ import '@babel/runtime/helpers/esm/initializerWarningHelper';
5
5
  import { setComponentTemplate } from '@ember/component';
6
6
  import { precompileTemplate } from '@ember/template-compilation';
7
7
  import Component from '@glimmer/component';
8
- import { tracked } from '@glimmer/tracking';
8
+ import { tracked, cached } from '@glimmer/tracking';
9
9
  import { assert, warn } from '@ember/debug';
10
10
  import { hash } from '@ember/helper';
11
11
  import { on } from '@ember/modifier';
@@ -22,14 +22,16 @@ var _class, _descriptor, _class3, _descriptor2, _descriptor3, _descriptor4;
22
22
  */
23
23
  let FieldData = (_class = class FieldData {
24
24
  constructor(fieldRegistration) {
25
+ /**
26
+ * 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.
27
+ */
25
28
  _initializerDefineProperty(this, "validationEnabled", _descriptor, this);
29
+ /**
30
+ * The *field* level validation callback passed to the field as in `<form.field @name="foo" @validate={{this.validateCallback}}>`
31
+ */
26
32
  _defineProperty(this, "validate", void 0);
27
33
  this.validate = fieldRegistration.validate;
28
34
  }
29
-
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
35
  }, (_descriptor = _applyDecoratedDescriptor(_class.prototype, "validationEnabled", [tracked], {
34
36
  configurable: true,
35
37
  enumerable: true,
@@ -74,22 +76,18 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
74
76
  ...attributes
75
77
  {{this.registerForm}}
76
78
  {{on "submit" this.onSubmit}}
77
- {{(if
78
- this.fieldValidationEvent
79
- (modifier this.on this.fieldValidationEvent this.handleFieldValidation)
80
- )}}
81
- {{(if
79
+ {{on "reset" this.onReset}}
80
+ {{this.onValidation this.fieldValidationEvent this.handleFieldValidation}}
81
+ {{this.onValidation
82
82
  this.fieldRevalidationEvent
83
- (modifier
84
- this.on this.fieldRevalidationEvent this.handleFieldRevalidation
85
- )
86
- )}}
83
+ this.handleFieldRevalidation
84
+ }}
87
85
  >
88
86
  {{yield
89
87
  (hash
90
88
  Field=(component
91
89
  this.FieldComponent
92
- data=this.internalData
90
+ data=this.effectiveData
93
91
  set=this.set
94
92
  errors=this.visibleErrors
95
93
  registerField=this.registerField
@@ -102,6 +100,8 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
102
100
  submissionState=this.submissionState
103
101
  isInvalid=this.hasValidationErrors
104
102
  rawErrors=this.visibleErrors
103
+ submit=this.onSubmit
104
+ reset=this.onReset
105
105
  )
106
106
  }}
107
107
  </form>
@@ -115,16 +115,61 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
115
115
  constructor(...args) {
116
116
  super(...args);
117
117
  _defineProperty(this, "FieldComponent", HeadlessFormFieldComponent);
118
- _defineProperty(this, "on", on);
119
118
  _defineProperty(this, "formElement", void 0);
120
119
  _defineProperty(this, "registerForm", modifier((el, _p) => {
121
120
  this.formElement = el;
122
121
  }));
123
- _defineProperty(this, "internalData", this.args.dataMode == 'mutable' && this.args.data ? this.args.data : new TrackedObject(this.args.data ?? {}));
122
+ /**
123
+ * A copy of the passed `@data` stored internally, which is only passed back to the component consumer after a (successful) form submission.
124
+ */
125
+ _defineProperty(this, "internalData", new TrackedObject({}));
124
126
  _defineProperty(this, "fields", new Map());
125
127
  _initializerDefineProperty(this, "validationState", _descriptor2, this);
126
128
  _initializerDefineProperty(this, "submissionState", _descriptor3, this);
129
+ /**
130
+ * 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`
131
+ */
127
132
  _initializerDefineProperty(this, "showAllValidations", _descriptor4, this);
133
+ _defineProperty(this, "onValidation", modifier((el, [eventName, handler]) => {
134
+ if (eventName) {
135
+ el.addEventListener(eventName, handler);
136
+ return () => el.removeEventListener(eventName, handler);
137
+ }
138
+ }));
139
+ }
140
+ get effectiveData() {
141
+ const obj = this.args.data ?? {};
142
+ if (this.args.dataMode === 'mutable') {
143
+ return obj;
144
+ }
145
+ const {
146
+ internalData
147
+ } = this;
148
+ return new Proxy(obj, {
149
+ get(target, prop) {
150
+ return prop in internalData ? internalData[prop] : Reflect.get(target, prop);
151
+ },
152
+ set(target, property, value) {
153
+ return Reflect.set(internalData, property, value);
154
+ },
155
+ has(target, prop) {
156
+ return prop in internalData ? true : Reflect.has(target, prop);
157
+ },
158
+ getOwnPropertyDescriptor(target, prop) {
159
+ return Reflect.getOwnPropertyDescriptor(prop in internalData ? internalData : target, prop);
160
+ },
161
+ ownKeys(target) {
162
+ return [...Reflect.ownKeys(target), ...Reflect.ownKeys(internalData)]
163
+ // return only unique values
164
+ .filter((value, index, array) => array.indexOf(value) === index);
165
+ },
166
+ deleteProperty(target, prop) {
167
+ if (prop in internalData) {
168
+ delete internalData[prop];
169
+ }
170
+ return true;
171
+ }
172
+ });
128
173
  }
129
174
  get validateOn() {
130
175
  return this.args.validateOn ?? 'submit';
@@ -177,10 +222,10 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
177
222
  */
178
223
  async validate() {
179
224
  const nativeValidation = this.args.ignoreNativeValidation !== true ? this.validateNative() : {};
180
- const customFormValidation = await this.args.validate?.(this.internalData, Array.from(this.fields.keys()));
225
+ const customFormValidation = await this.args.validate?.(this.effectiveData, Array.from(this.fields.keys()));
181
226
  const customFieldValidations = [];
182
227
  for (const [name, field] of this.fields) {
183
- const fieldValidationResult = await field.validate?.(this.internalData[name], name, this.internalData);
228
+ const fieldValidationResult = await field.validate?.(this.effectiveData[name], name, this.effectiveData);
184
229
  if (fieldValidationResult) {
185
230
  customFieldValidations.push({
186
231
  [name]: fieldValidationResult
@@ -191,7 +236,7 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
191
236
  }
192
237
  async _validate() {
193
238
  const promise = this.validate();
194
- this.validationState = new TrackedAsyncData(promise, this);
239
+ this.validationState = new TrackedAsyncData(promise);
195
240
  return promise;
196
241
  }
197
242
  validateNative() {
@@ -211,7 +256,7 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
211
256
  if (this.fields.has(name)) {
212
257
  errors[name] = [{
213
258
  type: 'native',
214
- value: this.internalData[name],
259
+ value: this.effectiveData[name],
215
260
  message: el.validationMessage
216
261
  }];
217
262
  } else {
@@ -248,17 +293,25 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
248
293
  return this.showAllValidations || (this.fields.get(field)?.validationEnabled ?? false);
249
294
  }
250
295
  async onSubmit(e) {
251
- e.preventDefault();
296
+ e?.preventDefault();
252
297
  await this._validate();
253
298
  this.showAllValidations = true;
254
299
  if (!this.hasValidationErrors) {
255
300
  if (this.args.onSubmit) {
256
- this.submissionState = new TrackedAsyncData(this.args.onSubmit(this.internalData), this);
301
+ this.submissionState = new TrackedAsyncData(this.args.onSubmit(this.effectiveData));
257
302
  }
258
303
  } else {
259
304
  assert('Validation errors expected to be present. If you see this, please report it as a bug to ember-headless-form!', this.validationState?.isResolved);
260
- this.args.onInvalid?.(this.internalData, this.validationState.value);
305
+ this.args.onInvalid?.(this.effectiveData, this.validationState.value);
306
+ }
307
+ }
308
+ async onReset(e) {
309
+ e?.preventDefault();
310
+ for (const key of Object.keys(this.internalData)) {
311
+ delete this.internalData[key];
261
312
  }
313
+ this.validationState = undefined;
314
+ this.submissionState = undefined;
262
315
  }
263
316
  registerField(name, field) {
264
317
  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));
@@ -268,8 +321,8 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
268
321
  this.fields.delete(name);
269
322
  }
270
323
  set(key, value) {
271
- // when @mutableData is set, our internalData is something we don't control, i.e. might require old-school set() to be on the safe side
272
- set(this.internalData, key, value);
324
+ // when @mutableData is set, our effectiveData is something we don't control, i.e. might require old-school set() to be on the safe side
325
+ set(this.effectiveData, key, value);
273
326
  }
274
327
 
275
328
  /**
@@ -324,7 +377,7 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
324
377
  });
325
378
  }
326
379
  }
327
- }, (_descriptor2 = _applyDecoratedDescriptor(_class3.prototype, "validationState", [tracked], {
380
+ }, (_applyDecoratedDescriptor(_class3.prototype, "effectiveData", [cached], Object.getOwnPropertyDescriptor(_class3.prototype, "effectiveData"), _class3.prototype), _descriptor2 = _applyDecoratedDescriptor(_class3.prototype, "validationState", [tracked], {
328
381
  configurable: true,
329
382
  enumerable: true,
330
383
  writable: true,
@@ -341,8 +394,7 @@ let HeadlessFormComponent = setComponentTemplate(precompileTemplate(`
341
394
  initializer: function () {
342
395
  return false;
343
396
  }
344
- }), _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));
345
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- workaround for unknown modifier helper: https://github.com/typed-ember/glint/issues/410
397
+ }), _applyDecoratedDescriptor(_class3.prototype, "onSubmit", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "onSubmit"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "onReset", [action], Object.getOwnPropertyDescriptor(_class3.prototype, "onReset"), _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));
346
398
 
347
399
  export { HeadlessFormComponent as default };
348
400
  //# sourceMappingURL=headless-form.js.map