adaptform 2.0.5 → 2.1.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 +103 -2
- package/CHANGELOG.ru.md +152 -0
- package/LICENSE.md +3 -1
- package/LICENSE.ru.md +25 -0
- package/README.md +271 -303
- package/README.ru.md +388 -0
- package/dist/{Form-Be3I6LX0.d.cts → Form-kPYL4f-n.d.cts} +58 -36
- package/dist/{Form-Be3I6LX0.d.ts → Form-kPYL4f-n.d.ts} +58 -36
- package/dist/index.cjs +184 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.mjs +183 -103
- package/dist/index.mjs.map +1 -1
- package/dist/luxon.d.cts +1 -1
- package/dist/luxon.d.ts +1 -1
- package/package.json +28 -9
package/dist/index.mjs
CHANGED
|
@@ -18,8 +18,9 @@ var Field = class {
|
|
|
18
18
|
this._valueClear = null;
|
|
19
19
|
this.isValid = null;
|
|
20
20
|
}
|
|
21
|
+
this.isTouched = false;
|
|
21
22
|
}
|
|
22
|
-
// ==========
|
|
23
|
+
// ========== Getters and setters ==========
|
|
23
24
|
get plugins() {
|
|
24
25
|
return [...this.options.plugins ?? []].sort((a, b) => {
|
|
25
26
|
return (a.pluginOptions?.priority ?? 0) - (b.pluginOptions?.priority ?? 0);
|
|
@@ -29,13 +30,26 @@ var Field = class {
|
|
|
29
30
|
return this.fieldType.options;
|
|
30
31
|
}
|
|
31
32
|
set options(options) {
|
|
32
|
-
|
|
33
|
-
this.fieldType.options = Object.assign(
|
|
33
|
+
const currentOptions = this.fieldType.options;
|
|
34
|
+
this.fieldType.options = Object.assign(currentOptions, options);
|
|
34
35
|
}
|
|
35
36
|
get rawValue() {
|
|
36
37
|
return this._rawValue;
|
|
37
38
|
}
|
|
38
39
|
set rawValue(input) {
|
|
40
|
+
this.setRawValue(input);
|
|
41
|
+
}
|
|
42
|
+
setRawValue(input, validate = true) {
|
|
43
|
+
this.assignRawValue(input);
|
|
44
|
+
this._errors = [];
|
|
45
|
+
this.isTouched = true;
|
|
46
|
+
if (validate) {
|
|
47
|
+
this.checkAndSetValid();
|
|
48
|
+
} else {
|
|
49
|
+
this.isValid = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
assignRawValue(input) {
|
|
39
53
|
let rawValue = input;
|
|
40
54
|
for (const plugin of this.plugins) {
|
|
41
55
|
if (plugin.toRawValue) {
|
|
@@ -50,9 +64,6 @@ var Field = class {
|
|
|
50
64
|
}
|
|
51
65
|
this._rawValue = rawValue;
|
|
52
66
|
this._valueClear = this.fieldType.cast(valueClear);
|
|
53
|
-
this._errors = [];
|
|
54
|
-
this.isTouched = true;
|
|
55
|
-
this.checkAndSetValid();
|
|
56
67
|
}
|
|
57
68
|
get errors() {
|
|
58
69
|
return this._errors;
|
|
@@ -71,7 +82,7 @@ var Field = class {
|
|
|
71
82
|
get valueClear() {
|
|
72
83
|
return this._valueClear;
|
|
73
84
|
}
|
|
74
|
-
// ==========
|
|
85
|
+
// ========== Validation ==========
|
|
75
86
|
isRequired(form) {
|
|
76
87
|
let isRequired;
|
|
77
88
|
if (typeof this.options.isRequired === "function") {
|
|
@@ -121,55 +132,61 @@ var Field = class {
|
|
|
121
132
|
get isEmpty() {
|
|
122
133
|
let isEmpty = false;
|
|
123
134
|
if (this._rawValue === null || this._rawValue === void 0) isEmpty = true;
|
|
124
|
-
else if (this._rawValue === "") isEmpty = true;
|
|
135
|
+
else if (typeof this._rawValue === "string" && this._rawValue.trim() === "") isEmpty = true;
|
|
125
136
|
else if (Array.isArray(this._rawValue) && this._rawValue.length === 0) isEmpty = true;
|
|
126
137
|
return isEmpty;
|
|
127
138
|
}
|
|
128
|
-
// ==========
|
|
139
|
+
// ========== Helper methods ==========
|
|
129
140
|
reset() {
|
|
130
141
|
if (this.defaultValue !== null && this.defaultValue !== void 0) {
|
|
131
|
-
this.
|
|
142
|
+
this.assignRawValue(this.defaultValue);
|
|
132
143
|
} else {
|
|
133
144
|
this._rawValue = null;
|
|
134
145
|
this._valueClear = null;
|
|
135
|
-
this.isValid = null;
|
|
136
146
|
}
|
|
137
147
|
this._errors = [];
|
|
148
|
+
this.isValid = null;
|
|
138
149
|
this.isTouched = false;
|
|
139
150
|
}
|
|
140
151
|
};
|
|
141
152
|
|
|
153
|
+
// src/core/fields/arrayUtils.ts
|
|
154
|
+
function isValidArrayIndex(index, length) {
|
|
155
|
+
return Number.isInteger(index) && index >= 0 && index < length;
|
|
156
|
+
}
|
|
157
|
+
|
|
142
158
|
// src/core/fields/ArrayField.ts
|
|
143
159
|
var ArrayField = class {
|
|
144
160
|
constructor(factory, options = {}, initial = []) {
|
|
145
161
|
this.factory = factory;
|
|
146
162
|
this._items = [];
|
|
147
163
|
this._errors = [];
|
|
164
|
+
this._hasValidationResult = false;
|
|
148
165
|
this.isTouched = false;
|
|
149
166
|
this.options = {
|
|
150
167
|
isRequired: true,
|
|
151
168
|
messages: {},
|
|
152
169
|
...options
|
|
153
170
|
};
|
|
154
|
-
this._items = initial.map((
|
|
171
|
+
this._items = initial.map((value) => this.factory(value));
|
|
155
172
|
this.checkValid();
|
|
156
173
|
}
|
|
157
174
|
// ===== value =====
|
|
158
175
|
set itemsValue(items) {
|
|
159
176
|
this.clear();
|
|
160
|
-
for (const
|
|
161
|
-
this.add(
|
|
177
|
+
for (const item of items) {
|
|
178
|
+
this.add(item, false);
|
|
162
179
|
}
|
|
163
180
|
this.checkValid();
|
|
164
181
|
}
|
|
165
182
|
get itemsValue() {
|
|
166
|
-
return this._items.map((
|
|
183
|
+
return this._items.map((item) => item.valueClear);
|
|
167
184
|
}
|
|
168
185
|
get items() {
|
|
169
186
|
return this._items;
|
|
170
187
|
}
|
|
171
188
|
// ===== actions =====
|
|
172
|
-
add(value, force_check) {
|
|
189
|
+
add(value, force_check = true) {
|
|
173
190
|
const field = this.factory(value);
|
|
174
191
|
this.isTouched = true;
|
|
175
192
|
this._items.push(field);
|
|
@@ -177,6 +194,7 @@ var ArrayField = class {
|
|
|
177
194
|
return field;
|
|
178
195
|
}
|
|
179
196
|
remove(index) {
|
|
197
|
+
if (!isValidArrayIndex(index, this._items.length)) return;
|
|
180
198
|
this._items.splice(index, 1);
|
|
181
199
|
this.checkValid();
|
|
182
200
|
}
|
|
@@ -195,6 +213,7 @@ var ArrayField = class {
|
|
|
195
213
|
return isRequired;
|
|
196
214
|
}
|
|
197
215
|
checkValid(form) {
|
|
216
|
+
this._hasValidationResult = true;
|
|
198
217
|
this._errors = [];
|
|
199
218
|
if (this.isRequired(form) && this._items.length === 0) {
|
|
200
219
|
this._errors.push(
|
|
@@ -220,7 +239,7 @@ var ArrayField = class {
|
|
|
220
239
|
if (!ok) valid = false;
|
|
221
240
|
}
|
|
222
241
|
if (this.options.validate) {
|
|
223
|
-
const values = this._items.map((
|
|
242
|
+
const values = this._items.map((item) => item.valueClear);
|
|
224
243
|
const result = this.options.validate(values, form);
|
|
225
244
|
if (result === false) {
|
|
226
245
|
this._errors.push(
|
|
@@ -239,8 +258,9 @@ var ArrayField = class {
|
|
|
239
258
|
return this.checkValid(form);
|
|
240
259
|
}
|
|
241
260
|
get isValid() {
|
|
261
|
+
if (!this._hasValidationResult) return false;
|
|
242
262
|
if (this._errors.length > 0) return false;
|
|
243
|
-
return this._items.every((
|
|
263
|
+
return this._items.every((item) => item.isValid === true);
|
|
244
264
|
}
|
|
245
265
|
get error() {
|
|
246
266
|
return this._errors[0] ?? "";
|
|
@@ -248,16 +268,19 @@ var ArrayField = class {
|
|
|
248
268
|
set error(message) {
|
|
249
269
|
if (message) {
|
|
250
270
|
this._errors = [message];
|
|
271
|
+
this._hasValidationResult = true;
|
|
251
272
|
} else {
|
|
252
273
|
this._errors = [];
|
|
274
|
+
this._hasValidationResult = false;
|
|
253
275
|
}
|
|
254
276
|
}
|
|
255
277
|
get errors() {
|
|
256
278
|
return this._errors;
|
|
257
279
|
}
|
|
258
280
|
reset() {
|
|
259
|
-
this._items.forEach((
|
|
281
|
+
this._items.forEach((item) => item.reset());
|
|
260
282
|
this._errors = [];
|
|
283
|
+
this._hasValidationResult = false;
|
|
261
284
|
this.isTouched = false;
|
|
262
285
|
}
|
|
263
286
|
};
|
|
@@ -269,38 +292,45 @@ var ArrayFormField = class {
|
|
|
269
292
|
this.options = options;
|
|
270
293
|
this._forms = [];
|
|
271
294
|
this._errors = [];
|
|
295
|
+
this._hasValidationResult = false;
|
|
272
296
|
this.isTouched = false;
|
|
273
297
|
this._forms = initial.map((data) => {
|
|
274
298
|
const form = new this.FormConstructor();
|
|
275
|
-
form.
|
|
299
|
+
form.setFields(data, false);
|
|
276
300
|
return form;
|
|
277
301
|
});
|
|
278
302
|
this.checkValid();
|
|
279
303
|
}
|
|
280
304
|
// ===== value =====
|
|
281
305
|
set forms(forms) {
|
|
282
|
-
this.
|
|
283
|
-
|
|
284
|
-
|
|
306
|
+
this.setForms(forms);
|
|
307
|
+
}
|
|
308
|
+
setForms(forms, validate = true) {
|
|
309
|
+
this._forms = [];
|
|
310
|
+
for (const formData of forms) {
|
|
311
|
+
this.add(formData, false);
|
|
285
312
|
}
|
|
286
|
-
this.checkValid();
|
|
313
|
+
if (validate) this.checkValid();
|
|
287
314
|
}
|
|
288
315
|
get forms() {
|
|
289
316
|
return this._forms;
|
|
290
317
|
}
|
|
291
318
|
get formsFieldsValue() {
|
|
292
|
-
return this._forms.map((
|
|
319
|
+
return this._forms.map((form) => form.fieldsValue);
|
|
293
320
|
}
|
|
294
321
|
// ===== actions =====
|
|
295
|
-
add(data, force_check) {
|
|
322
|
+
add(data, force_check = true) {
|
|
296
323
|
const form = new this.FormConstructor();
|
|
297
|
-
if (data
|
|
324
|
+
if (data !== void 0 && data !== null) {
|
|
325
|
+
form.setFields(data, false);
|
|
326
|
+
}
|
|
298
327
|
this.isTouched = true;
|
|
299
328
|
this._forms.push(form);
|
|
300
329
|
if (force_check) this.checkValid();
|
|
301
330
|
return form;
|
|
302
331
|
}
|
|
303
332
|
remove(index) {
|
|
333
|
+
if (!isValidArrayIndex(index, this._forms.length)) return;
|
|
304
334
|
this._forms.splice(index, 1);
|
|
305
335
|
this.checkValid();
|
|
306
336
|
}
|
|
@@ -309,8 +339,9 @@ var ArrayFormField = class {
|
|
|
309
339
|
this.checkValid();
|
|
310
340
|
}
|
|
311
341
|
reset() {
|
|
312
|
-
this._forms.forEach((
|
|
342
|
+
this._forms.forEach((form) => form.reset());
|
|
313
343
|
this._errors = [];
|
|
344
|
+
this._hasValidationResult = false;
|
|
314
345
|
this.isTouched = false;
|
|
315
346
|
}
|
|
316
347
|
// ===== validation =====
|
|
@@ -324,8 +355,9 @@ var ArrayFormField = class {
|
|
|
324
355
|
return isRequired;
|
|
325
356
|
}
|
|
326
357
|
checkValid(form) {
|
|
358
|
+
this._hasValidationResult = true;
|
|
327
359
|
this._errors = [];
|
|
328
|
-
if (this.isRequired(form) && this.
|
|
360
|
+
if (this.isRequired(form) && this._forms.length === 0) {
|
|
329
361
|
this._errors.push(
|
|
330
362
|
this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
|
|
331
363
|
);
|
|
@@ -344,12 +376,12 @@ var ArrayFormField = class {
|
|
|
344
376
|
return false;
|
|
345
377
|
}
|
|
346
378
|
let valid = true;
|
|
347
|
-
for (const
|
|
348
|
-
const ok =
|
|
379
|
+
for (const nestedForm of this._forms) {
|
|
380
|
+
const ok = nestedForm.checkValid(nestedForm);
|
|
349
381
|
if (!ok) valid = false;
|
|
350
382
|
}
|
|
351
383
|
if (this.options.validate) {
|
|
352
|
-
const result = this.options.validate(this.
|
|
384
|
+
const result = this.options.validate(this._forms, form);
|
|
353
385
|
if (result === false) {
|
|
354
386
|
this._errors.push(
|
|
355
387
|
this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
|
|
@@ -367,8 +399,9 @@ var ArrayFormField = class {
|
|
|
367
399
|
return this.checkValid(form);
|
|
368
400
|
}
|
|
369
401
|
get isValid() {
|
|
402
|
+
if (!this._hasValidationResult) return false;
|
|
370
403
|
if (this._errors.length > 0) return false;
|
|
371
|
-
return this._forms.every((
|
|
404
|
+
return this._forms.every((form) => form.isValid);
|
|
372
405
|
}
|
|
373
406
|
get errors() {
|
|
374
407
|
return this._errors;
|
|
@@ -379,8 +412,10 @@ var ArrayFormField = class {
|
|
|
379
412
|
set error(message) {
|
|
380
413
|
if (message) {
|
|
381
414
|
this._errors = [message];
|
|
415
|
+
this._hasValidationResult = true;
|
|
382
416
|
} else {
|
|
383
417
|
this._errors = [];
|
|
418
|
+
this._hasValidationResult = false;
|
|
384
419
|
}
|
|
385
420
|
}
|
|
386
421
|
};
|
|
@@ -393,19 +428,19 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
393
428
|
this._valueTransformers = [];
|
|
394
429
|
}
|
|
395
430
|
/**
|
|
396
|
-
*
|
|
397
|
-
* @param errorKey -
|
|
398
|
-
* @param fieldName -
|
|
431
|
+
* Add a static rule that matches an exact error key.
|
|
432
|
+
* @param errorKey - Exact error key returned by the server.
|
|
433
|
+
* @param fieldName - Form field name or a function that resolves it dynamically.
|
|
399
434
|
*/
|
|
400
435
|
staticKey(errorKey, fieldName) {
|
|
401
436
|
this._staticRules.set(errorKey, fieldName);
|
|
402
437
|
return this;
|
|
403
438
|
}
|
|
404
439
|
/**
|
|
405
|
-
*
|
|
406
|
-
* @param pattern -
|
|
407
|
-
* @param mapping -
|
|
408
|
-
* @param options -
|
|
440
|
+
* Add a dynamic rule using a regular expression.
|
|
441
|
+
* @param pattern - Regular expression used to match an error key.
|
|
442
|
+
* @param mapping - Field name or function that derives it from the match.
|
|
443
|
+
* @param options - Additional options, such as rule priority.
|
|
409
444
|
*/
|
|
410
445
|
dynamicKey(pattern, mapping, options) {
|
|
411
446
|
this._dynamicRules.push({
|
|
@@ -417,22 +452,22 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
417
452
|
return this;
|
|
418
453
|
}
|
|
419
454
|
/**
|
|
420
|
-
*
|
|
455
|
+
* Set a handler for errors that do not match any rule.
|
|
421
456
|
*/
|
|
422
457
|
fallback(handler) {
|
|
423
458
|
this._fallbackHandler = handler;
|
|
424
459
|
return this;
|
|
425
460
|
}
|
|
426
461
|
/**
|
|
427
|
-
*
|
|
428
|
-
*
|
|
462
|
+
* Add a transformer for error values.
|
|
463
|
+
* Useful for normalizing messages, such as server responses containing arrays.
|
|
429
464
|
*/
|
|
430
465
|
transformValue(transformer) {
|
|
431
466
|
this._valueTransformers.push(transformer);
|
|
432
467
|
return this;
|
|
433
468
|
}
|
|
434
469
|
/**
|
|
435
|
-
*
|
|
470
|
+
* Create a schema from a simple mapping object.
|
|
436
471
|
*/
|
|
437
472
|
static fromObject(mapping) {
|
|
438
473
|
const schema = new _ErrorsSchema();
|
|
@@ -442,24 +477,35 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
442
477
|
return schema;
|
|
443
478
|
}
|
|
444
479
|
/**
|
|
445
|
-
*
|
|
480
|
+
* Create a schema for an array of similarly structured forms.
|
|
446
481
|
*/
|
|
447
482
|
static forArray(itemSchema, arrayFieldName, indexExtractor) {
|
|
448
483
|
const schema = new _ErrorsSchema();
|
|
484
|
+
for (const transformer of itemSchema._valueTransformers) {
|
|
485
|
+
schema.transformValue(transformer);
|
|
486
|
+
}
|
|
487
|
+
const escapedArrayFieldName = arrayFieldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
488
|
+
const indexPattern = indexExtractor ? "(.+?)" : "(?:\\[(\\d+)\\]|\\.(\\d+))";
|
|
449
489
|
schema.dynamicKey(
|
|
450
|
-
new RegExp(`^${
|
|
451
|
-
(match) => {
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
490
|
+
new RegExp(`^${escapedArrayFieldName}${indexPattern}\\.(.+)$`),
|
|
491
|
+
(match, value) => {
|
|
492
|
+
const sourceKey = match[0];
|
|
493
|
+
const index = indexExtractor ? indexExtractor(sourceKey) : Number(match[1] ?? match[2]);
|
|
494
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
495
|
+
return "";
|
|
496
|
+
}
|
|
497
|
+
const fieldPath = match[indexExtractor ? 2 : 3];
|
|
498
|
+
const itemMapping = itemSchema.findMapping(fieldPath, value);
|
|
499
|
+
const mappedFieldPath = itemMapping ? typeof itemMapping === "function" ? itemMapping(value) : itemMapping : fieldPath;
|
|
500
|
+
return `${arrayFieldName}.${index}.${mappedFieldPath}`;
|
|
455
501
|
},
|
|
456
502
|
{ priority: 100 }
|
|
457
503
|
);
|
|
458
504
|
return schema;
|
|
459
505
|
}
|
|
460
506
|
/**
|
|
461
|
-
*
|
|
462
|
-
*
|
|
507
|
+
* Parse errors while applying configured value transformers.
|
|
508
|
+
* Supports nested structures using dot notation.
|
|
463
509
|
*/
|
|
464
510
|
parseErrors(errors, prefix = "") {
|
|
465
511
|
const result = {};
|
|
@@ -487,17 +533,12 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
487
533
|
} else {
|
|
488
534
|
result[mapping] = typeof transformedValue === "string" ? transformedValue : JSON.stringify(transformedValue);
|
|
489
535
|
}
|
|
490
|
-
} else if (this._fallbackHandler) {
|
|
491
|
-
const fieldName = this._fallbackHandler(fullKey, transformedValue);
|
|
492
|
-
if (fieldName) {
|
|
493
|
-
result[fieldName] = typeof transformedValue === "string" ? transformedValue : JSON.stringify(transformedValue);
|
|
494
|
-
}
|
|
495
536
|
}
|
|
496
537
|
}
|
|
497
538
|
return result;
|
|
498
539
|
}
|
|
499
540
|
/**
|
|
500
|
-
*
|
|
541
|
+
* Parse server errors and return detailed metadata.
|
|
501
542
|
*/
|
|
502
543
|
parseErrorsDetailed(errors, prefix = "") {
|
|
503
544
|
const result = {};
|
|
@@ -529,7 +570,7 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
529
570
|
return result;
|
|
530
571
|
}
|
|
531
572
|
/**
|
|
532
|
-
*
|
|
573
|
+
* Create a schema for a nested form.
|
|
533
574
|
*/
|
|
534
575
|
nest(prefix) {
|
|
535
576
|
const nestedSchema = new _ErrorsSchema();
|
|
@@ -554,7 +595,7 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
554
595
|
return nestedSchema;
|
|
555
596
|
}
|
|
556
597
|
/**
|
|
557
|
-
*
|
|
598
|
+
* Clone the current schema.
|
|
558
599
|
*/
|
|
559
600
|
clone() {
|
|
560
601
|
const cloned = new _ErrorsSchema();
|
|
@@ -569,7 +610,7 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
569
610
|
return cloned;
|
|
570
611
|
}
|
|
571
612
|
/**
|
|
572
|
-
*
|
|
613
|
+
* Merge the current schema with another schema.
|
|
573
614
|
*/
|
|
574
615
|
merge(other) {
|
|
575
616
|
const merged = this.clone();
|
|
@@ -596,7 +637,7 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
596
637
|
for (const rule of this._dynamicRules) {
|
|
597
638
|
const match = key.match(rule.pattern);
|
|
598
639
|
if (match) {
|
|
599
|
-
const fieldName = typeof rule.mapping === "function" ? rule.mapping(match) : rule.mapping;
|
|
640
|
+
const fieldName = typeof rule.mapping === "function" ? rule.mapping(match, value) : rule.mapping;
|
|
600
641
|
return fieldName ? { fieldName, matchedBy: "dynamic" } : null;
|
|
601
642
|
}
|
|
602
643
|
}
|
|
@@ -614,7 +655,7 @@ var ErrorsSchema = class _ErrorsSchema {
|
|
|
614
655
|
const match = key.match(rule.pattern);
|
|
615
656
|
if (match) {
|
|
616
657
|
if (typeof rule.mapping === "function") {
|
|
617
|
-
const fieldName = rule.mapping(match);
|
|
658
|
+
const fieldName = rule.mapping(match, value);
|
|
618
659
|
return fieldName;
|
|
619
660
|
}
|
|
620
661
|
return rule.mapping;
|
|
@@ -654,7 +695,7 @@ var Form = class {
|
|
|
654
695
|
isFormValid = false;
|
|
655
696
|
}
|
|
656
697
|
}
|
|
657
|
-
return isFormValid;
|
|
698
|
+
return isFormValid && Object.keys(this._globalErrors).length === 0;
|
|
658
699
|
}
|
|
659
700
|
get fieldsValue() {
|
|
660
701
|
const data = {};
|
|
@@ -671,16 +712,20 @@ var Form = class {
|
|
|
671
712
|
return data;
|
|
672
713
|
}
|
|
673
714
|
set fields(data) {
|
|
715
|
+
this.setFields(data);
|
|
716
|
+
}
|
|
717
|
+
setFields(data, validate = true) {
|
|
674
718
|
const fields = this._fields;
|
|
675
719
|
for (const key of Object.keys(data)) {
|
|
676
720
|
const field = fields[key];
|
|
677
721
|
if (field) {
|
|
678
|
-
if (field instanceof Field) field.
|
|
722
|
+
if (field instanceof Field) field.setRawValue(data[key], false);
|
|
679
723
|
else if (field instanceof ArrayField) field.itemsValue = data[key];
|
|
680
|
-
else if (field instanceof ArrayFormField) field.
|
|
724
|
+
else if (field instanceof ArrayFormField) field.setForms(data[key], false);
|
|
681
725
|
else console.error(`Invalid field "${key}" type`);
|
|
682
726
|
}
|
|
683
727
|
}
|
|
728
|
+
if (validate) this.checkValid();
|
|
684
729
|
}
|
|
685
730
|
get allErrors() {
|
|
686
731
|
const errors = {};
|
|
@@ -708,7 +753,7 @@ var Form = class {
|
|
|
708
753
|
return errors;
|
|
709
754
|
}
|
|
710
755
|
/**
|
|
711
|
-
*
|
|
756
|
+
* Recursively collect all errors from an ArrayFormField.
|
|
712
757
|
*/
|
|
713
758
|
collectArrayFormErrors(arrayField) {
|
|
714
759
|
const allErrors = [];
|
|
@@ -728,19 +773,30 @@ var Form = class {
|
|
|
728
773
|
return { ...this._globalErrors };
|
|
729
774
|
}
|
|
730
775
|
set errors(errors) {
|
|
776
|
+
this.clearErrorsRecursively();
|
|
731
777
|
const fields = this._fields;
|
|
732
|
-
this._globalErrors = {};
|
|
733
|
-
for (const key of Object.keys(fields)) {
|
|
734
|
-
fields[key].error = null;
|
|
735
|
-
}
|
|
736
778
|
const parsedErrors = this.errorsShema.parseErrors(errors);
|
|
737
779
|
for (const [fieldName, errorMessage] of Object.entries(parsedErrors)) {
|
|
738
780
|
this.applyErrorToField(fieldName, errorMessage, fields, this);
|
|
739
781
|
}
|
|
740
782
|
}
|
|
783
|
+
clearErrorsRecursively() {
|
|
784
|
+
this._globalErrors = {};
|
|
785
|
+
for (const field of Object.values(this._fields)) {
|
|
786
|
+
if (field instanceof Field) {
|
|
787
|
+
field.error = null;
|
|
788
|
+
} else if (field instanceof ArrayField) {
|
|
789
|
+
field.error = null;
|
|
790
|
+
for (const item of field.items) item.error = null;
|
|
791
|
+
} else if (field instanceof ArrayFormField) {
|
|
792
|
+
field.error = null;
|
|
793
|
+
for (const nestedForm of field.forms) nestedForm.clearErrorsRecursively();
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
741
797
|
/**
|
|
742
|
-
*
|
|
743
|
-
*
|
|
798
|
+
* Apply an error to the corresponding field.
|
|
799
|
+
* Supports nested fields using dot notation.
|
|
744
800
|
*/
|
|
745
801
|
applyErrorToField(fieldPath, errorMessage, fields, targetForm) {
|
|
746
802
|
if (!targetForm) {
|
|
@@ -807,7 +863,7 @@ var Form = class {
|
|
|
807
863
|
}
|
|
808
864
|
return false;
|
|
809
865
|
}
|
|
810
|
-
//
|
|
866
|
+
// Check whether the form is valid.
|
|
811
867
|
get isValid() {
|
|
812
868
|
const fields = this._fields;
|
|
813
869
|
for (const key of Object.keys(fields)) {
|
|
@@ -815,32 +871,50 @@ var Form = class {
|
|
|
815
871
|
}
|
|
816
872
|
return Object.keys(this._globalErrors).length === 0;
|
|
817
873
|
}
|
|
818
|
-
//
|
|
874
|
+
// Serialize form values for multipart requests.
|
|
819
875
|
toFormData() {
|
|
820
876
|
const formData = new FormData();
|
|
821
877
|
const data = this.fieldsValue;
|
|
822
878
|
for (const [key, value] of Object.entries(data)) {
|
|
823
|
-
if (value
|
|
879
|
+
if (value === null || value === void 0) continue;
|
|
880
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
881
|
+
formData.append(key, value);
|
|
882
|
+
} else if (value instanceof Date) {
|
|
824
883
|
formData.append(key, value.toISOString());
|
|
825
|
-
} else if (
|
|
884
|
+
} else if (typeof value === "object") {
|
|
885
|
+
const serialized = JSON.stringify(value);
|
|
886
|
+
if (serialized !== void 0) formData.append(key, serialized);
|
|
887
|
+
} else {
|
|
826
888
|
formData.append(key, String(value));
|
|
827
889
|
}
|
|
828
890
|
}
|
|
829
891
|
return formData;
|
|
830
892
|
}
|
|
831
|
-
//
|
|
893
|
+
// Get all values in JSON-compatible form.
|
|
832
894
|
toJSON() {
|
|
833
|
-
const data = this.fieldsValue;
|
|
834
895
|
const json = {};
|
|
835
|
-
for (const [key, value] of Object.entries(
|
|
836
|
-
|
|
837
|
-
json[key] = value.toISOString();
|
|
838
|
-
} else {
|
|
839
|
-
json[key] = value;
|
|
840
|
-
}
|
|
896
|
+
for (const [key, value] of Object.entries(this.fieldsValue)) {
|
|
897
|
+
json[key] = this.serializeJsonValue(value);
|
|
841
898
|
}
|
|
842
899
|
return json;
|
|
843
900
|
}
|
|
901
|
+
serializeJsonValue(value) {
|
|
902
|
+
if (value instanceof Date) {
|
|
903
|
+
return value.toISOString();
|
|
904
|
+
}
|
|
905
|
+
if (Array.isArray(value)) {
|
|
906
|
+
return value.map((item) => this.serializeJsonValue(item));
|
|
907
|
+
}
|
|
908
|
+
if (value !== null && typeof value === "object") {
|
|
909
|
+
const prototype = Object.getPrototypeOf(value);
|
|
910
|
+
if (prototype === Object.prototype || prototype === null) {
|
|
911
|
+
return Object.fromEntries(
|
|
912
|
+
Object.entries(value).map(([key, nestedValue]) => [key, this.serializeJsonValue(nestedValue)])
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return value;
|
|
917
|
+
}
|
|
844
918
|
};
|
|
845
919
|
|
|
846
920
|
// src/core/plugins/FieldPlugin.ts
|
|
@@ -860,13 +934,13 @@ var MaskPlugin = class extends BasePlugin {
|
|
|
860
934
|
this.maskParts = [];
|
|
861
935
|
this.config = config;
|
|
862
936
|
}
|
|
863
|
-
init(
|
|
937
|
+
init(_field) {
|
|
864
938
|
this.parseMask();
|
|
865
939
|
}
|
|
866
|
-
toRawValue(value,
|
|
940
|
+
toRawValue(value, _field) {
|
|
867
941
|
return this.applyMask(value);
|
|
868
942
|
}
|
|
869
|
-
toValueClear(value,
|
|
943
|
+
toValueClear(value, _field) {
|
|
870
944
|
return this.removeMask(value);
|
|
871
945
|
}
|
|
872
946
|
parseMask() {
|
|
@@ -1065,8 +1139,12 @@ var StringType = class extends FieldType {
|
|
|
1065
1139
|
this.options.messages?.maxLength ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 ${this.options.maxLength} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432`
|
|
1066
1140
|
);
|
|
1067
1141
|
}
|
|
1068
|
-
if (this.options.pattern != null
|
|
1069
|
-
|
|
1142
|
+
if (this.options.pattern != null) {
|
|
1143
|
+
const { source, flags } = this.options.pattern;
|
|
1144
|
+
const stablePattern = new RegExp(source, flags.replace(/[gy]/g, ""));
|
|
1145
|
+
if (!stablePattern.test(value)) {
|
|
1146
|
+
errors.push(this.options.messages?.pattern ?? "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442");
|
|
1147
|
+
}
|
|
1070
1148
|
}
|
|
1071
1149
|
return errors;
|
|
1072
1150
|
}
|
|
@@ -1079,15 +1157,21 @@ var StringType = class extends FieldType {
|
|
|
1079
1157
|
var NumberType = class extends FieldType {
|
|
1080
1158
|
cast(rawValue) {
|
|
1081
1159
|
if (rawValue === null || rawValue === void 0) return null;
|
|
1082
|
-
if (typeof rawValue === "number"
|
|
1160
|
+
if (typeof rawValue === "number") return Number.isFinite(rawValue) ? rawValue : null;
|
|
1083
1161
|
if (typeof rawValue === "string") {
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1162
|
+
const normalized = rawValue.trim();
|
|
1163
|
+
if (normalized.length === 0) return null;
|
|
1164
|
+
const num = Number(normalized);
|
|
1165
|
+
return Number.isFinite(num) ? num : null;
|
|
1086
1166
|
}
|
|
1087
1167
|
return null;
|
|
1088
1168
|
}
|
|
1089
1169
|
validate(value) {
|
|
1090
1170
|
const errors = [];
|
|
1171
|
+
if (!Number.isFinite(value)) {
|
|
1172
|
+
errors.push(this.options.messages?.invalid ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043A\u043E\u043D\u0435\u0447\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C");
|
|
1173
|
+
return errors;
|
|
1174
|
+
}
|
|
1091
1175
|
if (!Number.isInteger(value)) {
|
|
1092
1176
|
errors.push(this.options.messages?.invalid ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C");
|
|
1093
1177
|
}
|
|
@@ -1132,7 +1216,7 @@ var DecimalType = class extends FieldType {
|
|
|
1132
1216
|
if (typeof rawValue === "string") {
|
|
1133
1217
|
return this.castString(rawValue);
|
|
1134
1218
|
}
|
|
1135
|
-
if (typeof rawValue === "number" &&
|
|
1219
|
+
if (typeof rawValue === "number" && Number.isFinite(rawValue)) {
|
|
1136
1220
|
return rawValue;
|
|
1137
1221
|
}
|
|
1138
1222
|
return null;
|
|
@@ -1148,13 +1232,13 @@ var DecimalType = class extends FieldType {
|
|
|
1148
1232
|
}
|
|
1149
1233
|
validate(value) {
|
|
1150
1234
|
const errors = [];
|
|
1151
|
-
value = typeof value === "number" ?
|
|
1235
|
+
value = typeof value === "number" ? String(value) : value;
|
|
1152
1236
|
if (!this.isValidNumberString(value)) {
|
|
1153
1237
|
errors.push(this.options.messages?.invalid ?? "\u041F\u0440\u0438\u043C\u0435\u0440: 1.00");
|
|
1154
1238
|
return errors;
|
|
1155
1239
|
}
|
|
1156
|
-
const maxDigits = this.options.maxDigits
|
|
1157
|
-
const decimalPlaces = this.options.decimalPlaces
|
|
1240
|
+
const maxDigits = this.options.maxDigits ?? 8;
|
|
1241
|
+
const decimalPlaces = this.options.decimalPlaces ?? 2;
|
|
1158
1242
|
const maxIntDigits = maxDigits - decimalPlaces;
|
|
1159
1243
|
const isNegative = value.startsWith("-");
|
|
1160
1244
|
const normalizedValue = isNegative ? value.substring(1) : value;
|
|
@@ -1228,10 +1312,6 @@ var DecimalType = class extends FieldType {
|
|
|
1228
1312
|
if (dotCount > 1) return false;
|
|
1229
1313
|
return pattern.test(value);
|
|
1230
1314
|
}
|
|
1231
|
-
numberToString(value) {
|
|
1232
|
-
const decimalPlaces = this.options.decimalPlaces;
|
|
1233
|
-
return value.toFixed(decimalPlaces);
|
|
1234
|
-
}
|
|
1235
1315
|
getTypeName() {
|
|
1236
1316
|
return "\u0434\u0435\u0441\u044F\u0442\u0438\u0447\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E";
|
|
1237
1317
|
}
|
|
@@ -1308,7 +1388,7 @@ var DateType = class extends FieldType {
|
|
|
1308
1388
|
getTypeName() {
|
|
1309
1389
|
return this.options.isDatetime ? "\u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F" : "\u0434\u0430\u0442\u0430";
|
|
1310
1390
|
}
|
|
1311
|
-
//
|
|
1391
|
+
// Compare dates with optional time precision.
|
|
1312
1392
|
compareDates(value, boundary, type) {
|
|
1313
1393
|
if (this.options.isDatetime) {
|
|
1314
1394
|
if (type === "min") {
|
|
@@ -1331,6 +1411,6 @@ var DateType = class extends FieldType {
|
|
|
1331
1411
|
}
|
|
1332
1412
|
};
|
|
1333
1413
|
|
|
1334
|
-
export { ArrayField, ArrayFormField, BasePlugin, BooleanType, DateType, DecimalType, Field, FieldType, Form, MaskPlugin, NumberType, StringType };
|
|
1414
|
+
export { ArrayField, ArrayFormField, BasePlugin, BooleanType, DateType, DecimalType, DefaultErrorsSchema, ErrorsSchema, Field, FieldType, Form, MaskPlugin, NumberType, StringType };
|
|
1335
1415
|
//# sourceMappingURL=index.mjs.map
|
|
1336
1416
|
//# sourceMappingURL=index.mjs.map
|