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