@reformer/core 2.0.0-beta.6 → 2.0.0-beta.8
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/behaviors/compute-from.d.ts +2 -0
- package/dist/behaviors/compute-from.js +31 -0
- package/dist/behaviors/copy-from.d.ts +2 -0
- package/dist/behaviors/copy-from.js +29 -0
- package/dist/behaviors/enable-when.d.ts +2 -0
- package/dist/behaviors/enable-when.js +25 -0
- package/dist/behaviors/reset-when.d.ts +2 -0
- package/dist/behaviors/reset-when.js +24 -0
- package/dist/behaviors/revalidate-when.d.ts +2 -0
- package/dist/behaviors/revalidate-when.js +18 -0
- package/dist/behaviors/sync-fields.d.ts +2 -0
- package/dist/behaviors/sync-fields.js +41 -0
- package/dist/behaviors/transform-value.d.ts +2 -0
- package/dist/behaviors/transform-value.js +45 -0
- package/dist/behaviors/watch-field.d.ts +2 -0
- package/dist/behaviors/watch-field.js +21 -0
- package/dist/behaviors.js +26 -19
- package/dist/core/behavior/behavior-context.d.ts +26 -12
- package/dist/core/behavior/behavior-registry.d.ts +15 -27
- package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
- package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
- package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
- package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
- package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
- package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
- package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
- package/dist/core/behavior/compose-behavior.d.ts +2 -12
- package/dist/core/behavior/index.d.ts +0 -1
- package/dist/core/behavior/types.d.ts +2 -8
- package/dist/core/factories/node-factory.d.ts +6 -29
- package/dist/core/nodes/array-node.d.ts +39 -19
- package/dist/core/nodes/field-node.d.ts +43 -24
- package/dist/core/nodes/form-node.d.ts +18 -20
- package/dist/core/nodes/group-node.d.ts +25 -21
- package/dist/core/types/deep-schema.d.ts +2 -12
- package/dist/core/types/field-path.d.ts +1 -1
- package/dist/core/types/form-context.d.ts +26 -26
- package/dist/core/types/form-proxy.d.ts +2 -32
- package/dist/core/types/index.d.ts +16 -4
- package/dist/core/types/validation-schema.d.ts +3 -12
- package/dist/core/utils/abstract-registry.d.ts +74 -0
- package/dist/core/utils/aggregate-signals.d.ts +71 -0
- package/dist/core/utils/create-form.d.ts +1 -18
- package/dist/core/utils/error-handler.d.ts +1 -18
- package/dist/core/utils/field-path-navigator.d.ts +1 -1
- package/dist/core/utils/field-path.d.ts +23 -11
- package/dist/core/utils/form-observer.d.ts +176 -0
- package/dist/core/utils/form-proxy-builder.d.ts +25 -0
- package/dist/core/utils/form-submitter.d.ts +121 -0
- package/dist/core/utils/index.d.ts +9 -2
- package/dist/core/utils/registry-helpers.d.ts +0 -7
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/type-guards.d.ts +5 -23
- package/dist/core/utils/unique-id.d.ts +53 -0
- package/dist/core/validation/core/apply-when.d.ts +3 -9
- package/dist/core/validation/core/apply.d.ts +2 -13
- package/dist/core/validation/core/validate-async.d.ts +2 -8
- package/dist/core/validation/core/validate-tree.d.ts +0 -6
- package/dist/core/validation/core/validate.d.ts +1 -7
- package/dist/core/validation/index.d.ts +8 -2
- package/dist/core/validation/validate-form.d.ts +1 -38
- package/dist/core/validation/validation-applicator.d.ts +2 -21
- package/dist/core/validation/validation-context.d.ts +58 -42
- package/dist/core/validation/validation-registry.d.ts +11 -25
- package/dist/core/validation/validators/array-validators.d.ts +2 -12
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +2 -9
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +7 -1
- package/dist/core/validation/validators/is-date.d.ts +36 -0
- package/dist/core/validation/validators/max-age.d.ts +36 -0
- package/dist/core/validation/validators/max-date.d.ts +36 -0
- package/dist/core/validation/validators/max-length.d.ts +3 -10
- package/dist/core/validation/validators/max.d.ts +3 -10
- package/dist/core/validation/validators/min-age.d.ts +36 -0
- package/dist/core/validation/validators/min-date.d.ts +36 -0
- package/dist/core/validation/validators/min-length.d.ts +3 -10
- package/dist/core/validation/validators/min.d.ts +3 -10
- package/dist/core/validation/validators/number.d.ts +2 -9
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +2 -9
- package/dist/core/validation/validators/phone.d.ts +2 -9
- package/dist/core/validation/validators/required.d.ts +2 -9
- package/dist/core/validation/validators/url.d.ts +2 -9
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +1 -1
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +4 -4
- package/dist/hooks/useFormControlValue.d.ts +2 -2
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +1 -1
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1100 -740
- package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
- package/dist/safe-effect-Dh8uw81c.js +20 -0
- package/dist/validate-C3XiA_zf.js +10 -0
- package/dist/validators/email.d.ts +2 -0
- package/dist/validators/email.js +13 -0
- package/dist/validators/future-date.d.ts +2 -0
- package/dist/validators/future-date.js +20 -0
- package/dist/validators/is-date.d.ts +2 -0
- package/dist/validators/is-date.js +12 -0
- package/dist/validators/max-age.d.ts +2 -0
- package/dist/validators/max-age.js +20 -0
- package/dist/validators/max-date.d.ts +2 -0
- package/dist/validators/max-date.js +20 -0
- package/dist/validators/max-length.d.ts +2 -0
- package/dist/validators/max-length.js +11 -0
- package/dist/validators/max.d.ts +2 -0
- package/dist/validators/max.js +11 -0
- package/dist/validators/min-age.d.ts +2 -0
- package/dist/validators/min-age.js +20 -0
- package/dist/validators/min-date.d.ts +2 -0
- package/dist/validators/min-date.js +20 -0
- package/dist/validators/min-length.d.ts +2 -0
- package/dist/validators/min-length.js +11 -0
- package/dist/validators/min.d.ts +2 -0
- package/dist/validators/min.js +11 -0
- package/dist/validators/number.d.ts +2 -0
- package/dist/validators/number.js +35 -0
- package/dist/validators/past-date.d.ts +2 -0
- package/dist/validators/past-date.js +20 -0
- package/dist/validators/pattern.d.ts +2 -0
- package/dist/validators/pattern.js +11 -0
- package/dist/validators/phone.d.ts +2 -0
- package/dist/validators/phone.js +35 -0
- package/dist/validators/required.d.ts +2 -0
- package/dist/validators/required.js +15 -0
- package/dist/validators/url.d.ts +2 -0
- package/dist/validators/url.js +19 -0
- package/dist/validators-BGsNOgT1.js +207 -0
- package/dist/validators.js +54 -29
- package/llms.txt +7878 -311
- package/package.json +83 -9
- package/dist/behaviors-2HSqHPb4.js +0 -508
- package/dist/core/behavior/create-field-path.d.ts +0 -7
- package/dist/core/context/form-context-impl.d.ts +0 -29
- package/dist/core/utils/debounce.d.ts +0 -160
- package/dist/core/utils/resources.d.ts +0 -41
- package/dist/core/validation/field-path.d.ts +0 -7
- package/dist/core/validation/validators/date.d.ts +0 -38
- package/dist/registry-helpers-BRxAr6nG.js +0 -490
- package/dist/validators-gXoHPdqM.js +0 -418
package/dist/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
|
|
1
|
+
import { signal as g, computed as d, effect as m, batch as j } from "@preact/signals-core";
|
|
2
|
+
import { F as S, E as V, V as K, B as H } from "./registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { A as ke, R as xe, b as Fe, g as Te } from "./registry-helpers-Bv_BJ1s-.js";
|
|
4
|
+
import { i as M, a as N, A as z, V as J, T as Y } from "./validators-BGsNOgT1.js";
|
|
5
|
+
import { g as Pe, c as Ce, d as De, v as Re, b as Me } from "./validators-BGsNOgT1.js";
|
|
6
|
+
import { c as I } from "./field-path-DuKdGcIE.js";
|
|
7
|
+
import { a as Ie, e as Le, t as Be } from "./field-path-DuKdGcIE.js";
|
|
8
|
+
import U, { useRef as P, useCallback as b, useSyncExternalStore as Q } from "react";
|
|
9
|
+
import { i as $e } from "./index-D25LsbRm.js";
|
|
10
|
+
import { r as We, s as qe, a as je } from "./safe-effect-Dh8uw81c.js";
|
|
11
|
+
class C {
|
|
10
12
|
// ============================================================================
|
|
11
13
|
// Protected состояние (для Template Method паттерна)
|
|
12
14
|
// ============================================================================
|
|
@@ -14,17 +16,17 @@ class F {
|
|
|
14
16
|
* Пользователь взаимодействовал с узлом (touched)
|
|
15
17
|
* Protected: наследники могут читать/изменять через методы
|
|
16
18
|
*/
|
|
17
|
-
_touched =
|
|
19
|
+
_touched = g(!1);
|
|
18
20
|
/**
|
|
19
21
|
* Значение узла было изменено (dirty)
|
|
20
22
|
* Protected: наследники могут читать/изменять через методы
|
|
21
23
|
*/
|
|
22
|
-
_dirty =
|
|
24
|
+
_dirty = g(!1);
|
|
23
25
|
/**
|
|
24
26
|
* Текущий статус узла
|
|
25
27
|
* Protected: наследники могут читать/изменять через методы
|
|
26
28
|
*/
|
|
27
|
-
_status =
|
|
29
|
+
_status = g("valid");
|
|
28
30
|
// ============================================================================
|
|
29
31
|
// Публичные computed signals (readonly для внешнего мира)
|
|
30
32
|
// ============================================================================
|
|
@@ -32,33 +34,33 @@ class F {
|
|
|
32
34
|
* Пользователь взаимодействовал с узлом (touched)
|
|
33
35
|
* Computed из _touched для предоставления readonly интерфейса
|
|
34
36
|
*/
|
|
35
|
-
touched =
|
|
37
|
+
touched = d(() => this._touched.value);
|
|
36
38
|
/**
|
|
37
39
|
* Пользователь не взаимодействовал с узлом (untouched)
|
|
38
40
|
*/
|
|
39
|
-
untouched =
|
|
41
|
+
untouched = d(() => !this._touched.value);
|
|
40
42
|
/**
|
|
41
43
|
* Значение узла было изменено (dirty)
|
|
42
44
|
* Computed из _dirty для предоставления readonly интерфейса
|
|
43
45
|
*/
|
|
44
|
-
dirty =
|
|
46
|
+
dirty = d(() => this._dirty.value);
|
|
45
47
|
/**
|
|
46
48
|
* Значение узла не было изменено (pristine)
|
|
47
49
|
*/
|
|
48
|
-
pristine =
|
|
50
|
+
pristine = d(() => !this._dirty.value);
|
|
49
51
|
/**
|
|
50
52
|
* Текущий статус узла
|
|
51
53
|
* Computed из _status для предоставления readonly интерфейса
|
|
52
54
|
*/
|
|
53
|
-
status =
|
|
55
|
+
status = d(() => this._status.value);
|
|
54
56
|
/**
|
|
55
57
|
* Узел отключен (disabled)
|
|
56
58
|
*/
|
|
57
|
-
disabled =
|
|
59
|
+
disabled = d(() => this._status.value === "disabled");
|
|
58
60
|
/**
|
|
59
61
|
* Узел включен (enabled)
|
|
60
62
|
*/
|
|
61
|
-
enabled =
|
|
63
|
+
enabled = d(() => this._status.value !== "disabled");
|
|
62
64
|
/**
|
|
63
65
|
* Получить ошибки валидации с фильтрацией
|
|
64
66
|
*
|
|
@@ -100,17 +102,17 @@ class F {
|
|
|
100
102
|
*/
|
|
101
103
|
getErrors(e) {
|
|
102
104
|
const t = this.errors.value;
|
|
103
|
-
return e ? t.filter((
|
|
104
|
-
if (e.code !== void 0 && !(Array.isArray(e.code) ? e.code : [e.code]).includes(
|
|
105
|
+
return e ? t.filter((s) => {
|
|
106
|
+
if (e.code !== void 0 && !(Array.isArray(e.code) ? e.code : [e.code]).includes(s.code) || e.message !== void 0 && !s.message.toLowerCase().includes(e.message.toLowerCase()))
|
|
105
107
|
return !1;
|
|
106
108
|
if (e.params !== void 0) {
|
|
107
|
-
if (!
|
|
109
|
+
if (!s.params)
|
|
108
110
|
return !1;
|
|
109
|
-
for (const [
|
|
110
|
-
if (
|
|
111
|
+
for (const [i, r] of Object.entries(e.params))
|
|
112
|
+
if (s.params[i] !== r)
|
|
111
113
|
return !1;
|
|
112
114
|
}
|
|
113
|
-
return !(e.predicate !== void 0 && !e.predicate(
|
|
115
|
+
return !(e.predicate !== void 0 && !e.predicate(s));
|
|
114
116
|
}) : t;
|
|
115
117
|
}
|
|
116
118
|
// ============================================================================
|
|
@@ -283,7 +285,7 @@ class F {
|
|
|
283
285
|
onEnable() {
|
|
284
286
|
}
|
|
285
287
|
}
|
|
286
|
-
class
|
|
288
|
+
class D {
|
|
287
289
|
/**
|
|
288
290
|
* Хранилище подписок
|
|
289
291
|
* Ключ: уникальный идентификатор подписки
|
|
@@ -451,157 +453,196 @@ class P {
|
|
|
451
453
|
this.clear();
|
|
452
454
|
}
|
|
453
455
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
+
const w = {
|
|
457
|
+
/** FieldNode.watch() */
|
|
458
|
+
Watch: "watch",
|
|
459
|
+
/** FieldNode.computeFrom() */
|
|
460
|
+
ComputeFrom: "computeFrom",
|
|
461
|
+
/** GroupNode.linkFields() */
|
|
462
|
+
LinkFields: "linkFields",
|
|
463
|
+
/** GroupNode.watchField() */
|
|
464
|
+
WatchField: "watchField",
|
|
465
|
+
/** ArrayNode.watchItems() */
|
|
466
|
+
WatchItems: "watchItems",
|
|
467
|
+
/** ArrayNode.watchLength() */
|
|
468
|
+
WatchLength: "watchLength"
|
|
469
|
+
};
|
|
470
|
+
let X = 0;
|
|
471
|
+
function A(a) {
|
|
472
|
+
return `${a}-${++X}`;
|
|
473
|
+
}
|
|
474
|
+
class Z {
|
|
475
|
+
/** Внутренний сигнал статуса */
|
|
476
|
+
_status;
|
|
477
|
+
/** Публичный read-only сигнал статуса */
|
|
478
|
+
status;
|
|
479
|
+
/** Поле валидно */
|
|
480
|
+
valid;
|
|
481
|
+
/** Поле невалидно */
|
|
482
|
+
invalid;
|
|
483
|
+
/** Идет валидация */
|
|
484
|
+
pending;
|
|
485
|
+
/** Поле отключено */
|
|
486
|
+
disabled;
|
|
456
487
|
/**
|
|
457
|
-
*
|
|
488
|
+
* @param initial - Начальный статус (по умолчанию 'valid')
|
|
489
|
+
*/
|
|
490
|
+
constructor(e = "valid") {
|
|
491
|
+
this._status = g(e), this.status = d(() => this._status.value), this.valid = d(() => this._status.value === "valid"), this.invalid = d(() => this._status.value === "invalid"), this.pending = d(() => this._status.value === "pending"), this.disabled = d(() => this._status.value === "disabled");
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Начать валидацию
|
|
458
495
|
*
|
|
459
|
-
*
|
|
460
|
-
* @param context Контекст ошибки для логирования (например, 'AsyncValidator', 'BehaviorRegistry')
|
|
461
|
-
* @param strategy Стратегия обработки (THROW | LOG | CONVERT)
|
|
462
|
-
* @returns ValidationError если strategy = CONVERT, undefined если strategy = LOG, никогда не возвращается если strategy = THROW
|
|
496
|
+
* Переводит статус в 'pending' если поле не отключено
|
|
463
497
|
*
|
|
464
498
|
* @example
|
|
465
499
|
* ```typescript
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
500
|
+
* statusMachine.startValidation();
|
|
501
|
+
* // status: 'pending'
|
|
502
|
+
* ```
|
|
503
|
+
*/
|
|
504
|
+
startValidation() {
|
|
505
|
+
this._status.value !== "disabled" && (this._status.value = "pending");
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Завершить валидацию
|
|
473
509
|
*
|
|
474
|
-
*
|
|
475
|
-
* try {
|
|
476
|
-
* nonCriticalOperation();
|
|
477
|
-
* } catch (error) {
|
|
478
|
-
* FormErrorHandler.handle(error, 'NonCritical', ErrorStrategy.LOG);
|
|
479
|
-
* // Продолжаем выполнение
|
|
480
|
-
* }
|
|
510
|
+
* @param hasErrors - Есть ли ошибки валидации
|
|
481
511
|
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* return validationError;
|
|
492
|
-
* }
|
|
512
|
+
* @example
|
|
513
|
+
* ```typescript
|
|
514
|
+
* // Валидация успешна
|
|
515
|
+
* statusMachine.completeValidation(false);
|
|
516
|
+
* // status: 'valid'
|
|
517
|
+
*
|
|
518
|
+
* // Есть ошибки
|
|
519
|
+
* statusMachine.completeValidation(true);
|
|
520
|
+
* // status: 'invalid'
|
|
493
521
|
* ```
|
|
494
522
|
*/
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
switch (i) {
|
|
498
|
-
case "throw":
|
|
499
|
-
throw e;
|
|
500
|
-
case "log":
|
|
501
|
-
return;
|
|
502
|
-
case "convert":
|
|
503
|
-
return {
|
|
504
|
-
code: "validator_error",
|
|
505
|
-
message: r,
|
|
506
|
-
params: { field: t }
|
|
507
|
-
};
|
|
508
|
-
}
|
|
523
|
+
completeValidation(e) {
|
|
524
|
+
(this._status.value === "pending" || this._status.value !== "disabled") && (this._status.value = e ? "invalid" : "valid");
|
|
509
525
|
}
|
|
510
526
|
/**
|
|
511
|
-
*
|
|
527
|
+
* Установить ошибки напрямую (без перехода через pending)
|
|
512
528
|
*
|
|
513
|
-
*
|
|
514
|
-
* - Error объекты → error.message
|
|
515
|
-
* - Строки → возвращает как есть
|
|
516
|
-
* - Объекты с message → извлекает message
|
|
517
|
-
* - Другое → String(error)
|
|
529
|
+
* Используется для синхронной валидации или установки ошибок извне
|
|
518
530
|
*
|
|
519
|
-
* @param
|
|
520
|
-
* @returns Сообщение ошибки
|
|
521
|
-
* @private
|
|
531
|
+
* @param hasErrors - Есть ли ошибки
|
|
522
532
|
*
|
|
523
533
|
* @example
|
|
524
534
|
* ```typescript
|
|
525
|
-
*
|
|
526
|
-
* // '
|
|
527
|
-
*
|
|
528
|
-
|
|
529
|
-
|
|
535
|
+
* statusMachine.setErrors(true);
|
|
536
|
+
* // status: 'invalid'
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
setErrors(e) {
|
|
540
|
+
this._status.value !== "disabled" && (this._status.value = e ? "invalid" : "valid");
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Отключить поле
|
|
530
544
|
*
|
|
531
|
-
*
|
|
532
|
-
* // 'Object error'
|
|
545
|
+
* Переводит статус в 'disabled'
|
|
533
546
|
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* statusMachine.disable();
|
|
550
|
+
* // status: 'disabled'
|
|
536
551
|
* ```
|
|
537
552
|
*/
|
|
538
|
-
|
|
539
|
-
|
|
553
|
+
disable() {
|
|
554
|
+
this._status.value = "disabled";
|
|
540
555
|
}
|
|
541
556
|
/**
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* Утилитная функция для создания ValidationError объектов
|
|
557
|
+
* Включить поле
|
|
545
558
|
*
|
|
546
|
-
* @param
|
|
547
|
-
* @param message Сообщение ошибки
|
|
548
|
-
* @param field Поле (опционально)
|
|
549
|
-
* @returns ValidationError объект
|
|
559
|
+
* @param hasErrors - Есть ли ошибки (определяет valid/invalid)
|
|
550
560
|
*
|
|
551
561
|
* @example
|
|
552
562
|
* ```typescript
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
* // { code: 'required', message: 'This field is required', field: 'email' }
|
|
563
|
+
* statusMachine.enable(false);
|
|
564
|
+
* // status: 'valid'
|
|
565
|
+
*
|
|
566
|
+
* statusMachine.enable(true);
|
|
567
|
+
* // status: 'invalid'
|
|
559
568
|
* ```
|
|
560
569
|
*/
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
code: e,
|
|
564
|
-
message: t,
|
|
565
|
-
params: i ? { field: i } : void 0
|
|
566
|
-
};
|
|
570
|
+
enable(e = !1) {
|
|
571
|
+
this._status.value = e ? "invalid" : "valid";
|
|
567
572
|
}
|
|
568
573
|
/**
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
* Type guard для ValidationError
|
|
574
|
+
* Обработать событие (альтернативный API)
|
|
572
575
|
*
|
|
573
|
-
* @param
|
|
574
|
-
* @returns true если value является ValidationError
|
|
576
|
+
* @param event - Событие для обработки
|
|
575
577
|
*
|
|
576
578
|
* @example
|
|
577
579
|
* ```typescript
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
* }
|
|
580
|
+
* statusMachine.dispatch({ type: 'START_VALIDATION' });
|
|
581
|
+
* statusMachine.dispatch({ type: 'VALIDATION_FAILURE' });
|
|
581
582
|
* ```
|
|
582
583
|
*/
|
|
583
|
-
|
|
584
|
-
|
|
584
|
+
dispatch(e) {
|
|
585
|
+
switch (e.type) {
|
|
586
|
+
case "START_VALIDATION":
|
|
587
|
+
this.startValidation();
|
|
588
|
+
break;
|
|
589
|
+
case "VALIDATION_SUCCESS":
|
|
590
|
+
this.completeValidation(!1);
|
|
591
|
+
break;
|
|
592
|
+
case "VALIDATION_FAILURE":
|
|
593
|
+
this.completeValidation(!0);
|
|
594
|
+
break;
|
|
595
|
+
case "DISABLE":
|
|
596
|
+
this.disable();
|
|
597
|
+
break;
|
|
598
|
+
case "ENABLE":
|
|
599
|
+
this.enable(e.hasErrors);
|
|
600
|
+
break;
|
|
601
|
+
case "SET_ERRORS":
|
|
602
|
+
this.setErrors(e.hasErrors);
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Получить текущий статус
|
|
608
|
+
*/
|
|
609
|
+
getStatus() {
|
|
610
|
+
return this._status.value;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Проверить, можно ли начать валидацию
|
|
614
|
+
*/
|
|
615
|
+
canValidate() {
|
|
616
|
+
return this._status.value !== "disabled";
|
|
585
617
|
}
|
|
586
618
|
}
|
|
587
|
-
class
|
|
619
|
+
class ee extends C {
|
|
588
620
|
// ============================================================================
|
|
589
621
|
// Приватные сигналы
|
|
590
622
|
// ============================================================================
|
|
591
623
|
_value;
|
|
592
624
|
_errors;
|
|
593
|
-
// _touched, _dirty
|
|
594
|
-
|
|
625
|
+
// _touched, _dirty наследуются от FormNode (protected)
|
|
626
|
+
// _status управляется через statusMachine
|
|
595
627
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
596
628
|
_componentProps;
|
|
629
|
+
/**
|
|
630
|
+
* State machine для управления статусом поля
|
|
631
|
+
* Централизует логику переходов между valid/invalid/pending/disabled
|
|
632
|
+
*/
|
|
633
|
+
statusMachine;
|
|
597
634
|
// ============================================================================
|
|
598
635
|
// Публичные computed signals
|
|
599
636
|
// ============================================================================
|
|
600
637
|
value;
|
|
638
|
+
// valid, invalid, pending, status, disabled берутся из statusMachine
|
|
601
639
|
valid;
|
|
602
640
|
invalid;
|
|
603
|
-
// touched, dirty, status наследуются от FormNode
|
|
604
641
|
pending;
|
|
642
|
+
// Override status и disabled из базового класса
|
|
643
|
+
status;
|
|
644
|
+
disabled;
|
|
645
|
+
// touched, dirty наследуются от FormNode
|
|
605
646
|
errors;
|
|
606
647
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
607
648
|
componentProps;
|
|
@@ -617,23 +658,26 @@ class J extends F {
|
|
|
617
658
|
asyncValidators;
|
|
618
659
|
updateOn;
|
|
619
660
|
initialValue;
|
|
620
|
-
currentValidationId = 0;
|
|
621
661
|
currentAbortController;
|
|
622
662
|
debounceMs;
|
|
623
663
|
validateDebounceTimer;
|
|
624
|
-
|
|
664
|
+
/**
|
|
665
|
+
* Pending debounced validation state
|
|
666
|
+
* Contains resolve function and AbortController for cancellation
|
|
667
|
+
*/
|
|
668
|
+
pendingValidation;
|
|
625
669
|
/**
|
|
626
670
|
* Менеджер подписок для централизованного cleanup
|
|
627
671
|
* Использует SubscriptionManager вместо массива для управления подписками
|
|
628
672
|
*/
|
|
629
|
-
disposers = new
|
|
673
|
+
disposers = new D();
|
|
630
674
|
component;
|
|
631
675
|
// ============================================================================
|
|
632
676
|
// Конструктор
|
|
633
677
|
// ============================================================================
|
|
634
678
|
constructor(e) {
|
|
635
|
-
super(), this.initialValue = e.value, this.validators = e.validators || [], this.asyncValidators = e.asyncValidators || [], this.updateOn = e.updateOn || "blur", this.debounceMs = e.debounce || 0, this.component = e.component, this._value =
|
|
636
|
-
() => this.
|
|
679
|
+
super(), this.initialValue = e.value, this.validators = e.validators || [], this.asyncValidators = e.asyncValidators || [], this.updateOn = e.updateOn || "blur", this.debounceMs = e.debounce || 0, this.component = e.component, this._value = g(e.value), this._errors = g([]), this._componentProps = g(e.componentProps || {}), this.statusMachine = new Z(e.disabled ? "disabled" : "valid"), this.value = d(() => this._value.value), this.valid = d(() => this.statusMachine.valid.value), this.invalid = d(() => this.statusMachine.invalid.value), this.pending = d(() => this.statusMachine.pending.value), this.status = d(() => this.statusMachine.status.value), this.disabled = d(() => this.statusMachine.disabled.value), this.errors = d(() => this._errors.value), this.componentProps = d(() => this._componentProps.value), this.shouldShowError = d(
|
|
680
|
+
() => this.statusMachine.invalid.value && (this._touched.value || this._dirty.value)
|
|
637
681
|
);
|
|
638
682
|
}
|
|
639
683
|
// ============================================================================
|
|
@@ -645,12 +689,12 @@ class J extends F {
|
|
|
645
689
|
setValue(e, t) {
|
|
646
690
|
if (this._value.value = e, this._dirty.value = !0, t?.emitEvent === !1)
|
|
647
691
|
return;
|
|
648
|
-
const
|
|
692
|
+
const s = this.validators.length > 0 || this.asyncValidators.length > 0, i = this._errors.value.length > 0;
|
|
649
693
|
if (this.updateOn === "change") {
|
|
650
694
|
this.validate();
|
|
651
695
|
return;
|
|
652
696
|
}
|
|
653
|
-
|
|
697
|
+
i && s && this.validate();
|
|
654
698
|
}
|
|
655
699
|
patchValue(e) {
|
|
656
700
|
this.setValue(e);
|
|
@@ -679,7 +723,7 @@ class J extends F {
|
|
|
679
723
|
* ```
|
|
680
724
|
*/
|
|
681
725
|
reset(e) {
|
|
682
|
-
this._value.value = e !== void 0 ? e : this.initialValue, this._errors.value = [], this._touched.value = !1, this._dirty.value = !1, this.
|
|
726
|
+
this._value.value = e !== void 0 ? e : this.initialValue, this._errors.value = [], this._touched.value = !1, this._dirty.value = !1, this.statusMachine.setErrors(!1);
|
|
683
727
|
}
|
|
684
728
|
/**
|
|
685
729
|
* Сбросить поле к исходному значению (initialValue)
|
|
@@ -709,13 +753,25 @@ class J extends F {
|
|
|
709
753
|
resetToInitial() {
|
|
710
754
|
this.reset(this.initialValue);
|
|
711
755
|
}
|
|
756
|
+
/**
|
|
757
|
+
* Cancel any pending validation (debounced or running)
|
|
758
|
+
* @private
|
|
759
|
+
* @remarks
|
|
760
|
+
* Centralizes all cancellation logic:
|
|
761
|
+
* - Aborts pending debounced validation and resolves its promise
|
|
762
|
+
* - Clears debounce timer
|
|
763
|
+
* - Aborts currently running async validation
|
|
764
|
+
*/
|
|
765
|
+
cancelPendingValidation() {
|
|
766
|
+
this.pendingValidation && (this.pendingValidation.abortController.abort(), this.pendingValidation.resolve(!1), this.pendingValidation = void 0), this.validateDebounceTimer && (clearTimeout(this.validateDebounceTimer), this.validateDebounceTimer = void 0), this.currentAbortController && (this.currentAbortController.abort(), this.currentAbortController = void 0);
|
|
767
|
+
}
|
|
712
768
|
/**
|
|
713
769
|
* Запустить валидацию поля
|
|
714
770
|
* @param options - опции валидации
|
|
715
771
|
* @returns `Promise<boolean>` - true если поле валидно
|
|
716
772
|
*
|
|
717
773
|
* @remarks
|
|
718
|
-
* Метод защищен от race conditions через
|
|
774
|
+
* Метод защищен от race conditions через AbortController.
|
|
719
775
|
* При быстром вводе только последняя валидация применяет результаты.
|
|
720
776
|
*
|
|
721
777
|
* @example
|
|
@@ -729,86 +785,102 @@ class J extends F {
|
|
|
729
785
|
*/
|
|
730
786
|
async validate(e) {
|
|
731
787
|
const t = e?.debounce ?? this.debounceMs;
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
788
|
+
if (this.cancelPendingValidation(), t <= 0 || this.asyncValidators.length === 0)
|
|
789
|
+
return this.validateImmediate();
|
|
790
|
+
const s = new AbortController();
|
|
791
|
+
return new Promise((i) => {
|
|
792
|
+
this.pendingValidation = { resolve: i, abortController: s }, this.validateDebounceTimer = setTimeout(async () => {
|
|
793
|
+
if (this.validateDebounceTimer = void 0, s.signal.aborted) {
|
|
736
794
|
i(!1);
|
|
737
795
|
return;
|
|
738
796
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
797
|
+
this.pendingValidation = void 0;
|
|
798
|
+
const r = await this.validateImmediate(s);
|
|
799
|
+
i(r);
|
|
800
|
+
}, t), s.signal.addEventListener(
|
|
801
|
+
"abort",
|
|
802
|
+
() => {
|
|
803
|
+
this.validateDebounceTimer && (clearTimeout(this.validateDebounceTimer), this.validateDebounceTimer = void 0), i(!1);
|
|
804
|
+
},
|
|
805
|
+
{ once: !0 }
|
|
806
|
+
);
|
|
807
|
+
});
|
|
743
808
|
}
|
|
744
809
|
/**
|
|
745
810
|
* Немедленная валидация без debounce
|
|
746
811
|
* @private
|
|
812
|
+
* @param providedController - AbortController from debounced validate()
|
|
747
813
|
* @remarks
|
|
748
814
|
* Защищена от race conditions через AbortController:
|
|
749
|
-
* - Отменяет предыдущую валидацию при запуске новой
|
|
815
|
+
* - Отменяет предыдущую валидацию при запуске новой (if no controller provided)
|
|
750
816
|
* - Передаёт AbortSignal в async валидаторы для отмены операций (например, fetch)
|
|
751
817
|
* - Проверяет signal.aborted в ключевых точках
|
|
752
818
|
*/
|
|
753
|
-
async validateImmediate() {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
for (const s of this.validators) {
|
|
761
|
-
const n = s(this._value.value);
|
|
762
|
-
n && i.push(n);
|
|
819
|
+
async validateImmediate(e) {
|
|
820
|
+
const t = e ?? new AbortController();
|
|
821
|
+
e || this.currentAbortController?.abort(), this.currentAbortController = t;
|
|
822
|
+
const { signal: s } = t, i = [];
|
|
823
|
+
for (const n of this.validators) {
|
|
824
|
+
const o = n(this._value.value);
|
|
825
|
+
o && i.push(o);
|
|
763
826
|
}
|
|
764
|
-
if (
|
|
827
|
+
if (s.aborted)
|
|
765
828
|
return !1;
|
|
766
|
-
if (i.length > 0)
|
|
767
|
-
|
|
829
|
+
if (i.length > 0) {
|
|
830
|
+
this._errors.value = i;
|
|
831
|
+
const n = i.some((o) => o.severity !== "warning");
|
|
832
|
+
if (this.statusMachine.setErrors(n), n)
|
|
833
|
+
return !1;
|
|
834
|
+
}
|
|
768
835
|
if (this.asyncValidators.length > 0) {
|
|
769
|
-
if (
|
|
836
|
+
if (s.aborted)
|
|
770
837
|
return !1;
|
|
771
|
-
this.
|
|
838
|
+
this.statusMachine.startValidation();
|
|
772
839
|
try {
|
|
773
|
-
const
|
|
774
|
-
this.asyncValidators.map(async (
|
|
775
|
-
if (
|
|
840
|
+
const n = await Promise.all(
|
|
841
|
+
this.asyncValidators.map(async (l) => {
|
|
842
|
+
if (s.aborted)
|
|
776
843
|
throw new DOMException("Validation aborted", "AbortError");
|
|
777
844
|
try {
|
|
778
|
-
const
|
|
779
|
-
if (
|
|
845
|
+
const u = await l(this._value.value, { signal: s });
|
|
846
|
+
if (s.aborted)
|
|
780
847
|
throw new DOMException("Validation aborted", "AbortError");
|
|
781
|
-
return
|
|
782
|
-
} catch (
|
|
783
|
-
if (
|
|
784
|
-
throw
|
|
785
|
-
return
|
|
786
|
-
|
|
848
|
+
return u;
|
|
849
|
+
} catch (u) {
|
|
850
|
+
if (u instanceof DOMException && u.name === "AbortError")
|
|
851
|
+
throw u;
|
|
852
|
+
return S.handle(
|
|
853
|
+
u,
|
|
787
854
|
"FieldNode AsyncValidator",
|
|
788
|
-
|
|
855
|
+
V.CONVERT
|
|
789
856
|
);
|
|
790
857
|
}
|
|
791
858
|
})
|
|
792
859
|
);
|
|
793
|
-
if (
|
|
860
|
+
if (s.aborted)
|
|
794
861
|
return !1;
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
862
|
+
const o = n.filter(Boolean);
|
|
863
|
+
if (o.length > 0) {
|
|
864
|
+
this._errors.value = o;
|
|
865
|
+
const l = o.some((u) => u.severity !== "warning");
|
|
866
|
+
if (this.statusMachine.completeValidation(l), l)
|
|
867
|
+
return !1;
|
|
868
|
+
}
|
|
869
|
+
} catch (n) {
|
|
870
|
+
if (n instanceof DOMException && n.name === "AbortError")
|
|
801
871
|
return !1;
|
|
802
|
-
throw
|
|
872
|
+
throw n;
|
|
803
873
|
}
|
|
804
874
|
}
|
|
805
|
-
return
|
|
875
|
+
return s.aborted ? !1 : ((this.validators.length > 0 || this.asyncValidators.length > 0) && (this._errors.value = [], this.statusMachine.completeValidation(!1)), !this._errors.value.some((n) => n.severity !== "warning"));
|
|
806
876
|
}
|
|
807
877
|
setErrors(e) {
|
|
808
|
-
this._errors.value = e
|
|
878
|
+
this._errors.value = e;
|
|
879
|
+
const t = e.some((s) => s.severity !== "warning");
|
|
880
|
+
this.statusMachine.setErrors(t);
|
|
809
881
|
}
|
|
810
882
|
clearErrors() {
|
|
811
|
-
this._errors.value = [], this.
|
|
883
|
+
this._errors.value = [], this.statusMachine.setErrors(!1);
|
|
812
884
|
}
|
|
813
885
|
// ============================================================================
|
|
814
886
|
// Protected hooks (Template Method pattern)
|
|
@@ -824,18 +896,18 @@ class J extends F {
|
|
|
824
896
|
/**
|
|
825
897
|
* Hook: вызывается после disable()
|
|
826
898
|
*
|
|
827
|
-
* Для FieldNode: очищаем ошибки
|
|
899
|
+
* Для FieldNode: синхронизируем statusMachine и очищаем ошибки
|
|
828
900
|
*/
|
|
829
901
|
onDisable() {
|
|
830
|
-
this._errors.value = [];
|
|
902
|
+
this.statusMachine.disable(), this._errors.value = [];
|
|
831
903
|
}
|
|
832
904
|
/**
|
|
833
905
|
* Hook: вызывается после enable()
|
|
834
906
|
*
|
|
835
|
-
* Для FieldNode: запускаем валидацию
|
|
907
|
+
* Для FieldNode: синхронизируем statusMachine и запускаем валидацию
|
|
836
908
|
*/
|
|
837
909
|
onEnable() {
|
|
838
|
-
this.validate();
|
|
910
|
+
this.statusMachine.enable(this._errors.value.length > 0), this.validate();
|
|
839
911
|
}
|
|
840
912
|
/**
|
|
841
913
|
* Обновляет свойства компонента (например, опции для Select)
|
|
@@ -900,25 +972,35 @@ class J extends F {
|
|
|
900
972
|
* Подписка на изменения значения поля
|
|
901
973
|
* Автоматически отслеживает изменения через @preact/signals effect
|
|
902
974
|
*
|
|
903
|
-
* @param callback - Функция, вызываемая при изменении
|
|
975
|
+
* @param callback - Функция, вызываемая при изменении значения.
|
|
976
|
+
* Для async операций передается AbortSignal во втором параметре.
|
|
904
977
|
* @returns Функция отписки для cleanup
|
|
905
978
|
*
|
|
906
979
|
* @example
|
|
907
980
|
* ```typescript
|
|
981
|
+
* // Синхронный callback
|
|
908
982
|
* const unsubscribe = form.email.watch((value) => {
|
|
909
983
|
* console.log('Email changed:', value);
|
|
910
984
|
* });
|
|
911
985
|
*
|
|
986
|
+
* // Асинхронный callback с поддержкой отмены
|
|
987
|
+
* const unsubscribe = form.email.watch(async (value, signal) => {
|
|
988
|
+
* const result = await fetch('/api/validate', { signal });
|
|
989
|
+
* // ...
|
|
990
|
+
* });
|
|
991
|
+
*
|
|
912
992
|
* // Cleanup
|
|
913
993
|
* useEffect(() => unsubscribe, []);
|
|
914
994
|
* ```
|
|
915
995
|
*/
|
|
916
996
|
watch(e) {
|
|
917
|
-
const t =
|
|
997
|
+
const t = new AbortController(), s = m(() => {
|
|
918
998
|
const r = this.value.value;
|
|
919
|
-
e(r);
|
|
920
|
-
}), i =
|
|
921
|
-
return this.disposers.add(i,
|
|
999
|
+
e(r, t.signal);
|
|
1000
|
+
}), i = A(w.Watch);
|
|
1001
|
+
return this.disposers.add(i, () => {
|
|
1002
|
+
t.abort(), s();
|
|
1003
|
+
});
|
|
922
1004
|
}
|
|
923
1005
|
/**
|
|
924
1006
|
* Вычисляемое значение из других полей
|
|
@@ -943,11 +1025,11 @@ class J extends F {
|
|
|
943
1025
|
* ```
|
|
944
1026
|
*/
|
|
945
1027
|
computeFrom(e, t) {
|
|
946
|
-
const
|
|
947
|
-
const
|
|
1028
|
+
const s = m(() => {
|
|
1029
|
+
const r = e.map((o) => o.value), n = t(...r);
|
|
948
1030
|
this.setValue(n, { emitEvent: !1 });
|
|
949
|
-
}),
|
|
950
|
-
return this.disposers.add(
|
|
1031
|
+
}), i = A(w.ComputeFrom);
|
|
1032
|
+
return this.disposers.add(i, s);
|
|
951
1033
|
}
|
|
952
1034
|
/**
|
|
953
1035
|
* Очистить все ресурсы и таймеры
|
|
@@ -956,9 +1038,9 @@ class J extends F {
|
|
|
956
1038
|
* @remarks
|
|
957
1039
|
* Освобождает все ресурсы:
|
|
958
1040
|
* - Отписывает все subscriptions через SubscriptionManager
|
|
959
|
-
* -
|
|
960
|
-
*
|
|
961
|
-
* -
|
|
1041
|
+
* - Отменяет pending/running валидации через cancelPendingValidation()
|
|
1042
|
+
*
|
|
1043
|
+
* Использует try-finally для гарантированного cleanup даже при ошибках.
|
|
962
1044
|
*
|
|
963
1045
|
* @example
|
|
964
1046
|
* ```typescript
|
|
@@ -970,10 +1052,14 @@ class J extends F {
|
|
|
970
1052
|
* ```
|
|
971
1053
|
*/
|
|
972
1054
|
dispose() {
|
|
973
|
-
|
|
1055
|
+
try {
|
|
1056
|
+
this.disposers.dispose();
|
|
1057
|
+
} finally {
|
|
1058
|
+
this.cancelPendingValidation();
|
|
1059
|
+
}
|
|
974
1060
|
}
|
|
975
1061
|
}
|
|
976
|
-
class
|
|
1062
|
+
class te {
|
|
977
1063
|
form;
|
|
978
1064
|
constructor(e) {
|
|
979
1065
|
this.form = e;
|
|
@@ -989,8 +1075,8 @@ class Y {
|
|
|
989
1075
|
* @param validators Зарегистрированные валидаторы
|
|
990
1076
|
*/
|
|
991
1077
|
async apply(e) {
|
|
992
|
-
const { validatorsByField: t, treeValidators:
|
|
993
|
-
await this.applyFieldValidators(t), this.applyTreeValidators(
|
|
1078
|
+
const { validatorsByField: t, treeValidators: s } = this.groupValidators(e);
|
|
1079
|
+
await this.applyFieldValidators(t), this.applyTreeValidators(s);
|
|
994
1080
|
}
|
|
995
1081
|
/**
|
|
996
1082
|
* Группировка валидаторов по типам
|
|
@@ -1003,15 +1089,15 @@ class Y {
|
|
|
1003
1089
|
* @returns Сгруппированные валидаторы
|
|
1004
1090
|
*/
|
|
1005
1091
|
groupValidators(e) {
|
|
1006
|
-
const t = /* @__PURE__ */ new Map(),
|
|
1007
|
-
for (const
|
|
1008
|
-
if (
|
|
1009
|
-
|
|
1092
|
+
const t = /* @__PURE__ */ new Map(), s = [];
|
|
1093
|
+
for (const i of e)
|
|
1094
|
+
if (i.type === "tree")
|
|
1095
|
+
s.push(i);
|
|
1010
1096
|
else {
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1097
|
+
const r = t.get(i.fieldPath) || [];
|
|
1098
|
+
r.push(i), t.set(i.fieldPath, r);
|
|
1013
1099
|
}
|
|
1014
|
-
return { validatorsByField: t, treeValidators:
|
|
1100
|
+
return { validatorsByField: t, treeValidators: s };
|
|
1015
1101
|
}
|
|
1016
1102
|
/**
|
|
1017
1103
|
* Применение field валидаторов к полям
|
|
@@ -1025,37 +1111,44 @@ class Y {
|
|
|
1025
1111
|
* @param validatorsByField Валидаторы, сгруппированные по полям
|
|
1026
1112
|
*/
|
|
1027
1113
|
async applyFieldValidators(e) {
|
|
1028
|
-
for (const [t,
|
|
1029
|
-
const
|
|
1030
|
-
if (!
|
|
1114
|
+
for (const [t, s] of e) {
|
|
1115
|
+
const i = this.form.getFieldByPath(t);
|
|
1116
|
+
if (!i) {
|
|
1031
1117
|
console.warn(`Field ${t} not found in GroupNode`);
|
|
1032
1118
|
continue;
|
|
1033
1119
|
}
|
|
1034
|
-
if (!
|
|
1120
|
+
if (!M(i) && !N(i)) {
|
|
1035
1121
|
process.env.NODE_ENV !== "production" && console.warn(`Validation can only run on FieldNode or ArrayNode, skipping ${t}`);
|
|
1036
1122
|
continue;
|
|
1037
1123
|
}
|
|
1038
|
-
const
|
|
1124
|
+
const r = [];
|
|
1039
1125
|
let n;
|
|
1040
|
-
if (
|
|
1041
|
-
const o =
|
|
1042
|
-
n = new
|
|
1126
|
+
if (N(i)) {
|
|
1127
|
+
const o = i.getValue();
|
|
1128
|
+
n = new z(this.form, t, o);
|
|
1043
1129
|
} else
|
|
1044
|
-
n = new
|
|
1045
|
-
for (const o of
|
|
1130
|
+
n = new J(this.form, t, i);
|
|
1131
|
+
for (const o of s)
|
|
1046
1132
|
if (!(o.condition && !this.checkCondition(o.condition)))
|
|
1047
1133
|
try {
|
|
1048
1134
|
let l = null;
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1135
|
+
const u = n.value();
|
|
1136
|
+
if (o.type === "sync") {
|
|
1137
|
+
const v = o.validator;
|
|
1138
|
+
l = v(u, n);
|
|
1139
|
+
} else if (o.type === "async") {
|
|
1140
|
+
const v = o.validator;
|
|
1141
|
+
l = await v(u, n);
|
|
1142
|
+
}
|
|
1143
|
+
l && r.push(l);
|
|
1051
1144
|
} catch (l) {
|
|
1052
|
-
|
|
1145
|
+
S.handle(
|
|
1053
1146
|
l,
|
|
1054
1147
|
`ValidationApplicator: validator for ${t}`,
|
|
1055
|
-
|
|
1148
|
+
V.LOG
|
|
1056
1149
|
);
|
|
1057
1150
|
}
|
|
1058
|
-
|
|
1151
|
+
r.length > 0 ? i.setErrors(r) : i.clearErrors();
|
|
1059
1152
|
}
|
|
1060
1153
|
}
|
|
1061
1154
|
/**
|
|
@@ -1068,24 +1161,24 @@ class Y {
|
|
|
1068
1161
|
*/
|
|
1069
1162
|
applyTreeValidators(e) {
|
|
1070
1163
|
for (const t of e) {
|
|
1071
|
-
const
|
|
1164
|
+
const s = new Y(this.form);
|
|
1072
1165
|
if (!(t.condition && !this.checkCondition(t.condition)))
|
|
1073
1166
|
try {
|
|
1074
1167
|
if (t.type !== "tree")
|
|
1075
1168
|
continue;
|
|
1076
|
-
const
|
|
1169
|
+
const i = t.validator, r = i(s);
|
|
1077
1170
|
if (r && t.options && "targetField" in t.options) {
|
|
1078
|
-
const
|
|
1079
|
-
if (
|
|
1080
|
-
const
|
|
1081
|
-
if (
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1171
|
+
const n = t.options.targetField;
|
|
1172
|
+
if (n) {
|
|
1173
|
+
const o = this.form.getFieldByPath(String(n));
|
|
1174
|
+
if (o && M(o)) {
|
|
1175
|
+
const l = o.errors.value;
|
|
1176
|
+
o.setErrors([...l, r]);
|
|
1084
1177
|
}
|
|
1085
1178
|
}
|
|
1086
1179
|
}
|
|
1087
|
-
} catch (
|
|
1088
|
-
|
|
1180
|
+
} catch (i) {
|
|
1181
|
+
S.handle(i, "ValidationApplicator: tree validator", V.LOG);
|
|
1089
1182
|
}
|
|
1090
1183
|
}
|
|
1091
1184
|
}
|
|
@@ -1102,11 +1195,11 @@ class Y {
|
|
|
1102
1195
|
const t = this.form.getFieldByPath(e.fieldPath);
|
|
1103
1196
|
if (!t)
|
|
1104
1197
|
return !1;
|
|
1105
|
-
const
|
|
1106
|
-
return e.conditionFn(
|
|
1198
|
+
const s = t.value.value;
|
|
1199
|
+
return e.conditionFn(s);
|
|
1107
1200
|
}
|
|
1108
1201
|
}
|
|
1109
|
-
class
|
|
1202
|
+
class se {
|
|
1110
1203
|
/**
|
|
1111
1204
|
* Парсит путь в массив сегментов
|
|
1112
1205
|
*
|
|
@@ -1133,22 +1226,22 @@ class Q {
|
|
|
1133
1226
|
*/
|
|
1134
1227
|
parsePath(e) {
|
|
1135
1228
|
const t = [];
|
|
1136
|
-
let
|
|
1137
|
-
for (let
|
|
1138
|
-
const n = e[
|
|
1139
|
-
n === "[" ? (
|
|
1229
|
+
let s = "", i = !1;
|
|
1230
|
+
for (let r = 0; r < e.length; r++) {
|
|
1231
|
+
const n = e[r];
|
|
1232
|
+
n === "[" ? (i = !0, s += n) : n === "]" ? (i = !1, s += n) : n === "." && !i ? s && (this.addSegment(t, s), s = "") : s += n;
|
|
1140
1233
|
}
|
|
1141
|
-
return
|
|
1234
|
+
return s && this.addSegment(t, s), t;
|
|
1142
1235
|
}
|
|
1143
1236
|
/**
|
|
1144
1237
|
* Добавляет сегмент в массив, обрабатывая массивы
|
|
1145
1238
|
* @private
|
|
1146
1239
|
*/
|
|
1147
1240
|
addSegment(e, t) {
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1150
|
-
key:
|
|
1151
|
-
index: parseInt(
|
|
1241
|
+
const s = t.match(/^(.+)\[(\d+)\]$/);
|
|
1242
|
+
s ? e.push({
|
|
1243
|
+
key: s[1],
|
|
1244
|
+
index: parseInt(s[2], 10)
|
|
1152
1245
|
}) : e.push({ key: t });
|
|
1153
1246
|
}
|
|
1154
1247
|
/**
|
|
@@ -1183,16 +1276,16 @@ class Q {
|
|
|
1183
1276
|
* ```
|
|
1184
1277
|
*/
|
|
1185
1278
|
getValueByPath(e, t) {
|
|
1186
|
-
const
|
|
1187
|
-
let
|
|
1188
|
-
for (const
|
|
1189
|
-
if (
|
|
1190
|
-
if (
|
|
1191
|
-
if (!Array.isArray(
|
|
1192
|
-
|
|
1279
|
+
const s = this.parsePath(t);
|
|
1280
|
+
let i = e;
|
|
1281
|
+
for (const r of s) {
|
|
1282
|
+
if (i == null) return;
|
|
1283
|
+
if (i = i[r.key], r.index !== void 0) {
|
|
1284
|
+
if (!Array.isArray(i)) return;
|
|
1285
|
+
i = i[r.index];
|
|
1193
1286
|
}
|
|
1194
1287
|
}
|
|
1195
|
-
return
|
|
1288
|
+
return i;
|
|
1196
1289
|
}
|
|
1197
1290
|
/**
|
|
1198
1291
|
* Устанавливает значение по пути в объекте (мутирует объект)
|
|
@@ -1221,31 +1314,31 @@ class Q {
|
|
|
1221
1314
|
* // obj3.items[0].title === 'New'
|
|
1222
1315
|
* ```
|
|
1223
1316
|
*/
|
|
1224
|
-
setValueByPath(e, t,
|
|
1225
|
-
const
|
|
1226
|
-
if (
|
|
1317
|
+
setValueByPath(e, t, s) {
|
|
1318
|
+
const i = this.parsePath(t);
|
|
1319
|
+
if (i.length === 0)
|
|
1227
1320
|
throw new Error("Cannot set value: empty path");
|
|
1228
|
-
let
|
|
1229
|
-
for (let o = 0; o <
|
|
1230
|
-
const l =
|
|
1231
|
-
let
|
|
1321
|
+
let r = e;
|
|
1322
|
+
for (let o = 0; o < i.length - 1; o++) {
|
|
1323
|
+
const l = i[o];
|
|
1324
|
+
let u = r[l.key];
|
|
1232
1325
|
if (l.index !== void 0) {
|
|
1233
|
-
if (!Array.isArray(
|
|
1234
|
-
throw new Error(`Expected array at path segment: ${l.key}, but got ${typeof
|
|
1235
|
-
|
|
1326
|
+
if (!Array.isArray(u))
|
|
1327
|
+
throw new Error(`Expected array at path segment: ${l.key}, but got ${typeof u}`);
|
|
1328
|
+
r = u[l.index];
|
|
1236
1329
|
} else
|
|
1237
|
-
|
|
1330
|
+
u == null && (r[l.key] = {}, u = r[l.key]), r = u;
|
|
1238
1331
|
}
|
|
1239
|
-
const n =
|
|
1332
|
+
const n = i[i.length - 1];
|
|
1240
1333
|
if (n.index !== void 0) {
|
|
1241
|
-
const o =
|
|
1334
|
+
const o = r[n.key];
|
|
1242
1335
|
if (!Array.isArray(o))
|
|
1243
1336
|
throw new Error(
|
|
1244
1337
|
`Expected array at path segment: ${n.key}, but got ${typeof o}`
|
|
1245
1338
|
);
|
|
1246
|
-
o[n.index] =
|
|
1339
|
+
o[n.index] = s;
|
|
1247
1340
|
} else
|
|
1248
|
-
|
|
1341
|
+
r[n.key] = s;
|
|
1249
1342
|
}
|
|
1250
1343
|
/**
|
|
1251
1344
|
* Получить значение из FormNode по пути
|
|
@@ -1282,9 +1375,9 @@ class Q {
|
|
|
1282
1375
|
* ```
|
|
1283
1376
|
*/
|
|
1284
1377
|
getFormNodeValue(e, t) {
|
|
1285
|
-
const
|
|
1286
|
-
if (
|
|
1287
|
-
return this.isFormNode(
|
|
1378
|
+
const s = this.getNodeByPath(e, t);
|
|
1379
|
+
if (s != null)
|
|
1380
|
+
return this.isFormNode(s) ? s.value.value : s;
|
|
1288
1381
|
}
|
|
1289
1382
|
/**
|
|
1290
1383
|
* Type guard для проверки, является ли объект FormNode
|
|
@@ -1342,40 +1435,177 @@ class Q {
|
|
|
1342
1435
|
* ```
|
|
1343
1436
|
*/
|
|
1344
1437
|
getNodeByPath(e, t) {
|
|
1345
|
-
const
|
|
1346
|
-
let
|
|
1347
|
-
for (const
|
|
1348
|
-
if (
|
|
1349
|
-
const n =
|
|
1438
|
+
const s = this.parsePath(t);
|
|
1439
|
+
let i = e;
|
|
1440
|
+
for (const r of s) {
|
|
1441
|
+
if (i == null) return null;
|
|
1442
|
+
const n = i;
|
|
1350
1443
|
if (n.fields && n.fields instanceof Map) {
|
|
1351
|
-
if (
|
|
1352
|
-
if (
|
|
1444
|
+
if (i = n.fields.get(r.key), r.index === void 0) {
|
|
1445
|
+
if (i == null) return null;
|
|
1353
1446
|
continue;
|
|
1354
1447
|
}
|
|
1355
|
-
} else if (
|
|
1448
|
+
} else if (r.index !== void 0 && n.items) {
|
|
1356
1449
|
const o = n.items.value || n.items;
|
|
1357
|
-
if (!Array.isArray(o) || (
|
|
1450
|
+
if (!Array.isArray(o) || (i = o[r.index], i == null)) return null;
|
|
1358
1451
|
continue;
|
|
1359
|
-
} else if (
|
|
1360
|
-
if (
|
|
1452
|
+
} else if (r.index === void 0) {
|
|
1453
|
+
if (i = n[r.key], i == null) return null;
|
|
1361
1454
|
continue;
|
|
1362
1455
|
}
|
|
1363
|
-
if (
|
|
1364
|
-
const o =
|
|
1456
|
+
if (i && r.index !== void 0 && i.items) {
|
|
1457
|
+
const o = i.items.value || i.items;
|
|
1365
1458
|
if (!Array.isArray(o)) return null;
|
|
1366
|
-
|
|
1367
|
-
} else if (
|
|
1459
|
+
i = o[r.index];
|
|
1460
|
+
} else if (i && r.index !== void 0 && !i.items)
|
|
1368
1461
|
return null;
|
|
1369
|
-
if (
|
|
1462
|
+
if (i == null) return null;
|
|
1463
|
+
}
|
|
1464
|
+
return i;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function W(a) {
|
|
1468
|
+
const { getChildren: e, ownErrors: t, disabled: s } = a, i = d(() => t.value.length > 0 ? !1 : e().every((h) => h.disabled.value || h.valid.value)), r = d(() => !i.value), n = d(() => e().some((h) => h.pending.value)), o = d(() => e().some((h) => h.touched.value)), l = d(() => e().some((h) => h.dirty.value)), u = d(() => {
|
|
1469
|
+
const h = [...t.value];
|
|
1470
|
+
for (const f of e())
|
|
1471
|
+
h.push(...f.errors.value);
|
|
1472
|
+
return h;
|
|
1473
|
+
}), v = d(() => s?.value ? "disabled" : n.value ? "pending" : r.value ? "invalid" : "valid");
|
|
1474
|
+
return {
|
|
1475
|
+
valid: i,
|
|
1476
|
+
invalid: r,
|
|
1477
|
+
pending: n,
|
|
1478
|
+
touched: o,
|
|
1479
|
+
dirty: l,
|
|
1480
|
+
errors: u,
|
|
1481
|
+
status: v
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
function ie(a) {
|
|
1485
|
+
return typeof a == "object" && a !== null && "getProxy" in a && typeof a.getProxy == "function";
|
|
1486
|
+
}
|
|
1487
|
+
function re(a, e) {
|
|
1488
|
+
return new Proxy(a, {
|
|
1489
|
+
get: (t, s) => {
|
|
1490
|
+
if (s in t)
|
|
1491
|
+
return t[s];
|
|
1492
|
+
if (typeof s == "string" && e.has(s)) {
|
|
1493
|
+
const i = e.get(s);
|
|
1494
|
+
return i && ie(i) ? i.getProxy() : i;
|
|
1495
|
+
}
|
|
1496
|
+
},
|
|
1497
|
+
set: (t, s, i) => typeof s == "string" && e.has(s) ? !1 : (t[s] = i, !0),
|
|
1498
|
+
has: (t, s) => typeof s == "string" && e.has(s) ? !0 : s in t,
|
|
1499
|
+
ownKeys: (t) => {
|
|
1500
|
+
const s = Reflect.ownKeys(t), i = Array.from(e.keys());
|
|
1501
|
+
return [.../* @__PURE__ */ new Set([...s, ...i])];
|
|
1502
|
+
},
|
|
1503
|
+
getOwnPropertyDescriptor: (t, s) => typeof s == "string" && e.has(s) ? { enumerable: !0, configurable: !0 } : Reflect.getOwnPropertyDescriptor(t, s)
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
class ae {
|
|
1507
|
+
/**
|
|
1508
|
+
* @param form - Форма для отправки
|
|
1509
|
+
*/
|
|
1510
|
+
constructor(e) {
|
|
1511
|
+
this.form = e;
|
|
1512
|
+
}
|
|
1513
|
+
/** Внутренний сигнал состояния отправки */
|
|
1514
|
+
_submitting = g(!1);
|
|
1515
|
+
/** Публичный read-only сигнал состояния отправки */
|
|
1516
|
+
submitting = d(() => this._submitting.value);
|
|
1517
|
+
/**
|
|
1518
|
+
* Отправить форму
|
|
1519
|
+
*
|
|
1520
|
+
* Процесс:
|
|
1521
|
+
* 1. Помечает все поля как touched (для отображения ошибок)
|
|
1522
|
+
* 2. Валидирует форму
|
|
1523
|
+
* 3. Если валидация успешна - вызывает onSubmit
|
|
1524
|
+
* 4. Управляет состоянием submitting
|
|
1525
|
+
*
|
|
1526
|
+
* @param onSubmit - Callback для отправки данных
|
|
1527
|
+
* @param options - Опции submit
|
|
1528
|
+
* @returns Результат от onSubmit или null если валидация не пройдена
|
|
1529
|
+
*
|
|
1530
|
+
* @example
|
|
1531
|
+
* ```typescript
|
|
1532
|
+
* const result = await submitter.submit(async (values) => {
|
|
1533
|
+
* const response = await fetch('/api/form', {
|
|
1534
|
+
* method: 'POST',
|
|
1535
|
+
* body: JSON.stringify(values)
|
|
1536
|
+
* });
|
|
1537
|
+
* return response.json();
|
|
1538
|
+
* });
|
|
1539
|
+
*
|
|
1540
|
+
* if (result === null) {
|
|
1541
|
+
* console.log('Форма не прошла валидацию');
|
|
1542
|
+
* }
|
|
1543
|
+
* ```
|
|
1544
|
+
*/
|
|
1545
|
+
async submit(e, t) {
|
|
1546
|
+
const { skipValidation: s = !1, skipTouch: i = !1 } = t || {};
|
|
1547
|
+
if (i || this.form.markAsTouched(), !s && !await this.form.validate())
|
|
1548
|
+
return null;
|
|
1549
|
+
this._submitting.value = !0;
|
|
1550
|
+
try {
|
|
1551
|
+
return await e(this.form.getValue());
|
|
1552
|
+
} finally {
|
|
1553
|
+
this._submitting.value = !1;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Отправить форму с расширенным результатом
|
|
1558
|
+
*
|
|
1559
|
+
* В отличие от submit(), возвращает объект с информацией об успехе/ошибке
|
|
1560
|
+
*
|
|
1561
|
+
* @param onSubmit - Callback для отправки данных
|
|
1562
|
+
* @param options - Опции submit
|
|
1563
|
+
* @returns Объект SubmitResult с данными и статусом
|
|
1564
|
+
*
|
|
1565
|
+
* @example
|
|
1566
|
+
* ```typescript
|
|
1567
|
+
* const result = await submitter.submitWithResult(async (values) => {
|
|
1568
|
+
* return await api.saveForm(values);
|
|
1569
|
+
* });
|
|
1570
|
+
*
|
|
1571
|
+
* if (result.success) {
|
|
1572
|
+
* console.log('Сохранено:', result.data);
|
|
1573
|
+
* } else if (result.error) {
|
|
1574
|
+
* console.error('Ошибка:', result.error.message);
|
|
1575
|
+
* } else {
|
|
1576
|
+
* console.log('Валидация не пройдена');
|
|
1577
|
+
* }
|
|
1578
|
+
* ```
|
|
1579
|
+
*/
|
|
1580
|
+
async submitWithResult(e, t) {
|
|
1581
|
+
const { skipValidation: s = !1, skipTouch: i = !1 } = t || {};
|
|
1582
|
+
if (i || this.form.markAsTouched(), !s && !await this.form.validate())
|
|
1583
|
+
return { success: !1, data: null };
|
|
1584
|
+
this._submitting.value = !0;
|
|
1585
|
+
try {
|
|
1586
|
+
return { success: !0, data: await e(this.form.getValue()) };
|
|
1587
|
+
} catch (r) {
|
|
1588
|
+
return {
|
|
1589
|
+
success: !1,
|
|
1590
|
+
data: null,
|
|
1591
|
+
error: r instanceof Error ? r : new Error(String(r))
|
|
1592
|
+
};
|
|
1593
|
+
} finally {
|
|
1594
|
+
this._submitting.value = !1;
|
|
1370
1595
|
}
|
|
1371
|
-
|
|
1596
|
+
}
|
|
1597
|
+
/**
|
|
1598
|
+
* Проверить, идет ли отправка формы
|
|
1599
|
+
*/
|
|
1600
|
+
isSubmitting() {
|
|
1601
|
+
return this._submitting.value;
|
|
1372
1602
|
}
|
|
1373
1603
|
}
|
|
1374
|
-
class
|
|
1604
|
+
class k extends C {
|
|
1375
1605
|
// ============================================================================
|
|
1376
1606
|
// Приватные поля
|
|
1377
1607
|
// ============================================================================
|
|
1378
|
-
id =
|
|
1608
|
+
id = crypto.randomUUID();
|
|
1379
1609
|
/**
|
|
1380
1610
|
* Коллекция полей формы (упрощённый Map вместо FieldRegistry)
|
|
1381
1611
|
*/
|
|
@@ -1384,7 +1614,7 @@ class S extends F {
|
|
|
1384
1614
|
/**
|
|
1385
1615
|
* Менеджер подписок для централизованного cleanup
|
|
1386
1616
|
*/
|
|
1387
|
-
disposers = new
|
|
1617
|
+
disposers = new D();
|
|
1388
1618
|
/**
|
|
1389
1619
|
* Ссылка на Proxy-инстанс для использования в BehaviorContext
|
|
1390
1620
|
*/
|
|
@@ -1392,32 +1622,35 @@ class S extends F {
|
|
|
1392
1622
|
/**
|
|
1393
1623
|
* Навигатор для работы с путями к полям
|
|
1394
1624
|
*/
|
|
1395
|
-
pathNavigator = new
|
|
1625
|
+
pathNavigator = new se();
|
|
1396
1626
|
/**
|
|
1397
1627
|
* Фабрика для создания узлов формы
|
|
1398
1628
|
*/
|
|
1399
|
-
nodeFactory = new
|
|
1629
|
+
nodeFactory = new ne();
|
|
1400
1630
|
/**
|
|
1401
1631
|
* Реестр валидаторов для этой формы
|
|
1632
|
+
* Может быть инжектирован через config._validationRegistry для тестирования
|
|
1402
1633
|
*/
|
|
1403
|
-
validationRegistry
|
|
1634
|
+
validationRegistry;
|
|
1404
1635
|
/**
|
|
1405
1636
|
* Реестр behaviors для этой формы
|
|
1637
|
+
* Может быть инжектирован через config._behaviorRegistry для тестирования
|
|
1406
1638
|
*/
|
|
1407
|
-
behaviorRegistry
|
|
1639
|
+
behaviorRegistry;
|
|
1408
1640
|
/**
|
|
1409
1641
|
* Аппликатор для применения валидаторов к форме
|
|
1410
1642
|
*/
|
|
1411
|
-
validationApplicator = new
|
|
1643
|
+
validationApplicator = new te(this);
|
|
1412
1644
|
// ============================================================================
|
|
1413
1645
|
// Приватные сигналы состояния (inline из StateManager)
|
|
1414
1646
|
// ============================================================================
|
|
1415
|
-
/**
|
|
1416
|
-
|
|
1647
|
+
/** Управление отправкой формы */
|
|
1648
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1649
|
+
formSubmitter;
|
|
1417
1650
|
/** Флаг disabled состояния */
|
|
1418
|
-
_disabled =
|
|
1651
|
+
_disabled = g(!1);
|
|
1419
1652
|
/** Form-level validation errors */
|
|
1420
|
-
_formErrors =
|
|
1653
|
+
_formErrors = g([]);
|
|
1421
1654
|
// ============================================================================
|
|
1422
1655
|
// Публичные computed signals
|
|
1423
1656
|
// ============================================================================
|
|
@@ -1431,76 +1664,56 @@ class S extends F {
|
|
|
1431
1664
|
status;
|
|
1432
1665
|
submitting;
|
|
1433
1666
|
constructor(e) {
|
|
1434
|
-
super();
|
|
1435
|
-
const t = "form" in e, i = t ? e.form : e, r = t ? e.behavior : void 0,
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
this.
|
|
1667
|
+
super(), this.formSubmitter = new ae(this);
|
|
1668
|
+
const t = "form" in e, s = t ? e : void 0, i = t ? e.form : e, r = t ? e.behavior : void 0, n = t ? e.validation : void 0;
|
|
1669
|
+
this.validationRegistry = s?._validationRegistry ?? new K(), this.behaviorRegistry = s?._behaviorRegistry ?? new H();
|
|
1670
|
+
for (const [l, u] of Object.entries(i)) {
|
|
1671
|
+
const v = this.createNode(u);
|
|
1672
|
+
this._fields.set(l, v);
|
|
1439
1673
|
}
|
|
1440
|
-
this.value =
|
|
1441
|
-
const
|
|
1442
|
-
return this._fields.forEach((
|
|
1443
|
-
|
|
1444
|
-
}),
|
|
1445
|
-
})
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}), o;
|
|
1456
|
-
}), this.status = u(() => this._disabled.value ? "disabled" : this.pending.value ? "pending" : this.invalid.value ? "invalid" : "valid"), this.submitting = u(() => this._submitting.value);
|
|
1457
|
-
const n = this.buildProxy();
|
|
1458
|
-
return this._proxyInstance = n, r && this.applyBehaviorSchema(r), s && this.applyValidationSchema(s), n;
|
|
1459
|
-
}
|
|
1460
|
-
// ============================================================================
|
|
1461
|
-
// Приватный метод для создания Proxy (inline из ProxyBuilder)
|
|
1674
|
+
this.value = d(() => {
|
|
1675
|
+
const l = {};
|
|
1676
|
+
return this._fields.forEach((u, v) => {
|
|
1677
|
+
l[v] = u.value.value;
|
|
1678
|
+
}), l;
|
|
1679
|
+
});
|
|
1680
|
+
const o = W({
|
|
1681
|
+
getChildren: () => Array.from(this._fields.values()),
|
|
1682
|
+
ownErrors: this._formErrors,
|
|
1683
|
+
disabled: this._disabled
|
|
1684
|
+
});
|
|
1685
|
+
this.valid = o.valid, this.invalid = o.invalid, this.pending = o.pending, this.touched = o.touched, this.dirty = o.dirty, this.errors = o.errors, this.status = o.status, this.submitting = this.formSubmitter.submitting, r && this.applyBehaviorSchema(r), n && this.applyValidationSchema(n);
|
|
1686
|
+
}
|
|
1687
|
+
// ============================================================================
|
|
1688
|
+
// Приватный метод для создания Proxy
|
|
1462
1689
|
// ============================================================================
|
|
1463
1690
|
/**
|
|
1464
1691
|
* Создать Proxy для типобезопасного доступа к полям
|
|
1692
|
+
* @see buildFormProxy
|
|
1465
1693
|
*/
|
|
1466
1694
|
buildProxy() {
|
|
1467
|
-
|
|
1468
|
-
return new Proxy(this, {
|
|
1469
|
-
get: (t, i) => {
|
|
1470
|
-
if (i in t)
|
|
1471
|
-
return t[i];
|
|
1472
|
-
if (typeof i == "string" && e._fields.has(i))
|
|
1473
|
-
return e._fields.get(i);
|
|
1474
|
-
},
|
|
1475
|
-
set: (t, i, r) => typeof i == "string" && e._fields.has(i) ? !1 : (t[i] = r, !0),
|
|
1476
|
-
has: (t, i) => typeof i == "string" && e._fields.has(i) ? !0 : i in t,
|
|
1477
|
-
ownKeys: (t) => {
|
|
1478
|
-
const i = Reflect.ownKeys(t), r = Array.from(e._fields.keys());
|
|
1479
|
-
return [.../* @__PURE__ */ new Set([...i, ...r])];
|
|
1480
|
-
},
|
|
1481
|
-
getOwnPropertyDescriptor: (t, i) => typeof i == "string" && e._fields.has(i) ? { enumerable: !0, configurable: !0 } : Reflect.getOwnPropertyDescriptor(t, i)
|
|
1482
|
-
});
|
|
1695
|
+
return re(this, this._fields);
|
|
1483
1696
|
}
|
|
1484
1697
|
// ============================================================================
|
|
1485
1698
|
// Реализация абстрактных методов FormNode
|
|
1486
1699
|
// ============================================================================
|
|
1487
1700
|
getValue() {
|
|
1488
1701
|
const e = {};
|
|
1489
|
-
return this._fields.forEach((t,
|
|
1490
|
-
e[
|
|
1702
|
+
return this._fields.forEach((t, s) => {
|
|
1703
|
+
e[s] = t.getValue();
|
|
1491
1704
|
}), e;
|
|
1492
1705
|
}
|
|
1493
1706
|
setValue(e, t) {
|
|
1494
|
-
for (const [
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1707
|
+
for (const [s, i] of Object.entries(e)) {
|
|
1708
|
+
const r = this._fields.get(s);
|
|
1709
|
+
r && r.setValue(i, t);
|
|
1497
1710
|
}
|
|
1498
1711
|
}
|
|
1499
1712
|
patchValue(e) {
|
|
1500
|
-
|
|
1501
|
-
for (const [t,
|
|
1502
|
-
const
|
|
1503
|
-
|
|
1713
|
+
j(() => {
|
|
1714
|
+
for (const [t, s] of Object.entries(e)) {
|
|
1715
|
+
const i = this._fields.get(t);
|
|
1716
|
+
i && s !== void 0 && i.setValue(s, { emitEvent: !1 });
|
|
1504
1717
|
}
|
|
1505
1718
|
});
|
|
1506
1719
|
}
|
|
@@ -1522,9 +1735,9 @@ class S extends F {
|
|
|
1522
1735
|
* ```
|
|
1523
1736
|
*/
|
|
1524
1737
|
reset(e) {
|
|
1525
|
-
this._fields.forEach((t,
|
|
1526
|
-
const
|
|
1527
|
-
t.reset(
|
|
1738
|
+
this._fields.forEach((t, s) => {
|
|
1739
|
+
const i = e?.[s];
|
|
1740
|
+
t.reset(i);
|
|
1528
1741
|
});
|
|
1529
1742
|
}
|
|
1530
1743
|
/**
|
|
@@ -1538,7 +1751,9 @@ class S extends F {
|
|
|
1538
1751
|
async validate() {
|
|
1539
1752
|
this.clearErrors(), await Promise.all(Array.from(this._fields.values()).map((t) => t.validate()));
|
|
1540
1753
|
const e = this.validationRegistry.getValidators();
|
|
1541
|
-
return e && e.length > 0 && await this.applyContextualValidators(e), Array.from(this._fields.values()).every(
|
|
1754
|
+
return e && e.length > 0 && await this.applyContextualValidators(e), Array.from(this._fields.values()).every(
|
|
1755
|
+
(t) => t.valid.value || t.disabled.value
|
|
1756
|
+
);
|
|
1542
1757
|
}
|
|
1543
1758
|
/**
|
|
1544
1759
|
* Установить form-level validation errors
|
|
@@ -1591,7 +1806,7 @@ class S extends F {
|
|
|
1591
1806
|
* ```
|
|
1592
1807
|
*/
|
|
1593
1808
|
getProxy() {
|
|
1594
|
-
return this._proxyInstance || this;
|
|
1809
|
+
return this._proxyInstance || (this._proxyInstance = this.buildProxy()), this._proxyInstance;
|
|
1595
1810
|
}
|
|
1596
1811
|
/**
|
|
1597
1812
|
* Получить все поля формы как итератор
|
|
@@ -1619,16 +1834,23 @@ class S extends F {
|
|
|
1619
1834
|
// ============================================================================
|
|
1620
1835
|
/**
|
|
1621
1836
|
* Отправить форму
|
|
1837
|
+
*
|
|
1838
|
+
* @param onSubmit - Callback для отправки данных
|
|
1839
|
+
* @param options - Опции submit (skipValidation, skipTouch)
|
|
1840
|
+
* @returns Результат от onSubmit или null если валидация не пройдена
|
|
1622
1841
|
*/
|
|
1623
|
-
async submit(e) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1842
|
+
async submit(e, t) {
|
|
1843
|
+
return this.formSubmitter.submit(e, t);
|
|
1844
|
+
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Отправить форму с расширенным результатом
|
|
1847
|
+
*
|
|
1848
|
+
* @param onSubmit - Callback для отправки данных
|
|
1849
|
+
* @param options - Опции submit
|
|
1850
|
+
* @returns Объект SubmitResult с данными, статусом и возможной ошибкой
|
|
1851
|
+
*/
|
|
1852
|
+
async submitWithResult(e, t) {
|
|
1853
|
+
return this.formSubmitter.submitWithResult(e, t);
|
|
1632
1854
|
}
|
|
1633
1855
|
/**
|
|
1634
1856
|
* Применить validation schema к форме
|
|
@@ -1639,10 +1861,10 @@ class S extends F {
|
|
|
1639
1861
|
applyValidationSchema(e) {
|
|
1640
1862
|
this.validationRegistry.beginRegistration();
|
|
1641
1863
|
try {
|
|
1642
|
-
const t =
|
|
1864
|
+
const t = I();
|
|
1643
1865
|
e(t);
|
|
1644
|
-
const
|
|
1645
|
-
this.validationRegistry.endRegistration(
|
|
1866
|
+
const s = this.getProxy();
|
|
1867
|
+
this.validationRegistry.endRegistration(s);
|
|
1646
1868
|
} catch (t) {
|
|
1647
1869
|
throw console.error("Error applying validation schema:", t), t;
|
|
1648
1870
|
}
|
|
@@ -1654,7 +1876,7 @@ class S extends F {
|
|
|
1654
1876
|
applyBehaviorSchema(e) {
|
|
1655
1877
|
this.behaviorRegistry.beginRegistration();
|
|
1656
1878
|
try {
|
|
1657
|
-
const t =
|
|
1879
|
+
const t = I();
|
|
1658
1880
|
return e(t), this.behaviorRegistry.endRegistration(this.getProxy()).cleanup;
|
|
1659
1881
|
} catch (t) {
|
|
1660
1882
|
throw console.error("Error applying behavior schema:", t), t;
|
|
@@ -1695,18 +1917,18 @@ class S extends F {
|
|
|
1695
1917
|
const t = this.pathNavigator.parsePath(e);
|
|
1696
1918
|
if (t.length === 0)
|
|
1697
1919
|
return;
|
|
1698
|
-
let
|
|
1699
|
-
for (const
|
|
1700
|
-
if (!(
|
|
1701
|
-
if (
|
|
1702
|
-
if ("at" in
|
|
1703
|
-
const
|
|
1704
|
-
if (!
|
|
1705
|
-
|
|
1920
|
+
let s = this;
|
|
1921
|
+
for (const i of t) {
|
|
1922
|
+
if (!(s instanceof k) || (s = s.getField(i.key), !s)) return;
|
|
1923
|
+
if (i.index !== void 0)
|
|
1924
|
+
if ("at" in s && "length" in s && typeof s.at == "function") {
|
|
1925
|
+
const r = s.at(i.index);
|
|
1926
|
+
if (!r) return;
|
|
1927
|
+
s = r;
|
|
1706
1928
|
} else
|
|
1707
1929
|
return;
|
|
1708
1930
|
}
|
|
1709
|
-
return
|
|
1931
|
+
return s;
|
|
1710
1932
|
}
|
|
1711
1933
|
/**
|
|
1712
1934
|
* Применить contextual валидаторы к полям
|
|
@@ -1750,15 +1972,16 @@ class S extends F {
|
|
|
1750
1972
|
/**
|
|
1751
1973
|
* Связывает два поля: при изменении source автоматически обновляется target
|
|
1752
1974
|
*/
|
|
1753
|
-
linkFields(e, t,
|
|
1754
|
-
const
|
|
1755
|
-
if (!
|
|
1756
|
-
|
|
1757
|
-
};
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1975
|
+
linkFields(e, t, s) {
|
|
1976
|
+
const i = this._fields.get(e), r = this._fields.get(t);
|
|
1977
|
+
if (!i || !r) {
|
|
1978
|
+
const l = i ? t : e;
|
|
1979
|
+
throw new Error(`GroupNode.linkFields: field "${String(l)}" not found`);
|
|
1980
|
+
}
|
|
1981
|
+
const n = m(() => {
|
|
1982
|
+
const l = i.value.value, u = s ? s(l) : l;
|
|
1983
|
+
r.setValue(u, { emitEvent: !1 });
|
|
1984
|
+
}), o = A(w.LinkFields);
|
|
1762
1985
|
return this.disposers.add(o, n);
|
|
1763
1986
|
}
|
|
1764
1987
|
/**
|
|
@@ -1789,15 +2012,14 @@ class S extends F {
|
|
|
1789
2012
|
* ```
|
|
1790
2013
|
*/
|
|
1791
2014
|
watchField(e, t) {
|
|
1792
|
-
const
|
|
1793
|
-
if (!
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
const n = i.value.value;
|
|
2015
|
+
const s = this.getFieldByPath(e);
|
|
2016
|
+
if (!s)
|
|
2017
|
+
throw new Error(`GroupNode.watchField: field "${e}" not found`);
|
|
2018
|
+
const i = m(() => {
|
|
2019
|
+
const n = s.value.value;
|
|
1798
2020
|
t(n);
|
|
1799
|
-
}),
|
|
1800
|
-
return this.disposers.add(
|
|
2021
|
+
}), r = A(w.WatchField);
|
|
2022
|
+
return this.disposers.add(r, i);
|
|
1801
2023
|
}
|
|
1802
2024
|
/**
|
|
1803
2025
|
* Hook: вызывается после disable()
|
|
@@ -1820,7 +2042,7 @@ class S extends F {
|
|
|
1820
2042
|
});
|
|
1821
2043
|
}
|
|
1822
2044
|
}
|
|
1823
|
-
class
|
|
2045
|
+
class L extends C {
|
|
1824
2046
|
// ============================================================================
|
|
1825
2047
|
// Приватные поля
|
|
1826
2048
|
// ============================================================================
|
|
@@ -1831,7 +2053,9 @@ class T extends F {
|
|
|
1831
2053
|
* Менеджер подписок для централизованного cleanup
|
|
1832
2054
|
* Использует SubscriptionManager вместо массива для управления подписками
|
|
1833
2055
|
*/
|
|
1834
|
-
disposers = new
|
|
2056
|
+
disposers = new D();
|
|
2057
|
+
/** Array-level validation errors (e.g., "минимум 1 элемент") */
|
|
2058
|
+
_arrayErrors = g([]);
|
|
1835
2059
|
// ============================================================================
|
|
1836
2060
|
// Приватные поля для сохранения схем
|
|
1837
2061
|
// ============================================================================
|
|
@@ -1853,15 +2077,15 @@ class T extends F {
|
|
|
1853
2077
|
// Конструктор
|
|
1854
2078
|
// ============================================================================
|
|
1855
2079
|
constructor(e, t = []) {
|
|
1856
|
-
super(), this.itemSchema = e, this.initialItems = t, this.items =
|
|
2080
|
+
super(), this.itemSchema = e, this.initialItems = t, this.items = g([]);
|
|
1857
2081
|
for (const i of t)
|
|
1858
2082
|
this.push(i);
|
|
1859
|
-
this.length =
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2083
|
+
this.length = d(() => this.items.value.length), this.value = d(() => this.items.value.map((i) => i.value.value));
|
|
2084
|
+
const s = W({
|
|
2085
|
+
getChildren: () => this.items.value,
|
|
2086
|
+
ownErrors: this._arrayErrors
|
|
2087
|
+
});
|
|
2088
|
+
this.valid = s.valid, this.invalid = s.invalid, this.pending = s.pending, this.touched = s.touched, this.dirty = s.dirty, this.errors = s.errors, this.status = s.status;
|
|
1865
2089
|
}
|
|
1866
2090
|
// ============================================================================
|
|
1867
2091
|
// CRUD операции
|
|
@@ -1877,9 +2101,23 @@ class T extends F {
|
|
|
1877
2101
|
/**
|
|
1878
2102
|
* Удалить элемент по индексу
|
|
1879
2103
|
* @param index - Индекс элемента для удаления
|
|
2104
|
+
*
|
|
2105
|
+
* @remarks
|
|
2106
|
+
* Вызывает dispose() на удаляемом элементе для очистки подписок
|
|
1880
2107
|
*/
|
|
1881
2108
|
removeAt(e) {
|
|
1882
|
-
e < 0 || e >= this.items.value.length
|
|
2109
|
+
if (e < 0 || e >= this.items.value.length) {
|
|
2110
|
+
S.handle(
|
|
2111
|
+
new Error(
|
|
2112
|
+
`ArrayNode.removeAt: index ${e} out of bounds (length: ${this.items.value.length})`
|
|
2113
|
+
),
|
|
2114
|
+
"ArrayNode.removeAt",
|
|
2115
|
+
V.LOG
|
|
2116
|
+
);
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
const t = this.items.value[e];
|
|
2120
|
+
this.items.value = this.items.value.filter((s, i) => i !== e), t && "dispose" in t && typeof t.dispose == "function" && t.dispose();
|
|
1883
2121
|
}
|
|
1884
2122
|
/**
|
|
1885
2123
|
* Вставить элемент в массив
|
|
@@ -1887,24 +2125,40 @@ class T extends F {
|
|
|
1887
2125
|
* @param initialValue - Начальные значения для нового элемента
|
|
1888
2126
|
*/
|
|
1889
2127
|
insert(e, t) {
|
|
1890
|
-
if (e < 0 || e > this.items.value.length)
|
|
2128
|
+
if (e < 0 || e > this.items.value.length) {
|
|
2129
|
+
S.handle(
|
|
2130
|
+
new Error(
|
|
2131
|
+
`ArrayNode.insert: index ${e} out of bounds (length: ${this.items.value.length})`
|
|
2132
|
+
),
|
|
2133
|
+
"ArrayNode.insert",
|
|
2134
|
+
V.LOG
|
|
2135
|
+
);
|
|
1891
2136
|
return;
|
|
1892
|
-
|
|
1893
|
-
|
|
2137
|
+
}
|
|
2138
|
+
const s = this.createItem(t), i = [...this.items.value];
|
|
2139
|
+
i.splice(e, 0, s), this.items.value = i;
|
|
1894
2140
|
}
|
|
1895
2141
|
/**
|
|
1896
2142
|
* Удалить все элементы массива
|
|
2143
|
+
*
|
|
2144
|
+
* @remarks
|
|
2145
|
+
* Вызывает dispose() на всех элементах для очистки подписок
|
|
1897
2146
|
*/
|
|
1898
2147
|
clear() {
|
|
1899
|
-
this.items.value
|
|
2148
|
+
const e = [...this.items.value];
|
|
2149
|
+
this.items.value = [], e.forEach((t) => {
|
|
2150
|
+
"dispose" in t && typeof t.dispose == "function" && t.dispose();
|
|
2151
|
+
});
|
|
1900
2152
|
}
|
|
1901
2153
|
/**
|
|
1902
2154
|
* Получить элемент по индексу
|
|
1903
2155
|
* @param index - Индекс элемента
|
|
1904
|
-
* @returns Типизированный GroupNode или undefined если индекс вне границ
|
|
2156
|
+
* @returns Типизированный GroupNode proxy или undefined если индекс вне границ
|
|
1905
2157
|
*/
|
|
1906
2158
|
at(e) {
|
|
1907
|
-
|
|
2159
|
+
const t = this.items.value[e];
|
|
2160
|
+
if (t)
|
|
2161
|
+
return t.getProxy();
|
|
1908
2162
|
}
|
|
1909
2163
|
// ============================================================================
|
|
1910
2164
|
// Реализация абстрактных методов
|
|
@@ -1913,12 +2167,13 @@ class T extends F {
|
|
|
1913
2167
|
return this.items.value.map((e) => e.getValue());
|
|
1914
2168
|
}
|
|
1915
2169
|
setValue(e, t) {
|
|
1916
|
-
this.clear(), e.forEach((
|
|
2170
|
+
this.clear(), e.forEach((s) => this.push(s)), t?.emitEvent !== !1 && this.validate().catch((s) => {
|
|
2171
|
+
S.handle(s, "ArrayNode.setValue", V.LOG);
|
|
1917
2172
|
});
|
|
1918
2173
|
}
|
|
1919
2174
|
patchValue(e) {
|
|
1920
|
-
e.forEach((t,
|
|
1921
|
-
this.items.value[
|
|
2175
|
+
e.forEach((t, s) => {
|
|
2176
|
+
this.items.value[s] && t !== void 0 && this.items.value[s].patchValue(t);
|
|
1922
2177
|
});
|
|
1923
2178
|
}
|
|
1924
2179
|
/**
|
|
@@ -1939,7 +2194,7 @@ class T extends F {
|
|
|
1939
2194
|
* ```
|
|
1940
2195
|
*/
|
|
1941
2196
|
reset(e) {
|
|
1942
|
-
this.clear(), e && e.forEach((t) => this.push(t));
|
|
2197
|
+
this._arrayErrors.value = [], this.clear(), e && e.forEach((t) => this.push(t));
|
|
1943
2198
|
}
|
|
1944
2199
|
/**
|
|
1945
2200
|
* Сбросить массив к исходным значениям (initialItems)
|
|
@@ -1970,15 +2225,38 @@ class T extends F {
|
|
|
1970
2225
|
* ```
|
|
1971
2226
|
*/
|
|
1972
2227
|
resetToInitial() {
|
|
1973
|
-
this.clear(), this.initialItems.forEach((e) => this.push(e));
|
|
2228
|
+
this._arrayErrors.value = [], this.clear(), this.initialItems.forEach((e) => this.push(e));
|
|
1974
2229
|
}
|
|
1975
2230
|
async validate() {
|
|
1976
2231
|
return (await Promise.all(this.items.value.map((t) => t.validate()))).every(Boolean);
|
|
1977
2232
|
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Установить array-level validation errors
|
|
2235
|
+
*
|
|
2236
|
+
* @param errors - Массив ошибок валидации уровня массива
|
|
2237
|
+
*
|
|
2238
|
+
* @example
|
|
2239
|
+
* ```typescript
|
|
2240
|
+
* arrayNode.setErrors([{
|
|
2241
|
+
* code: 'minItems',
|
|
2242
|
+
* message: 'Минимум 1 элемент обязателен',
|
|
2243
|
+
* }]);
|
|
2244
|
+
* ```
|
|
2245
|
+
*/
|
|
1978
2246
|
setErrors(e) {
|
|
2247
|
+
this._arrayErrors.value = e;
|
|
1979
2248
|
}
|
|
2249
|
+
/**
|
|
2250
|
+
* Очистить все errors (array-level + item-level)
|
|
2251
|
+
*
|
|
2252
|
+
* @example
|
|
2253
|
+
* ```typescript
|
|
2254
|
+
* arrayNode.clearErrors();
|
|
2255
|
+
* console.log(arrayNode.errors.value); // []
|
|
2256
|
+
* ```
|
|
2257
|
+
*/
|
|
1980
2258
|
clearErrors() {
|
|
1981
|
-
this.items.value.forEach((e) => e.clearErrors());
|
|
2259
|
+
this._arrayErrors.value = [], this.items.value.forEach((e) => e.clearErrors());
|
|
1982
2260
|
}
|
|
1983
2261
|
// ============================================================================
|
|
1984
2262
|
// Protected hooks (Template Method pattern)
|
|
@@ -2020,20 +2298,24 @@ class T extends F {
|
|
|
2020
2298
|
// ============================================================================
|
|
2021
2299
|
/**
|
|
2022
2300
|
* Итерировать по элементам массива
|
|
2023
|
-
* @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode
|
|
2301
|
+
* @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode proxy
|
|
2024
2302
|
*/
|
|
2025
2303
|
forEach(e) {
|
|
2026
|
-
this.items.value.forEach((t,
|
|
2027
|
-
|
|
2304
|
+
this.items.value.forEach((t, s) => {
|
|
2305
|
+
const i = t.getProxy();
|
|
2306
|
+
e(i, s);
|
|
2028
2307
|
});
|
|
2029
2308
|
}
|
|
2030
2309
|
/**
|
|
2031
2310
|
* Маппинг элементов массива
|
|
2032
|
-
* @param callback - Функция преобразования с типизированным GroupNode
|
|
2311
|
+
* @param callback - Функция преобразования с типизированным GroupNode proxy
|
|
2033
2312
|
* @returns Новый массив результатов
|
|
2034
2313
|
*/
|
|
2035
2314
|
map(e) {
|
|
2036
|
-
return this.items.value.map((t,
|
|
2315
|
+
return this.items.value.map((t, s) => {
|
|
2316
|
+
const i = t.getProxy();
|
|
2317
|
+
return e(i, s);
|
|
2318
|
+
});
|
|
2037
2319
|
}
|
|
2038
2320
|
// ============================================================================
|
|
2039
2321
|
// Private методы
|
|
@@ -2044,7 +2326,7 @@ class T extends F {
|
|
|
2044
2326
|
*/
|
|
2045
2327
|
createItem(e) {
|
|
2046
2328
|
if (this.isGroupSchema(this.itemSchema)) {
|
|
2047
|
-
const t = new
|
|
2329
|
+
const t = new k(this.itemSchema);
|
|
2048
2330
|
return e && t.patchValue(e), this.validationSchemaFn && "applyValidationSchema" in t && t.applyValidationSchema(this.validationSchemaFn), this.behaviorSchemaFn && "applyBehaviorSchema" in t && t.applyBehaviorSchema(this.behaviorSchemaFn), t;
|
|
2049
2331
|
}
|
|
2050
2332
|
throw new Error(
|
|
@@ -2131,14 +2413,14 @@ class T extends F {
|
|
|
2131
2413
|
* ```
|
|
2132
2414
|
*/
|
|
2133
2415
|
watchItems(e, t) {
|
|
2134
|
-
const
|
|
2135
|
-
const
|
|
2136
|
-
if (n instanceof
|
|
2416
|
+
const s = m(() => {
|
|
2417
|
+
const r = this.items.value.map((n) => {
|
|
2418
|
+
if (n instanceof k)
|
|
2137
2419
|
return n.getFieldByPath(e)?.value.value;
|
|
2138
2420
|
});
|
|
2139
|
-
t(
|
|
2140
|
-
}),
|
|
2141
|
-
return this.disposers.add(
|
|
2421
|
+
t(r);
|
|
2422
|
+
}), i = A(w.WatchItems);
|
|
2423
|
+
return this.disposers.add(i, s);
|
|
2142
2424
|
}
|
|
2143
2425
|
/**
|
|
2144
2426
|
* Подписка на изменение длины массива
|
|
@@ -2163,11 +2445,11 @@ class T extends F {
|
|
|
2163
2445
|
* ```
|
|
2164
2446
|
*/
|
|
2165
2447
|
watchLength(e) {
|
|
2166
|
-
const t =
|
|
2167
|
-
const
|
|
2168
|
-
e(
|
|
2169
|
-
}),
|
|
2170
|
-
return this.disposers.add(
|
|
2448
|
+
const t = m(() => {
|
|
2449
|
+
const i = this.length.value;
|
|
2450
|
+
e(i);
|
|
2451
|
+
}), s = A(w.WatchLength);
|
|
2452
|
+
return this.disposers.add(s, t);
|
|
2171
2453
|
}
|
|
2172
2454
|
/**
|
|
2173
2455
|
* Очистить все ресурсы узла
|
|
@@ -2230,7 +2512,7 @@ class T extends F {
|
|
|
2230
2512
|
});
|
|
2231
2513
|
}
|
|
2232
2514
|
}
|
|
2233
|
-
class
|
|
2515
|
+
class ne {
|
|
2234
2516
|
/**
|
|
2235
2517
|
* Создает узел формы на основе конфигурации
|
|
2236
2518
|
*
|
|
@@ -2280,16 +2562,16 @@ class X {
|
|
|
2280
2562
|
if (Array.isArray(e) && e.length >= 1)
|
|
2281
2563
|
return this.createArrayNodeFromArray(e);
|
|
2282
2564
|
if (this.isFieldConfig(e))
|
|
2283
|
-
return new
|
|
2565
|
+
return new ee(e);
|
|
2284
2566
|
if (this.isArrayConfig(e)) {
|
|
2285
2567
|
const t = e;
|
|
2286
|
-
return new
|
|
2568
|
+
return new L(
|
|
2287
2569
|
t.schema,
|
|
2288
2570
|
t.initialItems
|
|
2289
2571
|
);
|
|
2290
2572
|
}
|
|
2291
2573
|
if (this.isGroupConfig(e))
|
|
2292
|
-
return new
|
|
2574
|
+
return new k(e);
|
|
2293
2575
|
throw new Error(
|
|
2294
2576
|
`NodeFactory: Unknown node config. Expected FieldConfig, GroupConfig, or ArrayConfig, but got: ${JSON.stringify(
|
|
2295
2577
|
e
|
|
@@ -2323,11 +2605,11 @@ class X {
|
|
|
2323
2605
|
*/
|
|
2324
2606
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2325
2607
|
createArrayNodeFromArray(e) {
|
|
2326
|
-
const [t, ...
|
|
2327
|
-
this.isGroupConfig(t) &&
|
|
2328
|
-
for (const
|
|
2329
|
-
this.isGroupConfig(
|
|
2330
|
-
return new
|
|
2608
|
+
const [t, ...s] = e, i = [];
|
|
2609
|
+
this.isGroupConfig(t) && i.push(this.extractValues(t));
|
|
2610
|
+
for (const r of s)
|
|
2611
|
+
this.isGroupConfig(r) ? i.push(this.extractValues(r)) : i.push(r);
|
|
2612
|
+
return new L(t, i);
|
|
2331
2613
|
}
|
|
2332
2614
|
/**
|
|
2333
2615
|
* Извлечь значения из схемы (рекурсивно)
|
|
@@ -2365,8 +2647,8 @@ class X {
|
|
|
2365
2647
|
return e.map((t) => this.extractValues(t));
|
|
2366
2648
|
if (this.isGroupConfig(e)) {
|
|
2367
2649
|
const t = {};
|
|
2368
|
-
for (const [
|
|
2369
|
-
t[
|
|
2650
|
+
for (const [s, i] of Object.entries(e))
|
|
2651
|
+
t[s] = this.extractValues(i);
|
|
2370
2652
|
return t;
|
|
2371
2653
|
}
|
|
2372
2654
|
return e;
|
|
@@ -2446,299 +2728,334 @@ class X {
|
|
|
2446
2728
|
return e != null && typeof e == "object" && !this.isFieldConfig(e) && !this.isArrayConfig(e);
|
|
2447
2729
|
}
|
|
2448
2730
|
}
|
|
2449
|
-
|
|
2731
|
+
function ge(a) {
|
|
2732
|
+
return new k(a).getProxy();
|
|
2733
|
+
}
|
|
2734
|
+
class be {
|
|
2450
2735
|
/**
|
|
2451
|
-
*
|
|
2736
|
+
* @param form - Форма для наблюдения
|
|
2737
|
+
* @param options - Опции observer
|
|
2738
|
+
*/
|
|
2739
|
+
constructor(e, t) {
|
|
2740
|
+
this.form = e, this.options = {
|
|
2741
|
+
enableLogging: !1,
|
|
2742
|
+
eventTypes: ["value", "status", "errors", "touched", "dirty"],
|
|
2743
|
+
pathFilter: [],
|
|
2744
|
+
...t
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
listeners = /* @__PURE__ */ new Set();
|
|
2748
|
+
disposers = [];
|
|
2749
|
+
options;
|
|
2750
|
+
/**
|
|
2751
|
+
* Подписаться на события изменения
|
|
2452
2752
|
*
|
|
2453
|
-
* @param
|
|
2753
|
+
* @param callback - Функция обработки события
|
|
2754
|
+
* @returns Функция отписки
|
|
2454
2755
|
*
|
|
2455
2756
|
* @example
|
|
2456
2757
|
* ```typescript
|
|
2457
|
-
* const
|
|
2458
|
-
*
|
|
2758
|
+
* const unsubscribe = observer.subscribe((event) => {
|
|
2759
|
+
* // Отправить событие в analytics
|
|
2760
|
+
* analytics.track('form_change', event);
|
|
2761
|
+
* });
|
|
2459
2762
|
* ```
|
|
2460
2763
|
*/
|
|
2461
|
-
|
|
2462
|
-
this.
|
|
2764
|
+
subscribe(e) {
|
|
2765
|
+
return this.listeners.add(e), () => this.listeners.delete(e);
|
|
2463
2766
|
}
|
|
2464
2767
|
/**
|
|
2465
|
-
*
|
|
2466
|
-
* @private
|
|
2467
|
-
*/
|
|
2468
|
-
timer;
|
|
2469
|
-
/**
|
|
2470
|
-
* Отложить выполнение функции
|
|
2768
|
+
* Включить трассировку формы
|
|
2471
2769
|
*
|
|
2472
|
-
*
|
|
2473
|
-
* и
|
|
2770
|
+
* Подписывается на изменения основных сигналов формы
|
|
2771
|
+
* и вызывает listeners при каждом изменении
|
|
2474
2772
|
*
|
|
2475
|
-
* @
|
|
2476
|
-
* @returns Promise, который разрешается результатом функции
|
|
2773
|
+
* @returns Функция для отключения трассировки
|
|
2477
2774
|
*
|
|
2478
2775
|
* @example
|
|
2479
2776
|
* ```typescript
|
|
2480
|
-
* const
|
|
2481
|
-
*
|
|
2482
|
-
* // Первый вызов - запланирован через 300мс
|
|
2483
|
-
* debouncer.debounce(async () => console.log('First'));
|
|
2777
|
+
* const dispose = observer.enableTracing();
|
|
2484
2778
|
*
|
|
2485
|
-
* //
|
|
2486
|
-
*
|
|
2487
|
-
*
|
|
2488
|
-
* // Через 300мс выведет только: "Second"
|
|
2779
|
+
* // Позже, для отключения
|
|
2780
|
+
* dispose();
|
|
2489
2781
|
* ```
|
|
2490
2782
|
*/
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
}
|
|
2783
|
+
enableTracing() {
|
|
2784
|
+
if (this.shouldTrack("value")) {
|
|
2785
|
+
let e = this.form.value.value;
|
|
2786
|
+
const t = m(() => {
|
|
2787
|
+
const s = this.form.value.value;
|
|
2788
|
+
s !== e && (this.emit({
|
|
2789
|
+
type: "value",
|
|
2790
|
+
path: "",
|
|
2791
|
+
timestamp: Date.now(),
|
|
2792
|
+
oldValue: e,
|
|
2793
|
+
newValue: s
|
|
2794
|
+
}), e = s);
|
|
2795
|
+
});
|
|
2796
|
+
this.disposers.push(t);
|
|
2797
|
+
}
|
|
2798
|
+
if (this.shouldTrack("status")) {
|
|
2799
|
+
let e = this.form.status.value;
|
|
2800
|
+
const t = m(() => {
|
|
2801
|
+
const s = this.form.status.value;
|
|
2802
|
+
s !== e && (this.emit({
|
|
2803
|
+
type: "status",
|
|
2804
|
+
path: "",
|
|
2805
|
+
timestamp: Date.now(),
|
|
2806
|
+
oldValue: e,
|
|
2807
|
+
newValue: s
|
|
2808
|
+
}), e = s);
|
|
2809
|
+
});
|
|
2810
|
+
this.disposers.push(t);
|
|
2811
|
+
}
|
|
2812
|
+
if (this.shouldTrack("errors")) {
|
|
2813
|
+
let e = this.form.errors.value;
|
|
2814
|
+
const t = m(() => {
|
|
2815
|
+
const s = this.form.errors.value;
|
|
2816
|
+
s !== e && (this.emit({
|
|
2817
|
+
type: "errors",
|
|
2818
|
+
path: "",
|
|
2819
|
+
timestamp: Date.now(),
|
|
2820
|
+
oldValue: e,
|
|
2821
|
+
newValue: s
|
|
2822
|
+
}), e = s);
|
|
2823
|
+
});
|
|
2824
|
+
this.disposers.push(t);
|
|
2825
|
+
}
|
|
2826
|
+
if (this.shouldTrack("touched")) {
|
|
2827
|
+
let e = this.form.touched.value;
|
|
2828
|
+
const t = m(() => {
|
|
2829
|
+
const s = this.form.touched.value;
|
|
2830
|
+
s !== e && (this.emit({
|
|
2831
|
+
type: "touched",
|
|
2832
|
+
path: "",
|
|
2833
|
+
timestamp: Date.now(),
|
|
2834
|
+
oldValue: e,
|
|
2835
|
+
newValue: s
|
|
2836
|
+
}), e = s);
|
|
2837
|
+
});
|
|
2838
|
+
this.disposers.push(t);
|
|
2839
|
+
}
|
|
2840
|
+
if (this.shouldTrack("dirty")) {
|
|
2841
|
+
let e = this.form.dirty.value;
|
|
2842
|
+
const t = m(() => {
|
|
2843
|
+
const s = this.form.dirty.value;
|
|
2844
|
+
s !== e && (this.emit({
|
|
2845
|
+
type: "dirty",
|
|
2846
|
+
path: "",
|
|
2847
|
+
timestamp: Date.now(),
|
|
2848
|
+
oldValue: e,
|
|
2849
|
+
newValue: s
|
|
2850
|
+
}), e = s);
|
|
2851
|
+
});
|
|
2852
|
+
this.disposers.push(t);
|
|
2853
|
+
}
|
|
2854
|
+
return () => {
|
|
2855
|
+
this.disposers.forEach((e) => e()), this.disposers = [];
|
|
2856
|
+
};
|
|
2506
2857
|
}
|
|
2507
2858
|
/**
|
|
2508
|
-
*
|
|
2859
|
+
* Наблюдать за конкретным полем
|
|
2509
2860
|
*
|
|
2510
|
-
*
|
|
2511
|
-
*
|
|
2861
|
+
* @param path - Путь к полю
|
|
2862
|
+
* @returns Функция для отключения наблюдения
|
|
2512
2863
|
*
|
|
2513
2864
|
* @example
|
|
2514
2865
|
* ```typescript
|
|
2515
|
-
*
|
|
2516
|
-
*
|
|
2517
|
-
* debouncer.debounce(async () => {
|
|
2518
|
-
* console.log('This will not execute');
|
|
2519
|
-
* });
|
|
2520
|
-
*
|
|
2521
|
-
* debouncer.cancel(); // Отменяем вызов
|
|
2866
|
+
* // Наблюдать за полем email
|
|
2867
|
+
* const dispose = observer.watchField('email');
|
|
2522
2868
|
* ```
|
|
2523
2869
|
*/
|
|
2524
|
-
|
|
2525
|
-
|
|
2870
|
+
watchField(e) {
|
|
2871
|
+
const t = this.form.getFieldByPath(e);
|
|
2872
|
+
if (!t)
|
|
2873
|
+
return () => {
|
|
2874
|
+
};
|
|
2875
|
+
const s = [];
|
|
2876
|
+
if (this.shouldTrack("value")) {
|
|
2877
|
+
let i = t.value.value;
|
|
2878
|
+
const r = m(() => {
|
|
2879
|
+
const n = t.value.value;
|
|
2880
|
+
n !== i && (this.emit({
|
|
2881
|
+
type: "value",
|
|
2882
|
+
path: e,
|
|
2883
|
+
timestamp: Date.now(),
|
|
2884
|
+
oldValue: i,
|
|
2885
|
+
newValue: n
|
|
2886
|
+
}), i = n);
|
|
2887
|
+
});
|
|
2888
|
+
s.push(r);
|
|
2889
|
+
}
|
|
2890
|
+
if (this.shouldTrack("status")) {
|
|
2891
|
+
let i = t.status.value;
|
|
2892
|
+
const r = m(() => {
|
|
2893
|
+
const n = t.status.value;
|
|
2894
|
+
n !== i && (this.emit({
|
|
2895
|
+
type: "status",
|
|
2896
|
+
path: e,
|
|
2897
|
+
timestamp: Date.now(),
|
|
2898
|
+
oldValue: i,
|
|
2899
|
+
newValue: n
|
|
2900
|
+
}), i = n);
|
|
2901
|
+
});
|
|
2902
|
+
s.push(r);
|
|
2903
|
+
}
|
|
2904
|
+
return () => s.forEach((i) => i());
|
|
2526
2905
|
}
|
|
2527
2906
|
/**
|
|
2528
|
-
*
|
|
2529
|
-
*
|
|
2530
|
-
* Полезно когда нужно принудительно выполнить действие сейчас,
|
|
2531
|
-
* игнорируя debounce.
|
|
2532
|
-
*
|
|
2533
|
-
* @param fn Функция для немедленного выполнения
|
|
2534
|
-
* @returns Promise с результатом функции
|
|
2535
|
-
*
|
|
2536
|
-
* @example
|
|
2537
|
-
* ```typescript
|
|
2538
|
-
* const debouncer = new Debouncer(300);
|
|
2539
|
-
*
|
|
2540
|
-
* // Запланировано через 300мс
|
|
2541
|
-
* debouncer.debounce(async () => console.log('Delayed'));
|
|
2542
|
-
*
|
|
2543
|
-
* // Отменяем отложенный и выполняем немедленно
|
|
2544
|
-
* await debouncer.flush(async () => console.log('Immediate'));
|
|
2545
|
-
* // Выведет: "Immediate" (сразу)
|
|
2546
|
-
* // "Delayed" не выполнится (отменен)
|
|
2547
|
-
* ```
|
|
2907
|
+
* Отправить событие всем listeners
|
|
2548
2908
|
*/
|
|
2549
|
-
|
|
2550
|
-
|
|
2909
|
+
emit(e) {
|
|
2910
|
+
this.matchesPathFilter(e.path) && (this.options.enableLogging && console.log(`[FormObserver] ${e.type} at "${e.path || "root"}":`, e.newValue), this.listeners.forEach((t) => {
|
|
2911
|
+
try {
|
|
2912
|
+
t(e);
|
|
2913
|
+
} catch {
|
|
2914
|
+
}
|
|
2915
|
+
}));
|
|
2551
2916
|
}
|
|
2552
2917
|
/**
|
|
2553
|
-
* Проверить,
|
|
2554
|
-
*
|
|
2555
|
-
* @returns true если есть запланированный вызов
|
|
2556
|
-
*
|
|
2557
|
-
* @example
|
|
2558
|
-
* ```typescript
|
|
2559
|
-
* const debouncer = new Debouncer(300);
|
|
2560
|
-
*
|
|
2561
|
-
* console.log(debouncer.isPending()); // false
|
|
2562
|
-
*
|
|
2563
|
-
* debouncer.debounce(() => console.log('Test'));
|
|
2564
|
-
* console.log(debouncer.isPending()); // true
|
|
2565
|
-
*
|
|
2566
|
-
* // Через 300мс
|
|
2567
|
-
* console.log(debouncer.isPending()); // false
|
|
2568
|
-
* ```
|
|
2918
|
+
* Проверить, нужно ли отслеживать тип события
|
|
2569
2919
|
*/
|
|
2570
|
-
|
|
2571
|
-
return this.
|
|
2920
|
+
shouldTrack(e) {
|
|
2921
|
+
return this.options.eventTypes.includes(e);
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* Проверить, соответствует ли путь фильтру
|
|
2925
|
+
*/
|
|
2926
|
+
matchesPathFilter(e) {
|
|
2927
|
+
const { pathFilter: t } = this.options;
|
|
2928
|
+
return !t || Array.isArray(t) && t.length === 0 ? !0 : t instanceof RegExp ? t.test(e) : t.includes(e);
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* Очистить все подписки и disposers
|
|
2932
|
+
*/
|
|
2933
|
+
dispose() {
|
|
2934
|
+
this.disposers.forEach((e) => e()), this.disposers = [], this.listeners.clear();
|
|
2572
2935
|
}
|
|
2573
2936
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
}
|
|
2586
|
-
|
|
2587
|
-
let e = null;
|
|
2588
|
-
return {
|
|
2589
|
-
type: "preload",
|
|
2590
|
-
load: async (t) => {
|
|
2591
|
-
if (!e) {
|
|
2592
|
-
const i = await a(t);
|
|
2593
|
-
e = {
|
|
2594
|
-
items: i,
|
|
2595
|
-
totalCount: i.length
|
|
2596
|
-
};
|
|
2597
|
-
}
|
|
2598
|
-
return e;
|
|
2599
|
-
}
|
|
2600
|
-
};
|
|
2601
|
-
}
|
|
2602
|
-
function te(a) {
|
|
2603
|
-
return {
|
|
2604
|
-
type: "partial",
|
|
2605
|
-
load: async (e) => {
|
|
2606
|
-
const t = await a(e);
|
|
2607
|
-
return {
|
|
2608
|
-
items: t,
|
|
2609
|
-
totalCount: t.length
|
|
2610
|
-
// Можно расширить для поддержки серверной пагинации
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
};
|
|
2614
|
-
}
|
|
2615
|
-
const pe = {
|
|
2616
|
-
static: Z,
|
|
2617
|
-
preload: ee,
|
|
2618
|
-
partial: te
|
|
2619
|
-
};
|
|
2620
|
-
var w = { exports: {} }, k = {};
|
|
2621
|
-
var M;
|
|
2622
|
-
function ie() {
|
|
2623
|
-
if (M) return k;
|
|
2624
|
-
M = 1;
|
|
2625
|
-
var a = B;
|
|
2626
|
-
function e(c, f) {
|
|
2627
|
-
return c === f && (c !== 0 || 1 / c === 1 / f) || c !== c && f !== f;
|
|
2628
|
-
}
|
|
2629
|
-
var t = typeof Object.is == "function" ? Object.is : e, i = a.useState, r = a.useEffect, s = a.useLayoutEffect, n = a.useDebugValue;
|
|
2630
|
-
function o(c, f) {
|
|
2631
|
-
var h = f(), v = i({ inst: { value: h, getSnapshot: f } }), p = v[0].inst, g = v[1];
|
|
2632
|
-
return s(
|
|
2937
|
+
var x = { exports: {} }, T = {};
|
|
2938
|
+
var B;
|
|
2939
|
+
function oe() {
|
|
2940
|
+
if (B) return T;
|
|
2941
|
+
B = 1;
|
|
2942
|
+
var a = U;
|
|
2943
|
+
function e(h, f) {
|
|
2944
|
+
return h === f && (h !== 0 || 1 / h === 1 / f) || h !== h && f !== f;
|
|
2945
|
+
}
|
|
2946
|
+
var t = typeof Object.is == "function" ? Object.is : e, s = a.useState, i = a.useEffect, r = a.useLayoutEffect, n = a.useDebugValue;
|
|
2947
|
+
function o(h, f) {
|
|
2948
|
+
var c = f(), p = s({ inst: { value: c, getSnapshot: f } }), y = p[0].inst, E = p[1];
|
|
2949
|
+
return r(
|
|
2633
2950
|
function() {
|
|
2634
|
-
|
|
2951
|
+
y.value = c, y.getSnapshot = f, l(y) && E({ inst: y });
|
|
2635
2952
|
},
|
|
2636
|
-
[
|
|
2637
|
-
),
|
|
2953
|
+
[h, c, f]
|
|
2954
|
+
), i(
|
|
2638
2955
|
function() {
|
|
2639
|
-
return l(
|
|
2640
|
-
l(
|
|
2956
|
+
return l(y) && E({ inst: y }), h(function() {
|
|
2957
|
+
l(y) && E({ inst: y });
|
|
2641
2958
|
});
|
|
2642
2959
|
},
|
|
2643
|
-
[
|
|
2644
|
-
), n(
|
|
2960
|
+
[h]
|
|
2961
|
+
), n(c), c;
|
|
2645
2962
|
}
|
|
2646
|
-
function l(
|
|
2647
|
-
var f =
|
|
2648
|
-
|
|
2963
|
+
function l(h) {
|
|
2964
|
+
var f = h.getSnapshot;
|
|
2965
|
+
h = h.value;
|
|
2649
2966
|
try {
|
|
2650
|
-
var
|
|
2651
|
-
return !t(
|
|
2967
|
+
var c = f();
|
|
2968
|
+
return !t(h, c);
|
|
2652
2969
|
} catch {
|
|
2653
2970
|
return !0;
|
|
2654
2971
|
}
|
|
2655
2972
|
}
|
|
2656
|
-
function
|
|
2973
|
+
function u(h, f) {
|
|
2657
2974
|
return f();
|
|
2658
2975
|
}
|
|
2659
|
-
var
|
|
2660
|
-
return
|
|
2976
|
+
var v = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? u : o;
|
|
2977
|
+
return T.useSyncExternalStore = a.useSyncExternalStore !== void 0 ? a.useSyncExternalStore : v, T;
|
|
2661
2978
|
}
|
|
2662
|
-
var
|
|
2663
|
-
var
|
|
2664
|
-
function
|
|
2665
|
-
return
|
|
2666
|
-
function a(
|
|
2667
|
-
return
|
|
2979
|
+
var O = {};
|
|
2980
|
+
var G;
|
|
2981
|
+
function le() {
|
|
2982
|
+
return G || (G = 1, process.env.NODE_ENV !== "production" && (function() {
|
|
2983
|
+
function a(c, p) {
|
|
2984
|
+
return c === p && (c !== 0 || 1 / c === 1 / p) || c !== c && p !== p;
|
|
2668
2985
|
}
|
|
2669
|
-
function e(
|
|
2670
|
-
|
|
2986
|
+
function e(c, p) {
|
|
2987
|
+
v || i.startTransition === void 0 || (v = !0, console.error(
|
|
2671
2988
|
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
|
|
2672
2989
|
));
|
|
2673
|
-
var
|
|
2674
|
-
if (!
|
|
2675
|
-
var
|
|
2676
|
-
|
|
2990
|
+
var y = p();
|
|
2991
|
+
if (!h) {
|
|
2992
|
+
var E = p();
|
|
2993
|
+
r(y, E) || (console.error(
|
|
2677
2994
|
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
2678
|
-
),
|
|
2995
|
+
), h = !0);
|
|
2679
2996
|
}
|
|
2680
|
-
|
|
2681
|
-
inst: { value:
|
|
2997
|
+
E = n({
|
|
2998
|
+
inst: { value: y, getSnapshot: p }
|
|
2682
2999
|
});
|
|
2683
|
-
var _ =
|
|
3000
|
+
var _ = E[0].inst, F = E[1];
|
|
2684
3001
|
return l(
|
|
2685
3002
|
function() {
|
|
2686
|
-
_.value =
|
|
3003
|
+
_.value = y, _.getSnapshot = p, t(_) && F({ inst: _ });
|
|
2687
3004
|
},
|
|
2688
|
-
[
|
|
3005
|
+
[c, y, p]
|
|
2689
3006
|
), o(
|
|
2690
3007
|
function() {
|
|
2691
|
-
return t(_) &&
|
|
2692
|
-
t(_) &&
|
|
3008
|
+
return t(_) && F({ inst: _ }), c(function() {
|
|
3009
|
+
t(_) && F({ inst: _ });
|
|
2693
3010
|
});
|
|
2694
3011
|
},
|
|
2695
|
-
[
|
|
2696
|
-
),
|
|
3012
|
+
[c]
|
|
3013
|
+
), u(y), y;
|
|
2697
3014
|
}
|
|
2698
|
-
function t(
|
|
2699
|
-
var
|
|
2700
|
-
|
|
3015
|
+
function t(c) {
|
|
3016
|
+
var p = c.getSnapshot;
|
|
3017
|
+
c = c.value;
|
|
2701
3018
|
try {
|
|
2702
|
-
var
|
|
2703
|
-
return !
|
|
3019
|
+
var y = p();
|
|
3020
|
+
return !r(c, y);
|
|
2704
3021
|
} catch {
|
|
2705
3022
|
return !0;
|
|
2706
3023
|
}
|
|
2707
3024
|
}
|
|
2708
|
-
function
|
|
2709
|
-
return
|
|
3025
|
+
function s(c, p) {
|
|
3026
|
+
return p();
|
|
2710
3027
|
}
|
|
2711
3028
|
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
2712
|
-
var
|
|
2713
|
-
|
|
2714
|
-
})()),
|
|
3029
|
+
var i = U, r = typeof Object.is == "function" ? Object.is : a, n = i.useState, o = i.useEffect, l = i.useLayoutEffect, u = i.useDebugValue, v = !1, h = !1, f = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? s : e;
|
|
3030
|
+
O.useSyncExternalStore = i.useSyncExternalStore !== void 0 ? i.useSyncExternalStore : f, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
3031
|
+
})()), O;
|
|
2715
3032
|
}
|
|
2716
|
-
var
|
|
2717
|
-
function
|
|
2718
|
-
return
|
|
3033
|
+
var $;
|
|
3034
|
+
function ue() {
|
|
3035
|
+
return $ || ($ = 1, process.env.NODE_ENV === "production" ? x.exports = oe() : x.exports = le()), x.exports;
|
|
2719
3036
|
}
|
|
2720
|
-
var
|
|
2721
|
-
function
|
|
3037
|
+
var R = ue();
|
|
3038
|
+
function he(a, e) {
|
|
2722
3039
|
if (a === e) return !0;
|
|
2723
3040
|
if (a.length !== e.length) return !1;
|
|
2724
3041
|
for (let t = 0; t < a.length; t++)
|
|
2725
3042
|
if (a[t] !== e[t]) return !1;
|
|
2726
3043
|
return !0;
|
|
2727
3044
|
}
|
|
2728
|
-
function
|
|
2729
|
-
const
|
|
2730
|
-
if (
|
|
3045
|
+
function q(a, e, t) {
|
|
3046
|
+
const s = P(null);
|
|
3047
|
+
if (s.current === null) {
|
|
2731
3048
|
const n = {};
|
|
2732
3049
|
for (const o in a)
|
|
2733
3050
|
n[o] = a[o].value;
|
|
2734
|
-
|
|
3051
|
+
s.current = { ...n, __snapshot: null };
|
|
2735
3052
|
}
|
|
2736
|
-
const
|
|
3053
|
+
const i = b(
|
|
2737
3054
|
(n) => {
|
|
2738
3055
|
let o = !0;
|
|
2739
|
-
return
|
|
2740
|
-
for (const
|
|
2741
|
-
a[
|
|
3056
|
+
return m(() => {
|
|
3057
|
+
for (const u in a)
|
|
3058
|
+
a[u].value;
|
|
2742
3059
|
if (o) {
|
|
2743
3060
|
o = !1;
|
|
2744
3061
|
return;
|
|
@@ -2747,32 +3064,32 @@ function G(a, e, t) {
|
|
|
2747
3064
|
});
|
|
2748
3065
|
},
|
|
2749
3066
|
[a]
|
|
2750
|
-
),
|
|
2751
|
-
const n =
|
|
2752
|
-
for (const
|
|
2753
|
-
o[
|
|
3067
|
+
), r = b(() => {
|
|
3068
|
+
const n = s.current, o = {};
|
|
3069
|
+
for (const u in a)
|
|
3070
|
+
o[u] = a[u].value;
|
|
2754
3071
|
let l = !1;
|
|
2755
|
-
for (const
|
|
2756
|
-
const { key:
|
|
2757
|
-
if (
|
|
2758
|
-
if (!
|
|
3072
|
+
for (const u of e) {
|
|
3073
|
+
const { key: v, useShallowArrayEqual: h } = u, f = o[v], c = n[v];
|
|
3074
|
+
if (h) {
|
|
3075
|
+
if (!he(c, f)) {
|
|
2759
3076
|
l = !0;
|
|
2760
3077
|
break;
|
|
2761
3078
|
}
|
|
2762
|
-
} else if (
|
|
3079
|
+
} else if (c !== f) {
|
|
2763
3080
|
l = !0;
|
|
2764
3081
|
break;
|
|
2765
3082
|
}
|
|
2766
3083
|
}
|
|
2767
3084
|
if (!l && n.__snapshot)
|
|
2768
3085
|
return n.__snapshot;
|
|
2769
|
-
for (const
|
|
2770
|
-
n[
|
|
3086
|
+
for (const u in a)
|
|
3087
|
+
n[u] = o[u];
|
|
2771
3088
|
return n.__snapshot = t(o), n.__snapshot;
|
|
2772
3089
|
}, [a, t]);
|
|
2773
|
-
return
|
|
3090
|
+
return R.useSyncExternalStore(i, r, r);
|
|
2774
3091
|
}
|
|
2775
|
-
function
|
|
3092
|
+
function de(a) {
|
|
2776
3093
|
const e = {
|
|
2777
3094
|
value: a.value,
|
|
2778
3095
|
disabled: a.disabled,
|
|
@@ -2793,23 +3110,23 @@ function ne(a) {
|
|
|
2793
3110
|
{ key: "touched" },
|
|
2794
3111
|
{ key: "shouldShowError" },
|
|
2795
3112
|
{ key: "componentProps" }
|
|
2796
|
-
],
|
|
2797
|
-
(
|
|
2798
|
-
value:
|
|
2799
|
-
pending:
|
|
2800
|
-
disabled:
|
|
2801
|
-
errors:
|
|
2802
|
-
valid:
|
|
2803
|
-
invalid:
|
|
2804
|
-
touched:
|
|
2805
|
-
shouldShowError:
|
|
2806
|
-
componentProps:
|
|
3113
|
+
], s = b(
|
|
3114
|
+
(i) => ({
|
|
3115
|
+
value: i.value,
|
|
3116
|
+
pending: i.pending,
|
|
3117
|
+
disabled: i.disabled,
|
|
3118
|
+
errors: i.errors,
|
|
3119
|
+
valid: i.valid,
|
|
3120
|
+
invalid: i.invalid,
|
|
3121
|
+
touched: i.touched,
|
|
3122
|
+
shouldShowError: i.shouldShowError,
|
|
3123
|
+
componentProps: i.componentProps
|
|
2807
3124
|
}),
|
|
2808
3125
|
[]
|
|
2809
3126
|
);
|
|
2810
|
-
return
|
|
3127
|
+
return q(e, t, s);
|
|
2811
3128
|
}
|
|
2812
|
-
function
|
|
3129
|
+
function ce(a) {
|
|
2813
3130
|
const e = {
|
|
2814
3131
|
value: a.value,
|
|
2815
3132
|
length: a.length,
|
|
@@ -2828,24 +3145,24 @@ function oe(a) {
|
|
|
2828
3145
|
{ key: "invalid" },
|
|
2829
3146
|
{ key: "touched" },
|
|
2830
3147
|
{ key: "dirty" }
|
|
2831
|
-
],
|
|
2832
|
-
(
|
|
2833
|
-
value:
|
|
2834
|
-
length:
|
|
2835
|
-
pending:
|
|
2836
|
-
errors:
|
|
2837
|
-
valid:
|
|
2838
|
-
invalid:
|
|
2839
|
-
touched:
|
|
2840
|
-
dirty:
|
|
3148
|
+
], s = b(
|
|
3149
|
+
(i) => ({
|
|
3150
|
+
value: i.value,
|
|
3151
|
+
length: i.length,
|
|
3152
|
+
pending: i.pending,
|
|
3153
|
+
errors: i.errors,
|
|
3154
|
+
valid: i.valid,
|
|
3155
|
+
invalid: i.invalid,
|
|
3156
|
+
touched: i.touched,
|
|
3157
|
+
dirty: i.dirty
|
|
2841
3158
|
}),
|
|
2842
3159
|
[]
|
|
2843
3160
|
);
|
|
2844
|
-
return
|
|
3161
|
+
return q(e, t, s);
|
|
2845
3162
|
}
|
|
2846
|
-
function
|
|
3163
|
+
function Ee(a) {
|
|
2847
3164
|
const e = a && "length" in a && "map" in a;
|
|
2848
|
-
return a ? e ?
|
|
3165
|
+
return a ? e ? ce(a) : de(a) : {
|
|
2849
3166
|
value: [],
|
|
2850
3167
|
length: 0,
|
|
2851
3168
|
pending: !1,
|
|
@@ -2856,56 +3173,99 @@ function ye(a) {
|
|
|
2856
3173
|
dirty: !1
|
|
2857
3174
|
};
|
|
2858
3175
|
}
|
|
2859
|
-
function
|
|
2860
|
-
const e =
|
|
2861
|
-
(
|
|
2862
|
-
let
|
|
2863
|
-
return
|
|
2864
|
-
if (a.value.value,
|
|
2865
|
-
|
|
3176
|
+
function _e(a) {
|
|
3177
|
+
const e = P({ value: a.value.value }), t = b(
|
|
3178
|
+
(i) => {
|
|
3179
|
+
let r = !0;
|
|
3180
|
+
return m(() => {
|
|
3181
|
+
if (a.value.value, r) {
|
|
3182
|
+
r = !1;
|
|
3183
|
+
return;
|
|
3184
|
+
}
|
|
3185
|
+
i();
|
|
3186
|
+
});
|
|
3187
|
+
},
|
|
3188
|
+
[a]
|
|
3189
|
+
), s = b(() => {
|
|
3190
|
+
const i = a.value.value;
|
|
3191
|
+
return e.current.value === i ? e.current.value : (e.current.value = i, i);
|
|
3192
|
+
}, [a]);
|
|
3193
|
+
return R.useSyncExternalStore(t, s, s);
|
|
3194
|
+
}
|
|
3195
|
+
function Se(a) {
|
|
3196
|
+
const e = P({ length: a.length.value }), t = b(
|
|
3197
|
+
(i) => {
|
|
3198
|
+
let r = !0;
|
|
3199
|
+
return m(() => {
|
|
3200
|
+
if (a.length.value, r) {
|
|
3201
|
+
r = !1;
|
|
2866
3202
|
return;
|
|
2867
3203
|
}
|
|
2868
|
-
|
|
3204
|
+
i();
|
|
2869
3205
|
});
|
|
2870
3206
|
},
|
|
2871
3207
|
[a]
|
|
2872
|
-
),
|
|
2873
|
-
const
|
|
2874
|
-
return e.current.
|
|
3208
|
+
), s = b(() => {
|
|
3209
|
+
const i = a.length.value;
|
|
3210
|
+
return e.current.length === i ? e.current.length : (e.current.length = i, i);
|
|
2875
3211
|
}, [a]);
|
|
2876
|
-
return
|
|
3212
|
+
return R.useSyncExternalStore(t, s, s);
|
|
3213
|
+
}
|
|
3214
|
+
function Ve(a, e, t) {
|
|
3215
|
+
const s = b(
|
|
3216
|
+
(r) => {
|
|
3217
|
+
const n = e, o = [];
|
|
3218
|
+
for (const l of Object.keys(n)) {
|
|
3219
|
+
const u = n[l];
|
|
3220
|
+
if (u && typeof u == "object" && u.value && typeof u.value.subscribe == "function") {
|
|
3221
|
+
const v = u.value.subscribe(r);
|
|
3222
|
+
o.push(v);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
return () => {
|
|
3226
|
+
o.forEach((l) => l());
|
|
3227
|
+
};
|
|
3228
|
+
},
|
|
3229
|
+
[e]
|
|
3230
|
+
), i = b(() => a ? a(e, t) : !1, [a, e, t]);
|
|
3231
|
+
return Q(s, i, i);
|
|
2877
3232
|
}
|
|
2878
3233
|
export {
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
3234
|
+
ke as AbstractRegistry,
|
|
3235
|
+
L as ArrayNode,
|
|
3236
|
+
V as ErrorStrategy,
|
|
3237
|
+
ee as FieldNode,
|
|
3238
|
+
se as FieldPathNavigator,
|
|
3239
|
+
S as FormErrorHandler,
|
|
3240
|
+
C as FormNode,
|
|
3241
|
+
be as FormObserver,
|
|
3242
|
+
Z as FormStatusMachine,
|
|
3243
|
+
ae as FormSubmitter,
|
|
3244
|
+
k as GroupNode,
|
|
3245
|
+
ne as NodeFactory,
|
|
3246
|
+
xe as RegistryStack,
|
|
3247
|
+
D as SubscriptionManager,
|
|
3248
|
+
$e as behaviors,
|
|
3249
|
+
I as createFieldPath,
|
|
3250
|
+
ge as createForm,
|
|
3251
|
+
Ie as extractKey,
|
|
3252
|
+
Le as extractPath,
|
|
3253
|
+
Fe as getCurrentBehaviorRegistry,
|
|
3254
|
+
Te as getCurrentValidationRegistry,
|
|
3255
|
+
Pe as getNodeType,
|
|
3256
|
+
N as isArrayNode,
|
|
3257
|
+
M as isFieldNode,
|
|
3258
|
+
Ce as isFormNode,
|
|
3259
|
+
De as isGroupNode,
|
|
3260
|
+
We as runOutsideEffect,
|
|
3261
|
+
qe as safeCallback,
|
|
3262
|
+
je as safeDebouncedCallback,
|
|
3263
|
+
Be as toFieldPath,
|
|
3264
|
+
A as uniqueId,
|
|
3265
|
+
Se as useArrayLength,
|
|
3266
|
+
Ee as useFormControl,
|
|
3267
|
+
_e as useFormControlValue,
|
|
3268
|
+
Ve as useHiddenCondition,
|
|
3269
|
+
Re as validateForm,
|
|
3270
|
+
Me as validators
|
|
2911
3271
|
};
|