@reformer/core 2.0.0-beta.6 → 2.0.0-beta.8

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