@reformer/core 1.0.0-beta.3

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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/behaviors.d.ts +2 -0
  4. package/dist/behaviors.js +230 -0
  5. package/dist/core/behavior/behavior-applicator.d.ts +71 -0
  6. package/dist/core/behavior/behavior-applicator.js +92 -0
  7. package/dist/core/behavior/behavior-context.d.ts +29 -0
  8. package/dist/core/behavior/behavior-context.js +38 -0
  9. package/dist/core/behavior/behavior-registry.d.ts +97 -0
  10. package/dist/core/behavior/behavior-registry.js +198 -0
  11. package/dist/core/behavior/behaviors/compute-from.d.ts +41 -0
  12. package/dist/core/behavior/behaviors/compute-from.js +84 -0
  13. package/dist/core/behavior/behaviors/copy-from.d.ts +31 -0
  14. package/dist/core/behavior/behaviors/copy-from.js +64 -0
  15. package/dist/core/behavior/behaviors/enable-when.d.ts +49 -0
  16. package/dist/core/behavior/behaviors/enable-when.js +81 -0
  17. package/dist/core/behavior/behaviors/index.d.ts +11 -0
  18. package/dist/core/behavior/behaviors/index.js +11 -0
  19. package/dist/core/behavior/behaviors/reset-when.d.ts +51 -0
  20. package/dist/core/behavior/behaviors/reset-when.js +63 -0
  21. package/dist/core/behavior/behaviors/revalidate-when.d.ts +30 -0
  22. package/dist/core/behavior/behaviors/revalidate-when.js +51 -0
  23. package/dist/core/behavior/behaviors/sync-fields.d.ts +28 -0
  24. package/dist/core/behavior/behaviors/sync-fields.js +66 -0
  25. package/dist/core/behavior/behaviors/transform-value.d.ts +120 -0
  26. package/dist/core/behavior/behaviors/transform-value.js +110 -0
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +35 -0
  28. package/dist/core/behavior/behaviors/watch-field.js +56 -0
  29. package/dist/core/behavior/compose-behavior.d.ts +106 -0
  30. package/dist/core/behavior/compose-behavior.js +166 -0
  31. package/dist/core/behavior/create-field-path.d.ts +20 -0
  32. package/dist/core/behavior/create-field-path.js +69 -0
  33. package/dist/core/behavior/index.d.ts +12 -0
  34. package/dist/core/behavior/index.js +17 -0
  35. package/dist/core/behavior/types.d.ts +152 -0
  36. package/dist/core/behavior/types.js +7 -0
  37. package/dist/core/context/form-context-impl.d.ts +29 -0
  38. package/dist/core/context/form-context-impl.js +37 -0
  39. package/dist/core/factories/index.d.ts +6 -0
  40. package/dist/core/factories/index.js +6 -0
  41. package/dist/core/factories/node-factory.d.ts +209 -0
  42. package/dist/core/factories/node-factory.js +281 -0
  43. package/dist/core/nodes/array-node.d.ts +308 -0
  44. package/dist/core/nodes/array-node.js +534 -0
  45. package/dist/core/nodes/field-node.d.ts +269 -0
  46. package/dist/core/nodes/field-node.js +510 -0
  47. package/dist/core/nodes/form-node.d.ts +342 -0
  48. package/dist/core/nodes/form-node.js +343 -0
  49. package/dist/core/nodes/group-node/field-registry.d.ts +191 -0
  50. package/dist/core/nodes/group-node/field-registry.js +215 -0
  51. package/dist/core/nodes/group-node/index.d.ts +11 -0
  52. package/dist/core/nodes/group-node/index.js +11 -0
  53. package/dist/core/nodes/group-node/proxy-builder.d.ts +71 -0
  54. package/dist/core/nodes/group-node/proxy-builder.js +161 -0
  55. package/dist/core/nodes/group-node/state-manager.d.ts +184 -0
  56. package/dist/core/nodes/group-node/state-manager.js +265 -0
  57. package/dist/core/nodes/group-node.d.ts +494 -0
  58. package/dist/core/nodes/group-node.js +770 -0
  59. package/dist/core/types/deep-schema.d.ts +78 -0
  60. package/dist/core/types/deep-schema.js +11 -0
  61. package/dist/core/types/field-path.d.ts +42 -0
  62. package/dist/core/types/field-path.js +4 -0
  63. package/dist/core/types/form-context.d.ts +83 -0
  64. package/dist/core/types/form-context.js +25 -0
  65. package/dist/core/types/group-node-proxy.d.ts +135 -0
  66. package/dist/core/types/group-node-proxy.js +31 -0
  67. package/dist/core/types/index.d.ts +163 -0
  68. package/dist/core/types/index.js +4 -0
  69. package/dist/core/types/validation-schema.d.ts +104 -0
  70. package/dist/core/types/validation-schema.js +10 -0
  71. package/dist/core/utils/create-form.d.ts +61 -0
  72. package/dist/core/utils/create-form.js +24 -0
  73. package/dist/core/utils/debounce.d.ts +160 -0
  74. package/dist/core/utils/debounce.js +197 -0
  75. package/dist/core/utils/error-handler.d.ts +180 -0
  76. package/dist/core/utils/error-handler.js +226 -0
  77. package/dist/core/utils/field-path-navigator.d.ts +240 -0
  78. package/dist/core/utils/field-path-navigator.js +374 -0
  79. package/dist/core/utils/index.d.ts +14 -0
  80. package/dist/core/utils/index.js +14 -0
  81. package/dist/core/utils/registry-helpers.d.ts +50 -0
  82. package/dist/core/utils/registry-helpers.js +79 -0
  83. package/dist/core/utils/registry-stack.d.ts +69 -0
  84. package/dist/core/utils/registry-stack.js +86 -0
  85. package/dist/core/utils/resources.d.ts +41 -0
  86. package/dist/core/utils/resources.js +69 -0
  87. package/dist/core/utils/subscription-manager.d.ts +180 -0
  88. package/dist/core/utils/subscription-manager.js +214 -0
  89. package/dist/core/utils/type-guards.d.ts +116 -0
  90. package/dist/core/utils/type-guards.js +169 -0
  91. package/dist/core/validation/core/apply-when.d.ts +28 -0
  92. package/dist/core/validation/core/apply-when.js +41 -0
  93. package/dist/core/validation/core/apply.d.ts +63 -0
  94. package/dist/core/validation/core/apply.js +38 -0
  95. package/dist/core/validation/core/index.d.ts +8 -0
  96. package/dist/core/validation/core/index.js +8 -0
  97. package/dist/core/validation/core/validate-async.d.ts +42 -0
  98. package/dist/core/validation/core/validate-async.js +45 -0
  99. package/dist/core/validation/core/validate-tree.d.ts +35 -0
  100. package/dist/core/validation/core/validate-tree.js +37 -0
  101. package/dist/core/validation/core/validate.d.ts +32 -0
  102. package/dist/core/validation/core/validate.js +38 -0
  103. package/dist/core/validation/field-path.d.ts +43 -0
  104. package/dist/core/validation/field-path.js +147 -0
  105. package/dist/core/validation/index.d.ts +21 -0
  106. package/dist/core/validation/index.js +33 -0
  107. package/dist/core/validation/validate-form.d.ts +85 -0
  108. package/dist/core/validation/validate-form.js +152 -0
  109. package/dist/core/validation/validation-applicator.d.ts +89 -0
  110. package/dist/core/validation/validation-applicator.js +217 -0
  111. package/dist/core/validation/validation-context.d.ts +47 -0
  112. package/dist/core/validation/validation-context.js +75 -0
  113. package/dist/core/validation/validation-registry.d.ts +156 -0
  114. package/dist/core/validation/validation-registry.js +298 -0
  115. package/dist/core/validation/validators/array-validators.d.ts +63 -0
  116. package/dist/core/validation/validators/array-validators.js +86 -0
  117. package/dist/core/validation/validators/date.d.ts +38 -0
  118. package/dist/core/validation/validators/date.js +117 -0
  119. package/dist/core/validation/validators/email.d.ts +44 -0
  120. package/dist/core/validation/validators/email.js +60 -0
  121. package/dist/core/validation/validators/index.d.ts +14 -0
  122. package/dist/core/validation/validators/index.js +14 -0
  123. package/dist/core/validation/validators/max-length.d.ts +45 -0
  124. package/dist/core/validation/validators/max-length.js +60 -0
  125. package/dist/core/validation/validators/max.d.ts +45 -0
  126. package/dist/core/validation/validators/max.js +60 -0
  127. package/dist/core/validation/validators/min-length.d.ts +45 -0
  128. package/dist/core/validation/validators/min-length.js +60 -0
  129. package/dist/core/validation/validators/min.d.ts +45 -0
  130. package/dist/core/validation/validators/min.js +60 -0
  131. package/dist/core/validation/validators/number.d.ts +38 -0
  132. package/dist/core/validation/validators/number.js +90 -0
  133. package/dist/core/validation/validators/pattern.d.ts +47 -0
  134. package/dist/core/validation/validators/pattern.js +62 -0
  135. package/dist/core/validation/validators/phone.d.ts +34 -0
  136. package/dist/core/validation/validators/phone.js +58 -0
  137. package/dist/core/validation/validators/required.d.ts +48 -0
  138. package/dist/core/validation/validators/required.js +69 -0
  139. package/dist/core/validation/validators/url.d.ts +29 -0
  140. package/dist/core/validation/validators/url.js +55 -0
  141. package/dist/create-field-path-CdPF3lIK.js +704 -0
  142. package/dist/hooks/useFormControl.d.ts +48 -0
  143. package/dist/hooks/useFormControl.js +298 -0
  144. package/dist/index.d.ts +10 -0
  145. package/dist/index.js +8 -0
  146. package/dist/node-factory-D7DOnSSN.js +3200 -0
  147. package/dist/validators.d.ts +2 -0
  148. package/dist/validators.js +298 -0
  149. package/llms.txt +847 -0
  150. package/package.json +86 -0
@@ -0,0 +1,184 @@
1
+ /**
2
+ * StateManager - управление состоянием GroupNode
3
+ *
4
+ * Инкапсулирует всю логику создания и управления сигналами состояния:
5
+ * - Приватные сигналы (submitting, disabled, formErrors)
6
+ * - Публичные computed signals (value, valid, invalid, touched, dirty, pending, errors, status, submitting)
7
+ *
8
+ * Извлечено из GroupNode для соблюдения SRP (Single Responsibility Principle).
9
+ * Отвечает только за логику управления состоянием формы.
10
+ *
11
+ * @template T Тип формы (объект)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class GroupNode {
16
+ * private stateManager: StateManager<T>;
17
+ *
18
+ * constructor(schema: FormSchema<T>) {
19
+ * this.fieldRegistry = new FieldRegistry<T>();
20
+ * // ... создание полей ...
21
+ * this.stateManager = new StateManager(this.fieldRegistry);
22
+ *
23
+ * // Доступ к computed signals
24
+ * this.value = this.stateManager.value;
25
+ * this.valid = this.stateManager.valid;
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ import type { ReadonlySignal } from '@preact/signals-core';
31
+ import type { ValidationError, FieldStatus } from '../../types';
32
+ import type { FieldRegistry } from './field-registry';
33
+ /**
34
+ * Менеджер состояния для GroupNode
35
+ *
36
+ * Создает и управляет всеми сигналами состояния формы:
37
+ * - value - значение формы как объект
38
+ * - valid/invalid - валидность формы
39
+ * - touched/dirty - пользовательское взаимодействие
40
+ * - pending - асинхронная валидация в процессе
41
+ * - errors - все ошибки валидации (form-level + field-level)
42
+ * - status - общий статус формы
43
+ * - submitting - флаг отправки формы
44
+ *
45
+ * @template T Тип формы (объект)
46
+ */
47
+ export declare class StateManager<T> {
48
+ private readonly fieldRegistry;
49
+ /**
50
+ * Флаг отправки формы
51
+ * Устанавливается в true во время отправки формы на сервер
52
+ */
53
+ private _submitting;
54
+ /**
55
+ * Флаг disabled состояния
56
+ * Если true, форма считается disabled
57
+ */
58
+ private _disabled;
59
+ /**
60
+ * Form-level validation errors (не связанные с конкретным полем)
61
+ * Используется для server-side errors или кросс-полевой валидации
62
+ */
63
+ private _formErrors;
64
+ /**
65
+ * Значение формы как объект
66
+ *
67
+ * Computed signal, который автоматически пересчитывается при изменении любого поля.
68
+ * Использует мемоизацию - если зависимости не изменились, вернет закешированный объект.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const form = new GroupNode({ email: { value: 'test@mail.com' } });
73
+ * console.log(form.value.value); // { email: 'test@mail.com' }
74
+ * ```
75
+ */
76
+ readonly value: ReadonlySignal<T>;
77
+ /**
78
+ * Форма валидна?
79
+ *
80
+ * Computed signal. Форма валидна, если:
81
+ * - Нет form-level errors
82
+ * - Все поля валидны
83
+ */
84
+ readonly valid: ReadonlySignal<boolean>;
85
+ /**
86
+ * Форма невалидна?
87
+ *
88
+ * Computed signal. Инверсия valid.
89
+ */
90
+ readonly invalid: ReadonlySignal<boolean>;
91
+ /**
92
+ * Хотя бы одно поле touched?
93
+ *
94
+ * Computed signal. Возвращает true, если хотя бы одно поле было touched.
95
+ */
96
+ readonly touched: ReadonlySignal<boolean>;
97
+ /**
98
+ * Хотя бы одно поле dirty?
99
+ *
100
+ * Computed signal. Возвращает true, если хотя бы одно поле изменилось.
101
+ */
102
+ readonly dirty: ReadonlySignal<boolean>;
103
+ /**
104
+ * Асинхронная валидация в процессе?
105
+ *
106
+ * Computed signal. Возвращает true, если хотя бы одно поле находится в pending состоянии.
107
+ */
108
+ readonly pending: ReadonlySignal<boolean>;
109
+ /**
110
+ * Все ошибки валидации
111
+ *
112
+ * Computed signal. Возвращает массив всех ошибок:
113
+ * - Form-level errors
114
+ * - Field-level errors (из всех вложенных полей)
115
+ */
116
+ readonly errors: ReadonlySignal<ValidationError[]>;
117
+ /**
118
+ * Общий статус формы
119
+ *
120
+ * Computed signal. Возможные значения:
121
+ * - 'disabled' - форма disabled
122
+ * - 'pending' - асинхронная валидация в процессе
123
+ * - 'invalid' - форма невалидна
124
+ * - 'valid' - форма валидна
125
+ */
126
+ readonly status: ReadonlySignal<FieldStatus>;
127
+ /**
128
+ * Форма в процессе отправки?
129
+ *
130
+ * Computed signal (обертка над _submitting для read-only доступа).
131
+ */
132
+ readonly submitting: ReadonlySignal<boolean>;
133
+ /**
134
+ * Создать менеджер состояния
135
+ *
136
+ * @param fieldRegistry - реестр полей формы
137
+ */
138
+ constructor(fieldRegistry: FieldRegistry<T>);
139
+ /**
140
+ * Установить form-level ошибки
141
+ *
142
+ * @param errors - массив ошибок валидации
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * // Server-side ошибки
147
+ * stateManager.setFormErrors([
148
+ * { code: 'server_error', message: 'Пользователь с таким email уже существует' }
149
+ * ]);
150
+ * ```
151
+ */
152
+ setFormErrors(errors: ValidationError[]): void;
153
+ /**
154
+ * Очистить form-level ошибки
155
+ */
156
+ clearFormErrors(): void;
157
+ /**
158
+ * Получить form-level ошибки
159
+ */
160
+ getFormErrors(): ValidationError[];
161
+ /**
162
+ * Установить флаг submitting
163
+ *
164
+ * @param value - true если форма отправляется, false если нет
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * stateManager.setSubmitting(true);
169
+ * await api.submitForm(form.getValue());
170
+ * stateManager.setSubmitting(false);
171
+ * ```
172
+ */
173
+ setSubmitting(value: boolean): void;
174
+ /**
175
+ * Установить флаг disabled
176
+ *
177
+ * @param value - true если форма disabled, false если нет
178
+ */
179
+ setDisabled(value: boolean): void;
180
+ /**
181
+ * Получить флаг disabled
182
+ */
183
+ isDisabled(): boolean;
184
+ }
@@ -0,0 +1,265 @@
1
+ /**
2
+ * StateManager - управление состоянием GroupNode
3
+ *
4
+ * Инкапсулирует всю логику создания и управления сигналами состояния:
5
+ * - Приватные сигналы (submitting, disabled, formErrors)
6
+ * - Публичные computed signals (value, valid, invalid, touched, dirty, pending, errors, status, submitting)
7
+ *
8
+ * Извлечено из GroupNode для соблюдения SRP (Single Responsibility Principle).
9
+ * Отвечает только за логику управления состоянием формы.
10
+ *
11
+ * @template T Тип формы (объект)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * class GroupNode {
16
+ * private stateManager: StateManager<T>;
17
+ *
18
+ * constructor(schema: FormSchema<T>) {
19
+ * this.fieldRegistry = new FieldRegistry<T>();
20
+ * // ... создание полей ...
21
+ * this.stateManager = new StateManager(this.fieldRegistry);
22
+ *
23
+ * // Доступ к computed signals
24
+ * this.value = this.stateManager.value;
25
+ * this.valid = this.stateManager.valid;
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ import { signal, computed } from '@preact/signals-core';
31
+ /**
32
+ * Менеджер состояния для GroupNode
33
+ *
34
+ * Создает и управляет всеми сигналами состояния формы:
35
+ * - value - значение формы как объект
36
+ * - valid/invalid - валидность формы
37
+ * - touched/dirty - пользовательское взаимодействие
38
+ * - pending - асинхронная валидация в процессе
39
+ * - errors - все ошибки валидации (form-level + field-level)
40
+ * - status - общий статус формы
41
+ * - submitting - флаг отправки формы
42
+ *
43
+ * @template T Тип формы (объект)
44
+ */
45
+ export class StateManager {
46
+ fieldRegistry;
47
+ // ============================================================================
48
+ // Приватные сигналы (мутабельные)
49
+ // ============================================================================
50
+ /**
51
+ * Флаг отправки формы
52
+ * Устанавливается в true во время отправки формы на сервер
53
+ */
54
+ _submitting;
55
+ /**
56
+ * Флаг disabled состояния
57
+ * Если true, форма считается disabled
58
+ */
59
+ _disabled;
60
+ /**
61
+ * Form-level validation errors (не связанные с конкретным полем)
62
+ * Используется для server-side errors или кросс-полевой валидации
63
+ */
64
+ _formErrors;
65
+ // ============================================================================
66
+ // Публичные computed signals (read-only)
67
+ // ============================================================================
68
+ /**
69
+ * Значение формы как объект
70
+ *
71
+ * Computed signal, который автоматически пересчитывается при изменении любого поля.
72
+ * Использует мемоизацию - если зависимости не изменились, вернет закешированный объект.
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const form = new GroupNode({ email: { value: 'test@mail.com' } });
77
+ * console.log(form.value.value); // { email: 'test@mail.com' }
78
+ * ```
79
+ */
80
+ value;
81
+ /**
82
+ * Форма валидна?
83
+ *
84
+ * Computed signal. Форма валидна, если:
85
+ * - Нет form-level errors
86
+ * - Все поля валидны
87
+ */
88
+ valid;
89
+ /**
90
+ * Форма невалидна?
91
+ *
92
+ * Computed signal. Инверсия valid.
93
+ */
94
+ invalid;
95
+ /**
96
+ * Хотя бы одно поле touched?
97
+ *
98
+ * Computed signal. Возвращает true, если хотя бы одно поле было touched.
99
+ */
100
+ touched;
101
+ /**
102
+ * Хотя бы одно поле dirty?
103
+ *
104
+ * Computed signal. Возвращает true, если хотя бы одно поле изменилось.
105
+ */
106
+ dirty;
107
+ /**
108
+ * Асинхронная валидация в процессе?
109
+ *
110
+ * Computed signal. Возвращает true, если хотя бы одно поле находится в pending состоянии.
111
+ */
112
+ pending;
113
+ /**
114
+ * Все ошибки валидации
115
+ *
116
+ * Computed signal. Возвращает массив всех ошибок:
117
+ * - Form-level errors
118
+ * - Field-level errors (из всех вложенных полей)
119
+ */
120
+ errors;
121
+ /**
122
+ * Общий статус формы
123
+ *
124
+ * Computed signal. Возможные значения:
125
+ * - 'disabled' - форма disabled
126
+ * - 'pending' - асинхронная валидация в процессе
127
+ * - 'invalid' - форма невалидна
128
+ * - 'valid' - форма валидна
129
+ */
130
+ status;
131
+ /**
132
+ * Форма в процессе отправки?
133
+ *
134
+ * Computed signal (обертка над _submitting для read-only доступа).
135
+ */
136
+ submitting;
137
+ // ============================================================================
138
+ // Конструктор
139
+ // ============================================================================
140
+ /**
141
+ * Создать менеджер состояния
142
+ *
143
+ * @param fieldRegistry - реестр полей формы
144
+ */
145
+ constructor(fieldRegistry) {
146
+ this.fieldRegistry = fieldRegistry;
147
+ // Инициализация приватных сигналов
148
+ this._submitting = signal(false);
149
+ this._disabled = signal(false);
150
+ this._formErrors = signal([]);
151
+ // Создание computed signals
152
+ // Computed signal для значения формы
153
+ // Автоматически кеширует результат (мемоизация)
154
+ // Первый вызов: O(n) где n = количество полей
155
+ // Повторные вызовы (если зависимости не изменились): O(1) (возврат кешированного объекта)
156
+ this.value = computed(() => {
157
+ const result = {};
158
+ this.fieldRegistry.forEach((field, key) => {
159
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ result[key] = field.value.value;
161
+ });
162
+ return result;
163
+ });
164
+ // Computed signal для валидности формы
165
+ this.valid = computed(() => {
166
+ // Проверяем отсутствие form-level errors
167
+ const hasFormErrors = this._formErrors.value.length > 0;
168
+ if (hasFormErrors)
169
+ return false;
170
+ // Проверяем все поля
171
+ return Array.from(this.fieldRegistry.values()).every((field) => field.valid.value);
172
+ });
173
+ // Computed signal для невалидности (инверсия valid)
174
+ this.invalid = computed(() => !this.valid.value);
175
+ // Computed signal для pending состояния
176
+ this.pending = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.pending.value));
177
+ // Computed signal для touched состояния
178
+ this.touched = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.touched.value));
179
+ // Computed signal для dirty состояния
180
+ this.dirty = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.dirty.value));
181
+ // Computed signal для ошибок (form-level + field-level)
182
+ this.errors = computed(() => {
183
+ const allErrors = [];
184
+ // Добавляем form-level errors
185
+ allErrors.push(...this._formErrors.value);
186
+ // Добавляем field-level errors
187
+ this.fieldRegistry.forEach((field) => {
188
+ allErrors.push(...field.errors.value);
189
+ });
190
+ return allErrors;
191
+ });
192
+ // Computed signal для статуса формы
193
+ this.status = computed(() => {
194
+ if (this._disabled.value)
195
+ return 'disabled';
196
+ if (this.pending.value)
197
+ return 'pending';
198
+ if (this.invalid.value)
199
+ return 'invalid';
200
+ return 'valid';
201
+ });
202
+ // Computed signal для submitting (read-only обертка)
203
+ this.submitting = computed(() => this._submitting.value);
204
+ }
205
+ // ============================================================================
206
+ // Публичные методы для управления состоянием
207
+ // ============================================================================
208
+ /**
209
+ * Установить form-level ошибки
210
+ *
211
+ * @param errors - массив ошибок валидации
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // Server-side ошибки
216
+ * stateManager.setFormErrors([
217
+ * { code: 'server_error', message: 'Пользователь с таким email уже существует' }
218
+ * ]);
219
+ * ```
220
+ */
221
+ setFormErrors(errors) {
222
+ this._formErrors.value = errors;
223
+ }
224
+ /**
225
+ * Очистить form-level ошибки
226
+ */
227
+ clearFormErrors() {
228
+ this._formErrors.value = [];
229
+ }
230
+ /**
231
+ * Получить form-level ошибки
232
+ */
233
+ getFormErrors() {
234
+ return this._formErrors.value;
235
+ }
236
+ /**
237
+ * Установить флаг submitting
238
+ *
239
+ * @param value - true если форма отправляется, false если нет
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * stateManager.setSubmitting(true);
244
+ * await api.submitForm(form.getValue());
245
+ * stateManager.setSubmitting(false);
246
+ * ```
247
+ */
248
+ setSubmitting(value) {
249
+ this._submitting.value = value;
250
+ }
251
+ /**
252
+ * Установить флаг disabled
253
+ *
254
+ * @param value - true если форма disabled, false если нет
255
+ */
256
+ setDisabled(value) {
257
+ this._disabled.value = value;
258
+ }
259
+ /**
260
+ * Получить флаг disabled
261
+ */
262
+ isDisabled() {
263
+ return this._disabled.value;
264
+ }
265
+ }