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