@reformer/core 2.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/behaviors/compute-from.d.ts +2 -0
  2. package/dist/behaviors/compute-from.js +31 -0
  3. package/dist/behaviors/copy-from.d.ts +2 -0
  4. package/dist/behaviors/copy-from.js +29 -0
  5. package/dist/behaviors/enable-when.d.ts +2 -0
  6. package/dist/behaviors/enable-when.js +25 -0
  7. package/dist/behaviors/reset-when.d.ts +2 -0
  8. package/dist/behaviors/reset-when.js +24 -0
  9. package/dist/behaviors/revalidate-when.d.ts +2 -0
  10. package/dist/behaviors/revalidate-when.js +18 -0
  11. package/dist/behaviors/sync-fields.d.ts +2 -0
  12. package/dist/behaviors/sync-fields.js +41 -0
  13. package/dist/behaviors/transform-value.d.ts +2 -0
  14. package/dist/behaviors/transform-value.js +45 -0
  15. package/dist/behaviors/watch-field.d.ts +2 -0
  16. package/dist/behaviors/watch-field.js +21 -0
  17. package/dist/behaviors.js +26 -19
  18. package/dist/core/behavior/behavior-context.d.ts +27 -13
  19. package/dist/core/behavior/behavior-registry.d.ts +15 -27
  20. package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
  21. package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
  22. package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
  23. package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
  24. package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
  25. package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
  26. package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
  28. package/dist/core/behavior/compose-behavior.d.ts +2 -12
  29. package/dist/core/behavior/index.d.ts +0 -1
  30. package/dist/core/behavior/types.d.ts +2 -8
  31. package/dist/core/factories/node-factory.d.ts +6 -29
  32. package/dist/core/nodes/array-node.d.ts +42 -22
  33. package/dist/core/nodes/field-node.d.ts +51 -26
  34. package/dist/core/nodes/form-node.d.ts +18 -20
  35. package/dist/core/nodes/group-node.d.ts +26 -22
  36. package/dist/core/types/deep-schema.d.ts +2 -12
  37. package/dist/core/types/field-path.d.ts +1 -1
  38. package/dist/core/types/form-context.d.ts +27 -27
  39. package/dist/core/types/{group-node-proxy.d.ts → form-proxy.d.ts} +12 -42
  40. package/dist/core/types/index.d.ts +52 -6
  41. package/dist/core/types/validation-schema.d.ts +3 -12
  42. package/dist/core/utils/abstract-registry.d.ts +74 -0
  43. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  44. package/dist/core/utils/create-form.d.ts +3 -20
  45. package/dist/core/utils/error-handler.d.ts +1 -18
  46. package/dist/core/utils/field-path-navigator.d.ts +1 -1
  47. package/dist/core/utils/field-path.d.ts +23 -11
  48. package/dist/core/utils/form-observer.d.ts +176 -0
  49. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  50. package/dist/core/utils/form-submitter.d.ts +121 -0
  51. package/dist/core/utils/index.d.ts +9 -2
  52. package/dist/core/utils/registry-helpers.d.ts +0 -7
  53. package/dist/core/utils/safe-effect.d.ts +73 -0
  54. package/dist/core/utils/status-machine.d.ts +153 -0
  55. package/dist/core/utils/type-guards.d.ts +5 -23
  56. package/dist/core/utils/unique-id.d.ts +53 -0
  57. package/dist/core/validation/core/apply-when.d.ts +3 -9
  58. package/dist/core/validation/core/apply.d.ts +2 -13
  59. package/dist/core/validation/core/validate-async.d.ts +2 -8
  60. package/dist/core/validation/core/validate-tree.d.ts +0 -6
  61. package/dist/core/validation/core/validate.d.ts +1 -7
  62. package/dist/core/validation/index.d.ts +8 -2
  63. package/dist/core/validation/validate-form.d.ts +1 -38
  64. package/dist/core/validation/validation-applicator.d.ts +2 -21
  65. package/dist/core/validation/validation-context.d.ts +59 -43
  66. package/dist/core/validation/validation-registry.d.ts +11 -25
  67. package/dist/core/validation/validators/array-validators.d.ts +2 -12
  68. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  69. package/dist/core/validation/validators/email.d.ts +2 -9
  70. package/dist/core/validation/validators/future-date.d.ts +35 -0
  71. package/dist/core/validation/validators/index.d.ts +7 -1
  72. package/dist/core/validation/validators/is-date.d.ts +36 -0
  73. package/dist/core/validation/validators/max-age.d.ts +36 -0
  74. package/dist/core/validation/validators/max-date.d.ts +36 -0
  75. package/dist/core/validation/validators/max-length.d.ts +3 -10
  76. package/dist/core/validation/validators/max.d.ts +3 -10
  77. package/dist/core/validation/validators/min-age.d.ts +36 -0
  78. package/dist/core/validation/validators/min-date.d.ts +36 -0
  79. package/dist/core/validation/validators/min-length.d.ts +3 -10
  80. package/dist/core/validation/validators/min.d.ts +3 -10
  81. package/dist/core/validation/validators/number.d.ts +2 -9
  82. package/dist/core/validation/validators/past-date.d.ts +35 -0
  83. package/dist/core/validation/validators/pattern.d.ts +2 -9
  84. package/dist/core/validation/validators/phone.d.ts +2 -9
  85. package/dist/core/validation/validators/required.d.ts +2 -9
  86. package/dist/core/validation/validators/url.d.ts +2 -9
  87. package/dist/date-utils-xUWFslTj.js +29 -0
  88. package/dist/field-path-DuKdGcIE.js +66 -0
  89. package/dist/hooks/types.d.ts +1 -1
  90. package/dist/hooks/useArrayLength.d.ts +31 -0
  91. package/dist/hooks/useFormControl.d.ts +4 -4
  92. package/dist/hooks/useFormControlValue.d.ts +2 -2
  93. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  94. package/dist/hooks/useSignalSubscription.d.ts +1 -1
  95. package/dist/index-D25LsbRm.js +73 -0
  96. package/dist/index.d.ts +2 -0
  97. package/dist/index.js +1171 -786
  98. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  99. package/dist/safe-effect-Dh8uw81c.js +20 -0
  100. package/dist/validate-C3XiA_zf.js +10 -0
  101. package/dist/validators/email.d.ts +2 -0
  102. package/dist/validators/email.js +13 -0
  103. package/dist/validators/future-date.d.ts +2 -0
  104. package/dist/validators/future-date.js +20 -0
  105. package/dist/validators/is-date.d.ts +2 -0
  106. package/dist/validators/is-date.js +12 -0
  107. package/dist/validators/max-age.d.ts +2 -0
  108. package/dist/validators/max-age.js +20 -0
  109. package/dist/validators/max-date.d.ts +2 -0
  110. package/dist/validators/max-date.js +20 -0
  111. package/dist/validators/max-length.d.ts +2 -0
  112. package/dist/validators/max-length.js +11 -0
  113. package/dist/validators/max.d.ts +2 -0
  114. package/dist/validators/max.js +11 -0
  115. package/dist/validators/min-age.d.ts +2 -0
  116. package/dist/validators/min-age.js +20 -0
  117. package/dist/validators/min-date.d.ts +2 -0
  118. package/dist/validators/min-date.js +20 -0
  119. package/dist/validators/min-length.d.ts +2 -0
  120. package/dist/validators/min-length.js +11 -0
  121. package/dist/validators/min.d.ts +2 -0
  122. package/dist/validators/min.js +11 -0
  123. package/dist/validators/number.d.ts +2 -0
  124. package/dist/validators/number.js +35 -0
  125. package/dist/validators/past-date.d.ts +2 -0
  126. package/dist/validators/past-date.js +20 -0
  127. package/dist/validators/pattern.d.ts +2 -0
  128. package/dist/validators/pattern.js +11 -0
  129. package/dist/validators/phone.d.ts +2 -0
  130. package/dist/validators/phone.js +35 -0
  131. package/dist/validators/required.d.ts +2 -0
  132. package/dist/validators/required.js +15 -0
  133. package/dist/validators/url.d.ts +2 -0
  134. package/dist/validators/url.js +19 -0
  135. package/dist/validators-BGsNOgT1.js +207 -0
  136. package/dist/validators.js +54 -29
  137. package/llms.txt +7885 -318
  138. package/package.json +83 -8
  139. package/dist/behaviors-DzYL8kY_.js +0 -499
  140. package/dist/core/behavior/create-field-path.d.ts +0 -7
  141. package/dist/core/context/form-context-impl.d.ts +0 -29
  142. package/dist/core/utils/debounce.d.ts +0 -160
  143. package/dist/core/utils/resources.d.ts +0 -41
  144. package/dist/core/validation/field-path.d.ts +0 -7
  145. package/dist/core/validation/validators/date.d.ts +0 -38
  146. package/dist/registry-helpers-BRxAr6nG.js +0 -490
  147. package/dist/validators-gXoHPdqM.js +0 -418
package/dist/index.js CHANGED
@@ -1,12 +1,14 @@
1
- import { d as y, w as u, E, r as U } from "./behaviors-DzYL8kY_.js";
2
- import { i as Ee } from "./behaviors-DzYL8kY_.js";
3
- import { i as T, a as R, A as j, V as q, T as K } from "./validators-gXoHPdqM.js";
4
- import { g as be, c as Ve, d as we, v as Ae, b as ke } from "./validators-gXoHPdqM.js";
5
- import { V as H, B as W, c as I } from "./registry-helpers-BRxAr6nG.js";
6
- import { R as Fe, a as Oe, e as Pe, b as Te, g as Re, t as Ie } from "./registry-helpers-BRxAr6nG.js";
7
- import { v4 as z } from "uuid";
8
- import B, { useRef as L, useCallback as S } from "react";
9
- class O {
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 O {
14
16
  * Пользователь взаимодействовал с узлом (touched)
15
17
  * Protected: наследники могут читать/изменять через методы
16
18
  */
17
- _touched = y(!1);
19
+ _touched = g(!1);
18
20
  /**
19
21
  * Значение узла было изменено (dirty)
20
22
  * Protected: наследники могут читать/изменять через методы
21
23
  */
22
- _dirty = y(!1);
24
+ _dirty = g(!1);
23
25
  /**
24
26
  * Текущий статус узла
25
27
  * Protected: наследники могут читать/изменять через методы
26
28
  */
27
- _status = y("valid");
29
+ _status = g("valid");
28
30
  // ============================================================================
29
31
  // Публичные computed signals (readonly для внешнего мира)
30
32
  // ============================================================================
@@ -32,33 +34,33 @@ class O {
32
34
  * Пользователь взаимодействовал с узлом (touched)
33
35
  * Computed из _touched для предоставления readonly интерфейса
34
36
  */
35
- touched = u(() => this._touched.value);
37
+ touched = d(() => this._touched.value);
36
38
  /**
37
39
  * Пользователь не взаимодействовал с узлом (untouched)
38
40
  */
39
- untouched = u(() => !this._touched.value);
41
+ untouched = d(() => !this._touched.value);
40
42
  /**
41
43
  * Значение узла было изменено (dirty)
42
44
  * Computed из _dirty для предоставления readonly интерфейса
43
45
  */
44
- dirty = u(() => this._dirty.value);
46
+ dirty = d(() => this._dirty.value);
45
47
  /**
46
48
  * Значение узла не было изменено (pristine)
47
49
  */
48
- pristine = u(() => !this._dirty.value);
50
+ pristine = d(() => !this._dirty.value);
49
51
  /**
50
52
  * Текущий статус узла
51
53
  * Computed из _status для предоставления readonly интерфейса
52
54
  */
53
- status = u(() => this._status.value);
55
+ status = d(() => this._status.value);
54
56
  /**
55
57
  * Узел отключен (disabled)
56
58
  */
57
- disabled = u(() => this._status.value === "disabled");
59
+ disabled = d(() => this._status.value === "disabled");
58
60
  /**
59
61
  * Узел включен (enabled)
60
62
  */
61
- enabled = u(() => this._status.value !== "disabled");
63
+ enabled = d(() => this._status.value !== "disabled");
62
64
  /**
63
65
  * Получить ошибки валидации с фильтрацией
64
66
  *
@@ -100,17 +102,17 @@ class O {
100
102
  */
101
103
  getErrors(e) {
102
104
  const t = this.errors.value;
103
- return e ? t.filter((i) => {
104
- if (e.code !== void 0 && !(Array.isArray(e.code) ? e.code : [e.code]).includes(i.code) || e.message !== void 0 && !i.message.toLowerCase().includes(e.message.toLowerCase()))
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 (!i.params)
109
+ if (!s.params)
108
110
  return !1;
109
- for (const [s, a] of Object.entries(e.params))
110
- if (i.params[s] !== a)
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(i));
115
+ return !(e.predicate !== void 0 && !e.predicate(s));
114
116
  }) : t;
115
117
  }
116
118
  // ============================================================================
@@ -283,7 +285,7 @@ class O {
283
285
  onEnable() {
284
286
  }
285
287
  }
286
- class P {
288
+ class D {
287
289
  /**
288
290
  * Хранилище подписок
289
291
  * Ключ: уникальный идентификатор подписки
@@ -451,157 +453,196 @@ class P {
451
453
  this.clear();
452
454
  }
453
455
  }
454
- var w = /* @__PURE__ */ ((r) => (r.THROW = "throw", r.LOG = "log", r.CONVERT = "convert", r))(w || {});
455
- class F {
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
- * @param error Ошибка для обработки (Error | string | unknown)
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
- * // THROW - пробросить ошибку
467
- * try {
468
- * riskyOperation();
469
- * } catch (error) {
470
- * FormErrorHandler.handle(error, 'RiskyOperation', ErrorStrategy.THROW);
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
- * // LOG - залогировать и продолжить
475
- * try {
476
- * nonCriticalOperation();
477
- * } catch (error) {
478
- * FormErrorHandler.handle(error, 'NonCritical', ErrorStrategy.LOG);
479
- * // Продолжаем выполнение
480
- * }
510
+ * @param hasErrors - Есть ли ошибки валидации
481
511
  *
482
- * // CONVERT - конвертировать в ValidationError
483
- * try {
484
- * await validator(value);
485
- * } catch (error) {
486
- * const validationError = FormErrorHandler.handle(
487
- * error,
488
- * 'AsyncValidator',
489
- * ErrorStrategy.CONVERT
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
- static handle(e, t, i = "throw") {
496
- const s = this.extractMessage(e);
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: s,
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 error Ошибка для извлечения сообщения
520
- * @returns Сообщение ошибки
521
- * @private
531
+ * @param hasErrors - Есть ли ошибки
522
532
  *
523
533
  * @example
524
534
  * ```typescript
525
- * FormErrorHandler.extractMessage(new Error('Test'));
526
- * // 'Test'
527
- *
528
- * FormErrorHandler.extractMessage('String error');
529
- * // 'String error'
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
- * FormErrorHandler.extractMessage({ message: 'Object error' });
532
- * // 'Object error'
545
+ * Переводит статус в 'disabled'
533
546
  *
534
- * FormErrorHandler.extractMessage(null);
535
- * // 'null'
547
+ * @example
548
+ * ```typescript
549
+ * statusMachine.disable();
550
+ * // status: 'disabled'
536
551
  * ```
537
552
  */
538
- static extractMessage(e) {
539
- return e instanceof Error ? e.message : typeof e == "string" ? e : typeof e == "object" && e !== null && "message" in e ? String(e.message) : String(e);
553
+ disable() {
554
+ this._status.value = "disabled";
540
555
  }
541
556
  /**
542
- * Создать ValidationError с заданными параметрами
543
- *
544
- * Утилитная функция для создания ValidationError объектов
557
+ * Включить поле
545
558
  *
546
- * @param code Код ошибки
547
- * @param message Сообщение ошибки
548
- * @param field Поле (опционально)
549
- * @returns ValidationError объект
559
+ * @param hasErrors - Есть ли ошибки (определяет valid/invalid)
550
560
  *
551
561
  * @example
552
562
  * ```typescript
553
- * const error = FormErrorHandler.createValidationError(
554
- * 'required',
555
- * 'This field is required',
556
- * 'email'
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
- static createValidationError(e, t, i) {
562
- return {
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
- * Проверить, является ли объект ValidationError
570
- *
571
- * Type guard для ValidationError
574
+ * Обработать событие (альтернативный API)
572
575
  *
573
- * @param value Значение для проверки
574
- * @returns true если value является ValidationError
576
+ * @param event - Событие для обработки
575
577
  *
576
578
  * @example
577
579
  * ```typescript
578
- * if (FormErrorHandler.isValidationError(result)) {
579
- * console.log(result.code); // OK, типобезопасно
580
- * }
580
+ * statusMachine.dispatch({ type: 'START_VALIDATION' });
581
+ * statusMachine.dispatch({ type: 'VALIDATION_FAILURE' });
581
582
  * ```
582
583
  */
583
- static isValidationError(e) {
584
- return typeof e == "object" && e !== null && "code" in e && "message" in e && typeof e.code == "string" && typeof e.message == "string";
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 J extends O {
619
+ class ee extends C {
588
620
  // ============================================================================
589
621
  // Приватные сигналы
590
622
  // ============================================================================
591
623
  _value;
592
624
  _errors;
593
- // _touched, _dirty, _status наследуются от FormNode (protected)
594
- _pending;
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,22 +658,26 @@ class J extends O {
617
658
  asyncValidators;
618
659
  updateOn;
619
660
  initialValue;
620
- currentValidationId = 0;
661
+ currentAbortController;
621
662
  debounceMs;
622
663
  validateDebounceTimer;
623
- validateDebounceResolve;
664
+ /**
665
+ * Pending debounced validation state
666
+ * Contains resolve function and AbortController for cancellation
667
+ */
668
+ pendingValidation;
624
669
  /**
625
670
  * Менеджер подписок для централизованного cleanup
626
671
  * Использует SubscriptionManager вместо массива для управления подписками
627
672
  */
628
- disposers = new P();
673
+ disposers = new D();
629
674
  component;
630
675
  // ============================================================================
631
676
  // Конструктор
632
677
  // ============================================================================
633
678
  constructor(e) {
634
- 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 = y(e.value), this._errors = y([]), this._pending = y(!1), this._componentProps = y(e.componentProps || {}), e.disabled && (this._status.value = "disabled"), this.value = u(() => this._value.value), this.valid = u(() => this._status.value === "valid"), this.invalid = u(() => this._status.value === "invalid"), this.pending = u(() => this._pending.value), this.errors = u(() => this._errors.value), this.componentProps = u(() => this._componentProps.value), this.shouldShowError = u(
635
- () => this._status.value === "invalid" && (this._touched.value || this._dirty.value)
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)
636
681
  );
637
682
  }
638
683
  // ============================================================================
@@ -644,12 +689,12 @@ class J extends O {
644
689
  setValue(e, t) {
645
690
  if (this._value.value = e, this._dirty.value = !0, t?.emitEvent === !1)
646
691
  return;
647
- const i = this.validators.length > 0 || this.asyncValidators.length > 0, s = this._errors.value.length > 0;
692
+ const s = this.validators.length > 0 || this.asyncValidators.length > 0, i = this._errors.value.length > 0;
648
693
  if (this.updateOn === "change") {
649
694
  this.validate();
650
695
  return;
651
696
  }
652
- s && i && this.validate();
697
+ i && s && this.validate();
653
698
  }
654
699
  patchValue(e) {
655
700
  this.setValue(e);
@@ -678,7 +723,7 @@ class J extends O {
678
723
  * ```
679
724
  */
680
725
  reset(e) {
681
- this._value.value = e !== void 0 ? e : this.initialValue, this._errors.value = [], this._touched.value = !1, this._dirty.value = !1, this._status.value = "valid";
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);
682
727
  }
683
728
  /**
684
729
  * Сбросить поле к исходному значению (initialValue)
@@ -708,13 +753,25 @@ class J extends O {
708
753
  resetToInitial() {
709
754
  this.reset(this.initialValue);
710
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
+ }
711
768
  /**
712
769
  * Запустить валидацию поля
713
770
  * @param options - опции валидации
714
771
  * @returns `Promise<boolean>` - true если поле валидно
715
772
  *
716
773
  * @remarks
717
- * Метод защищен от race conditions через validationId.
774
+ * Метод защищен от race conditions через AbortController.
718
775
  * При быстром вводе только последняя валидация применяет результаты.
719
776
  *
720
777
  * @example
@@ -728,69 +785,102 @@ class J extends O {
728
785
  */
729
786
  async validate(e) {
730
787
  const t = e?.debounce ?? this.debounceMs;
731
- return t > 0 && this.asyncValidators.length > 0 ? new Promise((i) => {
732
- const s = this.currentValidationId;
733
- this.validateDebounceResolve && this.validateDebounceResolve(!1), this.validateDebounceTimer && clearTimeout(this.validateDebounceTimer), this.validateDebounceResolve = i, this.validateDebounceTimer = setTimeout(async () => {
734
- if (this.validateDebounceResolve = void 0, s !== this.currentValidationId) {
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) {
735
794
  i(!1);
736
795
  return;
737
796
  }
738
- const a = await this.validateImmediate();
739
- i(a);
740
- }, t);
741
- }) : this.validateImmediate();
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
+ });
742
808
  }
743
809
  /**
744
810
  * Немедленная валидация без debounce
745
811
  * @private
812
+ * @param providedController - AbortController from debounced validate()
746
813
  * @remarks
747
- * Защищена от race conditions:
748
- * - Проверка validationId после синхронной валидации
749
- * - Проверка перед установкой pending
750
- * - Проверка после Promise.all
751
- * - Проверка перед обработкой async результатов
752
- * - Проверка перед очисткой errors
753
- */
754
- async validateImmediate() {
755
- const e = ++this.currentValidationId, t = [];
756
- for (const s of this.validators) {
757
- const a = s(this._value.value);
758
- a && t.push(a);
814
+ * Защищена от race conditions через AbortController:
815
+ * - Отменяет предыдущую валидацию при запуске новой (if no controller provided)
816
+ * - Передаёт AbortSignal в async валидаторы для отмены операций (например, fetch)
817
+ * - Проверяет signal.aborted в ключевых точках
818
+ */
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);
759
826
  }
760
- if (e !== this.currentValidationId)
827
+ if (s.aborted)
761
828
  return !1;
762
- if (t.length > 0)
763
- return this._errors.value = t, this._status.value = "invalid", !1;
764
- if (this.asyncValidators.length > 0) {
765
- if (e !== this.currentValidationId)
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)
766
833
  return !1;
767
- this._pending.value = !0, this._status.value = "pending";
768
- const s = await Promise.all(
769
- this.asyncValidators.map(async (o) => {
770
- try {
771
- return await o(this._value.value);
772
- } catch (n) {
773
- return F.handle(
774
- n,
775
- "FieldNode AsyncValidator",
776
- w.CONVERT
777
- );
778
- }
779
- })
780
- );
781
- if (e !== this.currentValidationId || (this._pending.value = !1, e !== this.currentValidationId))
834
+ }
835
+ if (this.asyncValidators.length > 0) {
836
+ if (s.aborted)
782
837
  return !1;
783
- const a = s.filter(Boolean);
784
- if (a.length > 0)
785
- return this._errors.value = a, this._status.value = "invalid", !1;
838
+ this.statusMachine.startValidation();
839
+ try {
840
+ const n = await Promise.all(
841
+ this.asyncValidators.map(async (l) => {
842
+ if (s.aborted)
843
+ throw new DOMException("Validation aborted", "AbortError");
844
+ try {
845
+ const u = await l(this._value.value, { signal: s });
846
+ if (s.aborted)
847
+ throw new DOMException("Validation aborted", "AbortError");
848
+ return u;
849
+ } catch (u) {
850
+ if (u instanceof DOMException && u.name === "AbortError")
851
+ throw u;
852
+ return S.handle(
853
+ u,
854
+ "FieldNode AsyncValidator",
855
+ V.CONVERT
856
+ );
857
+ }
858
+ })
859
+ );
860
+ if (s.aborted)
861
+ return !1;
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")
871
+ return !1;
872
+ throw n;
873
+ }
786
874
  }
787
- return e !== this.currentValidationId ? !1 : ((this.validators.length > 0 || this.asyncValidators.length > 0) && (this._errors.value = [], this._status.value = "valid"), this._errors.value.length === 0);
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"));
788
876
  }
789
877
  setErrors(e) {
790
- this._errors.value = e, this._status.value = e.length > 0 ? "invalid" : "valid";
878
+ this._errors.value = e;
879
+ const t = e.some((s) => s.severity !== "warning");
880
+ this.statusMachine.setErrors(t);
791
881
  }
792
882
  clearErrors() {
793
- this._errors.value = [], this._status.value = "valid";
883
+ this._errors.value = [], this.statusMachine.setErrors(!1);
794
884
  }
795
885
  // ============================================================================
796
886
  // Protected hooks (Template Method pattern)
@@ -806,18 +896,18 @@ class J extends O {
806
896
  /**
807
897
  * Hook: вызывается после disable()
808
898
  *
809
- * Для FieldNode: очищаем ошибки валидации
899
+ * Для FieldNode: синхронизируем statusMachine и очищаем ошибки
810
900
  */
811
901
  onDisable() {
812
- this._errors.value = [];
902
+ this.statusMachine.disable(), this._errors.value = [];
813
903
  }
814
904
  /**
815
905
  * Hook: вызывается после enable()
816
906
  *
817
- * Для FieldNode: запускаем валидацию
907
+ * Для FieldNode: синхронизируем statusMachine и запускаем валидацию
818
908
  */
819
909
  onEnable() {
820
- this.validate();
910
+ this.statusMachine.enable(this._errors.value.length > 0), this.validate();
821
911
  }
822
912
  /**
823
913
  * Обновляет свойства компонента (например, опции для Select)
@@ -882,25 +972,35 @@ class J extends O {
882
972
  * Подписка на изменения значения поля
883
973
  * Автоматически отслеживает изменения через @preact/signals effect
884
974
  *
885
- * @param callback - Функция, вызываемая при изменении значения
975
+ * @param callback - Функция, вызываемая при изменении значения.
976
+ * Для async операций передается AbortSignal во втором параметре.
886
977
  * @returns Функция отписки для cleanup
887
978
  *
888
979
  * @example
889
980
  * ```typescript
981
+ * // Синхронный callback
890
982
  * const unsubscribe = form.email.watch((value) => {
891
983
  * console.log('Email changed:', value);
892
984
  * });
893
985
  *
986
+ * // Асинхронный callback с поддержкой отмены
987
+ * const unsubscribe = form.email.watch(async (value, signal) => {
988
+ * const result = await fetch('/api/validate', { signal });
989
+ * // ...
990
+ * });
991
+ *
894
992
  * // Cleanup
895
993
  * useEffect(() => unsubscribe, []);
896
994
  * ```
897
995
  */
898
996
  watch(e) {
899
- const t = E(() => {
900
- const s = this.value.value;
901
- e(s);
902
- }), i = `watch-${Date.now()}-${Math.random()}`;
903
- return this.disposers.add(i, t);
997
+ const t = new AbortController(), s = m(() => {
998
+ const r = this.value.value;
999
+ e(r, t.signal);
1000
+ }), i = A(w.Watch);
1001
+ return this.disposers.add(i, () => {
1002
+ t.abort(), s();
1003
+ });
904
1004
  }
905
1005
  /**
906
1006
  * Вычисляемое значение из других полей
@@ -925,16 +1025,23 @@ class J extends O {
925
1025
  * ```
926
1026
  */
927
1027
  computeFrom(e, t) {
928
- const i = E(() => {
929
- const a = e.map((n) => n.value), o = t(...a);
930
- this.setValue(o, { emitEvent: !1 });
931
- }), s = `computeFrom-${Date.now()}-${Math.random()}`;
932
- return this.disposers.add(s, i);
1028
+ const s = m(() => {
1029
+ const r = e.map((o) => o.value), n = t(...r);
1030
+ this.setValue(n, { emitEvent: !1 });
1031
+ }), i = A(w.ComputeFrom);
1032
+ return this.disposers.add(i, s);
933
1033
  }
934
1034
  /**
935
1035
  * Очистить все ресурсы и таймеры
936
1036
  * Должен вызываться при unmount компонента
937
1037
  *
1038
+ * @remarks
1039
+ * Освобождает все ресурсы:
1040
+ * - Отписывает все subscriptions через SubscriptionManager
1041
+ * - Отменяет pending/running валидации через cancelPendingValidation()
1042
+ *
1043
+ * Использует try-finally для гарантированного cleanup даже при ошибках.
1044
+ *
938
1045
  * @example
939
1046
  * ```typescript
940
1047
  * useEffect(() => {
@@ -945,10 +1052,14 @@ class J extends O {
945
1052
  * ```
946
1053
  */
947
1054
  dispose() {
948
- this.disposers.dispose(), this.validateDebounceTimer && (clearTimeout(this.validateDebounceTimer), this.validateDebounceTimer = void 0);
1055
+ try {
1056
+ this.disposers.dispose();
1057
+ } finally {
1058
+ this.cancelPendingValidation();
1059
+ }
949
1060
  }
950
1061
  }
951
- class Y {
1062
+ class te {
952
1063
  form;
953
1064
  constructor(e) {
954
1065
  this.form = e;
@@ -964,8 +1075,8 @@ class Y {
964
1075
  * @param validators Зарегистрированные валидаторы
965
1076
  */
966
1077
  async apply(e) {
967
- const { validatorsByField: t, treeValidators: i } = this.groupValidators(e);
968
- await this.applyFieldValidators(t), this.applyTreeValidators(i);
1078
+ const { validatorsByField: t, treeValidators: s } = this.groupValidators(e);
1079
+ await this.applyFieldValidators(t), this.applyTreeValidators(s);
969
1080
  }
970
1081
  /**
971
1082
  * Группировка валидаторов по типам
@@ -978,15 +1089,15 @@ class Y {
978
1089
  * @returns Сгруппированные валидаторы
979
1090
  */
980
1091
  groupValidators(e) {
981
- const t = /* @__PURE__ */ new Map(), i = [];
982
- for (const s of e)
983
- if (s.type === "tree")
984
- i.push(s);
1092
+ const t = /* @__PURE__ */ new Map(), s = [];
1093
+ for (const i of e)
1094
+ if (i.type === "tree")
1095
+ s.push(i);
985
1096
  else {
986
- const a = t.get(s.fieldPath) || [];
987
- a.push(s), t.set(s.fieldPath, a);
1097
+ const r = t.get(i.fieldPath) || [];
1098
+ r.push(i), t.set(i.fieldPath, r);
988
1099
  }
989
- return { validatorsByField: t, treeValidators: i };
1100
+ return { validatorsByField: t, treeValidators: s };
990
1101
  }
991
1102
  /**
992
1103
  * Применение field валидаторов к полям
@@ -1000,37 +1111,44 @@ class Y {
1000
1111
  * @param validatorsByField Валидаторы, сгруппированные по полям
1001
1112
  */
1002
1113
  async applyFieldValidators(e) {
1003
- for (const [t, i] of e) {
1004
- const s = this.form.getFieldByPath(t);
1005
- if (!s) {
1114
+ for (const [t, s] of e) {
1115
+ const i = this.form.getFieldByPath(t);
1116
+ if (!i) {
1006
1117
  console.warn(`Field ${t} not found in GroupNode`);
1007
1118
  continue;
1008
1119
  }
1009
- if (!T(s) && !R(s)) {
1120
+ if (!M(i) && !N(i)) {
1010
1121
  process.env.NODE_ENV !== "production" && console.warn(`Validation can only run on FieldNode or ArrayNode, skipping ${t}`);
1011
1122
  continue;
1012
1123
  }
1013
- const a = [];
1014
- let o;
1015
- if (R(s)) {
1016
- const n = s.getValue();
1017
- o = new j(this.form, t, n);
1124
+ const r = [];
1125
+ let n;
1126
+ if (N(i)) {
1127
+ const o = i.getValue();
1128
+ n = new z(this.form, t, o);
1018
1129
  } else
1019
- o = new q(this.form, t, s);
1020
- for (const n of i)
1021
- if (!(n.condition && !this.checkCondition(n.condition)))
1130
+ n = new J(this.form, t, i);
1131
+ for (const o of s)
1132
+ if (!(o.condition && !this.checkCondition(o.condition)))
1022
1133
  try {
1023
1134
  let l = null;
1024
- const d = o.value(), m = n.validator;
1025
- n.type === "sync" ? l = m(d, o) : n.type === "async" && (l = await m(d, o)), l && a.push(l);
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);
1026
1144
  } catch (l) {
1027
- F.handle(
1145
+ S.handle(
1028
1146
  l,
1029
1147
  `ValidationApplicator: validator for ${t}`,
1030
- w.LOG
1148
+ V.LOG
1031
1149
  );
1032
1150
  }
1033
- a.length > 0 ? s.setErrors(a) : s.errors.value.length > 0 && !s.errors.value.some((n) => n.code !== "contextual") && s.clearErrors();
1151
+ r.length > 0 ? i.setErrors(r) : i.clearErrors();
1034
1152
  }
1035
1153
  }
1036
1154
  /**
@@ -1043,24 +1161,24 @@ class Y {
1043
1161
  */
1044
1162
  applyTreeValidators(e) {
1045
1163
  for (const t of e) {
1046
- const i = new K(this.form);
1164
+ const s = new Y(this.form);
1047
1165
  if (!(t.condition && !this.checkCondition(t.condition)))
1048
1166
  try {
1049
1167
  if (t.type !== "tree")
1050
1168
  continue;
1051
- const s = t.validator(i);
1052
- if (s && t.options && "targetField" in t.options) {
1053
- const a = t.options.targetField;
1054
- if (a) {
1055
- const o = this.form.getFieldByPath(String(a));
1056
- if (o && T(o)) {
1057
- const n = o.errors.value;
1058
- o.setErrors([...n, s]);
1169
+ const i = t.validator, r = i(s);
1170
+ if (r && t.options && "targetField" in t.options) {
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]);
1059
1177
  }
1060
1178
  }
1061
1179
  }
1062
- } catch (s) {
1063
- F.handle(s, "ValidationApplicator: tree validator", w.LOG);
1180
+ } catch (i) {
1181
+ S.handle(i, "ValidationApplicator: tree validator", V.LOG);
1064
1182
  }
1065
1183
  }
1066
1184
  }
@@ -1077,11 +1195,11 @@ class Y {
1077
1195
  const t = this.form.getFieldByPath(e.fieldPath);
1078
1196
  if (!t)
1079
1197
  return !1;
1080
- const i = t.value.value;
1081
- return e.conditionFn(i);
1198
+ const s = t.value.value;
1199
+ return e.conditionFn(s);
1082
1200
  }
1083
1201
  }
1084
- class Q {
1202
+ class se {
1085
1203
  /**
1086
1204
  * Парсит путь в массив сегментов
1087
1205
  *
@@ -1108,22 +1226,22 @@ class Q {
1108
1226
  */
1109
1227
  parsePath(e) {
1110
1228
  const t = [];
1111
- let i = "", s = !1;
1112
- for (let a = 0; a < e.length; a++) {
1113
- const o = e[a];
1114
- o === "[" ? (s = !0, i += o) : o === "]" ? (s = !1, i += o) : o === "." && !s ? i && (this.addSegment(t, i), i = "") : i += o;
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;
1115
1233
  }
1116
- return i && this.addSegment(t, i), t;
1234
+ return s && this.addSegment(t, s), t;
1117
1235
  }
1118
1236
  /**
1119
1237
  * Добавляет сегмент в массив, обрабатывая массивы
1120
1238
  * @private
1121
1239
  */
1122
1240
  addSegment(e, t) {
1123
- const i = t.match(/^(.+)\[(\d+)\]$/);
1124
- i ? e.push({
1125
- key: i[1],
1126
- index: parseInt(i[2], 10)
1241
+ const s = t.match(/^(.+)\[(\d+)\]$/);
1242
+ s ? e.push({
1243
+ key: s[1],
1244
+ index: parseInt(s[2], 10)
1127
1245
  }) : e.push({ key: t });
1128
1246
  }
1129
1247
  /**
@@ -1158,16 +1276,16 @@ class Q {
1158
1276
  * ```
1159
1277
  */
1160
1278
  getValueByPath(e, t) {
1161
- const i = this.parsePath(t);
1162
- let s = e;
1163
- for (const a of i) {
1164
- if (s == null) return;
1165
- if (s = s[a.key], a.index !== void 0) {
1166
- if (!Array.isArray(s)) return;
1167
- s = s[a.index];
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];
1168
1286
  }
1169
1287
  }
1170
- return s;
1288
+ return i;
1171
1289
  }
1172
1290
  /**
1173
1291
  * Устанавливает значение по пути в объекте (мутирует объект)
@@ -1196,31 +1314,31 @@ class Q {
1196
1314
  * // obj3.items[0].title === 'New'
1197
1315
  * ```
1198
1316
  */
1199
- setValueByPath(e, t, i) {
1200
- const s = this.parsePath(t);
1201
- if (s.length === 0)
1317
+ setValueByPath(e, t, s) {
1318
+ const i = this.parsePath(t);
1319
+ if (i.length === 0)
1202
1320
  throw new Error("Cannot set value: empty path");
1203
- let a = e;
1204
- for (let n = 0; n < s.length - 1; n++) {
1205
- const l = s[n];
1206
- let d = a[l.key];
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];
1207
1325
  if (l.index !== void 0) {
1208
- if (!Array.isArray(d))
1209
- throw new Error(`Expected array at path segment: ${l.key}, but got ${typeof d}`);
1210
- a = d[l.index];
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];
1211
1329
  } else
1212
- d == null && (a[l.key] = {}, d = a[l.key]), a = d;
1330
+ u == null && (r[l.key] = {}, u = r[l.key]), r = u;
1213
1331
  }
1214
- const o = s[s.length - 1];
1215
- if (o.index !== void 0) {
1216
- const n = a[o.key];
1217
- if (!Array.isArray(n))
1332
+ const n = i[i.length - 1];
1333
+ if (n.index !== void 0) {
1334
+ const o = r[n.key];
1335
+ if (!Array.isArray(o))
1218
1336
  throw new Error(
1219
- `Expected array at path segment: ${o.key}, but got ${typeof n}`
1337
+ `Expected array at path segment: ${n.key}, but got ${typeof o}`
1220
1338
  );
1221
- n[o.index] = i;
1339
+ o[n.index] = s;
1222
1340
  } else
1223
- a[o.key] = i;
1341
+ r[n.key] = s;
1224
1342
  }
1225
1343
  /**
1226
1344
  * Получить значение из FormNode по пути
@@ -1257,9 +1375,9 @@ class Q {
1257
1375
  * ```
1258
1376
  */
1259
1377
  getFormNodeValue(e, t) {
1260
- const i = this.getNodeByPath(e, t);
1261
- if (i != null)
1262
- return this.isFormNode(i) ? i.value.value : i;
1378
+ const s = this.getNodeByPath(e, t);
1379
+ if (s != null)
1380
+ return this.isFormNode(s) ? s.value.value : s;
1263
1381
  }
1264
1382
  /**
1265
1383
  * Type guard для проверки, является ли объект FormNode
@@ -1317,40 +1435,177 @@ class Q {
1317
1435
  * ```
1318
1436
  */
1319
1437
  getNodeByPath(e, t) {
1320
- const i = this.parsePath(t);
1321
- let s = e;
1322
- for (const a of i) {
1323
- if (s == null) return null;
1324
- const o = s;
1325
- if (o.fields && o.fields instanceof Map) {
1326
- if (s = o.fields.get(a.key), a.index === void 0) {
1327
- if (s == null) return null;
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;
1443
+ if (n.fields && n.fields instanceof Map) {
1444
+ if (i = n.fields.get(r.key), r.index === void 0) {
1445
+ if (i == null) return null;
1328
1446
  continue;
1329
1447
  }
1330
- } else if (a.index !== void 0 && o.items) {
1331
- const n = o.items.value || o.items;
1332
- if (!Array.isArray(n) || (s = n[a.index], s == null)) return null;
1448
+ } else if (r.index !== void 0 && n.items) {
1449
+ const o = n.items.value || n.items;
1450
+ if (!Array.isArray(o) || (i = o[r.index], i == null)) return null;
1333
1451
  continue;
1334
- } else if (a.index === void 0) {
1335
- if (s = o[a.key], s == null) return null;
1452
+ } else if (r.index === void 0) {
1453
+ if (i = n[r.key], i == null) return null;
1336
1454
  continue;
1337
1455
  }
1338
- if (s && a.index !== void 0 && s.items) {
1339
- const n = s.items.value || s.items;
1340
- if (!Array.isArray(n)) return null;
1341
- s = n[a.index];
1342
- } else if (s && a.index !== void 0 && !s.items)
1456
+ if (i && r.index !== void 0 && i.items) {
1457
+ const o = i.items.value || i.items;
1458
+ if (!Array.isArray(o)) return null;
1459
+ i = o[r.index];
1460
+ } else if (i && r.index !== void 0 && !i.items)
1343
1461
  return null;
1344
- if (s == null) return null;
1462
+ if (i == null) return null;
1345
1463
  }
1346
- return s;
1464
+ return i;
1347
1465
  }
1348
1466
  }
1349
- class b extends O {
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;
1595
+ }
1596
+ }
1597
+ /**
1598
+ * Проверить, идет ли отправка формы
1599
+ */
1600
+ isSubmitting() {
1601
+ return this._submitting.value;
1602
+ }
1603
+ }
1604
+ class k extends C {
1350
1605
  // ============================================================================
1351
1606
  // Приватные поля
1352
1607
  // ============================================================================
1353
- id = z();
1608
+ id = crypto.randomUUID();
1354
1609
  /**
1355
1610
  * Коллекция полей формы (упрощённый Map вместо FieldRegistry)
1356
1611
  */
@@ -1359,7 +1614,7 @@ class b extends O {
1359
1614
  /**
1360
1615
  * Менеджер подписок для централизованного cleanup
1361
1616
  */
1362
- disposers = new P();
1617
+ disposers = new D();
1363
1618
  /**
1364
1619
  * Ссылка на Proxy-инстанс для использования в BehaviorContext
1365
1620
  */
@@ -1367,32 +1622,35 @@ class b extends O {
1367
1622
  /**
1368
1623
  * Навигатор для работы с путями к полям
1369
1624
  */
1370
- pathNavigator = new Q();
1625
+ pathNavigator = new se();
1371
1626
  /**
1372
1627
  * Фабрика для создания узлов формы
1373
1628
  */
1374
- nodeFactory = new X();
1629
+ nodeFactory = new ne();
1375
1630
  /**
1376
1631
  * Реестр валидаторов для этой формы
1632
+ * Может быть инжектирован через config._validationRegistry для тестирования
1377
1633
  */
1378
- validationRegistry = new H();
1634
+ validationRegistry;
1379
1635
  /**
1380
1636
  * Реестр behaviors для этой формы
1637
+ * Может быть инжектирован через config._behaviorRegistry для тестирования
1381
1638
  */
1382
- behaviorRegistry = new W();
1639
+ behaviorRegistry;
1383
1640
  /**
1384
1641
  * Аппликатор для применения валидаторов к форме
1385
1642
  */
1386
- validationApplicator = new Y(this);
1643
+ validationApplicator = new te(this);
1387
1644
  // ============================================================================
1388
1645
  // Приватные сигналы состояния (inline из StateManager)
1389
1646
  // ============================================================================
1390
- /** Флаг отправки формы */
1391
- _submitting = y(!1);
1647
+ /** Управление отправкой формы */
1648
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1649
+ formSubmitter;
1392
1650
  /** Флаг disabled состояния */
1393
- _disabled = y(!1);
1651
+ _disabled = g(!1);
1394
1652
  /** Form-level validation errors */
1395
- _formErrors = y([]);
1653
+ _formErrors = g([]);
1396
1654
  // ============================================================================
1397
1655
  // Публичные computed signals
1398
1656
  // ============================================================================
@@ -1406,76 +1664,56 @@ class b extends O {
1406
1664
  status;
1407
1665
  submitting;
1408
1666
  constructor(e) {
1409
- super();
1410
- const t = "form" in e, i = t ? e.form : e, s = t ? e.behavior : void 0, a = t ? e.validation : void 0;
1411
- for (const [n, l] of Object.entries(i)) {
1412
- const d = this.createNode(l);
1413
- this._fields.set(n, d);
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);
1414
1673
  }
1415
- this.value = u(() => {
1416
- const n = {};
1417
- return this._fields.forEach((l, d) => {
1418
- n[d] = l.value.value;
1419
- }), n;
1420
- }), this.valid = u(() => this._formErrors.value.length > 0 ? !1 : Array.from(this._fields.values()).every((n) => n.valid.value)), this.invalid = u(() => !this.valid.value), this.pending = u(
1421
- () => Array.from(this._fields.values()).some((n) => n.pending.value)
1422
- ), this.touched = u(
1423
- () => Array.from(this._fields.values()).some((n) => n.touched.value)
1424
- ), this.dirty = u(
1425
- () => Array.from(this._fields.values()).some((n) => n.dirty.value)
1426
- ), this.errors = u(() => {
1427
- const n = [...this._formErrors.value];
1428
- return this._fields.forEach((l) => {
1429
- n.push(...l.errors.value);
1430
- }), n;
1431
- }), this.status = u(() => this._disabled.value ? "disabled" : this.pending.value ? "pending" : this.invalid.value ? "invalid" : "valid"), this.submitting = u(() => this._submitting.value);
1432
- const o = this.buildProxy();
1433
- return this._proxyInstance = o, s && this.applyBehaviorSchema(s), a && this.applyValidationSchema(a), o;
1434
- }
1435
- // ============================================================================
1436
- // Приватный метод для создания 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
1437
1689
  // ============================================================================
1438
1690
  /**
1439
1691
  * Создать Proxy для типобезопасного доступа к полям
1692
+ * @see buildFormProxy
1440
1693
  */
1441
1694
  buildProxy() {
1442
- const e = this;
1443
- return new Proxy(this, {
1444
- get: (t, i) => {
1445
- if (i in t)
1446
- return t[i];
1447
- if (typeof i == "string" && e._fields.has(i))
1448
- return e._fields.get(i);
1449
- },
1450
- set: (t, i, s) => typeof i == "string" && e._fields.has(i) ? !1 : (t[i] = s, !0),
1451
- has: (t, i) => typeof i == "string" && e._fields.has(i) ? !0 : i in t,
1452
- ownKeys: (t) => {
1453
- const i = Reflect.ownKeys(t), s = Array.from(e._fields.keys());
1454
- return [.../* @__PURE__ */ new Set([...i, ...s])];
1455
- },
1456
- getOwnPropertyDescriptor: (t, i) => typeof i == "string" && e._fields.has(i) ? { enumerable: !0, configurable: !0 } : Reflect.getOwnPropertyDescriptor(t, i)
1457
- });
1695
+ return re(this, this._fields);
1458
1696
  }
1459
1697
  // ============================================================================
1460
1698
  // Реализация абстрактных методов FormNode
1461
1699
  // ============================================================================
1462
1700
  getValue() {
1463
1701
  const e = {};
1464
- return this._fields.forEach((t, i) => {
1465
- e[i] = t.getValue();
1702
+ return this._fields.forEach((t, s) => {
1703
+ e[s] = t.getValue();
1466
1704
  }), e;
1467
1705
  }
1468
1706
  setValue(e, t) {
1469
- for (const [i, s] of Object.entries(e)) {
1470
- const a = this._fields.get(i);
1471
- a && a.setValue(s, t);
1707
+ for (const [s, i] of Object.entries(e)) {
1708
+ const r = this._fields.get(s);
1709
+ r && r.setValue(i, t);
1472
1710
  }
1473
1711
  }
1474
1712
  patchValue(e) {
1475
- U(() => {
1476
- for (const [t, i] of Object.entries(e)) {
1477
- const s = this._fields.get(t);
1478
- s && i !== void 0 && s.setValue(i);
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 });
1479
1717
  }
1480
1718
  });
1481
1719
  }
@@ -1497,9 +1735,9 @@ class b extends O {
1497
1735
  * ```
1498
1736
  */
1499
1737
  reset(e) {
1500
- this._fields.forEach((t, i) => {
1501
- const s = e?.[i];
1502
- t.reset(s);
1738
+ this._fields.forEach((t, s) => {
1739
+ const i = e?.[s];
1740
+ t.reset(i);
1503
1741
  });
1504
1742
  }
1505
1743
  /**
@@ -1513,7 +1751,9 @@ class b extends O {
1513
1751
  async validate() {
1514
1752
  this.clearErrors(), await Promise.all(Array.from(this._fields.values()).map((t) => t.validate()));
1515
1753
  const e = this.validationRegistry.getValidators();
1516
- return e && e.length > 0 && await this.applyContextualValidators(e), Array.from(this._fields.values()).every((t) => t.valid.value);
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
+ );
1517
1757
  }
1518
1758
  /**
1519
1759
  * Установить form-level validation errors
@@ -1566,7 +1806,7 @@ class b extends O {
1566
1806
  * ```
1567
1807
  */
1568
1808
  getProxy() {
1569
- return this._proxyInstance || this;
1809
+ return this._proxyInstance || (this._proxyInstance = this.buildProxy()), this._proxyInstance;
1570
1810
  }
1571
1811
  /**
1572
1812
  * Получить все поля формы как итератор
@@ -1594,16 +1834,23 @@ class b extends O {
1594
1834
  // ============================================================================
1595
1835
  /**
1596
1836
  * Отправить форму
1837
+ *
1838
+ * @param onSubmit - Callback для отправки данных
1839
+ * @param options - Опции submit (skipValidation, skipTouch)
1840
+ * @returns Результат от onSubmit или null если валидация не пройдена
1597
1841
  */
1598
- async submit(e) {
1599
- if (this.markAsTouched(), !await this.validate())
1600
- return null;
1601
- this._submitting.value = !0;
1602
- try {
1603
- return await e(this.getValue());
1604
- } finally {
1605
- this._submitting.value = !1;
1606
- }
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);
1607
1854
  }
1608
1855
  /**
1609
1856
  * Применить validation schema к форме
@@ -1616,8 +1863,8 @@ class b extends O {
1616
1863
  try {
1617
1864
  const t = I();
1618
1865
  e(t);
1619
- const i = this.getProxy();
1620
- this.validationRegistry.endRegistration(i);
1866
+ const s = this.getProxy();
1867
+ this.validationRegistry.endRegistration(s);
1621
1868
  } catch (t) {
1622
1869
  throw console.error("Error applying validation schema:", t), t;
1623
1870
  }
@@ -1670,18 +1917,18 @@ class b extends O {
1670
1917
  const t = this.pathNavigator.parsePath(e);
1671
1918
  if (t.length === 0)
1672
1919
  return;
1673
- let i = this;
1674
- for (const s of t) {
1675
- if (!(i instanceof b) || (i = i.getField(s.key), !i)) return;
1676
- if (s.index !== void 0)
1677
- if ("at" in i && "length" in i && typeof i.at == "function") {
1678
- const a = i.at(s.index);
1679
- if (!a) return;
1680
- i = a;
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;
1681
1928
  } else
1682
1929
  return;
1683
1930
  }
1684
- return i;
1931
+ return s;
1685
1932
  }
1686
1933
  /**
1687
1934
  * Применить contextual валидаторы к полям
@@ -1725,16 +1972,17 @@ class b extends O {
1725
1972
  /**
1726
1973
  * Связывает два поля: при изменении source автоматически обновляется target
1727
1974
  */
1728
- linkFields(e, t, i) {
1729
- const s = this._fields.get(e), a = this._fields.get(t);
1730
- if (!s || !a)
1731
- return () => {
1732
- };
1733
- const o = E(() => {
1734
- const l = s.value.value, d = i ? i(l) : l;
1735
- a.setValue(d, { emitEvent: !1 });
1736
- }), n = `linkFields-${Date.now()}-${Math.random()}`;
1737
- return this.disposers.add(n, o);
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);
1985
+ return this.disposers.add(o, n);
1738
1986
  }
1739
1987
  /**
1740
1988
  * Подписка на изменения вложенного поля по строковому пути
@@ -1764,15 +2012,14 @@ class b extends O {
1764
2012
  * ```
1765
2013
  */
1766
2014
  watchField(e, t) {
1767
- const i = this.getFieldByPath(e);
1768
- if (!i)
1769
- return () => {
1770
- };
1771
- const s = E(() => {
1772
- const o = i.value.value;
1773
- t(o);
1774
- }), a = `watchField-${Date.now()}-${Math.random()}`;
1775
- return this.disposers.add(a, s);
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;
2020
+ t(n);
2021
+ }), r = A(w.WatchField);
2022
+ return this.disposers.add(r, i);
1776
2023
  }
1777
2024
  /**
1778
2025
  * Hook: вызывается после disable()
@@ -1795,7 +2042,7 @@ class b extends O {
1795
2042
  });
1796
2043
  }
1797
2044
  }
1798
- class C extends O {
2045
+ class L extends C {
1799
2046
  // ============================================================================
1800
2047
  // Приватные поля
1801
2048
  // ============================================================================
@@ -1806,7 +2053,9 @@ class C extends O {
1806
2053
  * Менеджер подписок для централизованного cleanup
1807
2054
  * Использует SubscriptionManager вместо массива для управления подписками
1808
2055
  */
1809
- disposers = new P();
2056
+ disposers = new D();
2057
+ /** Array-level validation errors (e.g., "минимум 1 элемент") */
2058
+ _arrayErrors = g([]);
1810
2059
  // ============================================================================
1811
2060
  // Приватные поля для сохранения схем
1812
2061
  // ============================================================================
@@ -1828,15 +2077,15 @@ class C extends O {
1828
2077
  // Конструктор
1829
2078
  // ============================================================================
1830
2079
  constructor(e, t = []) {
1831
- super(), this.itemSchema = e, this.initialItems = t, this.items = y([]);
2080
+ super(), this.itemSchema = e, this.initialItems = t, this.items = g([]);
1832
2081
  for (const i of t)
1833
2082
  this.push(i);
1834
- this.length = u(() => this.items.value.length), this.value = u(() => this.items.value.map((i) => i.value.value)), this.valid = u(() => this.items.value.every((i) => i.valid.value)), this.invalid = u(() => !this.valid.value), this.pending = u(() => this.items.value.some((i) => i.pending.value)), this.touched = u(() => this.items.value.some((i) => i.touched.value)), this.dirty = u(() => this.items.value.some((i) => i.dirty.value)), this.errors = u(() => {
1835
- const i = [];
1836
- return this.items.value.forEach((s) => {
1837
- i.push(...s.errors.value);
1838
- }), i;
1839
- }), this.status = u(() => this.pending.value ? "pending" : this.invalid.value ? "invalid" : "valid");
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;
1840
2089
  }
1841
2090
  // ============================================================================
1842
2091
  // CRUD операции
@@ -1852,9 +2101,23 @@ class C extends O {
1852
2101
  /**
1853
2102
  * Удалить элемент по индексу
1854
2103
  * @param index - Индекс элемента для удаления
2104
+ *
2105
+ * @remarks
2106
+ * Вызывает dispose() на удаляемом элементе для очистки подписок
1855
2107
  */
1856
2108
  removeAt(e) {
1857
- e < 0 || e >= this.items.value.length || (this.items.value = this.items.value.filter((t, i) => i !== e));
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();
1858
2121
  }
1859
2122
  /**
1860
2123
  * Вставить элемент в массив
@@ -1862,24 +2125,40 @@ class C extends O {
1862
2125
  * @param initialValue - Начальные значения для нового элемента
1863
2126
  */
1864
2127
  insert(e, t) {
1865
- 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
+ );
1866
2136
  return;
1867
- const i = this.createItem(t), s = [...this.items.value];
1868
- s.splice(e, 0, i), this.items.value = s;
2137
+ }
2138
+ const s = this.createItem(t), i = [...this.items.value];
2139
+ i.splice(e, 0, s), this.items.value = i;
1869
2140
  }
1870
2141
  /**
1871
2142
  * Удалить все элементы массива
2143
+ *
2144
+ * @remarks
2145
+ * Вызывает dispose() на всех элементах для очистки подписок
1872
2146
  */
1873
2147
  clear() {
1874
- 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
+ });
1875
2152
  }
1876
2153
  /**
1877
2154
  * Получить элемент по индексу
1878
2155
  * @param index - Индекс элемента
1879
- * @returns Типизированный GroupNode или undefined если индекс вне границ
2156
+ * @returns Типизированный GroupNode proxy или undefined если индекс вне границ
1880
2157
  */
1881
2158
  at(e) {
1882
- return this.items.value[e];
2159
+ const t = this.items.value[e];
2160
+ if (t)
2161
+ return t.getProxy();
1883
2162
  }
1884
2163
  // ============================================================================
1885
2164
  // Реализация абстрактных методов
@@ -1888,12 +2167,13 @@ class C extends O {
1888
2167
  return this.items.value.map((e) => e.getValue());
1889
2168
  }
1890
2169
  setValue(e, t) {
1891
- this.clear(), e.forEach((i) => this.push(i)), t?.emitEvent !== !1 && this.validate().catch(() => {
2170
+ this.clear(), e.forEach((s) => this.push(s)), t?.emitEvent !== !1 && this.validate().catch((s) => {
2171
+ S.handle(s, "ArrayNode.setValue", V.LOG);
1892
2172
  });
1893
2173
  }
1894
2174
  patchValue(e) {
1895
- e.forEach((t, i) => {
1896
- this.items.value[i] && t !== void 0 && this.items.value[i].patchValue(t);
2175
+ e.forEach((t, s) => {
2176
+ this.items.value[s] && t !== void 0 && this.items.value[s].patchValue(t);
1897
2177
  });
1898
2178
  }
1899
2179
  /**
@@ -1914,7 +2194,7 @@ class C extends O {
1914
2194
  * ```
1915
2195
  */
1916
2196
  reset(e) {
1917
- this.clear(), e && e.forEach((t) => this.push(t));
2197
+ this._arrayErrors.value = [], this.clear(), e && e.forEach((t) => this.push(t));
1918
2198
  }
1919
2199
  /**
1920
2200
  * Сбросить массив к исходным значениям (initialItems)
@@ -1945,15 +2225,38 @@ class C extends O {
1945
2225
  * ```
1946
2226
  */
1947
2227
  resetToInitial() {
1948
- this.clear(), this.initialItems.forEach((e) => this.push(e));
2228
+ this._arrayErrors.value = [], this.clear(), this.initialItems.forEach((e) => this.push(e));
1949
2229
  }
1950
2230
  async validate() {
1951
2231
  return (await Promise.all(this.items.value.map((t) => t.validate()))).every(Boolean);
1952
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
+ */
1953
2246
  setErrors(e) {
2247
+ this._arrayErrors.value = e;
1954
2248
  }
2249
+ /**
2250
+ * Очистить все errors (array-level + item-level)
2251
+ *
2252
+ * @example
2253
+ * ```typescript
2254
+ * arrayNode.clearErrors();
2255
+ * console.log(arrayNode.errors.value); // []
2256
+ * ```
2257
+ */
1955
2258
  clearErrors() {
1956
- this.items.value.forEach((e) => e.clearErrors());
2259
+ this._arrayErrors.value = [], this.items.value.forEach((e) => e.clearErrors());
1957
2260
  }
1958
2261
  // ============================================================================
1959
2262
  // Protected hooks (Template Method pattern)
@@ -1995,20 +2298,24 @@ class C extends O {
1995
2298
  // ============================================================================
1996
2299
  /**
1997
2300
  * Итерировать по элементам массива
1998
- * @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode
2301
+ * @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode proxy
1999
2302
  */
2000
2303
  forEach(e) {
2001
- this.items.value.forEach((t, i) => {
2002
- e(t, i);
2304
+ this.items.value.forEach((t, s) => {
2305
+ const i = t.getProxy();
2306
+ e(i, s);
2003
2307
  });
2004
2308
  }
2005
2309
  /**
2006
2310
  * Маппинг элементов массива
2007
- * @param callback - Функция преобразования с типизированным GroupNode
2311
+ * @param callback - Функция преобразования с типизированным GroupNode proxy
2008
2312
  * @returns Новый массив результатов
2009
2313
  */
2010
2314
  map(e) {
2011
- return this.items.value.map((t, i) => e(t, i));
2315
+ return this.items.value.map((t, s) => {
2316
+ const i = t.getProxy();
2317
+ return e(i, s);
2318
+ });
2012
2319
  }
2013
2320
  // ============================================================================
2014
2321
  // Private методы
@@ -2019,7 +2326,7 @@ class C extends O {
2019
2326
  */
2020
2327
  createItem(e) {
2021
2328
  if (this.isGroupSchema(this.itemSchema)) {
2022
- const t = new b(this.itemSchema);
2329
+ const t = new k(this.itemSchema);
2023
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;
2024
2331
  }
2025
2332
  throw new Error(
@@ -2106,14 +2413,14 @@ class C extends O {
2106
2413
  * ```
2107
2414
  */
2108
2415
  watchItems(e, t) {
2109
- const i = E(() => {
2110
- const a = this.items.value.map((o) => {
2111
- if (o instanceof b)
2112
- return o.getFieldByPath(e)?.value.value;
2416
+ const s = m(() => {
2417
+ const r = this.items.value.map((n) => {
2418
+ if (n instanceof k)
2419
+ return n.getFieldByPath(e)?.value.value;
2113
2420
  });
2114
- t(a);
2115
- }), s = `watchItems-${Date.now()}-${Math.random()}`;
2116
- return this.disposers.add(s, i);
2421
+ t(r);
2422
+ }), i = A(w.WatchItems);
2423
+ return this.disposers.add(i, s);
2117
2424
  }
2118
2425
  /**
2119
2426
  * Подписка на изменение длины массива
@@ -2138,11 +2445,11 @@ class C extends O {
2138
2445
  * ```
2139
2446
  */
2140
2447
  watchLength(e) {
2141
- const t = E(() => {
2142
- const s = this.length.value;
2143
- e(s);
2144
- }), i = `watchLength-${Date.now()}-${Math.random()}`;
2145
- return this.disposers.add(i, t);
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);
2146
2453
  }
2147
2454
  /**
2148
2455
  * Очистить все ресурсы узла
@@ -2205,7 +2512,7 @@ class C extends O {
2205
2512
  });
2206
2513
  }
2207
2514
  }
2208
- class X {
2515
+ class ne {
2209
2516
  /**
2210
2517
  * Создает узел формы на основе конфигурации
2211
2518
  *
@@ -2255,16 +2562,16 @@ class X {
2255
2562
  if (Array.isArray(e) && e.length >= 1)
2256
2563
  return this.createArrayNodeFromArray(e);
2257
2564
  if (this.isFieldConfig(e))
2258
- return new J(e);
2565
+ return new ee(e);
2259
2566
  if (this.isArrayConfig(e)) {
2260
2567
  const t = e;
2261
- return new C(
2568
+ return new L(
2262
2569
  t.schema,
2263
2570
  t.initialItems
2264
2571
  );
2265
2572
  }
2266
2573
  if (this.isGroupConfig(e))
2267
- return new b(e);
2574
+ return new k(e);
2268
2575
  throw new Error(
2269
2576
  `NodeFactory: Unknown node config. Expected FieldConfig, GroupConfig, or ArrayConfig, but got: ${JSON.stringify(
2270
2577
  e
@@ -2298,11 +2605,11 @@ class X {
2298
2605
  */
2299
2606
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2300
2607
  createArrayNodeFromArray(e) {
2301
- const [t, ...i] = e, s = [];
2302
- this.isGroupConfig(t) && s.push(this.extractValues(t));
2303
- for (const a of i)
2304
- this.isGroupConfig(a) ? s.push(this.extractValues(a)) : s.push(a);
2305
- return new C(t, s);
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);
2306
2613
  }
2307
2614
  /**
2308
2615
  * Извлечь значения из схемы (рекурсивно)
@@ -2340,8 +2647,8 @@ class X {
2340
2647
  return e.map((t) => this.extractValues(t));
2341
2648
  if (this.isGroupConfig(e)) {
2342
2649
  const t = {};
2343
- for (const [i, s] of Object.entries(e))
2344
- t[i] = this.extractValues(s);
2650
+ for (const [s, i] of Object.entries(e))
2651
+ t[s] = this.extractValues(i);
2345
2652
  return t;
2346
2653
  }
2347
2654
  return e;
@@ -2421,343 +2728,378 @@ class X {
2421
2728
  return e != null && typeof e == "object" && !this.isFieldConfig(e) && !this.isArrayConfig(e);
2422
2729
  }
2423
2730
  }
2424
- class fe {
2731
+ function ge(a) {
2732
+ return new k(a).getProxy();
2733
+ }
2734
+ class be {
2735
+ /**
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;
2425
2750
  /**
2426
- * Создать Debouncer с заданной задержкой
2751
+ * Подписаться на события изменения
2427
2752
  *
2428
- * @param delay Задержка в миллисекундах (0 = без задержки)
2753
+ * @param callback - Функция обработки события
2754
+ * @returns Функция отписки
2429
2755
  *
2430
2756
  * @example
2431
2757
  * ```typescript
2432
- * const debouncer = new Debouncer(300); // 300мс задержка
2433
- * const immediate = new Debouncer(0); // Без задержки
2758
+ * const unsubscribe = observer.subscribe((event) => {
2759
+ * // Отправить событие в analytics
2760
+ * analytics.track('form_change', event);
2761
+ * });
2434
2762
  * ```
2435
2763
  */
2436
- constructor(e) {
2437
- this.delay = e;
2764
+ subscribe(e) {
2765
+ return this.listeners.add(e), () => this.listeners.delete(e);
2438
2766
  }
2439
2767
  /**
2440
- * Таймер для отложенного выполнения
2441
- * @private
2442
- */
2443
- timer;
2444
- /**
2445
- * Отложить выполнение функции
2768
+ * Включить трассировку формы
2446
2769
  *
2447
- * Если вызывается повторно до истечения delay, предыдущий вызов отменяется
2448
- * и таймер перезапускается.
2770
+ * Подписывается на изменения основных сигналов формы
2771
+ * и вызывает listeners при каждом изменении
2449
2772
  *
2450
- * @param fn Функция для выполнения (может быть async)
2451
- * @returns Promise, который разрешается результатом функции
2773
+ * @returns Функция для отключения трассировки
2452
2774
  *
2453
2775
  * @example
2454
2776
  * ```typescript
2455
- * const debouncer = new Debouncer(300);
2456
- *
2457
- * // Первый вызов - запланирован через 300мс
2458
- * debouncer.debounce(async () => console.log('First'));
2459
- *
2460
- * // Второй вызов через 100мс - отменяет первый, запланирован через 300мс
2461
- * debouncer.debounce(async () => console.log('Second'));
2777
+ * const dispose = observer.enableTracing();
2462
2778
  *
2463
- * // Через 300мс выведет только: "Second"
2779
+ * // Позже, для отключения
2780
+ * dispose();
2464
2781
  * ```
2465
2782
  */
2466
- async debounce(e) {
2467
- return new Promise((t, i) => {
2468
- if (this.timer && clearTimeout(this.timer), this.delay === 0) {
2469
- Promise.resolve().then(() => e()).then(t).catch(i);
2470
- return;
2471
- }
2472
- this.timer = setTimeout(async () => {
2473
- try {
2474
- const s = await e();
2475
- t(s);
2476
- } catch (s) {
2477
- i(s);
2478
- }
2479
- }, this.delay);
2480
- });
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
+ };
2481
2857
  }
2482
2858
  /**
2483
- * Отменить отложенное выполнение
2859
+ * Наблюдать за конкретным полем
2484
2860
  *
2485
- * Если есть запланированный вызов, он будет отменен и не выполнится.
2486
- * Promise из debounce() никогда не разрешится.
2861
+ * @param path - Путь к полю
2862
+ * @returns Функция для отключения наблюдения
2487
2863
  *
2488
2864
  * @example
2489
2865
  * ```typescript
2490
- * const debouncer = new Debouncer(300);
2491
- *
2492
- * debouncer.debounce(async () => {
2493
- * console.log('This will not execute');
2494
- * });
2495
- *
2496
- * debouncer.cancel(); // Отменяем вызов
2866
+ * // Наблюдать за полем email
2867
+ * const dispose = observer.watchField('email');
2497
2868
  * ```
2498
2869
  */
2499
- cancel() {
2500
- this.timer && (clearTimeout(this.timer), this.timer = void 0);
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());
2501
2905
  }
2502
2906
  /**
2503
- * Выполнить функцию немедленно, отменив любой отложенный вызов
2504
- *
2505
- * Полезно когда нужно принудительно выполнить действие сейчас,
2506
- * игнорируя debounce.
2507
- *
2508
- * @param fn Функция для немедленного выполнения
2509
- * @returns Promise с результатом функции
2510
- *
2511
- * @example
2512
- * ```typescript
2513
- * const debouncer = new Debouncer(300);
2514
- *
2515
- * // Запланировано через 300мс
2516
- * debouncer.debounce(async () => console.log('Delayed'));
2517
- *
2518
- * // Отменяем отложенный и выполняем немедленно
2519
- * await debouncer.flush(async () => console.log('Immediate'));
2520
- * // Выведет: "Immediate" (сразу)
2521
- * // "Delayed" не выполнится (отменен)
2522
- * ```
2907
+ * Отправить событие всем listeners
2523
2908
  */
2524
- async flush(e) {
2525
- return this.cancel(), await e();
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
+ }));
2526
2916
  }
2527
2917
  /**
2528
- * Проверить, есть ли активный (запланированный) вызов
2529
- *
2530
- * @returns true если есть запланированный вызов
2531
- *
2532
- * @example
2533
- * ```typescript
2534
- * const debouncer = new Debouncer(300);
2535
- *
2536
- * console.log(debouncer.isPending()); // false
2537
- *
2538
- * debouncer.debounce(() => console.log('Test'));
2539
- * console.log(debouncer.isPending()); // true
2540
- *
2541
- * // Через 300мс
2542
- * console.log(debouncer.isPending()); // false
2543
- * ```
2918
+ * Проверить, нужно ли отслеживать тип события
2544
2919
  */
2545
- isPending() {
2546
- return this.timer !== void 0;
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();
2547
2935
  }
2548
2936
  }
2549
- function ve(r) {
2550
- return new b(r);
2551
- }
2552
- function Z(r) {
2553
- return {
2554
- type: "static",
2555
- load: async () => ({
2556
- items: r,
2557
- totalCount: r.length
2558
- })
2559
- };
2560
- }
2561
- function ee(r) {
2562
- let e = null;
2563
- return {
2564
- type: "preload",
2565
- load: async (t) => {
2566
- if (!e) {
2567
- const i = await r(t);
2568
- e = {
2569
- items: i,
2570
- totalCount: i.length
2571
- };
2572
- }
2573
- return e;
2574
- }
2575
- };
2576
- }
2577
- function te(r) {
2578
- return {
2579
- type: "partial",
2580
- load: async (e) => {
2581
- const t = await r(e);
2582
- return {
2583
- items: t,
2584
- totalCount: t.length
2585
- // Можно расширить для поддержки серверной пагинации
2586
- };
2587
- }
2588
- };
2589
- }
2590
- const pe = {
2591
- static: Z,
2592
- preload: ee,
2593
- partial: te
2594
- };
2595
- var V = { exports: {} }, k = {};
2596
- var D;
2597
- function ie() {
2598
- if (D) return k;
2599
- D = 1;
2600
- var r = B;
2601
- function e(c, f) {
2602
- return c === f && (c !== 0 || 1 / c === 1 / f) || c !== c && f !== f;
2603
- }
2604
- var t = typeof Object.is == "function" ? Object.is : e, i = r.useState, s = r.useEffect, a = r.useLayoutEffect, o = r.useDebugValue;
2605
- function n(c, f) {
2606
- var h = f(), v = i({ inst: { value: h, getSnapshot: f } }), p = v[0].inst, g = v[1];
2607
- return a(
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(
2608
2950
  function() {
2609
- p.value = h, p.getSnapshot = f, l(p) && g({ inst: p });
2951
+ y.value = c, y.getSnapshot = f, l(y) && E({ inst: y });
2610
2952
  },
2611
- [c, h, f]
2612
- ), s(
2953
+ [h, c, f]
2954
+ ), i(
2613
2955
  function() {
2614
- return l(p) && g({ inst: p }), c(function() {
2615
- l(p) && g({ inst: p });
2956
+ return l(y) && E({ inst: y }), h(function() {
2957
+ l(y) && E({ inst: y });
2616
2958
  });
2617
2959
  },
2618
- [c]
2619
- ), o(h), h;
2960
+ [h]
2961
+ ), n(c), c;
2620
2962
  }
2621
- function l(c) {
2622
- var f = c.getSnapshot;
2623
- c = c.value;
2963
+ function l(h) {
2964
+ var f = h.getSnapshot;
2965
+ h = h.value;
2624
2966
  try {
2625
- var h = f();
2626
- return !t(c, h);
2967
+ var c = f();
2968
+ return !t(h, c);
2627
2969
  } catch {
2628
2970
  return !0;
2629
2971
  }
2630
2972
  }
2631
- function d(c, f) {
2973
+ function u(h, f) {
2632
2974
  return f();
2633
2975
  }
2634
- var m = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? d : n;
2635
- return k.useSyncExternalStore = r.useSyncExternalStore !== void 0 ? r.useSyncExternalStore : m, k;
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;
2636
2978
  }
2637
- var x = {};
2638
- var N;
2639
- function se() {
2640
- return N || (N = 1, process.env.NODE_ENV !== "production" && (function() {
2641
- function r(h, v) {
2642
- return h === v && (h !== 0 || 1 / h === 1 / v) || h !== h && v !== v;
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;
2643
2985
  }
2644
- function e(h, v) {
2645
- m || s.startTransition === void 0 || (m = !0, console.error(
2986
+ function e(c, p) {
2987
+ v || i.startTransition === void 0 || (v = !0, console.error(
2646
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."
2647
2989
  ));
2648
- var p = v();
2649
- if (!c) {
2650
- var g = v();
2651
- a(p, g) || (console.error(
2990
+ var y = p();
2991
+ if (!h) {
2992
+ var E = p();
2993
+ r(y, E) || (console.error(
2652
2994
  "The result of getSnapshot should be cached to avoid an infinite loop"
2653
- ), c = !0);
2995
+ ), h = !0);
2654
2996
  }
2655
- g = o({
2656
- inst: { value: p, getSnapshot: v }
2997
+ E = n({
2998
+ inst: { value: y, getSnapshot: p }
2657
2999
  });
2658
- var _ = g[0].inst, A = g[1];
3000
+ var _ = E[0].inst, F = E[1];
2659
3001
  return l(
2660
3002
  function() {
2661
- _.value = p, _.getSnapshot = v, t(_) && A({ inst: _ });
3003
+ _.value = y, _.getSnapshot = p, t(_) && F({ inst: _ });
2662
3004
  },
2663
- [h, p, v]
2664
- ), n(
3005
+ [c, y, p]
3006
+ ), o(
2665
3007
  function() {
2666
- return t(_) && A({ inst: _ }), h(function() {
2667
- t(_) && A({ inst: _ });
3008
+ return t(_) && F({ inst: _ }), c(function() {
3009
+ t(_) && F({ inst: _ });
2668
3010
  });
2669
3011
  },
2670
- [h]
2671
- ), d(p), p;
3012
+ [c]
3013
+ ), u(y), y;
2672
3014
  }
2673
- function t(h) {
2674
- var v = h.getSnapshot;
2675
- h = h.value;
3015
+ function t(c) {
3016
+ var p = c.getSnapshot;
3017
+ c = c.value;
2676
3018
  try {
2677
- var p = v();
2678
- return !a(h, p);
3019
+ var y = p();
3020
+ return !r(c, y);
2679
3021
  } catch {
2680
3022
  return !0;
2681
3023
  }
2682
3024
  }
2683
- function i(h, v) {
2684
- return v();
3025
+ function s(c, p) {
3026
+ return p();
2685
3027
  }
2686
3028
  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
2687
- var s = B, a = typeof Object.is == "function" ? Object.is : r, o = s.useState, n = s.useEffect, l = s.useLayoutEffect, d = s.useDebugValue, m = !1, c = !1, f = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? i : e;
2688
- x.useSyncExternalStore = s.useSyncExternalStore !== void 0 ? s.useSyncExternalStore : f, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
2689
- })()), x;
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;
2690
3032
  }
2691
- var M;
2692
- function re() {
2693
- return M || (M = 1, process.env.NODE_ENV === "production" ? V.exports = ie() : V.exports = se()), V.exports;
3033
+ var $;
3034
+ function ue() {
3035
+ return $ || ($ = 1, process.env.NODE_ENV === "production" ? x.exports = oe() : x.exports = le()), x.exports;
2694
3036
  }
2695
- var $ = re();
2696
- function ae(r, e) {
2697
- if (r === e) return !0;
2698
- if (r.length !== e.length) return !1;
2699
- for (let t = 0; t < r.length; t++)
2700
- if (r[t] !== e[t]) return !1;
3037
+ var R = ue();
3038
+ function he(a, e) {
3039
+ if (a === e) return !0;
3040
+ if (a.length !== e.length) return !1;
3041
+ for (let t = 0; t < a.length; t++)
3042
+ if (a[t] !== e[t]) return !1;
2701
3043
  return !0;
2702
3044
  }
2703
- function G(r, e, t) {
2704
- const i = L(null);
2705
- if (i.current === null) {
2706
- const o = {};
2707
- for (const n in r)
2708
- o[n] = r[n].value;
2709
- i.current = { ...o, __snapshot: null };
2710
- }
2711
- const s = S(
2712
- (o) => {
2713
- let n = !0;
2714
- return E(() => {
2715
- for (const d in r)
2716
- r[d].value;
2717
- if (n) {
2718
- n = !1;
3045
+ function q(a, e, t) {
3046
+ const s = P(null);
3047
+ if (s.current === null) {
3048
+ const n = {};
3049
+ for (const o in a)
3050
+ n[o] = a[o].value;
3051
+ s.current = { ...n, __snapshot: null };
3052
+ }
3053
+ const i = b(
3054
+ (n) => {
3055
+ let o = !0;
3056
+ return m(() => {
3057
+ for (const u in a)
3058
+ a[u].value;
3059
+ if (o) {
3060
+ o = !1;
2719
3061
  return;
2720
3062
  }
2721
- o();
3063
+ n();
2722
3064
  });
2723
3065
  },
2724
- [r]
2725
- ), a = S(() => {
2726
- const o = i.current, n = {};
2727
- for (const d in r)
2728
- n[d] = r[d].value;
3066
+ [a]
3067
+ ), r = b(() => {
3068
+ const n = s.current, o = {};
3069
+ for (const u in a)
3070
+ o[u] = a[u].value;
2729
3071
  let l = !1;
2730
- for (const d of e) {
2731
- const { key: m, useShallowArrayEqual: c } = d, f = n[m], h = o[m];
2732
- if (c) {
2733
- if (!ae(h, f)) {
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)) {
2734
3076
  l = !0;
2735
3077
  break;
2736
3078
  }
2737
- } else if (h !== f) {
3079
+ } else if (c !== f) {
2738
3080
  l = !0;
2739
3081
  break;
2740
3082
  }
2741
3083
  }
2742
- if (!l && o.__snapshot)
2743
- return o.__snapshot;
2744
- for (const d in r)
2745
- o[d] = n[d];
2746
- return o.__snapshot = t(n), o.__snapshot;
2747
- }, [r, t]);
2748
- return $.useSyncExternalStore(s, a, a);
3084
+ if (!l && n.__snapshot)
3085
+ return n.__snapshot;
3086
+ for (const u in a)
3087
+ n[u] = o[u];
3088
+ return n.__snapshot = t(o), n.__snapshot;
3089
+ }, [a, t]);
3090
+ return R.useSyncExternalStore(i, r, r);
2749
3091
  }
2750
- function ne(r) {
3092
+ function de(a) {
2751
3093
  const e = {
2752
- value: r.value,
2753
- disabled: r.disabled,
2754
- errors: r.errors,
2755
- pending: r.pending,
2756
- valid: r.valid,
2757
- invalid: r.invalid,
2758
- touched: r.touched,
2759
- shouldShowError: r.shouldShowError,
2760
- componentProps: r.componentProps
3094
+ value: a.value,
3095
+ disabled: a.disabled,
3096
+ errors: a.errors,
3097
+ pending: a.pending,
3098
+ valid: a.valid,
3099
+ invalid: a.invalid,
3100
+ touched: a.touched,
3101
+ shouldShowError: a.shouldShowError,
3102
+ componentProps: a.componentProps
2761
3103
  }, t = [
2762
3104
  { key: "value" },
2763
3105
  { key: "disabled" },
@@ -2768,32 +3110,32 @@ function ne(r) {
2768
3110
  { key: "touched" },
2769
3111
  { key: "shouldShowError" },
2770
3112
  { key: "componentProps" }
2771
- ], i = S(
2772
- (s) => ({
2773
- value: s.value,
2774
- pending: s.pending,
2775
- disabled: s.disabled,
2776
- errors: s.errors,
2777
- valid: s.valid,
2778
- invalid: s.invalid,
2779
- touched: s.touched,
2780
- shouldShowError: s.shouldShowError,
2781
- componentProps: s.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
2782
3124
  }),
2783
3125
  []
2784
3126
  );
2785
- return G(e, t, i);
3127
+ return q(e, t, s);
2786
3128
  }
2787
- function oe(r) {
3129
+ function ce(a) {
2788
3130
  const e = {
2789
- value: r.value,
2790
- length: r.length,
2791
- errors: r.errors,
2792
- pending: r.pending,
2793
- valid: r.valid,
2794
- invalid: r.invalid,
2795
- touched: r.touched,
2796
- dirty: r.dirty
3131
+ value: a.value,
3132
+ length: a.length,
3133
+ errors: a.errors,
3134
+ pending: a.pending,
3135
+ valid: a.valid,
3136
+ invalid: a.invalid,
3137
+ touched: a.touched,
3138
+ dirty: a.dirty
2797
3139
  }, t = [
2798
3140
  { key: "value" },
2799
3141
  { key: "length" },
@@ -2803,24 +3145,24 @@ function oe(r) {
2803
3145
  { key: "invalid" },
2804
3146
  { key: "touched" },
2805
3147
  { key: "dirty" }
2806
- ], i = S(
2807
- (s) => ({
2808
- value: s.value,
2809
- length: s.length,
2810
- pending: s.pending,
2811
- errors: s.errors,
2812
- valid: s.valid,
2813
- invalid: s.invalid,
2814
- touched: s.touched,
2815
- dirty: s.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
2816
3158
  }),
2817
3159
  []
2818
3160
  );
2819
- return G(e, t, i);
3161
+ return q(e, t, s);
2820
3162
  }
2821
- function ye(r) {
2822
- const e = r && "length" in r && "map" in r;
2823
- return r ? e ? oe(r) : ne(r) : {
3163
+ function Ee(a) {
3164
+ const e = a && "length" in a && "map" in a;
3165
+ return a ? e ? ce(a) : de(a) : {
2824
3166
  value: [],
2825
3167
  length: 0,
2826
3168
  pending: !1,
@@ -2831,56 +3173,99 @@ function ye(r) {
2831
3173
  dirty: !1
2832
3174
  };
2833
3175
  }
2834
- function me(r) {
2835
- const e = L({ value: r.value.value }), t = S(
2836
- (s) => {
2837
- let a = !0;
2838
- return E(() => {
2839
- if (r.value.value, a) {
2840
- a = !1;
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;
2841
3202
  return;
2842
3203
  }
2843
- s();
3204
+ i();
2844
3205
  });
2845
3206
  },
2846
- [r]
2847
- ), i = S(() => {
2848
- const s = r.value.value;
2849
- return e.current.value === s ? e.current.value : (e.current.value = s, s);
2850
- }, [r]);
2851
- return $.useSyncExternalStore(t, i, i);
3207
+ [a]
3208
+ ), s = b(() => {
3209
+ const i = a.length.value;
3210
+ return e.current.length === i ? e.current.length : (e.current.length = i, i);
3211
+ }, [a]);
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);
2852
3232
  }
2853
3233
  export {
2854
- C as ArrayNode,
2855
- fe as Debouncer,
2856
- w as ErrorStrategy,
2857
- J as FieldNode,
2858
- Q as FieldPathNavigator,
2859
- F as FormErrorHandler,
2860
- O as FormNode,
2861
- b as GroupNode,
2862
- X as NodeFactory,
2863
- Fe as RegistryStack,
2864
- pe as Resources,
2865
- P as SubscriptionManager,
2866
- Ee as behaviors,
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,
2867
3249
  I as createFieldPath,
2868
- ve as createForm,
2869
- Oe as extractKey,
2870
- Pe as extractPath,
2871
- Te as getCurrentBehaviorRegistry,
2872
- Re as getCurrentValidationRegistry,
2873
- be as getNodeType,
2874
- R as isArrayNode,
2875
- T as isFieldNode,
2876
- Ve as isFormNode,
2877
- we as isGroupNode,
2878
- te as partialResource,
2879
- ee as preloadResource,
2880
- Z as staticResource,
2881
- Ie as toFieldPath,
2882
- ye as useFormControl,
2883
- me as useFormControlValue,
2884
- Ae as validateForm,
2885
- ke as validators
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
2886
3271
  };