@nanoporetech-digital/components 2.12.0 → 2.13.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/CHANGELOG.md +26 -0
- package/dist/cjs/index.cjs.js +4 -2
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/nano-components.cjs.js +1 -1
- package/dist/cjs/nano-field-validator.cjs.entry.js +266 -124
- package/dist/cjs/nano-field-validator.cjs.entry.js.map +1 -1
- package/dist/cjs/nano-file-upload.cjs.entry.js +1 -1
- package/dist/cjs/nano-file-upload.cjs.entry.js.map +1 -1
- package/dist/cjs/nano-input.cjs.entry.js +16 -3
- package/dist/cjs/nano-input.cjs.entry.js.map +1 -1
- package/dist/cjs/nano-nav-item_2.cjs.entry.js +1 -0
- package/dist/cjs/nano-nav-item_2.cjs.entry.js.map +1 -1
- package/dist/collection/components/accordion/accordion.js +1 -1
- package/dist/collection/components/alert/alert.helpers.js +2 -2
- package/dist/collection/components/alert/alert.helpers.js.map +1 -1
- package/dist/collection/components/alert/alert.js +1 -1
- package/dist/collection/components/algolia/algolia-filter.js +2 -2
- package/dist/collection/components/algolia/algolia-input.js +5 -5
- package/dist/collection/components/algolia/algolia-results.js +1 -1
- package/dist/collection/components/algolia/algolia.js +6 -6
- package/dist/collection/components/checkbox/checkbox-group.js +2 -2
- package/dist/collection/components/checkbox/checkbox.js +3 -3
- package/dist/collection/components/datalist/datalist.js +1 -1
- package/dist/collection/components/date-input/date-input.js +8 -8
- package/dist/collection/components/date-picker/date-picker.js +5 -5
- package/dist/collection/components/details/details.js +1 -1
- package/dist/collection/components/dialog/dialog.js +1 -1
- package/dist/collection/components/dropdown/dropdown.js +1 -1
- package/dist/collection/components/field-validator/field-validator-interface.js.map +1 -1
- package/dist/collection/components/field-validator/field-validator.js +345 -130
- package/dist/collection/components/field-validator/field-validator.js.map +1 -1
- package/dist/collection/components/file-upload/file-upload.css +0 -1
- package/dist/collection/components/file-upload/file-upload.js +4 -4
- package/dist/collection/components/global-nav/global-nav.js +4 -4
- package/dist/collection/components/grid/grid-item.js +1 -1
- package/dist/collection/components/icon/icon.js +1 -1
- package/dist/collection/components/input/input.js +37 -8
- package/dist/collection/components/input/input.js.map +1 -1
- package/dist/collection/components/nav-item/nav-item.js +4 -4
- package/dist/collection/components/range/range.js +4 -4
- package/dist/collection/components/resize-observe/resize-observe.js +1 -1
- package/dist/collection/components/select/select.js +8 -7
- package/dist/collection/components/select/select.js.map +1 -1
- package/dist/collection/components/slides/slides.js +7 -7
- package/dist/collection/components/tabs/tab-group.js +2 -2
- package/dist/collection/index.js +1 -0
- package/dist/collection/index.js.map +1 -1
- package/dist/components/index.js +3 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/input.js +17 -3
- package/dist/components/input.js.map +1 -1
- package/dist/components/nano-field-validator.js +271 -126
- package/dist/components/nano-field-validator.js.map +1 -1
- package/dist/components/nano-file-upload.js +1 -1
- package/dist/components/nano-file-upload.js.map +1 -1
- package/dist/components/select.js +1 -0
- package/dist/components/select.js.map +1 -1
- package/dist/custom-elements/index.js +288 -132
- package/dist/custom-elements/index.js.map +1 -1
- package/dist/esm/index.js +3 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/nano-components.js +1 -1
- package/dist/esm/nano-field-validator.entry.js +266 -124
- package/dist/esm/nano-field-validator.entry.js.map +1 -1
- package/dist/esm/nano-file-upload.entry.js +1 -1
- package/dist/esm/nano-file-upload.entry.js.map +1 -1
- package/dist/esm/nano-input.entry.js +16 -3
- package/dist/esm/nano-input.entry.js.map +1 -1
- package/dist/esm/nano-nav-item_2.entry.js +1 -0
- package/dist/esm/nano-nav-item_2.entry.js.map +1 -1
- package/dist/esm-es5/index.js +2 -2
- package/dist/esm-es5/index.js.map +1 -1
- package/dist/esm-es5/loader.js +1 -1
- package/dist/esm-es5/loader.js.map +1 -1
- package/dist/esm-es5/nano-components.js +1 -1
- package/dist/esm-es5/nano-components.js.map +1 -1
- package/dist/esm-es5/nano-field-validator.entry.js +2 -2
- package/dist/esm-es5/nano-field-validator.entry.js.map +1 -1
- package/dist/esm-es5/nano-file-upload.entry.js +1 -1
- package/dist/esm-es5/nano-file-upload.entry.js.map +1 -1
- package/dist/esm-es5/nano-input.entry.js +1 -1
- package/dist/esm-es5/nano-input.entry.js.map +1 -1
- package/dist/esm-es5/nano-nav-item_2.entry.js +1 -1
- package/dist/esm-es5/nano-nav-item_2.entry.js.map +1 -1
- package/dist/nano-components/index.esm.js +1 -1
- package/dist/nano-components/index.esm.js.map +1 -1
- package/dist/nano-components/nano-components.esm.js +1 -1
- package/dist/nano-components/nano-components.esm.js.map +1 -1
- package/dist/nano-components/p-085e03db.system.entry.js +5 -0
- package/dist/nano-components/p-085e03db.system.entry.js.map +1 -0
- package/dist/nano-components/p-53957ec6.system.js +1 -1
- package/dist/nano-components/p-53957ec6.system.js.map +1 -1
- package/dist/nano-components/{p-01667573.entry.js → p-634a58f7.entry.js} +2 -2
- package/dist/nano-components/p-634a58f7.entry.js.map +1 -0
- package/dist/nano-components/p-a07cf44c.system.entry.js +5 -0
- package/dist/nano-components/{p-4558a9c6.system.entry.js.map → p-a07cf44c.system.entry.js.map} +1 -1
- package/dist/nano-components/{p-96d9b8b9.system.entry.js → p-c2bbf0fb.system.entry.js} +2 -2
- package/dist/nano-components/p-c2bbf0fb.system.entry.js.map +1 -0
- package/dist/nano-components/{p-72893d12.system.entry.js → p-cb512cff.system.entry.js} +2 -2
- package/dist/nano-components/p-cb512cff.system.entry.js.map +1 -0
- package/dist/nano-components/p-e35226a9.entry.js +5 -0
- package/dist/nano-components/p-e35226a9.entry.js.map +1 -0
- package/dist/nano-components/p-e9fddc1a.entry.js +5 -0
- package/dist/nano-components/{p-91614b43.entry.js.map → p-e9fddc1a.entry.js.map} +1 -1
- package/dist/nano-components/{p-055f7d35.entry.js → p-ed0bdea9.entry.js} +2 -2
- package/dist/nano-components/p-ed0bdea9.entry.js.map +1 -0
- package/dist/nano-components/p-f62a40ea.system.js +5 -0
- package/dist/nano-components/{p-3258c568.system.js.map → p-f62a40ea.system.js.map} +1 -1
- package/dist/themes/nanopore.css +1 -1
- package/dist/themes/nanopore.css.map +1 -1
- package/dist/types/components/alert/alert.helpers.d.ts +2 -2
- package/dist/types/components/field-validator/field-validator-interface.d.ts +5 -1
- package/dist/types/components/field-validator/field-validator.d.ts +68 -12
- package/dist/types/components/input/input.d.ts +6 -1
- package/dist/types/components.d.ts +25 -3
- package/dist/types/index.d.ts +1 -0
- package/docs-json.json +65 -3
- package/docs-vscode.json +6 -2
- package/package.json +2 -2
- package/dist/nano-components/p-01667573.entry.js.map +0 -1
- package/dist/nano-components/p-055f7d35.entry.js.map +0 -1
- package/dist/nano-components/p-2b478ca1.system.entry.js +0 -5
- package/dist/nano-components/p-2b478ca1.system.entry.js.map +0 -1
- package/dist/nano-components/p-3258c568.system.js +0 -5
- package/dist/nano-components/p-4558a9c6.system.entry.js +0 -5
- package/dist/nano-components/p-5f4fc2b4.entry.js +0 -5
- package/dist/nano-components/p-5f4fc2b4.entry.js.map +0 -1
- package/dist/nano-components/p-72893d12.system.entry.js.map +0 -1
- package/dist/nano-components/p-91614b43.entry.js +0 -5
- package/dist/nano-components/p-96d9b8b9.system.entry.js.map +0 -1
@@ -195,8 +195,15 @@ let FieldValidator = class extends HTMLElement {
|
|
195
195
|
this.nanoSubmit = createEvent(this, "nanoSubmit", 7);
|
196
196
|
this.nanoInvalid = createEvent(this, "nanoInvalid", 7);
|
197
197
|
this.submitted = false;
|
198
|
-
this.
|
199
|
-
|
198
|
+
this.allFields = [];
|
199
|
+
this.nanoFieldSelector = `
|
200
|
+
nano-input,
|
201
|
+
nano-select,
|
202
|
+
nano-file-upload,
|
203
|
+
nano-date-input,
|
204
|
+
nano-checkbox
|
205
|
+
`;
|
206
|
+
// annoyingly, whenever we attempt to `checkValidty()` it fires `invalid` events.
|
200
207
|
// this is used to prevent infinite loops / multiple calls
|
201
208
|
this.internalValidate = false;
|
202
209
|
// Public API
|
@@ -205,12 +212,27 @@ let FieldValidator = class extends HTMLElement {
|
|
205
212
|
/** Tries to scroll to the first invalid field on submit */
|
206
213
|
this.scrollToInvalid = true;
|
207
214
|
this._dirty = false;
|
215
|
+
/** By default, `nano-field-validator` will also track all native form field elements.
|
216
|
+
* You can add extra web-component form fields to listen to
|
217
|
+
* (as long as they match the standard form field spec) by using the `fieldSelector` prop.
|
218
|
+
*/
|
219
|
+
this.extraFieldSelector = 'input, select, textarea';
|
208
220
|
// Event handlers
|
209
|
-
/**
|
221
|
+
/**
|
222
|
+
* Fired whenever store values change and potentially checks validity
|
223
|
+
* @param key - the key of the store that's just changed
|
224
|
+
* @param newVal - the incoming, new value
|
225
|
+
*/
|
210
226
|
this.handleStoreChange = async (key, newVal) => {
|
211
|
-
const found = this.
|
212
|
-
|
227
|
+
const found = this.allFields.find((field) => this.getName(field) === key);
|
228
|
+
// field update has come programmatically (not from ui),
|
229
|
+
// so let's update the underlying ui field
|
230
|
+
if ((found &&
|
231
|
+
found.tagName === 'NANO-FILE-UPLOAD' &&
|
232
|
+
!this.fileStateEqual(key, found)) ||
|
233
|
+
(found.tagName !== 'NANO-FILE-UPLOAD' && found.value !== newVal)) {
|
213
234
|
this.storeToFields([found]);
|
235
|
+
}
|
214
236
|
if (this.validateOn === 'dirty' && this.dirty) {
|
215
237
|
this.internalValidate = true;
|
216
238
|
await this.validateAllFields();
|
@@ -219,17 +241,40 @@ let FieldValidator = class extends HTMLElement {
|
|
219
241
|
}
|
220
242
|
this.nanoPayloadChange.emit(this._store.state);
|
221
243
|
};
|
222
|
-
/**
|
244
|
+
/**
|
245
|
+
* Handles nano field value changes and passes to store
|
246
|
+
* @param ev - the incoming change event
|
247
|
+
*/
|
223
248
|
this.handleFieldChange = (ev) => {
|
249
|
+
if (!this.nanoFields.includes(ev.target))
|
250
|
+
return;
|
224
251
|
this._dirty = true;
|
225
252
|
this.fieldsToStore([ev.target]);
|
226
253
|
};
|
227
|
-
/**
|
254
|
+
/**
|
255
|
+
* Handles non-nano field value changes and passes to store
|
256
|
+
* @param ev - the incoming change event
|
257
|
+
*/
|
258
|
+
this.handlePlainFieldChange = (ev) => {
|
259
|
+
if (!this.plainFields.includes(ev.target))
|
260
|
+
return;
|
261
|
+
this.fieldsToStore([ev.target]);
|
262
|
+
};
|
263
|
+
/**
|
264
|
+
* Handles default field validation events
|
265
|
+
* @param ev - the invalid event
|
266
|
+
*/
|
228
267
|
this.handleFormInvalid = async (ev) => {
|
229
|
-
|
268
|
+
// if it's a non-nano field, we'll let default html5 validation do it's thing
|
269
|
+
if (!this.plainFields.includes(ev.target)) {
|
270
|
+
ev.preventDefault();
|
271
|
+
}
|
230
272
|
this._valid = false;
|
273
|
+
// whenever `checkValidity` is called, this handler is in-turn called.
|
274
|
+
// this flag is used to stop infinite loops
|
231
275
|
if (this.internalValidate)
|
232
276
|
return;
|
277
|
+
// a submit must have happened to if 'submitThenDirty' turn on 'dirty' checking now
|
233
278
|
if (this.validateOn === 'submitThenDirty')
|
234
279
|
this.validateOn = 'dirty';
|
235
280
|
this.submitted = true;
|
@@ -249,7 +294,10 @@ let FieldValidator = class extends HTMLElement {
|
|
249
294
|
this.scrollToFirstInvalid();
|
250
295
|
this.nanoInvalid.emit();
|
251
296
|
};
|
252
|
-
/**
|
297
|
+
/**
|
298
|
+
* stops default form submission, checks if valid, then submits manually
|
299
|
+
* @param e - a submit event from the nested form element
|
300
|
+
*/
|
253
301
|
this.handleSubmit = async (e) => {
|
254
302
|
e.preventDefault();
|
255
303
|
if (this.validateOn === 'submitThenDirty')
|
@@ -274,6 +322,7 @@ let FieldValidator = class extends HTMLElement {
|
|
274
322
|
return this._activeForm;
|
275
323
|
}
|
276
324
|
set activeForm(form) {
|
325
|
+
// manages event listners on whatever form is used (slotted on created here)
|
277
326
|
if (!form)
|
278
327
|
return;
|
279
328
|
if (this._activeForm) {
|
@@ -284,7 +333,7 @@ let FieldValidator = class extends HTMLElement {
|
|
284
333
|
}
|
285
334
|
/** Sync up validateOn with all fields */
|
286
335
|
validateOnChange() {
|
287
|
-
this.
|
336
|
+
this.nanoFields.forEach((field) => {
|
288
337
|
if (field.tagName === 'NANO-CHECKBOX') {
|
289
338
|
const cbg = field.closest('nano-checkbox-group');
|
290
339
|
if (cbg)
|
@@ -312,7 +361,7 @@ let FieldValidator = class extends HTMLElement {
|
|
312
361
|
get payload() {
|
313
362
|
return this._store.state;
|
314
363
|
}
|
315
|
-
/** Returns true if validation errors will be displayed to the user */
|
364
|
+
/** Returns true if validation errors will be displayed to the user. @readonly */
|
316
365
|
get showValidation() {
|
317
366
|
return (this.validateOn === 'dirty' && this.dirty) || this.submitted;
|
318
367
|
}
|
@@ -329,26 +378,58 @@ let FieldValidator = class extends HTMLElement {
|
|
329
378
|
```
|
330
379
|
*/
|
331
380
|
get validationState() {
|
381
|
+
// TODO - migrate nano-fields away from using proprietary methods in a bid to be closer to the spec
|
382
|
+
// this is big and ugly.
|
383
|
+
// why? Cos' it must unify checking validity state for both
|
384
|
+
// `nano-...` and plain form fields.
|
332
385
|
const validationState = [];
|
333
|
-
this.
|
334
|
-
const found = validationState.find((v) => v.name === field
|
386
|
+
this.allFields.forEach(async (field) => {
|
387
|
+
const found = validationState.find((v) => v.name === this.getName(field));
|
388
|
+
let pf;
|
389
|
+
let nf;
|
335
390
|
if (found) {
|
336
|
-
|
337
|
-
|
338
|
-
|
391
|
+
if (field.validationMessage) {
|
392
|
+
pf = field;
|
393
|
+
found.validityMessage = pf.validationMessage.length
|
394
|
+
? pf.validationMessage
|
395
|
+
: found.validityMessage;
|
396
|
+
this.internalValidate = true;
|
397
|
+
if (found.valid && !pf.checkValidity())
|
398
|
+
found.valid = false;
|
399
|
+
this.internalValidate = false;
|
400
|
+
}
|
401
|
+
else if (field.validityMessage) {
|
402
|
+
nf = field;
|
403
|
+
found.validityMessage = nf.validityMessage.length
|
404
|
+
? nf.validityMessage
|
405
|
+
: nf.validityMessage;
|
406
|
+
if (found.valid && nf.invalid)
|
407
|
+
found.valid = false;
|
408
|
+
}
|
339
409
|
if (!found.fields.find((f) => f === field))
|
340
410
|
found.fields.push(field);
|
341
|
-
|
342
|
-
|
343
|
-
|
411
|
+
}
|
412
|
+
let valid;
|
413
|
+
let validityMessage;
|
414
|
+
if (field.checkValidity) {
|
415
|
+
pf = field;
|
416
|
+
this.internalValidate = true;
|
417
|
+
valid = pf.checkValidity();
|
418
|
+
this.internalValidate = false;
|
419
|
+
validityMessage = pf.validationMessage;
|
420
|
+
}
|
421
|
+
else {
|
422
|
+
nf = field;
|
423
|
+
valid = !nf.invalid;
|
424
|
+
validityMessage = nf.validityMessage;
|
344
425
|
}
|
345
426
|
validationState.push({
|
346
427
|
fields: [field],
|
347
|
-
name: field
|
348
|
-
|
349
|
-
value: this._store.state[field.name],
|
428
|
+
name: this.getName(field),
|
429
|
+
value: this._store.state[this.getName(field)],
|
350
430
|
dirty: false,
|
351
|
-
|
431
|
+
valid,
|
432
|
+
validityMessage,
|
352
433
|
});
|
353
434
|
});
|
354
435
|
return validationState;
|
@@ -360,6 +441,24 @@ let FieldValidator = class extends HTMLElement {
|
|
360
441
|
async setStore(state) {
|
361
442
|
Object.entries(state).forEach(([key, val]) => (this.store.state[key] = val));
|
362
443
|
}
|
444
|
+
/**
|
445
|
+
* Sets custom validity for all / some form fields.
|
446
|
+
* @param validity - a validity object of `{fieldName: errorString}` pairs. Set as an empty string to clear the error.
|
447
|
+
*/
|
448
|
+
async setCustomValidity(validity) {
|
449
|
+
return await Promise.all(Object.entries(validity).map(async ([key, err]) => {
|
450
|
+
const field = this.allFields.find((f) => this.getName(f) === key);
|
451
|
+
if (!!field)
|
452
|
+
await this.setFieldError(field, err);
|
453
|
+
}));
|
454
|
+
}
|
455
|
+
/**
|
456
|
+
* Clear all custom validation.
|
457
|
+
* @param validity
|
458
|
+
*/
|
459
|
+
async resetValidity() {
|
460
|
+
return await Promise.all(this.allFields.map(async (field) => await this.setFieldError(field, '')));
|
461
|
+
}
|
363
462
|
// private methods
|
364
463
|
attachSlotObserver() {
|
365
464
|
if (!!this.mo)
|
@@ -377,118 +476,149 @@ let FieldValidator = class extends HTMLElement {
|
|
377
476
|
subtree: true,
|
378
477
|
});
|
379
478
|
}
|
479
|
+
/**
|
480
|
+
* During spec tests, mockelement props aren't set - only attributes.
|
481
|
+
* This irons out that kink
|
482
|
+
* @param field
|
483
|
+
* @returns
|
484
|
+
*/
|
485
|
+
getName(field) {
|
486
|
+
return field.name || field.getAttribute('name');
|
487
|
+
}
|
380
488
|
/** Checks for new `nano-...` fields and adds them to our watch array and value store */
|
381
489
|
setupFields() {
|
382
|
-
let
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
nano-date-input,
|
387
|
-
nano-checkbox
|
388
|
-
`));
|
389
|
-
fields = fields.filter((f) => !!f.name && !!f.name.length);
|
490
|
+
let nanoFields = Array.from(this.host.querySelectorAll(this.nanoFieldSelector));
|
491
|
+
let plainFields = Array.from(this.host.querySelectorAll(this.extraFieldSelector)).filter((e) => !e.closest(this.nanoFieldSelector));
|
492
|
+
nanoFields = nanoFields.filter((f) => !!this.getName(f) && !!this.getName(f).length);
|
493
|
+
plainFields = plainFields.filter((f) => !!this.getName(f) && !!this.getName(f).length);
|
390
494
|
// do we have any currently un-watched fields?
|
391
|
-
if (!
|
495
|
+
if (![...nanoFields, ...plainFields].filter((f) => !this.allFields.includes(f)).length)
|
392
496
|
return;
|
393
497
|
// setup the initial store state / refresh on new fields
|
394
|
-
this.
|
395
|
-
this.
|
498
|
+
this.nanoFields = nanoFields;
|
499
|
+
this.plainFields = plainFields;
|
500
|
+
this.allFields = [...nanoFields, ...plainFields];
|
501
|
+
this.storeToFields(this.allFields);
|
396
502
|
this.validateOnChange();
|
397
|
-
this.fieldsToStore(this.
|
503
|
+
this.fieldsToStore(this.allFields);
|
398
504
|
this.nanoPayloadChange.emit(this._store.state);
|
399
505
|
}
|
400
506
|
storeToFields(fields) {
|
401
507
|
fields.forEach((field) => {
|
402
|
-
|
508
|
+
var _a;
|
509
|
+
const fieldName = this.getName(field);
|
403
510
|
if (!fieldName.length ||
|
404
511
|
typeof this._store.state[fieldName] === 'undefined')
|
405
512
|
return;
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
513
|
+
if (field.tagName === 'NANO-CHECKBOX' ||
|
514
|
+
['radio', 'checkbox'].includes(field.type)) {
|
515
|
+
let cb = field;
|
516
|
+
if (cb.type === 'radio' ||
|
517
|
+
cb.type === 'segment' ||
|
518
|
+
cb.type === 'segment-pill') {
|
519
|
+
// single radio type control
|
520
|
+
if (this._store.state[fieldName] === cb.value)
|
521
|
+
cb.checked = true;
|
522
|
+
else
|
523
|
+
cb.checked = false;
|
524
|
+
}
|
525
|
+
else if (Array.isArray(this._store.state[fieldName])) {
|
526
|
+
// multiple checkbox like controls
|
527
|
+
if (this._store.state[fieldName].includes(cb.value))
|
528
|
+
cb.checked = true;
|
529
|
+
else
|
530
|
+
cb.checked = false;
|
531
|
+
}
|
532
|
+
else {
|
533
|
+
// single checkbox like control
|
534
|
+
if (this._store.state[fieldName] === cb.value)
|
535
|
+
cb.checked = true;
|
536
|
+
else
|
537
|
+
cb.checked = false;
|
538
|
+
}
|
539
|
+
return;
|
540
|
+
}
|
541
|
+
if (field.tagName === 'NANO-FILE-UPLOAD') {
|
542
|
+
const ff = field;
|
543
|
+
// this can only work if the field is empty rn... a one-time deal
|
544
|
+
if (!((_a = ff.files) === null || _a === void 0 ? void 0 : _a.length))
|
545
|
+
ff.files = this._store.state[fieldName];
|
546
|
+
return;
|
437
547
|
}
|
548
|
+
// default
|
549
|
+
field.value = this._store.state[fieldName];
|
438
550
|
});
|
439
551
|
}
|
440
552
|
/** Loops through all `nano-...` fields and extracts their values into our store */
|
441
553
|
fieldsToStore(fields) {
|
442
554
|
fields.forEach((field) => {
|
443
|
-
const fieldName = field
|
555
|
+
const fieldName = this.getName(field);
|
444
556
|
if (!fieldName.length)
|
445
557
|
return;
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
if (cb.
|
466
|
-
|
467
|
-
this._store.state[fieldName] = [...currentArr, cb.value];
|
468
|
-
}
|
469
|
-
}
|
470
|
-
else {
|
471
|
-
this._store.state[fieldName] = currentArr.filter((v) => v !== cb.value);
|
558
|
+
if (field.tagName === 'NANO-CHECKBOX' ||
|
559
|
+
['radio', 'checkbox'].includes(field.type)) {
|
560
|
+
let cb = field;
|
561
|
+
if (cb.type === 'radio' ||
|
562
|
+
cb.type === 'segment' ||
|
563
|
+
cb.type === 'segment-pill') {
|
564
|
+
// radio type control - only one can be checked
|
565
|
+
if (cb.checked)
|
566
|
+
this._store.state[fieldName] = cb.value;
|
567
|
+
}
|
568
|
+
else if (this.allFields.filter((f) => !!this.getName(field) &&
|
569
|
+
(f.tagName === 'NANO-CHECKBOX' ||
|
570
|
+
f.type === 'checkbox')).length > 1) {
|
571
|
+
// multiple checkbox type control
|
572
|
+
const currentArr = Array.isArray(this._store.state[fieldName])
|
573
|
+
? this._store.state[fieldName]
|
574
|
+
: [];
|
575
|
+
if (cb.checked) {
|
576
|
+
// checked
|
577
|
+
if (!this._store.state[fieldName].includes(cb.value)) {
|
578
|
+
this._store.state[fieldName] = [...currentArr, cb.value];
|
472
579
|
}
|
473
580
|
}
|
474
581
|
else {
|
475
|
-
//
|
476
|
-
|
477
|
-
this._store.state[fieldName] = cb.value;
|
478
|
-
else
|
479
|
-
this._store.state[fieldName] = '';
|
582
|
+
// unchecked
|
583
|
+
this._store.state[fieldName] = currentArr.filter((v) => v !== cb.value);
|
480
584
|
}
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
585
|
+
}
|
586
|
+
else {
|
587
|
+
// single checkbox - on or off
|
588
|
+
if (cb.checked)
|
589
|
+
this._store.state[fieldName] = cb.value;
|
590
|
+
else
|
591
|
+
this._store.state[fieldName] = '';
|
592
|
+
}
|
593
|
+
return;
|
594
|
+
}
|
595
|
+
if (field.tagName === 'NANO-FILE-UPLOAD') {
|
596
|
+
const ff = field;
|
597
|
+
if (!this.fileStateEqual(fieldName, ff))
|
598
|
+
this._store.state[fieldName] = ff.files;
|
599
|
+
return;
|
488
600
|
}
|
601
|
+
// default
|
602
|
+
this._store.state[fieldName] = field.value;
|
489
603
|
});
|
490
604
|
}
|
491
|
-
/**
|
605
|
+
/**
|
606
|
+
* Tries to ascertain whether the current model
|
607
|
+
* value is the same as the `nano-file-upload` value
|
608
|
+
* @param fieldName - the key to access from the data store
|
609
|
+
* @param field - the nano-file-upload field to assess against
|
610
|
+
* @returns true for equal, false for not equal
|
611
|
+
*/
|
612
|
+
fileStateEqual(fieldName, field) {
|
613
|
+
return (JSON.stringify(this._store.state[fieldName]) ===
|
614
|
+
JSON.stringify(field.files) ||
|
615
|
+
this._store.state[fieldName] == field.files);
|
616
|
+
}
|
617
|
+
/**
|
618
|
+
* Checks for user defined validations
|
619
|
+
* @param key - current key of the data model to validate
|
620
|
+
* @param newVal - the newly set, incoming value to validate
|
621
|
+
*/
|
492
622
|
async validate(key, newVal) {
|
493
623
|
if (!this.validation)
|
494
624
|
return;
|
@@ -501,21 +631,33 @@ let FieldValidator = class extends HTMLElement {
|
|
501
631
|
// collection loop into a promise
|
502
632
|
await Promise.all(Object.entries(res).map(async ([key, o]) => {
|
503
633
|
// switch on/off validation messages
|
504
|
-
const field = this.
|
634
|
+
const field = this.allFields.find((f) => this.getName(f) === key);
|
505
635
|
let validityTarget = field;
|
506
636
|
if (field.tagName === 'NANO-CHECKBOX') {
|
637
|
+
// if we have a checkbox-group, set the validation message there
|
507
638
|
const cbg = field.closest('nano-checkbox-group');
|
508
639
|
validityTarget = cbg || field;
|
509
640
|
}
|
510
|
-
|
511
|
-
|
641
|
+
if ((validityTarget.validityMessage ||
|
642
|
+
validityTarget.validationMessage) === o.msg &&
|
643
|
+
o.valid) {
|
644
|
+
// status is now valid - clear the error
|
512
645
|
await this.setFieldError(validityTarget, '');
|
513
|
-
|
646
|
+
}
|
514
647
|
else if (!o.valid) {
|
648
|
+
// status is invalid. Set the error
|
515
649
|
await this.setFieldError(validityTarget, o.msg);
|
516
650
|
}
|
517
651
|
}));
|
518
652
|
}
|
653
|
+
/** Loops through all store entries and checks custom validation */
|
654
|
+
async validateAllFields() {
|
655
|
+
// This forces our loop to `await` and finish sequentially ... silly async stencil methods
|
656
|
+
await Object.entries(this._store.state).reduce(async (memo, [key, value]) => {
|
657
|
+
await memo;
|
658
|
+
await this.validate(key, value);
|
659
|
+
}, undefined);
|
660
|
+
}
|
519
661
|
/**
|
520
662
|
* Utility to smooth out setting error messages
|
521
663
|
* (it's a different method on `nano-checkbox` 'cos they don't show errors themselves)
|
@@ -523,18 +665,13 @@ let FieldValidator = class extends HTMLElement {
|
|
523
665
|
* @param msg
|
524
666
|
*/
|
525
667
|
async setFieldError(field, msg) {
|
526
|
-
if (field['showError'])
|
668
|
+
if (field['showError']) {
|
527
669
|
await field.showError(msg);
|
528
|
-
|
670
|
+
}
|
671
|
+
else if (field['setError'])
|
529
672
|
await field.setError(msg);
|
530
|
-
|
531
|
-
|
532
|
-
async validateAllFields() {
|
533
|
-
// This forces our loop to `await` and finish sequentially ... silly async stencil methods
|
534
|
-
await Object.entries(this._store.state).reduce(async (memo, [key, value]) => {
|
535
|
-
await memo;
|
536
|
-
await this.validate(key, value);
|
537
|
-
}, undefined);
|
673
|
+
else
|
674
|
+
field.setCustomValidity(msg);
|
538
675
|
}
|
539
676
|
scrollToFirstInvalid() {
|
540
677
|
if (!this.scrollToInvalid)
|
@@ -563,17 +700,21 @@ let FieldValidator = class extends HTMLElement {
|
|
563
700
|
requestAnimationFrame(() => {
|
564
701
|
this.setupFields();
|
565
702
|
this.attachSlotObserver();
|
566
|
-
this._store.on('set', (key, value) => this.handleStoreChange(key, value));
|
567
703
|
this.host.addEventListener('nanoChange', this.handleFieldChange);
|
704
|
+
this.host.addEventListener('input', this.handlePlainFieldChange);
|
705
|
+
this.host.addEventListener('change', this.handlePlainFieldChange);
|
568
706
|
this.host.addEventListener('submit', this.handleSubmit);
|
707
|
+
this._store.on('set', this.handleStoreChange);
|
569
708
|
});
|
570
709
|
}
|
571
710
|
disconnectedCallback() {
|
572
711
|
if (this.mo)
|
573
712
|
this.mo.disconnect();
|
574
|
-
this._store.reset();
|
575
713
|
this.host.removeEventListener('nanoChange', this.handleFieldChange);
|
714
|
+
this.host.removeEventListener('input', this.handlePlainFieldChange);
|
715
|
+
this.host.removeEventListener('change', this.handlePlainFieldChange);
|
576
716
|
this.host.removeEventListener('submit', this.handleSubmit);
|
717
|
+
this._store.reset();
|
577
718
|
if (this.activeForm)
|
578
719
|
this.activeForm.removeEventListener('invalid', this.handleFormInvalid, true);
|
579
720
|
}
|
@@ -583,7 +724,8 @@ let FieldValidator = class extends HTMLElement {
|
|
583
724
|
get host() { return this; }
|
584
725
|
static get watchers() { return {
|
585
726
|
"userForm": ["userFormChange"],
|
586
|
-
"validateOn": ["validateOnChange"]
|
727
|
+
"validateOn": ["validateOnChange"],
|
728
|
+
"extraFieldSelector": ["attachSlotObserver"]
|
587
729
|
}; }
|
588
730
|
};
|
589
731
|
FieldValidator = /*@__PURE__*/ proxyCustomElement(FieldValidator, [4, "nano-field-validator", {
|
@@ -595,13 +737,16 @@ FieldValidator = /*@__PURE__*/ proxyCustomElement(FieldValidator, [4, "nano-fiel
|
|
595
737
|
"payload": [2064],
|
596
738
|
"showValidation": [2052, "show-validation"],
|
597
739
|
"validationState": [2064],
|
740
|
+
"extraFieldSelector": [1, "extra-field-selector"],
|
598
741
|
"validation": [16],
|
599
|
-
"userForm": [32],
|
600
742
|
"submitted": [32],
|
743
|
+
"userForm": [32],
|
601
744
|
"_dirty": [32],
|
602
745
|
"_valid": [32],
|
603
746
|
"_store": [32],
|
604
|
-
"setStore": [64]
|
747
|
+
"setStore": [64],
|
748
|
+
"setCustomValidity": [64],
|
749
|
+
"resetValidity": [64]
|
605
750
|
}]);
|
606
751
|
function defineCustomElement$1() {
|
607
752
|
if (typeof customElements === "undefined") {
|