@kupola/kupola 1.5.2 → 1.5.4
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/css/components-ext.css +58 -0
- package/dist/css/components-ext.css +58 -0
- package/dist/kupola.cjs.js +21 -21
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.esm.js +1110 -970
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.umd.js +26 -26
- package/dist/kupola.umd.js.map +1 -1
- package/dist/types/kupola.d.ts +135 -0
- package/js/datepicker.js +177 -106
- package/js/dropdown.js +186 -98
- package/js/kupola-config.js +64 -36
- package/js/message.js +66 -53
- package/js/modal.js +62 -59
- package/js/notification.js +63 -60
- package/js/security.js +52 -0
- package/js/select.js +88 -3
- package/js/tooltip.js +300 -297
- package/js/validation.js +155 -140
- package/package.json +2 -1
- package/types/kupola.d.ts +135 -0
package/js/validation.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { getValidationConfig } from './kupola-config.js';
|
|
2
|
+
import { getPerformanceConfig } from './kupola-config.js';
|
|
3
|
+
|
|
1
4
|
class KupolaValidator {
|
|
2
5
|
constructor() {
|
|
3
6
|
this.validators = {
|
|
@@ -12,9 +15,9 @@ class KupolaValidator {
|
|
|
12
15
|
equalTo: this.validateEqualTo,
|
|
13
16
|
phone: this.validatePhone,
|
|
14
17
|
date: this.validateDate,
|
|
15
|
-
number: this.validateNumber
|
|
18
|
+
number: this.validateNumber,
|
|
16
19
|
};
|
|
17
|
-
|
|
20
|
+
|
|
18
21
|
this.customValidators = {};
|
|
19
22
|
this.asyncValidators = {};
|
|
20
23
|
this.customAsyncValidators = {};
|
|
@@ -35,13 +38,13 @@ class KupolaValidator {
|
|
|
35
38
|
const errors = {};
|
|
36
39
|
const inputs = form.querySelectorAll('[data-validate]');
|
|
37
40
|
let hasError = false;
|
|
38
|
-
|
|
41
|
+
|
|
39
42
|
inputs.forEach(input => {
|
|
40
43
|
const name = input.name || input.id;
|
|
41
44
|
const rules = this.parseRules(input.getAttribute('data-validate'));
|
|
42
45
|
const value = this.getValue(input);
|
|
43
|
-
|
|
44
|
-
for (const [rule, params] of Object.entries(rules)) {
|
|
46
|
+
|
|
47
|
+
for (const [ rule, params ] of Object.entries(rules)) {
|
|
45
48
|
const validatorFunc = this.customValidators[rule] || this.validators[rule];
|
|
46
49
|
const isValid = validatorFunc?.(value, params);
|
|
47
50
|
if (!isValid) {
|
|
@@ -54,15 +57,15 @@ class KupolaValidator {
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
});
|
|
57
|
-
|
|
60
|
+
|
|
58
61
|
this.formStates[formId] = {
|
|
59
62
|
valid: !hasError,
|
|
60
63
|
errors: errors,
|
|
61
|
-
errorCount: Object.keys(errors).length
|
|
64
|
+
errorCount: Object.keys(errors).length,
|
|
62
65
|
};
|
|
63
|
-
|
|
66
|
+
|
|
64
67
|
this.updateFormState(form);
|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
return !hasError;
|
|
67
70
|
}
|
|
68
71
|
|
|
@@ -70,27 +73,27 @@ class KupolaValidator {
|
|
|
70
73
|
if (input.classList.contains('ds-datepicker__input') || input.classList.contains('ds-timepicker__input')) {
|
|
71
74
|
return input.value.trim();
|
|
72
75
|
}
|
|
73
|
-
|
|
76
|
+
|
|
74
77
|
if (input.closest('.ds-select')) {
|
|
75
78
|
const select = input.closest('.ds-select');
|
|
76
79
|
const valueEl = select.querySelector('.ds-select__value') || select.querySelector('.ds-select__trigger span');
|
|
77
80
|
return valueEl ? valueEl.textContent.trim() : '';
|
|
78
81
|
}
|
|
79
|
-
|
|
82
|
+
|
|
80
83
|
if (input.closest('.ds-fileupload')) {
|
|
81
84
|
const upload = input.closest('.ds-fileupload');
|
|
82
85
|
const uploadInstance = upload.__fileUploadInstance;
|
|
83
86
|
return uploadInstance && uploadInstance.getFiles().length > 0 ? 'has-files' : '';
|
|
84
87
|
}
|
|
85
|
-
|
|
88
|
+
|
|
86
89
|
return input.value.trim();
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
validateInput(input) {
|
|
90
93
|
const rules = this.parseRules(input.getAttribute('data-validate'));
|
|
91
94
|
const value = this.getValue(input);
|
|
92
|
-
|
|
93
|
-
for (const [rule, params] of Object.entries(rules)) {
|
|
95
|
+
|
|
96
|
+
for (const [ rule, params ] of Object.entries(rules)) {
|
|
94
97
|
const validatorFunc = this.customValidators[rule] || this.validators[rule];
|
|
95
98
|
const isValid = validatorFunc?.(value, params);
|
|
96
99
|
if (!isValid) {
|
|
@@ -98,7 +101,7 @@ class KupolaValidator {
|
|
|
98
101
|
return false;
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
|
-
|
|
104
|
+
|
|
102
105
|
this.clearError(input);
|
|
103
106
|
return true;
|
|
104
107
|
}
|
|
@@ -106,13 +109,13 @@ class KupolaValidator {
|
|
|
106
109
|
validateAll() {
|
|
107
110
|
const forms = document.querySelectorAll('form[data-validation]');
|
|
108
111
|
let allValid = true;
|
|
109
|
-
|
|
112
|
+
|
|
110
113
|
forms.forEach(form => {
|
|
111
114
|
if (!this.validate(form)) {
|
|
112
115
|
allValid = false;
|
|
113
116
|
}
|
|
114
117
|
});
|
|
115
|
-
|
|
118
|
+
|
|
116
119
|
return allValid;
|
|
117
120
|
}
|
|
118
121
|
|
|
@@ -120,19 +123,19 @@ class KupolaValidator {
|
|
|
120
123
|
const formId = form.id || `form-${Math.random().toString(36).substr(2, 9)}`;
|
|
121
124
|
const errors = {};
|
|
122
125
|
const group = options.group;
|
|
123
|
-
const inputs = group
|
|
126
|
+
const inputs = group
|
|
124
127
|
? form.querySelectorAll(`[data-validate][data-validate-group="${group}"]`)
|
|
125
128
|
: form.querySelectorAll('[data-validate]');
|
|
126
|
-
|
|
129
|
+
|
|
127
130
|
let hasError = false;
|
|
128
|
-
|
|
131
|
+
|
|
129
132
|
for (const input of inputs) {
|
|
130
133
|
const isValid = await this.validateInputAsync(input);
|
|
131
134
|
if (!isValid) {
|
|
132
135
|
hasError = true;
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
|
-
|
|
138
|
+
|
|
136
139
|
const formErrors = {};
|
|
137
140
|
inputs.forEach(input => {
|
|
138
141
|
const name = input.name || input.id;
|
|
@@ -141,15 +144,15 @@ class KupolaValidator {
|
|
|
141
144
|
formErrors[name] = errorElement.textContent;
|
|
142
145
|
}
|
|
143
146
|
});
|
|
144
|
-
|
|
147
|
+
|
|
145
148
|
this.formStates[formId] = {
|
|
146
149
|
valid: !hasError,
|
|
147
150
|
errors: formErrors,
|
|
148
|
-
errorCount: Object.keys(formErrors).length
|
|
151
|
+
errorCount: Object.keys(formErrors).length,
|
|
149
152
|
};
|
|
150
|
-
|
|
153
|
+
|
|
151
154
|
this.updateFormState(form);
|
|
152
|
-
|
|
155
|
+
|
|
153
156
|
return !hasError;
|
|
154
157
|
}
|
|
155
158
|
|
|
@@ -157,8 +160,8 @@ class KupolaValidator {
|
|
|
157
160
|
const rules = this.parseRules(input.getAttribute('data-validate'));
|
|
158
161
|
const asyncRules = this.parseRules(input.getAttribute('data-validate-async') || '');
|
|
159
162
|
const value = this.getValue(input);
|
|
160
|
-
|
|
161
|
-
for (const [rule, params] of Object.entries(rules)) {
|
|
163
|
+
|
|
164
|
+
for (const [ rule, params ] of Object.entries(rules)) {
|
|
162
165
|
const validatorFunc = this.customValidators[rule] || this.validators[rule];
|
|
163
166
|
const isValid = validatorFunc?.(value, params);
|
|
164
167
|
if (!isValid) {
|
|
@@ -166,8 +169,8 @@ class KupolaValidator {
|
|
|
166
169
|
return false;
|
|
167
170
|
}
|
|
168
171
|
}
|
|
169
|
-
|
|
170
|
-
for (const [rule, params] of Object.entries(asyncRules)) {
|
|
172
|
+
|
|
173
|
+
for (const [ rule, params ] of Object.entries(asyncRules)) {
|
|
171
174
|
const validatorFunc = this.customAsyncValidators[rule] || this.asyncValidators[rule];
|
|
172
175
|
if (validatorFunc) {
|
|
173
176
|
try {
|
|
@@ -182,7 +185,7 @@ class KupolaValidator {
|
|
|
182
185
|
}
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
|
-
|
|
188
|
+
|
|
186
189
|
this.clearError(input);
|
|
187
190
|
return true;
|
|
188
191
|
}
|
|
@@ -190,14 +193,14 @@ class KupolaValidator {
|
|
|
190
193
|
async validateGroup(form, groupName) {
|
|
191
194
|
const inputs = form.querySelectorAll(`[data-validate][data-validate-group="${groupName}"]`);
|
|
192
195
|
let hasError = false;
|
|
193
|
-
|
|
196
|
+
|
|
194
197
|
for (const input of inputs) {
|
|
195
198
|
const isValid = await this.validateInputAsync(input);
|
|
196
199
|
if (!isValid) {
|
|
197
200
|
hasError = true;
|
|
198
201
|
}
|
|
199
202
|
}
|
|
200
|
-
|
|
203
|
+
|
|
201
204
|
return !hasError;
|
|
202
205
|
}
|
|
203
206
|
|
|
@@ -216,7 +219,7 @@ class KupolaValidator {
|
|
|
216
219
|
|
|
217
220
|
updateFormState(form) {
|
|
218
221
|
const state = this.getFormState(form);
|
|
219
|
-
|
|
222
|
+
|
|
220
223
|
if (state.valid) {
|
|
221
224
|
form.classList.remove('ds-form--invalid');
|
|
222
225
|
form.classList.add('ds-form--valid');
|
|
@@ -224,19 +227,19 @@ class KupolaValidator {
|
|
|
224
227
|
form.classList.remove('ds-form--valid');
|
|
225
228
|
form.classList.add('ds-form--invalid');
|
|
226
229
|
}
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
if (state.loading) {
|
|
229
232
|
form.classList.add('ds-form--loading');
|
|
230
233
|
} else {
|
|
231
234
|
form.classList.remove('ds-form--loading');
|
|
232
235
|
}
|
|
233
|
-
|
|
236
|
+
|
|
234
237
|
if (state.submitting) {
|
|
235
238
|
form.classList.add('ds-form--submitting');
|
|
236
239
|
} else {
|
|
237
240
|
form.classList.remove('ds-form--submitting');
|
|
238
241
|
}
|
|
239
|
-
|
|
242
|
+
|
|
240
243
|
if (state.disabled) {
|
|
241
244
|
form.classList.add('ds-form--disabled');
|
|
242
245
|
form.querySelectorAll('input, select, textarea, button').forEach(el => el.disabled = true);
|
|
@@ -248,7 +251,7 @@ class KupolaValidator {
|
|
|
248
251
|
}
|
|
249
252
|
});
|
|
250
253
|
}
|
|
251
|
-
|
|
254
|
+
|
|
252
255
|
const statusElement = form.querySelector('.ds-form__status');
|
|
253
256
|
if (statusElement) {
|
|
254
257
|
if (state.errorCount > 0) {
|
|
@@ -305,12 +308,12 @@ class KupolaValidator {
|
|
|
305
308
|
parseRules(rulesString) {
|
|
306
309
|
const rules = {};
|
|
307
310
|
const parts = rulesString.split('|');
|
|
308
|
-
|
|
311
|
+
|
|
309
312
|
parts.forEach(part => {
|
|
310
|
-
const [rule, params] = part.split(':');
|
|
313
|
+
const [ rule, params ] = part.split(':');
|
|
311
314
|
rules[rule] = params ? params.split(',') : [];
|
|
312
315
|
});
|
|
313
|
-
|
|
316
|
+
|
|
314
317
|
return rules;
|
|
315
318
|
}
|
|
316
319
|
|
|
@@ -328,34 +331,34 @@ class KupolaValidator {
|
|
|
328
331
|
return urlRegex.test(value);
|
|
329
332
|
}
|
|
330
333
|
|
|
331
|
-
validateMinLength(value, [min]) {
|
|
334
|
+
validateMinLength(value, [ min ]) {
|
|
332
335
|
return value.length >= parseInt(min);
|
|
333
336
|
}
|
|
334
337
|
|
|
335
|
-
validateMaxLength(value, [max]) {
|
|
338
|
+
validateMaxLength(value, [ max ]) {
|
|
336
339
|
return value.length <= parseInt(max);
|
|
337
340
|
}
|
|
338
341
|
|
|
339
|
-
validatePattern(value, [pattern]) {
|
|
342
|
+
validatePattern(value, [ pattern ]) {
|
|
340
343
|
const regex = new RegExp(pattern);
|
|
341
344
|
return regex.test(value);
|
|
342
345
|
}
|
|
343
346
|
|
|
344
|
-
validateMin(value, [min]) {
|
|
347
|
+
validateMin(value, [ min ]) {
|
|
345
348
|
return parseFloat(value) >= parseFloat(min);
|
|
346
349
|
}
|
|
347
350
|
|
|
348
|
-
validateMax(value, [max]) {
|
|
351
|
+
validateMax(value, [ max ]) {
|
|
349
352
|
return parseFloat(value) <= parseFloat(max);
|
|
350
353
|
}
|
|
351
354
|
|
|
352
|
-
validateEqualTo(value, [targetId]) {
|
|
355
|
+
validateEqualTo(value, [ targetId ]) {
|
|
353
356
|
const target = document.getElementById(targetId);
|
|
354
357
|
return target && value === target.value;
|
|
355
358
|
}
|
|
356
359
|
|
|
357
360
|
validatePhone(value) {
|
|
358
|
-
const phoneRegex = /^[\d\s
|
|
361
|
+
const phoneRegex = /^[\d\s\-+()]{7,20}$/;
|
|
359
362
|
return phoneRegex.test(value);
|
|
360
363
|
}
|
|
361
364
|
|
|
@@ -372,7 +375,7 @@ class KupolaValidator {
|
|
|
372
375
|
input.classList.add('ds-input--error');
|
|
373
376
|
input.classList.remove('ds-input--success');
|
|
374
377
|
input.setAttribute('aria-invalid', 'true');
|
|
375
|
-
|
|
378
|
+
|
|
376
379
|
let errorElement = input.parentElement.querySelector('.ds-input__error');
|
|
377
380
|
if (!errorElement) {
|
|
378
381
|
errorElement = document.createElement('span');
|
|
@@ -382,21 +385,21 @@ class KupolaValidator {
|
|
|
382
385
|
input.parentElement.appendChild(errorElement);
|
|
383
386
|
}
|
|
384
387
|
errorElement.textContent = message;
|
|
385
|
-
|
|
388
|
+
|
|
386
389
|
this.removeStatusIcon(input);
|
|
387
|
-
|
|
390
|
+
|
|
388
391
|
input.dispatchEvent(new CustomEvent('validation-error', { detail: { message } }));
|
|
389
392
|
}
|
|
390
393
|
|
|
391
394
|
clearError(input) {
|
|
392
395
|
input.classList.remove('ds-input--error');
|
|
393
396
|
input.setAttribute('aria-invalid', 'false');
|
|
394
|
-
|
|
397
|
+
|
|
395
398
|
const errorElement = input.parentElement.querySelector('.ds-input__error');
|
|
396
399
|
if (errorElement) {
|
|
397
400
|
errorElement.remove();
|
|
398
401
|
}
|
|
399
|
-
|
|
402
|
+
|
|
400
403
|
input.dispatchEvent(new CustomEvent('validation-success'));
|
|
401
404
|
}
|
|
402
405
|
|
|
@@ -404,13 +407,13 @@ class KupolaValidator {
|
|
|
404
407
|
input.classList.add('ds-input--success');
|
|
405
408
|
input.classList.remove('ds-input--error');
|
|
406
409
|
input.setAttribute('aria-invalid', 'false');
|
|
407
|
-
|
|
410
|
+
|
|
408
411
|
this.removeStatusIcon(input);
|
|
409
|
-
|
|
412
|
+
|
|
410
413
|
const icon = document.createElement('span');
|
|
411
414
|
icon.className = 'ds-input__status-icon ds-input__status-icon--success';
|
|
412
415
|
icon.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>';
|
|
413
|
-
|
|
416
|
+
|
|
414
417
|
input.parentElement.appendChild(icon);
|
|
415
418
|
}
|
|
416
419
|
|
|
@@ -423,8 +426,8 @@ class KupolaValidator {
|
|
|
423
426
|
|
|
424
427
|
getErrorMessage(rule, params, input) {
|
|
425
428
|
const customMessage = input.getAttribute(`data-message-${rule}`);
|
|
426
|
-
if (customMessage) return customMessage;
|
|
427
|
-
|
|
429
|
+
if (customMessage) {return customMessage;}
|
|
430
|
+
|
|
428
431
|
const messages = {
|
|
429
432
|
required: 'This field is required',
|
|
430
433
|
email: 'Please enter a valid email address',
|
|
@@ -437,7 +440,7 @@ class KupolaValidator {
|
|
|
437
440
|
equalTo: 'Values do not match',
|
|
438
441
|
phone: 'Please enter a valid phone number',
|
|
439
442
|
date: 'Please enter a valid date (YYYY-MM-DD)',
|
|
440
|
-
number: 'Please enter a valid number'
|
|
443
|
+
number: 'Please enter a valid number',
|
|
441
444
|
};
|
|
442
445
|
return messages[rule] || 'Invalid input';
|
|
443
446
|
}
|
|
@@ -448,105 +451,117 @@ const validator = new KupolaValidator();
|
|
|
448
451
|
if (!window.__kupolaValidationInitialized) {
|
|
449
452
|
window.__kupolaValidationInitialized = true;
|
|
450
453
|
document.addEventListener('DOMContentLoaded', () => {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
e.preventDefault();
|
|
461
|
-
|
|
462
|
-
const hasAsyncValidation = form.querySelector('[data-validate-async]') !== null;
|
|
463
|
-
|
|
464
|
-
let isValid;
|
|
465
|
-
if (hasAsyncValidation) {
|
|
466
|
-
isValid = await validator.validateAsync(form);
|
|
467
|
-
} else {
|
|
468
|
-
isValid = validator.validate(form);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
if (!isValid) {
|
|
472
|
-
const firstError = form.querySelector('.ds-input--error');
|
|
473
|
-
if (firstError) {
|
|
474
|
-
firstError.focus();
|
|
454
|
+
document.querySelectorAll('form[data-validation]').forEach(form => {
|
|
455
|
+
form.addEventListener('submit', async (e) => {
|
|
456
|
+
const formId = form.id || `form-${Math.random().toString(36).substr(2, 9)}`;
|
|
457
|
+
|
|
458
|
+
if (validator.submitting.has(formId)) {
|
|
459
|
+
e.preventDefault();
|
|
460
|
+
return;
|
|
475
461
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
462
|
+
|
|
463
|
+
e.preventDefault();
|
|
464
|
+
|
|
465
|
+
const hasAsyncValidation = form.querySelector('[data-validate-async]') !== null;
|
|
466
|
+
|
|
467
|
+
let isValid;
|
|
468
|
+
if (hasAsyncValidation) {
|
|
469
|
+
isValid = await validator.validateAsync(form);
|
|
470
|
+
} else {
|
|
471
|
+
isValid = validator.validate(form);
|
|
484
472
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
} else {
|
|
491
|
-
form.submit();
|
|
473
|
+
|
|
474
|
+
if (!isValid) {
|
|
475
|
+
const firstError = form.querySelector('.ds-input--error');
|
|
476
|
+
if (firstError) {
|
|
477
|
+
firstError.focus();
|
|
492
478
|
}
|
|
493
|
-
}
|
|
494
|
-
validator.submitting.
|
|
479
|
+
} else {
|
|
480
|
+
validator.submitting.add(formId);
|
|
481
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
495
482
|
if (submitBtn) {
|
|
496
|
-
|
|
497
|
-
submitBtn.
|
|
483
|
+
const originalText = submitBtn.textContent;
|
|
484
|
+
submitBtn.setAttribute('data-original-text', originalText);
|
|
485
|
+
submitBtn.textContent = 'Submitting...';
|
|
486
|
+
submitBtn.disabled = true;
|
|
498
487
|
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
488
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
489
|
+
try {
|
|
490
|
+
const onSubmit = form.getAttribute('data-on-submit');
|
|
491
|
+
if (onSubmit && window[onSubmit]) {
|
|
492
|
+
await window[onSubmit](form);
|
|
493
|
+
} else {
|
|
494
|
+
form.submit();
|
|
495
|
+
}
|
|
496
|
+
} finally {
|
|
497
|
+
validator.submitting.delete(formId);
|
|
498
|
+
if (submitBtn) {
|
|
499
|
+
submitBtn.textContent = submitBtn.getAttribute('data-original-text') || 'Submit';
|
|
500
|
+
submitBtn.disabled = false;
|
|
501
|
+
}
|
|
509
502
|
}
|
|
510
|
-
|
|
511
|
-
if (isValid && input.value.trim()) {
|
|
512
|
-
validator.showSuccess(input);
|
|
513
|
-
}
|
|
514
|
-
}, 50);
|
|
503
|
+
}
|
|
515
504
|
});
|
|
516
505
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
506
|
+
form.querySelectorAll('[data-validate]').forEach(input => {
|
|
507
|
+
const validationConfig = getValidationConfig();
|
|
508
|
+
const trigger = validationConfig.trigger || 'blur';
|
|
509
|
+
|
|
510
|
+
const validateAndShow = () => {
|
|
511
|
+
if (!validationConfig.showErrors) {return;}
|
|
512
|
+
setTimeout(() => {
|
|
513
|
+
const activeElement = document.activeElement;
|
|
514
|
+
if (activeElement && activeElement.closest('.ds-select')) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const isValid = validator.validateInput(input);
|
|
518
|
+
if (isValid && input.value.trim()) {
|
|
519
|
+
validator.showSuccess(input);
|
|
520
|
+
}
|
|
521
|
+
}, 50);
|
|
522
522
|
};
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const value = validator.getValue(input);
|
|
527
|
-
if (value.length > 0 || input.classList.contains('ds-input--error')) {
|
|
528
|
-
const isValid = validator.validateInput(input);
|
|
529
|
-
if (isValid && value) {
|
|
530
|
-
validator.showSuccess(input);
|
|
531
|
-
}
|
|
532
|
-
} else {
|
|
533
|
-
validator.removeStatusIcon(input);
|
|
523
|
+
|
|
524
|
+
if (trigger === 'blur' || trigger === 'both') {
|
|
525
|
+
input.addEventListener('blur', validateAndShow);
|
|
534
526
|
}
|
|
535
|
-
}, 300);
|
|
536
527
|
|
|
537
|
-
|
|
528
|
+
const debounce = (func, wait) => {
|
|
529
|
+
let timeout;
|
|
530
|
+
return (...args) => {
|
|
531
|
+
clearTimeout(timeout);
|
|
532
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
533
|
+
};
|
|
534
|
+
};
|
|
538
535
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
536
|
+
const performanceConfig = getPerformanceConfig();
|
|
537
|
+
const validateOnInput = debounce(() => {
|
|
538
|
+
if (!validationConfig.showErrors) {return;}
|
|
539
|
+
const value = validator.getValue(input);
|
|
540
|
+
if (value.length > 0 || input.classList.contains('ds-input--error')) {
|
|
541
|
+
const isValid = validator.validateInput(input);
|
|
542
|
+
if (isValid && value) {
|
|
543
|
+
validator.showSuccess(input);
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
validator.removeStatusIcon(input);
|
|
544
547
|
}
|
|
548
|
+
}, performanceConfig.debounceDelay);
|
|
549
|
+
|
|
550
|
+
if (trigger === 'input' || trigger === 'both') {
|
|
551
|
+
input.addEventListener('input', validateOnInput);
|
|
545
552
|
}
|
|
553
|
+
|
|
554
|
+
input.addEventListener('keyup', (e) => {
|
|
555
|
+
if (e.key === 'Enter') {
|
|
556
|
+
const isValid = validator.validateInput(input);
|
|
557
|
+
if (isValid && input.value.trim()) {
|
|
558
|
+
validator.showSuccess(input);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
});
|
|
546
562
|
});
|
|
547
563
|
});
|
|
548
564
|
});
|
|
549
|
-
});
|
|
550
565
|
}
|
|
551
566
|
|
|
552
|
-
export { KupolaValidator, validator };
|
|
567
|
+
export { KupolaValidator, validator };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kupola/kupola",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "A lightweight UI toolkit for any web project. No heavy frontend frameworks required.",
|
|
5
5
|
"main": "dist/kupola.cjs.js",
|
|
6
6
|
"module": "dist/kupola.esm.js",
|
|
@@ -120,6 +120,7 @@
|
|
|
120
120
|
"@rollup/plugin-terser": "^0.4.4",
|
|
121
121
|
"eslint": "^8.57.0",
|
|
122
122
|
"jest": "^29.7.0",
|
|
123
|
+
"jest-environment-jsdom": "^30.4.1",
|
|
123
124
|
"prettier": "^3.2.5",
|
|
124
125
|
"rollup": "^4.13.0",
|
|
125
126
|
"rollup-plugin-copy": "^3.5.0",
|