adaptform 2.0.0 → 2.0.2

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/dist/index.cjs CHANGED
@@ -1,5 +1,529 @@
1
1
  'use strict';
2
2
 
3
+ // src/core/fields/Field.ts
4
+ var Field = class {
5
+ constructor(TypeConstructor, defaultValue, options) {
6
+ this._rawValue = null;
7
+ this._valueClear = null;
8
+ this._errors = [];
9
+ this.isValid = null;
10
+ this.isTouched = false;
11
+ this.filed_type = new TypeConstructor(options ?? {});
12
+ this.defaultValue = defaultValue ?? null;
13
+ for (const plugin of this.options.plugins ?? []) {
14
+ plugin.init?.(this);
15
+ }
16
+ if (defaultValue !== void 0 && defaultValue !== null) {
17
+ this.rawValue = defaultValue;
18
+ } else {
19
+ this._rawValue = null;
20
+ this._valueClear = null;
21
+ this.isValid = null;
22
+ }
23
+ }
24
+ // ========== Геттеры/сеттеры ==========
25
+ get plugins() {
26
+ return [...this.options.plugins ?? []].sort((a, b) => {
27
+ return (a.pluginOptions?.priority ?? 0) - (b.pluginOptions?.priority ?? 0);
28
+ });
29
+ }
30
+ get options() {
31
+ return this.filed_type.options;
32
+ }
33
+ set options(options) {
34
+ let cur_options = this.filed_type.options;
35
+ this.filed_type.options = Object.assign(cur_options, options);
36
+ }
37
+ get rawValue() {
38
+ return this._rawValue;
39
+ }
40
+ set rawValue(input) {
41
+ let rawValue = input;
42
+ for (const plugin of this.plugins) {
43
+ if (plugin.toRawValue) {
44
+ rawValue = plugin.toRawValue(rawValue, this);
45
+ }
46
+ }
47
+ let valueClear = rawValue;
48
+ for (const plugin of this.plugins) {
49
+ if (plugin.toValueClear) {
50
+ valueClear = plugin.toValueClear(valueClear, this);
51
+ }
52
+ }
53
+ this._rawValue = rawValue;
54
+ this._valueClear = this.filed_type.cast(valueClear);
55
+ this._errors = [];
56
+ this.isTouched = true;
57
+ this.checkAndSetValid();
58
+ }
59
+ get errors() {
60
+ return this._errors;
61
+ }
62
+ get error() {
63
+ return this._errors[0] ?? "";
64
+ }
65
+ set error(message) {
66
+ if (message) {
67
+ this._errors = [message];
68
+ } else {
69
+ this._errors = [];
70
+ }
71
+ this.isValid = message ? false : null;
72
+ }
73
+ get valueClear() {
74
+ return this._valueClear;
75
+ }
76
+ // ========== Валидация ==========
77
+ isRequired(form) {
78
+ let isRequired;
79
+ if (typeof this.options.isRequired === "function") {
80
+ isRequired = this.options.isRequired(form ?? null);
81
+ } else {
82
+ isRequired = this.options.isRequired ?? false;
83
+ }
84
+ return isRequired;
85
+ }
86
+ checkValid(form) {
87
+ this._errors = [];
88
+ if (this.isEmpty) {
89
+ if (this.isRequired(form)) {
90
+ this._errors.push(this.options.messages?.isRequired ?? "\u041F\u043E\u043B\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0434\u043B\u044F \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F");
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+ if (this._valueClear === null) {
96
+ this._errors.push(
97
+ this.options.messages?.type ?? `\u041E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${this.filed_type.getTypeName()}`
98
+ );
99
+ return false;
100
+ }
101
+ const typeErrors = this.filed_type.validate(this._valueClear, form);
102
+ if (typeErrors.length > 0) {
103
+ this._errors.push(...typeErrors);
104
+ return false;
105
+ }
106
+ if (this.options.validate) {
107
+ const result = this.options.validate(this._valueClear, form);
108
+ if (result === false) {
109
+ this._errors.push(this.options.messages?.validate ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u043F\u0440\u043E\u0448\u043B\u043E \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044E");
110
+ return false;
111
+ }
112
+ if (typeof result === "string") {
113
+ this._errors.push(result);
114
+ return false;
115
+ }
116
+ }
117
+ return true;
118
+ }
119
+ checkAndSetValid(form) {
120
+ this.isValid = this.checkValid(form);
121
+ return this.isValid;
122
+ }
123
+ get isEmpty() {
124
+ let isEmpty = false;
125
+ if (this._rawValue === null || this._rawValue === void 0) isEmpty = true;
126
+ else if (this._rawValue === "") isEmpty = true;
127
+ else if (Array.isArray(this._rawValue) && this._rawValue.length === 0) isEmpty = true;
128
+ return isEmpty;
129
+ }
130
+ // ========== Вспомогательные методы ==========
131
+ reset() {
132
+ if (this.defaultValue !== null && this.defaultValue !== void 0) {
133
+ this.rawValue = this.defaultValue;
134
+ this.isValid = true;
135
+ } else {
136
+ this._rawValue = null;
137
+ this._valueClear = null;
138
+ this.isValid = null;
139
+ }
140
+ this._errors = [];
141
+ this.isTouched = false;
142
+ }
143
+ };
144
+
145
+ // src/core/fields/ArrayField.ts
146
+ var ArrayField = class {
147
+ constructor(factory, options = {}, initial = []) {
148
+ this.factory = factory;
149
+ this._items = [];
150
+ this._errors = [];
151
+ this.isTouched = false;
152
+ this.options = {
153
+ isRequired: true,
154
+ messages: {},
155
+ ...options
156
+ };
157
+ this._items = initial.map((v) => this.factory(v));
158
+ }
159
+ // ===== value =====
160
+ set itemsValue(items) {
161
+ this.clear();
162
+ for (const i of items) {
163
+ this.add(i, false);
164
+ }
165
+ this.checkValid();
166
+ }
167
+ get itemsValue() {
168
+ return this._items.map((i) => i.valueClear);
169
+ }
170
+ get items() {
171
+ return this._items;
172
+ }
173
+ // ===== actions =====
174
+ add(value, force_check) {
175
+ const field = this.factory(value);
176
+ this.isTouched = true;
177
+ this._items.push(field);
178
+ if (force_check) this.checkValid();
179
+ return field;
180
+ }
181
+ remove(index) {
182
+ this._items.splice(index, 1);
183
+ this.checkValid();
184
+ }
185
+ clear() {
186
+ this._items = [];
187
+ this.checkValid();
188
+ }
189
+ // ===== validation =====
190
+ isRequired(form) {
191
+ let isRequired;
192
+ if (typeof this.options.isRequired === "function") {
193
+ isRequired = this.options.isRequired(form ?? null);
194
+ } else {
195
+ isRequired = this.options.isRequired ?? false;
196
+ }
197
+ return isRequired;
198
+ }
199
+ checkValid(form) {
200
+ this._errors = [];
201
+ if (this.isRequired(form) && this._items.length === 0) {
202
+ this._errors.push(
203
+ 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"
204
+ );
205
+ return false;
206
+ }
207
+ if (this.options.minItems != null && this._items.length < this.options.minItems) {
208
+ this._errors.push(
209
+ this.options.messages?.minItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minItems}`
210
+ );
211
+ return false;
212
+ }
213
+ if (this.options.maxItems != null && this._items.length > this.options.maxItems) {
214
+ this._errors.push(
215
+ this.options.messages?.maxItems ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxItems}`
216
+ );
217
+ return false;
218
+ }
219
+ let valid = true;
220
+ for (const field of this._items) {
221
+ const ok = field.checkAndSetValid(form);
222
+ if (!ok) valid = false;
223
+ }
224
+ if (this.options.validate) {
225
+ const result = this.options.validate(this._items, form);
226
+ if (result === false) {
227
+ this._errors.push(
228
+ this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
229
+ );
230
+ return false;
231
+ }
232
+ if (typeof result === "string") {
233
+ this._errors.push(result);
234
+ return false;
235
+ }
236
+ }
237
+ return valid && this._errors.length === 0;
238
+ }
239
+ checkAndSetValid(form) {
240
+ return this.checkValid(form);
241
+ }
242
+ get isValid() {
243
+ return this._errors.length === 0 && this._items.every((i) => i.isValid === true);
244
+ }
245
+ get error() {
246
+ return this._errors[0] ?? "";
247
+ }
248
+ set error(message) {
249
+ if (message) {
250
+ this._errors = [message];
251
+ } else {
252
+ this._errors = [];
253
+ }
254
+ }
255
+ get errors() {
256
+ return this._errors;
257
+ }
258
+ reset() {
259
+ this._items.forEach((i) => i.reset());
260
+ this._errors = [];
261
+ this.isTouched = false;
262
+ }
263
+ };
264
+
265
+ // src/core/fields/ArrayFormField.ts
266
+ var ArrayFormField = class {
267
+ constructor(FormConstructor, options = {}, initial = []) {
268
+ this.FormConstructor = FormConstructor;
269
+ this.options = options;
270
+ this._forms = [];
271
+ this._errors = [];
272
+ this.isTouched = false;
273
+ this._forms = initial.map((data) => {
274
+ const form = new this.FormConstructor();
275
+ form.fields = data;
276
+ return form;
277
+ });
278
+ }
279
+ // ===== value =====
280
+ set forms(forms) {
281
+ this.clear();
282
+ for (const f of forms) {
283
+ this.add(f, false);
284
+ }
285
+ this.checkValid();
286
+ }
287
+ get forms() {
288
+ return this._forms;
289
+ }
290
+ get formsFieldsValue() {
291
+ return this._forms.map((i) => i.fieldsValue);
292
+ }
293
+ // ===== actions =====
294
+ add(data, force_check) {
295
+ const form = new this.FormConstructor();
296
+ if (data) form.fields = data;
297
+ this.isTouched = true;
298
+ this._forms.push(form);
299
+ if (force_check) this.checkValid();
300
+ return form;
301
+ }
302
+ remove(index) {
303
+ this._forms.splice(index, 1);
304
+ this.checkValid();
305
+ }
306
+ clear() {
307
+ this._forms = [];
308
+ this.checkValid();
309
+ }
310
+ reset() {
311
+ this._forms.forEach((f) => f.reset());
312
+ this._errors = [];
313
+ this.isTouched = false;
314
+ }
315
+ // ===== validation =====
316
+ isRequired(form) {
317
+ let isRequired;
318
+ if (typeof this.options.isRequired === "function") {
319
+ isRequired = this.options.isRequired(form ?? null);
320
+ } else {
321
+ isRequired = this.options.isRequired ?? false;
322
+ }
323
+ return isRequired;
324
+ }
325
+ checkValid(form) {
326
+ this._errors = [];
327
+ if (this.isRequired(form) && this.forms.length === 0) {
328
+ this._errors.push(
329
+ 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"
330
+ );
331
+ return false;
332
+ }
333
+ if (this.options.minForms != null && this._forms.length < this.options.minForms) {
334
+ this._errors.push(
335
+ this.options.messages?.minForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.minForms}`
336
+ );
337
+ return false;
338
+ }
339
+ if (this.options.maxForms != null && this._forms.length > this.options.maxForms) {
340
+ this._errors.push(
341
+ this.options.messages?.maxForms ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.maxForms}`
342
+ );
343
+ return false;
344
+ }
345
+ let valid = true;
346
+ for (const form2 of this.forms) {
347
+ const ok = form2.checkValid(form2);
348
+ if (!ok) valid = false;
349
+ }
350
+ if (this.options.validate) {
351
+ const result = this.options.validate(this.forms, form);
352
+ if (result === false) {
353
+ this._errors.push(
354
+ this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
355
+ );
356
+ return false;
357
+ }
358
+ if (typeof result === "string") {
359
+ this._errors.push(result);
360
+ return false;
361
+ }
362
+ }
363
+ return valid && this._errors.length === 0;
364
+ }
365
+ checkAndSetValid(form) {
366
+ return this.checkValid(form);
367
+ }
368
+ get isValid() {
369
+ return this._errors.length === 0 && this._forms.every((i) => i.checkValid() === true);
370
+ }
371
+ get errors() {
372
+ return this._errors;
373
+ }
374
+ get error() {
375
+ return this._errors[0] ?? "";
376
+ }
377
+ set error(message) {
378
+ if (message) {
379
+ this._errors = [message];
380
+ } else {
381
+ this._errors = [];
382
+ }
383
+ }
384
+ };
385
+
386
+ // src/core/Form.ts
387
+ var Form = class {
388
+ constructor() {
389
+ this._globalErrors = {};
390
+ }
391
+ get _fields() {
392
+ const fields = {};
393
+ for (const key of Object.keys(this)) {
394
+ const property = this[key];
395
+ if (property instanceof Field || property instanceof ArrayField || property instanceof ArrayFormField) {
396
+ fields[key] = property;
397
+ }
398
+ }
399
+ return fields;
400
+ }
401
+ checkValid(form) {
402
+ let isFormValid = true;
403
+ const fields = this._fields;
404
+ for (const key of Object.keys(fields)) {
405
+ const field = fields[key];
406
+ if (!field.checkAndSetValid(form ?? this)) {
407
+ isFormValid = false;
408
+ }
409
+ }
410
+ return isFormValid;
411
+ }
412
+ get fieldsValue() {
413
+ const data = {};
414
+ const fields = this._fields;
415
+ for (const key of Object.keys(fields)) {
416
+ let valueClear = null;
417
+ const field = fields[key];
418
+ if (field instanceof Field) valueClear = field.valueClear;
419
+ else if (field instanceof ArrayField) valueClear = field.itemsValue;
420
+ else if (field instanceof ArrayFormField) valueClear = field.formsFieldsValue;
421
+ else console.error(`Invalid field "${key}" type`);
422
+ data[key] = valueClear;
423
+ }
424
+ return data;
425
+ }
426
+ set fields(data) {
427
+ const fields = this._fields;
428
+ for (const key of Object.keys(data)) {
429
+ const field = fields[key];
430
+ if (field) {
431
+ if (field instanceof Field) field.rawValue = data[key];
432
+ else if (field instanceof ArrayField) field.itemsValue = data[key];
433
+ else if (field instanceof ArrayFormField) field.forms = data[key];
434
+ else console.error(`Invalid field "${key}" type`);
435
+ }
436
+ }
437
+ }
438
+ get allErrors() {
439
+ const errors = {};
440
+ const fields = this._fields;
441
+ for (const key of Object.keys(fields)) {
442
+ const fieldErrors = fields[key].errors;
443
+ if (fieldErrors.length > 0) {
444
+ errors[key] = fieldErrors;
445
+ }
446
+ }
447
+ for (const key of Object.keys(this._globalErrors)) {
448
+ if (!errors[key]) {
449
+ errors[key] = [];
450
+ }
451
+ errors[key].push(this._globalErrors[key]);
452
+ }
453
+ return errors;
454
+ }
455
+ get globalErrors() {
456
+ return { ...this._globalErrors };
457
+ }
458
+ set errors(errors) {
459
+ const fields = this._fields;
460
+ this._globalErrors = {};
461
+ for (const key of Object.keys(errors)) {
462
+ const keys = key.split(".");
463
+ const cleanKey = keys.length > 1 ? keys[1] : key;
464
+ if (cleanKey in fields && fields[cleanKey]) {
465
+ fields[cleanKey].error = errors[key];
466
+ } else {
467
+ this._globalErrors[key] = errors[key];
468
+ }
469
+ }
470
+ }
471
+ setGlobalError(key, message) {
472
+ this._globalErrors[key] = message;
473
+ }
474
+ clearGlobalErrors() {
475
+ this._globalErrors = {};
476
+ }
477
+ reset() {
478
+ const fields = this._fields;
479
+ for (const key of Object.keys(fields)) {
480
+ fields[key].reset();
481
+ }
482
+ this._globalErrors = {};
483
+ }
484
+ get isTouched() {
485
+ const fields = this._fields;
486
+ for (const key of Object.keys(fields)) {
487
+ if (fields[key].isTouched) return true;
488
+ }
489
+ return false;
490
+ }
491
+ // Проверить, валидна ли форма
492
+ get isValid() {
493
+ const fields = this._fields;
494
+ for (const key of Object.keys(fields)) {
495
+ if (fields[key].isValid !== true) return false;
496
+ }
497
+ return Object.keys(this._globalErrors).length === 0;
498
+ }
499
+ // Получить все значения в виде FormData (для отправки на сервер)
500
+ toFormData() {
501
+ const formData = new FormData();
502
+ const data = this.fieldsValue;
503
+ for (const [key, value] of Object.entries(data)) {
504
+ if (value instanceof Date) {
505
+ formData.append(key, value.toISOString());
506
+ } else if (value !== null && value !== void 0) {
507
+ formData.append(key, String(value));
508
+ }
509
+ }
510
+ return formData;
511
+ }
512
+ // Получить все значения в виде JSON
513
+ toJSON() {
514
+ const data = this.fieldsValue;
515
+ const json = {};
516
+ for (const [key, value] of Object.entries(data)) {
517
+ if (value instanceof Date) {
518
+ json[key] = value.toISOString();
519
+ } else {
520
+ json[key] = value;
521
+ }
522
+ }
523
+ return json;
524
+ }
525
+ };
526
+
3
527
  // src/core/plugins/FieldPlugin.ts
4
528
  var BasePlugin = class {
5
529
  constructor(pluginOptions = {}) {
@@ -10,6 +534,188 @@ var BasePlugin = class {
10
534
  }
11
535
  };
12
536
 
537
+ // src/core/plugins/MaskPlugin.ts
538
+ var MaskPlugin = class extends BasePlugin {
539
+ constructor(config, pluginOptions) {
540
+ super(pluginOptions);
541
+ this.maskParts = [];
542
+ this.config = config;
543
+ }
544
+ init(field) {
545
+ this.parseMask();
546
+ }
547
+ toRawValue(value, field) {
548
+ return this.applyMask(value);
549
+ }
550
+ toValueClear(value, field) {
551
+ return this.removeMask(value);
552
+ }
553
+ parseMask() {
554
+ this.maskParts = [];
555
+ let i = 0;
556
+ let escaped = false;
557
+ while (i < this.config.maskFormat.length) {
558
+ const char = this.config.maskFormat[i];
559
+ if (char === "/" && !escaped) {
560
+ escaped = true;
561
+ i++;
562
+ continue;
563
+ }
564
+ if (char === this.config.maskPlaceholder && i + 1 < this.config.maskFormat.length && this.config.maskFormat[i + 1] === "{" && !escaped) {
565
+ const openBracket = i + 1;
566
+ const closeBracket = this.config.maskFormat.indexOf("}", openBracket);
567
+ if (closeBracket !== -1 && closeBracket > openBracket + 1) {
568
+ const configString = this.config.maskFormat.substring(openBracket + 1, closeBracket).trim();
569
+ if (configString.includes(">")) {
570
+ const parts = configString.split(">");
571
+ const allowedChars = parts[0].trim();
572
+ const replacementOnMatch = parts[1]?.trim() || "";
573
+ let replacementOnMismatch = parts[2]?.trim() || "";
574
+ let pushToNext = false;
575
+ if (parts.length > 2 && parts[2] === "" && parts[3] !== void 0) {
576
+ pushToNext = true;
577
+ replacementOnMismatch = parts[3]?.trim() || "";
578
+ } else if (replacementOnMismatch === "" && parts.length > 3) {
579
+ pushToNext = true;
580
+ replacementOnMismatch = parts[3]?.trim() || "";
581
+ }
582
+ this.maskParts.push({
583
+ char: replacementOnMatch || this.config.maskPlaceholder,
584
+ isPlaceholder: true,
585
+ isEscaped: escaped,
586
+ allowedChars,
587
+ transformOnMatch: replacementOnMatch,
588
+ transformOnMismatch: replacementOnMismatch,
589
+ defaultValue: replacementOnMatch,
590
+ pushToNext
591
+ });
592
+ } else {
593
+ this.maskParts.push({
594
+ char: configString,
595
+ isPlaceholder: true,
596
+ isEscaped: escaped,
597
+ replacementValue: configString,
598
+ defaultValue: configString
599
+ });
600
+ }
601
+ escaped = false;
602
+ i = closeBracket + 1;
603
+ continue;
604
+ }
605
+ }
606
+ const isPlaceholder = char === this.config.maskPlaceholder;
607
+ this.maskParts.push({
608
+ char,
609
+ isPlaceholder,
610
+ isEscaped: escaped
611
+ });
612
+ escaped = false;
613
+ i++;
614
+ }
615
+ }
616
+ applyMask(value) {
617
+ if (typeof value !== "string" || !value) return "";
618
+ let result = "";
619
+ let inputIndex = 0;
620
+ for (let maskIndex = 0; maskIndex < this.maskParts.length; maskIndex++) {
621
+ const part = this.maskParts[maskIndex];
622
+ if (inputIndex >= value.length) {
623
+ if (part.replacementValue) {
624
+ result += part.replacementValue;
625
+ continue;
626
+ }
627
+ if (part.transformOnMatch) {
628
+ result += part.transformOnMatch;
629
+ continue;
630
+ }
631
+ break;
632
+ }
633
+ const inputChar = value[inputIndex];
634
+ if (part.isPlaceholder) {
635
+ if (part.replacementValue) {
636
+ result += part.replacementValue;
637
+ inputIndex++;
638
+ } else if (part.allowedChars) {
639
+ if (part.allowedChars.includes(inputChar)) {
640
+ result += part.transformOnMatch || inputChar;
641
+ inputIndex++;
642
+ } else if (part.pushToNext) {
643
+ result += part.transformOnMismatch || this.config.maskPlaceholder;
644
+ } else if (part.transformOnMismatch !== void 0) {
645
+ result += part.transformOnMismatch || this.config.maskPlaceholder;
646
+ inputIndex++;
647
+ } else {
648
+ result += this.config.maskPlaceholder;
649
+ }
650
+ } else {
651
+ if (this.config.digitPattern.test(inputChar)) {
652
+ result += inputChar;
653
+ inputIndex++;
654
+ } else if (inputChar === this.config.maskPlaceholder) {
655
+ result += this.config.maskPlaceholder;
656
+ inputIndex++;
657
+ } else {
658
+ inputIndex++;
659
+ maskIndex--;
660
+ }
661
+ }
662
+ } else {
663
+ if (inputChar === part.char) {
664
+ result += part.char;
665
+ inputIndex++;
666
+ } else if (this.config.digitPattern.test(inputChar)) {
667
+ result += part.char;
668
+ } else {
669
+ result += part.char;
670
+ }
671
+ }
672
+ }
673
+ return result;
674
+ }
675
+ removeMask(value) {
676
+ if (typeof value !== "string" || !value) return "";
677
+ let result = "";
678
+ let inputIndex = 0;
679
+ for (let maskIndex = 0; maskIndex < this.maskParts.length; maskIndex++) {
680
+ const part = this.maskParts[maskIndex];
681
+ if (inputIndex >= value.length) {
682
+ if (part.replacementValue) {
683
+ result += part.replacementValue;
684
+ } else if (part.transformOnMatch) {
685
+ result += part.transformOnMatch;
686
+ }
687
+ continue;
688
+ }
689
+ const inputChar = value[inputIndex];
690
+ if (part.isPlaceholder) {
691
+ if (part.replacementValue) {
692
+ result += part.replacementValue;
693
+ } else if (part.allowedChars) {
694
+ if (part.allowedChars.includes(inputChar)) {
695
+ result += part.transformOnMatch || inputChar;
696
+ } else if (part.pushToNext) {
697
+ result += part.transformOnMismatch || "";
698
+ continue;
699
+ } else {
700
+ result += part.transformOnMatch || "";
701
+ }
702
+ } else {
703
+ if (inputChar !== this.config.maskPlaceholder && this.config.digitPattern.test(inputChar)) {
704
+ result += inputChar;
705
+ }
706
+ }
707
+ inputIndex++;
708
+ } else if (part.isEscaped) {
709
+ result += part.char;
710
+ if (inputChar === part.char) inputIndex++;
711
+ } else {
712
+ if (inputChar === part.char) inputIndex++;
713
+ }
714
+ }
715
+ return result;
716
+ }
717
+ };
718
+
13
719
  // src/core/types/FieldType.ts
14
720
  var FieldType = class {
15
721
  constructor(options) {
@@ -21,6 +727,197 @@ var FieldType = class {
21
727
  }
22
728
  };
23
729
 
730
+ // src/core/types/StringType.ts
731
+ var StringType = class extends FieldType {
732
+ cast(rawValue) {
733
+ if (rawValue === null || rawValue === void 0) return null;
734
+ if (typeof rawValue === "string") return rawValue;
735
+ return String(rawValue);
736
+ }
737
+ validate(value) {
738
+ const errors = [];
739
+ if (this.options.minLength != null && value.length < this.options.minLength) {
740
+ errors.push(
741
+ this.options.messages?.minLength ?? `\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 ${this.options.minLength} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432`
742
+ );
743
+ }
744
+ if (this.options.maxLength != null && value.length > this.options.maxLength) {
745
+ errors.push(
746
+ 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`
747
+ );
748
+ }
749
+ if (this.options.pattern != null && !this.options.pattern.test(value)) {
750
+ errors.push(this.options.messages?.pattern ?? "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442");
751
+ }
752
+ return errors;
753
+ }
754
+ getTypeName() {
755
+ return "\u0441\u0442\u0440\u043E\u043A\u0430";
756
+ }
757
+ };
758
+
759
+ // src/core/types/NumberType.ts
760
+ var NumberType = class extends FieldType {
761
+ cast(rawValue) {
762
+ if (rawValue === null || rawValue === void 0) return null;
763
+ if (typeof rawValue === "number" && !isNaN(rawValue)) return rawValue;
764
+ if (typeof rawValue === "string") {
765
+ const num = Number(rawValue);
766
+ return isNaN(num) ? null : num;
767
+ }
768
+ return null;
769
+ }
770
+ validate(value) {
771
+ const errors = [];
772
+ if (!Number.isInteger(value)) {
773
+ 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");
774
+ }
775
+ if (this.options.gt != null && value <= this.options.gt) {
776
+ errors.push(
777
+ this.options.messages?.gt ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.gt}`
778
+ );
779
+ }
780
+ if (this.options.ge != null && value < this.options.ge) {
781
+ errors.push(
782
+ this.options.messages?.ge ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 ${this.options.ge}`
783
+ );
784
+ }
785
+ if (this.options.lt != null && value >= this.options.lt) {
786
+ errors.push(
787
+ this.options.messages?.lt ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.lt}`
788
+ );
789
+ }
790
+ if (this.options.le != null && value > this.options.le) {
791
+ errors.push(
792
+ this.options.messages?.le ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 ${this.options.le}`
793
+ );
794
+ }
795
+ return errors;
796
+ }
797
+ getTypeName() {
798
+ return "\u0447\u0438\u0441\u043B\u043E";
799
+ }
800
+ };
801
+
802
+ // src/core/types/DecimalType.ts
803
+ var DecimalType = class extends FieldType {
804
+ constructor(options = {}) {
805
+ super({
806
+ decimalPlaces: 2,
807
+ maxDigits: 8,
808
+ ...options
809
+ });
810
+ }
811
+ cast(rawValue) {
812
+ if (rawValue === null || rawValue === void 0) return null;
813
+ if (typeof rawValue === "string") {
814
+ return this.castString(rawValue);
815
+ }
816
+ if (typeof rawValue === "number" && !isNaN(rawValue)) {
817
+ return rawValue;
818
+ }
819
+ return null;
820
+ }
821
+ castString(value) {
822
+ const trimmed = value.trim();
823
+ if (!trimmed) return null;
824
+ const normalized = trimmed.replace(",", ".");
825
+ if (!this.isValidNumberString(normalized)) {
826
+ return null;
827
+ }
828
+ return normalized;
829
+ }
830
+ validate(value) {
831
+ const errors = [];
832
+ value = typeof value === "number" ? this.numberToString(value) : value;
833
+ if (!this.isValidNumberString(value)) {
834
+ errors.push(this.options.messages?.invalid ?? "\u041F\u0440\u0438\u043C\u0435\u0440: 1.00");
835
+ return errors;
836
+ }
837
+ const maxDigits = this.options.maxDigits || 8;
838
+ const decimalPlaces = this.options.decimalPlaces || 2;
839
+ const maxIntDigits = maxDigits - decimalPlaces;
840
+ const isNegative = value.startsWith("-");
841
+ const normalizedValue = isNegative ? value.substring(1) : value;
842
+ const parts = normalizedValue.split(".");
843
+ const intPart = parts[0];
844
+ const decPart = parts.length > 1 ? parts[1] : "";
845
+ if (normalizedValue.endsWith(".")) {
846
+ if (intPart.length > maxIntDigits) {
847
+ errors.push(
848
+ this.options.messages?.maxDigits ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0437\u043D\u0430\u043A\u043E\u0432 \u043F\u0435\u0440\u0435\u0434 \u0437\u0430\u043F\u044F\u0442\u043E\u0439 ${maxIntDigits}`
849
+ );
850
+ }
851
+ return errors;
852
+ }
853
+ if (intPart.length === 0) {
854
+ errors.push(this.options.messages?.invalid ?? "\u041F\u0440\u0438\u043C\u0435\u0440: 1.00");
855
+ return errors;
856
+ }
857
+ if (intPart.length > maxIntDigits) {
858
+ errors.push(
859
+ this.options.messages?.maxDigits ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0437\u043D\u0430\u043A\u043E\u0432 \u043F\u0435\u0440\u0435\u0434 \u0437\u0430\u043F\u044F\u0442\u043E\u0439 ${maxIntDigits}`
860
+ );
861
+ }
862
+ if (parts.length === 2) {
863
+ if (intPart.length + decPart.length > maxDigits) {
864
+ errors.push(
865
+ this.options.messages?.maxDigits ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0437\u043D\u0430\u043A\u043E\u0432 ${maxDigits}`
866
+ );
867
+ }
868
+ if (decPart.length === 0) {
869
+ errors.push(
870
+ this.options.messages?.invalid ?? "\u041F\u043E\u0441\u043B\u0435 \u0442\u043E\u0447\u043A\u0438 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043C\u0438\u043D\u0438\u043C\u0443\u043C 1 \u0437\u043D\u0430\u043A"
871
+ );
872
+ } else if (decPart.length > decimalPlaces) {
873
+ errors.push(
874
+ this.options.messages?.decimalPlaces ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0437\u043D\u0430\u043A\u043E\u0432 \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u043F\u044F\u0442\u043E\u0439 ${decimalPlaces}`
875
+ );
876
+ }
877
+ }
878
+ if (errors.length > 0) return errors;
879
+ if (!value.endsWith(".")) {
880
+ const numValue = parseFloat(value);
881
+ if (!isNaN(numValue)) {
882
+ if (this.options.gt != null && numValue <= this.options.gt) {
883
+ errors.push(
884
+ this.options.messages?.gt ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0431\u043E\u043B\u044C\u0448\u0435 ${this.options.gt}`
885
+ );
886
+ }
887
+ if (this.options.ge != null && numValue < this.options.ge) {
888
+ errors.push(
889
+ this.options.messages?.ge ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 ${this.options.ge}`
890
+ );
891
+ }
892
+ if (this.options.lt != null && numValue >= this.options.lt) {
893
+ errors.push(
894
+ this.options.messages?.lt ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043C\u0435\u043D\u044C\u0448\u0435 ${this.options.lt}`
895
+ );
896
+ }
897
+ if (this.options.le != null && numValue > this.options.le) {
898
+ errors.push(
899
+ this.options.messages?.le ?? `\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 ${this.options.le}`
900
+ );
901
+ }
902
+ }
903
+ }
904
+ return errors;
905
+ }
906
+ isValidNumberString(value) {
907
+ const pattern = /^-?\d+\.?\d*$/;
908
+ const dotCount = (value.match(/\./g) || []).length;
909
+ if (dotCount > 1) return false;
910
+ return pattern.test(value);
911
+ }
912
+ numberToString(value) {
913
+ const decimalPlaces = this.options.decimalPlaces;
914
+ return value.toFixed(decimalPlaces);
915
+ }
916
+ getTypeName() {
917
+ return "\u0434\u0435\u0441\u044F\u0442\u0438\u0447\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E";
918
+ }
919
+ };
920
+
24
921
  // src/core/types/BooleanType.ts
25
922
  var BooleanType = class extends FieldType {
26
923
  cast(rawValue) {
@@ -51,14 +948,78 @@ var BooleanType = class extends FieldType {
51
948
  }
52
949
  };
53
950
 
951
+ // src/core/types/DateType.ts
952
+ var DateType = class extends FieldType {
953
+ constructor(options = {}) {
954
+ super(options);
955
+ }
956
+ cast(rawValue) {
957
+ if (rawValue === null || rawValue === void 0) return null;
958
+ if (rawValue instanceof Date) {
959
+ return isNaN(rawValue.getTime()) ? null : rawValue;
960
+ }
961
+ if (typeof rawValue === "string") {
962
+ const date = new Date(rawValue);
963
+ return isNaN(date.getTime()) ? null : date;
964
+ }
965
+ return null;
966
+ }
967
+ validate(value) {
968
+ const errors = [];
969
+ if (isNaN(value.getTime())) {
970
+ errors.push(this.options.messages?.invalid ?? "\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u0434\u0430\u0442\u0430");
971
+ return errors;
972
+ }
973
+ if (this.options.minDate) {
974
+ if (!this.compareDates(value, this.options.minDate, "min")) {
975
+ errors.push(
976
+ this.options.messages?.minDate ?? `\u0414\u0430\u0442\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u0440\u0430\u043D\u0435\u0435 ${this.options.minDate.toLocaleDateString()}`
977
+ );
978
+ }
979
+ }
980
+ if (this.options.maxDate) {
981
+ if (!this.compareDates(value, this.options.maxDate, "max")) {
982
+ errors.push(
983
+ this.options.messages?.maxDate ?? `\u0414\u0430\u0442\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u043F\u043E\u0437\u0434\u043D\u0435\u0435 ${this.options.maxDate.toLocaleDateString()}`
984
+ );
985
+ }
986
+ }
987
+ return errors;
988
+ }
989
+ getTypeName() {
990
+ return this.options.isDatetime ? "\u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F" : "\u0434\u0430\u0442\u0430";
991
+ }
992
+ // Сравнение дат с учётом времени
993
+ compareDates(value, boundary, type) {
994
+ if (this.options.isDatetime) {
995
+ if (type === "min") {
996
+ return value >= boundary;
997
+ } else {
998
+ return value <= boundary;
999
+ }
1000
+ } else {
1001
+ const valueDate = this.toDateOnly(value);
1002
+ const boundaryDate = this.toDateOnly(boundary);
1003
+ if (type === "min") {
1004
+ return valueDate >= boundaryDate;
1005
+ } else {
1006
+ return valueDate <= boundaryDate;
1007
+ }
1008
+ }
1009
+ }
1010
+ toDateOnly(date) {
1011
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
1012
+ }
1013
+ };
1014
+
54
1015
  // src/core/utils/luxon-loader.ts
55
- var DateTime = null;
1016
+ var DateTimeConstructor = null;
56
1017
  var isLoading = false;
57
1018
  var loadError = null;
58
1019
  var loadPromise = null;
59
- function getDateTime() {
60
- if (DateTime) {
61
- return DateTime;
1020
+ function getDateTimeConstructor() {
1021
+ if (DateTimeConstructor) {
1022
+ return DateTimeConstructor;
62
1023
  }
63
1024
  if (loadError) {
64
1025
  throw loadError;
@@ -69,12 +1030,12 @@ function getDateTime() {
69
1030
  );
70
1031
  }
71
1032
  throw new Error(
72
- "Luxon is not initialized. Call initLuxon() first or install: npm install luxon"
1033
+ "Luxon is not initialized. Install: npm install luxon"
73
1034
  );
74
1035
  }
75
1036
  function initLuxon() {
76
- if (DateTime) {
77
- return Promise.resolve(DateTime);
1037
+ if (DateTimeConstructor) {
1038
+ return Promise.resolve(DateTimeConstructor);
78
1039
  }
79
1040
  if (loadPromise) {
80
1041
  return loadPromise;
@@ -83,11 +1044,11 @@ function initLuxon() {
83
1044
  loadPromise = (async () => {
84
1045
  try {
85
1046
  const luxon = await import('luxon');
86
- DateTime = luxon.DateTime;
87
- return DateTime;
1047
+ DateTimeConstructor = luxon.DateTime;
1048
+ return DateTimeConstructor;
88
1049
  } catch (error) {
89
1050
  loadError = new Error(
90
- 'DateLuxonType requires the "luxon" package to be installed.\nPlease install it by running:\n\n npm install luxon\n # or\n yarn add luxon\n # or\n pnpm add luxon\n'
1051
+ 'DateLuxonType requires the "luxon" package to be installed.\nInstall: npm install luxon'
91
1052
  );
92
1053
  throw loadError;
93
1054
  } finally {
@@ -97,10 +1058,10 @@ function initLuxon() {
97
1058
  return loadPromise;
98
1059
  }
99
1060
  function isLuxonAvailable() {
100
- return DateTime !== null;
1061
+ return DateTimeConstructor !== null;
101
1062
  }
102
1063
  function resetLuxon() {
103
- DateTime = null;
1064
+ DateTimeConstructor = null;
104
1065
  isLoading = false;
105
1066
  loadError = null;
106
1067
  loadPromise = null;
@@ -108,9 +1069,19 @@ function resetLuxon() {
108
1069
  initLuxon().catch(() => {
109
1070
  });
110
1071
 
1072
+ exports.ArrayField = ArrayField;
1073
+ exports.ArrayFormField = ArrayFormField;
111
1074
  exports.BasePlugin = BasePlugin;
112
1075
  exports.BooleanType = BooleanType;
113
- exports.getDateTime = getDateTime;
1076
+ exports.DateType = DateType;
1077
+ exports.DecimalType = DecimalType;
1078
+ exports.Field = Field;
1079
+ exports.FieldType = FieldType;
1080
+ exports.Form = Form;
1081
+ exports.MaskPlugin = MaskPlugin;
1082
+ exports.NumberType = NumberType;
1083
+ exports.StringType = StringType;
1084
+ exports.getDateTimeConstructor = getDateTimeConstructor;
114
1085
  exports.initLuxon = initLuxon;
115
1086
  exports.isLuxonAvailable = isLuxonAvailable;
116
1087
  exports.resetLuxon = resetLuxon;