@reformer/core 10.1.0 → 11.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{behaviors-node-DUrqAqp1.js → behaviors-node-DGEFMTQu.js} +1 -1
- package/dist/{behaviors-value-lCpqicfa.js → behaviors-value-C7dSEhCc.js} +43 -57
- package/dist/behaviors.js +108 -107
- package/dist/derived-registry-CluZCQ7U.js +16 -0
- package/dist/form/form-submitter.d.ts +0 -4
- package/dist/form/hooks/types.d.ts +3 -3
- package/dist/form/hooks/use-form-validation.d.ts +48 -0
- package/dist/form/index.d.ts +2 -3
- package/dist/form/nodes/array-node.d.ts +0 -84
- package/dist/form/nodes/form-node.d.ts +0 -14
- package/dist/form/nodes/group-node.d.ts +0 -4
- package/dist/form/status-machine.d.ts +0 -38
- package/dist/form/types/contracts.d.ts +0 -6
- package/dist/form/types/deep-schema.d.ts +0 -9
- package/dist/form/types/index.d.ts +4 -38
- package/dist/form/types/schema-node.d.ts +13 -16
- package/dist/form/types/validation-schema.d.ts +0 -25
- package/dist/form/unique-id.d.ts +3 -11
- package/dist/form/validation-schema.d.ts +16 -3
- package/dist/form/validation-strategy.d.ts +55 -0
- package/dist/form/validators.d.ts +8 -3
- package/dist/form-model-DYCzGGKF.js +286 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +477 -648
- package/dist/runtime-token.d.ts +23 -0
- package/dist/state/form-model.d.ts +12 -1
- package/dist/state.js +17 -15
- package/dist/subscription-manager-705bls97.js +171 -0
- package/dist/validation.js +133 -81
- package/dist/validators.d.ts +0 -4
- package/dist/validators.js +88 -122
- package/docs/llms/01-api-reference.md +63 -0
- package/docs/llms/02-quick-start.md +143 -0
- package/docs/llms/03-api-signatures.md +273 -0
- package/docs/llms/04-common-patterns.md +202 -0
- package/docs/llms/05-common-mistakes.md +167 -0
- package/docs/llms/06-troubleshooting.md +11 -0
- package/docs/llms/07-complete-import.md +99 -0
- package/docs/llms/08-form-types.md +47 -0
- package/docs/llms/09-formschema.md +143 -0
- package/docs/llms/10-arrays.md +161 -0
- package/docs/llms/11-async-watchfield.md +53 -0
- package/docs/llms/12-array-cleanup.md +31 -0
- package/docs/llms/13-multi-step.md +91 -0
- package/docs/llms/14-extended-mistakes.md +98 -0
- package/docs/llms/15-project-structure.md +125 -0
- package/docs/llms/16-ui-components.md +189 -0
- package/docs/llms/17-nonexistent-api.md +93 -0
- package/docs/llms/18-conditional-fields.md +183 -0
- package/docs/llms/19-reading-values.md +59 -0
- package/docs/llms/20-compute-vs-watch.md +138 -0
- package/docs/llms/21-array-operations.md +113 -0
- package/docs/llms/22-cycle-detection.md +86 -0
- package/docs/llms/23-copy-from.md +141 -0
- package/docs/llms/24-sync-fields.md +114 -0
- package/docs/llms/25-reset-when.md +115 -0
- package/docs/llms/26-transform-value.md +136 -0
- package/docs/llms/27-revalidate-when.md +132 -0
- package/docs/llms/28-submit-and-reset.md +259 -0
- package/docs/llms/29-async-preload.md +193 -0
- package/docs/llms/30-type-safety-recipes.md +159 -0
- package/docs/llms/31-async-validator-debounce.md +135 -0
- package/docs/llms/32-async-options-loading.md +108 -0
- package/docs/llms/33-validation-strategy.md +193 -0
- package/llms.txt +435 -1580
- package/package.json +33 -10
- package/dist/form-model-C8Fi83k4.js +0 -439
package/llms.txt
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
- 30-type-safety-recipes.md — type-safety-recipes
|
|
38
38
|
- 31-async-validator-debounce.md — async-validator-debounce
|
|
39
39
|
- 32-async-options-loading.md — async-options-loading
|
|
40
|
+
- 33-validation-strategy.md — useFormValidation — Единый выбор стратегии валидации
|
|
40
41
|
- API Reference (auto-generated from JSDoc)
|
|
41
42
|
|
|
42
43
|
## 1. 1. API Reference
|
|
@@ -4113,39 +4114,215 @@ loadOptionsOn(model.$.carBrand, form.carModel, fetchCarModels, { resetTarget: tr
|
|
|
4113
4114
|
- [29-async-preload.md](29-async-preload.md) — preload данных при инициализации
|
|
4114
4115
|
- [31-async-validator-debounce.md](31-async-validator-debounce.md) — async **валидация** (не options)
|
|
4115
4116
|
|
|
4116
|
-
## 77.
|
|
4117
|
+
## 77. Purpose
|
|
4117
4118
|
|
|
4118
|
-
|
|
4119
|
+
Одна декларативная точка выбора «когда прогонять схему валидации» вместо ручной разводки
|
|
4120
|
+
`markAsTouched` + `validateModel` + `revalidateWhen` + `useState(pending)`. Аддитивный слой над
|
|
4121
|
+
функциональной схемой (`@reformer/core/validation`): переиспользует `validateModel` как
|
|
4122
|
+
ЕДИНСТВЕННЫЙ движок (роутинг ошибок в ноды, отмена устаревших прогонов, дедуп по `(model, schema)`),
|
|
4123
|
+
второго движка не заводит. Node-level `updateOn` / `debounce` на самой ноде поля (legacy-триггеры)
|
|
4124
|
+
этот API НЕ трогает.
|
|
4119
4125
|
|
|
4120
|
-
|
|
4126
|
+
Стратегия определяет только момент запуска и раскрытие ошибок — сами правила остаются в отдельной
|
|
4127
|
+
`defineValidationSchema<T>(({ model }) => …)`.
|
|
4121
4128
|
|
|
4122
|
-
|
|
4129
|
+
## 78. API
|
|
4123
4130
|
|
|
4124
|
-
|
|
4125
|
-
|
|
4131
|
+
Основной способ — React-хук `useFormValidation` из `@reformer/core` (рядом с `useFormControl`).
|
|
4132
|
+
Под ним — headless-фабрика `createFormValidation` из `@reformer/core/validation` (для SSR / тестов /
|
|
4133
|
+
не-React потребителей).
|
|
4126
4134
|
|
|
4127
|
-
**Signature:**
|
|
4128
4135
|
```typescript
|
|
4129
|
-
|
|
4136
|
+
// React (@reformer/core)
|
|
4137
|
+
function useFormValidation<T>(args: {
|
|
4138
|
+
model: FormModel<T>;
|
|
4139
|
+
schema: ValidationSchema<T>; // СТАБИЛЬНАЯ ссылка (module-level const / useMemo)
|
|
4140
|
+
strategy?: ValidationStrategyKind; // default 'submit'
|
|
4141
|
+
debounce?: number; // мс, для live-фаз (change / live-часть afterFirstSubmit)
|
|
4142
|
+
liveAfterSubmit?: 'change' | 'blur'; // default 'change'
|
|
4143
|
+
}): { submit: () => Promise<boolean>; validate: () => Promise<boolean>; isValidating: boolean };
|
|
4144
|
+
|
|
4145
|
+
// headless (@reformer/core/validation)
|
|
4146
|
+
type ValidationStrategyKind = 'submit' | 'blur' | 'change' | 'afterFirstSubmit';
|
|
4147
|
+
interface ValidationStrategyOptions {
|
|
4148
|
+
strategy?: ValidationStrategyKind;
|
|
4149
|
+
debounce?: number;
|
|
4150
|
+
liveAfterSubmit?: 'change' | 'blur';
|
|
4151
|
+
}
|
|
4152
|
+
interface FormValidationController {
|
|
4153
|
+
validate(): Promise<boolean>; // полный прогон, touch:true (раскрыть ВСЕ ошибки); переводит afterFirstSubmit в live-фазу
|
|
4154
|
+
start(): () => void; // армит реактивные подписки (ТОЛЬКО на клиенте) → dispose
|
|
4155
|
+
dispose(): void;
|
|
4156
|
+
readonly isValidating: boolean;
|
|
4157
|
+
readonly validating: ReadonlySignal<boolean>;
|
|
4158
|
+
}
|
|
4159
|
+
function createFormValidation<T>(
|
|
4160
|
+
model: FormModel<T>,
|
|
4161
|
+
schema: ValidationSchema<T>,
|
|
4162
|
+
options?: ValidationStrategyOptions,
|
|
4163
|
+
): FormValidationController;
|
|
4130
4164
|
```
|
|
4131
4165
|
|
|
4132
|
-
|
|
4166
|
+
- `useFormValidation` мемоизирует контроллер по `[model, schema, strategy, debounce, liveAfterSubmit]`,
|
|
4167
|
+
армит стратегию в `useEffect` (SSR-safe), а `submit()` = `controller.validate()`.
|
|
4168
|
+
- `createFormValidation` ЧИСТА до `start()` (никаких подписок) → SSR-safe; `start()` возвращает
|
|
4169
|
+
`dispose` и арминует триггеры только на клиенте.
|
|
4133
4170
|
|
|
4134
|
-
###
|
|
4171
|
+
### Стратегии
|
|
4135
4172
|
|
|
4136
|
-
|
|
4173
|
+
| strategy | когда прогон | touch | раскрытие ошибок |
|
|
4174
|
+
| --- | --- | --- | --- |
|
|
4175
|
+
| `submit` (default) | только `validate()` / `submit()` | `true` | всё на submit |
|
|
4176
|
+
| `blur` | смена `touched` поля (потеря фокуса) | `false` | только сблюренные (по `touched`) |
|
|
4177
|
+
| `change` | на каждый ввод (+ `debounce`) | `false` | только редактированные (по `dirty`) |
|
|
4178
|
+
| `afterFirstSubmit` | тихо до 1-го submit, затем live (`liveAfterSubmit: 'change'` \| `'blur'`, default `'change'`) | `true` один раз на 1-м submit, дальше `false` | тихо → раскрыть всё на submit → далее live |
|
|
4137
4179
|
|
|
4138
|
-
|
|
4180
|
+
## 79. Examples
|
|
4181
|
+
|
|
4182
|
+
### Простая форма — afterFirstSubmit + debounce
|
|
4183
|
+
|
|
4184
|
+
Тихо до первой отправки, `submit()` раскрывает все ошибки и переводит форму в живую фазу
|
|
4185
|
+
(дальше проверка на ввод с задержкой 400 мс). `submit()` сам метит `touched` — ручной
|
|
4186
|
+
`markAsTouched` не нужен.
|
|
4187
|
+
|
|
4188
|
+
```tsx
|
|
4189
|
+
import { createModel, createForm, useFormValidation } from '@reformer/core';
|
|
4190
|
+
import { defineValidationSchema, validate } from '@reformer/core/validation';
|
|
4191
|
+
import { required, email, minLength } from '@reformer/core/validators';
|
|
4192
|
+
|
|
4193
|
+
type RegistrationData = { username: string; email: string; password: string };
|
|
4194
|
+
|
|
4195
|
+
// Схема — стабильный module-level const (иначе ломается дедуп раннера).
|
|
4196
|
+
const registrationValidation = defineValidationSchema<RegistrationData>(({ model }) => {
|
|
4197
|
+
validate(model.$.username, [required(), minLength(3)]);
|
|
4198
|
+
validate(model.$.email, [required(), email()]);
|
|
4199
|
+
validate(model.$.password, [required(), minLength(8)]);
|
|
4200
|
+
});
|
|
4201
|
+
|
|
4202
|
+
function RegistrationForm() {
|
|
4203
|
+
const model = useMemo(() => createModel<RegistrationData>({ username: '', email: '', password: '' }), []);
|
|
4204
|
+
const form = useMemo(() => createForm({ model }), [model]);
|
|
4205
|
+
|
|
4206
|
+
const { submit, isValidating } = useFormValidation({
|
|
4207
|
+
model,
|
|
4208
|
+
schema: registrationValidation,
|
|
4209
|
+
strategy: 'afterFirstSubmit',
|
|
4210
|
+
debounce: 400,
|
|
4211
|
+
});
|
|
4212
|
+
|
|
4213
|
+
const onSubmit = async (e: React.FormEvent) => {
|
|
4214
|
+
e.preventDefault();
|
|
4215
|
+
if (await submit()) await api.save(model.get()); // true = нет блокирующих ошибок
|
|
4216
|
+
};
|
|
4217
|
+
|
|
4218
|
+
return (
|
|
4219
|
+
<form onSubmit={onSubmit}>
|
|
4220
|
+
<FormField control={form.username} />
|
|
4221
|
+
<FormField control={form.email} />
|
|
4222
|
+
<FormField control={form.password} />
|
|
4223
|
+
<button type="submit" disabled={isValidating}>Отправить</button>
|
|
4224
|
+
</form>
|
|
4225
|
+
);
|
|
4226
|
+
}
|
|
4227
|
+
```
|
|
4228
|
+
|
|
4229
|
+
### Wizard — live-стратегия внутри активного шага
|
|
4230
|
+
|
|
4231
|
+
`defineSteps(..., { strategy })` задаёт ЖИВУЮ стратегию ВНУТРИ шага; `useWizardStepValidation`
|
|
4232
|
+
арминует её под текущий шаг (`currentStep` из `FormWizardContext`) и снимает при смене шага / unmount.
|
|
4233
|
+
Per-step gate (`validateStep` на «Далее») и `validateAll` (submit) при этом НЕ меняются — стратегия
|
|
4234
|
+
добавляет живой слой ПОВЕРХ них. No-op, если `strategy` не задана / `'submit'` / у шага нет правил.
|
|
4235
|
+
|
|
4236
|
+
```tsx
|
|
4237
|
+
import { defineSteps, useWizardStepValidation, FormWizard } from '@reformer/cdk/form-wizard';
|
|
4238
|
+
|
|
4239
|
+
const config = defineSteps<'loan' | 'applicant' | 'confirm', CreditForm>(model, {
|
|
4240
|
+
steps: { loan: loanStep, applicant: applicantStep, confirm: null }, // confirm — без правил, ЯВНО
|
|
4241
|
+
extras: crossFieldRules, // применяются только в validateAll (submit)
|
|
4242
|
+
strategy: 'blur', // живая валидация полей текущего шага при потере фокуса
|
|
4243
|
+
});
|
|
4244
|
+
|
|
4245
|
+
function LoanStepBody() {
|
|
4246
|
+
useWizardStepValidation(config); // армит 'blur' под активный шаг, снимает при переходе
|
|
4247
|
+
return <>{/* поля шага */}</>;
|
|
4248
|
+
}
|
|
4249
|
+
|
|
4250
|
+
<FormWizard form={form} config={config}>
|
|
4251
|
+
<LoanStepBody />
|
|
4252
|
+
</FormWizard>;
|
|
4253
|
+
```
|
|
4254
|
+
|
|
4255
|
+
### Headless / SSR / тесты — createFormValidation
|
|
4256
|
+
|
|
4257
|
+
```typescript
|
|
4258
|
+
import { createFormValidation } from '@reformer/core/validation';
|
|
4259
|
+
|
|
4260
|
+
const ctrl = createFormValidation(model, registrationValidation, {
|
|
4261
|
+
strategy: 'afterFirstSubmit',
|
|
4262
|
+
debounce: 300,
|
|
4263
|
+
});
|
|
4264
|
+
const dispose = ctrl.start(); // ТОЛЬКО на клиенте (в React — из useEffect)
|
|
4265
|
+
const ok = await ctrl.validate(); // submit → раскрыть все ошибки
|
|
4266
|
+
dispose();
|
|
4267
|
+
```
|
|
4268
|
+
|
|
4269
|
+
## 80. Anti-patterns
|
|
4139
4270
|
|
|
4140
|
-
**Signature:**
|
|
4141
4271
|
```typescript
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4272
|
+
// ❌ schema пересоздаётся каждый рендер → контроллер и дедуп раннера ломаются
|
|
4273
|
+
function MyForm() {
|
|
4274
|
+
const schema = defineValidationSchema<Form>(({ model }) => { … }); // новая ссылка на каждый рендер
|
|
4275
|
+
useFormValidation({ model, schema, strategy: 'change' });
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
// ✅ Стабильная ссылка: module-level const (или useMemo с пустыми deps)
|
|
4279
|
+
const formValidation = defineValidationSchema<Form>(({ model }) => { … });
|
|
4280
|
+
function MyForm() {
|
|
4281
|
+
useFormValidation({ model, schema: formValidation, strategy: 'change' });
|
|
4145
4282
|
}
|
|
4146
4283
|
```
|
|
4147
4284
|
|
|
4148
|
-
|
|
4285
|
+
```typescript
|
|
4286
|
+
// ❌ Node-level updateOn (Слой B) И активная schema-стратегия на ОДНОМ поле → оба пишут ошибки в ноду → мерцание
|
|
4287
|
+
// узел поля: { updateOn: 'blur', … } + useFormValidation({ strategy: 'blur', schema: включает это же поле })
|
|
4288
|
+
|
|
4289
|
+
// ✅ Одно поле обслуживает ОДИН слой: либо node-level updateOn, либо schema-стратегия — не оба сразу
|
|
4290
|
+
```
|
|
4291
|
+
|
|
4292
|
+
```typescript
|
|
4293
|
+
// ❌ start() на сервере — арминует реактивные подписки при SSR
|
|
4294
|
+
const ctrl = createFormValidation(model, schema, { strategy: 'change' });
|
|
4295
|
+
ctrl.start(); // на сервере подписок быть не должно
|
|
4296
|
+
|
|
4297
|
+
// ✅ Фабрика чиста до start(); армить только на клиенте (useFormValidation делает это в useEffect)
|
|
4298
|
+
const ctrl = createFormValidation(model, schema, { strategy: 'change' });
|
|
4299
|
+
if (typeof window !== 'undefined') ctrl.start();
|
|
4300
|
+
```
|
|
4301
|
+
|
|
4302
|
+
## 81. See also
|
|
4303
|
+
|
|
4304
|
+
- [28-submit-and-reset.md](./28-submit-and-reset.md) — submit-флоу и `validateModel` (движок под стратегией)
|
|
4305
|
+
- [27-revalidate-when.md](./27-revalidate-when.md) — ручные триггеры перевалидации (низкоуровневый примитив)
|
|
4306
|
+
- [31-async-validator-debounce.md](./31-async-validator-debounce.md) — async-правила и отмена устаревших прогонов
|
|
4307
|
+
- [13-multi-step.md](./13-multi-step.md) — per-step / полная валидация wizard (`validateStep` / `validateAll`)
|
|
4308
|
+
|
|
4309
|
+
## 82. API Reference
|
|
4310
|
+
|
|
4311
|
+
_Auto-generated from JSDoc on public exports._
|
|
4312
|
+
|
|
4313
|
+
### AnyFunction
|
|
4314
|
+
|
|
4315
|
+
**Kind:** `type`
|
|
4316
|
+
|
|
4317
|
+
Тип для проверки на функцию в conditional types
|
|
4318
|
+
Используется вместо Function для type narrowing
|
|
4319
|
+
|
|
4320
|
+
**Signature:**
|
|
4321
|
+
```typescript
|
|
4322
|
+
export type AnyFunction = (...args: never[]) => unknown;
|
|
4323
|
+
```
|
|
4324
|
+
|
|
4325
|
+
_Source: src/form/types/index.ts_
|
|
4149
4326
|
|
|
4150
4327
|
### ArrayControlState
|
|
4151
4328
|
|
|
@@ -4291,7 +4468,7 @@ return (
|
|
|
4291
4468
|
<PhoneItem
|
|
4292
4469
|
key={item.id}
|
|
4293
4470
|
control={item}
|
|
4294
|
-
onRemove={() => control.
|
|
4471
|
+
onRemove={() => control.removeAt(index)}
|
|
4295
4472
|
/>
|
|
4296
4473
|
))}
|
|
4297
4474
|
|
|
@@ -4359,28 +4536,6 @@ export interface ArrayNodeLike {
|
|
|
4359
4536
|
|
|
4360
4537
|
_Source: src/form/types/index.ts_
|
|
4361
4538
|
|
|
4362
|
-
### AsyncValidator
|
|
4363
|
-
|
|
4364
|
-
**Kind:** `type`
|
|
4365
|
-
|
|
4366
|
-
Чистый асинхронный валидатор поля. Та же тройка аргументов `(value, scope, root)`, что у
|
|
4367
|
-
{@link Validator}, но возвращает `Promise`.
|
|
4368
|
-
|
|
4369
|
-
**Signature:**
|
|
4370
|
-
```typescript
|
|
4371
|
-
export type AsyncValidator<TForm, TField> = (
|
|
4372
|
-
value: TField,
|
|
4373
|
-
scope: unknown,
|
|
4374
|
-
root: FormModel<TForm>
|
|
4375
|
-
) => Promise<ValidationError | null>;
|
|
4376
|
-
```
|
|
4377
|
-
|
|
4378
|
-
**Deprecated:** Осиротевший остаток удалённого оператора `validateAsync` (Ф7). Рантаймом не
|
|
4379
|
-
потребляется — живой async-путь узла поля использует `AsyncValidatorFn` `(value, { signal })`.
|
|
4380
|
-
Экспортируется только ради обратной совместимости.
|
|
4381
|
-
|
|
4382
|
-
_Source: src/form/types/validation-schema.ts_
|
|
4383
|
-
|
|
4384
4539
|
### AsyncValidatorFn
|
|
4385
4540
|
|
|
4386
4541
|
**Kind:** `type`
|
|
@@ -4484,22 +4639,6 @@ computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price *
|
|
|
4484
4639
|
|
|
4485
4640
|
_Source: src/state/behaviors-value.ts_
|
|
4486
4641
|
|
|
4487
|
-
### ConditionFn
|
|
4488
|
-
|
|
4489
|
-
**Kind:** `type`
|
|
4490
|
-
|
|
4491
|
-
Функция-предикат `(value) => boolean`.
|
|
4492
|
-
|
|
4493
|
-
**Signature:**
|
|
4494
|
-
```typescript
|
|
4495
|
-
export type ConditionFn<T> = (value: T) => boolean;
|
|
4496
|
-
```
|
|
4497
|
-
|
|
4498
|
-
**Deprecated:** Осиротевший остаток удалённого оператора `applyWhen` (Ф7). Рантаймом не
|
|
4499
|
-
потребляется; экспортируется только ради обратной совместимости.
|
|
4500
|
-
|
|
4501
|
-
_Source: src/form/types/validation-schema.ts_
|
|
4502
|
-
|
|
4503
4642
|
### ConfigWithSchema
|
|
4504
4643
|
|
|
4505
4644
|
**Kind:** `interface`
|
|
@@ -4554,6 +4693,40 @@ copyFrom(model.$.email, model.$.emailAdditional, { when: () => model.sameEmail }
|
|
|
4554
4693
|
|
|
4555
4694
|
_Source: src/state/behaviors-value.ts_
|
|
4556
4695
|
|
|
4696
|
+
### CORE_RUNTIME_TOKEN
|
|
4697
|
+
|
|
4698
|
+
**Kind:** `const`
|
|
4699
|
+
|
|
4700
|
+
Штамп копии рантайма ядра.
|
|
4701
|
+
|
|
4702
|
+
Единственное назначение — быть объектом, уникальным в пределах ОДНОЙ копии модуля. Две
|
|
4703
|
+
независимо загруженные копии `@reformer/core` дадут два разных объекта, и по их несовпадению
|
|
4704
|
+
guard распознаёт дубль рантайма.
|
|
4705
|
+
|
|
4706
|
+
Почему именно объект, а не строка с версией: две копии ОДНОЙ версии ломают всё ровно так же,
|
|
4707
|
+
как две копии разных версий, — раздваиваются модульные `WeakMap` (`derived-registry`,
|
|
4708
|
+
`signal-node-registry`) и перестают работать проверки `instanceof Signal`. Сравнение версий
|
|
4709
|
+
такой случай пропустило бы.
|
|
4710
|
+
|
|
4711
|
+
**Signature:**
|
|
4712
|
+
```typescript
|
|
4713
|
+
export const CORE_RUNTIME_TOKEN: object
|
|
4714
|
+
```
|
|
4715
|
+
|
|
4716
|
+
**Examples:**
|
|
4717
|
+
|
|
4718
|
+
```ts
|
|
4719
|
+
import { CORE_RUNTIME_TOKEN } from '@reformer/core';
|
|
4720
|
+
import { stampRuntime } from '@reformer/form-registry/guard';
|
|
4721
|
+
|
|
4722
|
+
stampRuntime('@reformer/core', CORE_RUNTIME_TOKEN);
|
|
4723
|
+
```
|
|
4724
|
+
|
|
4725
|
+
**See also:**
|
|
4726
|
+
- `@reformer/form-registry/guard`
|
|
4727
|
+
|
|
4728
|
+
_Source: src/runtime-token.ts_
|
|
4729
|
+
|
|
4557
4730
|
### createForm
|
|
4558
4731
|
|
|
4559
4732
|
**Kind:** `function`
|
|
@@ -4759,43 +4932,6 @@ disableWhen(model.$.discount, () => model.plan !== 'promo', { resetOnDisable: tr
|
|
|
4759
4932
|
|
|
4760
4933
|
_Source: src/form/behaviors-node.ts_
|
|
4761
4934
|
|
|
4762
|
-
### email
|
|
4763
|
-
|
|
4764
|
-
**Kind:** `function`
|
|
4765
|
-
|
|
4766
|
-
Фабрика валидатора формата email.
|
|
4767
|
-
|
|
4768
|
-
Проверяет по упрощённому regex `^[^\s@]+@[^\s@]+\.[^\s@]+$`. Пустые значения
|
|
4769
|
-
(`''`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
|
|
4770
|
-
|
|
4771
|
-
**Signature:**
|
|
4772
|
-
```typescript
|
|
4773
|
-
export function email<TForm = unknown, TField extends string | null | undefined = string>(
|
|
4774
|
-
options?: ValidateOptions
|
|
4775
|
-
): Validator<TForm, TField>
|
|
4776
|
-
```
|
|
4777
|
-
|
|
4778
|
-
**Parameters:**
|
|
4779
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
4780
|
-
|
|
4781
|
-
**Returns:** Чистый валидатор {@link Validator} для строкового поля
|
|
4782
|
-
|
|
4783
|
-
**Examples:**
|
|
4784
|
-
|
|
4785
|
-
Проверка формата email
|
|
4786
|
-
```typescript
|
|
4787
|
-
import { required, email } from '@reformer/core/validators';
|
|
4788
|
-
|
|
4789
|
-
// Внутри FieldConfig схемы формы:
|
|
4790
|
-
email: {
|
|
4791
|
-
value: model.$.email,
|
|
4792
|
-
component: Input,
|
|
4793
|
-
validators: [required(), email({ message: 'Введите корректный email' })],
|
|
4794
|
-
},
|
|
4795
|
-
```
|
|
4796
|
-
|
|
4797
|
-
_Source: src/form/validation/validators/email.ts_
|
|
4798
|
-
|
|
4799
4935
|
### enableWhen
|
|
4800
4936
|
|
|
4801
4937
|
**Kind:** `function`
|
|
@@ -5085,12 +5221,12 @@ export interface FieldControlState<T> {
|
|
|
5085
5221
|
|
|
5086
5222
|
/**
|
|
5087
5223
|
* Пользовательские props для передачи в UI-компоненты.
|
|
5088
|
-
* Устанавливаются через {@link FieldNode.
|
|
5224
|
+
* Устанавливаются через {@link FieldNode.updateComponentProps}.
|
|
5089
5225
|
*
|
|
5090
5226
|
* @example
|
|
5091
5227
|
* ```tsx
|
|
5092
5228
|
* // Установка props
|
|
5093
|
-
* field.
|
|
5229
|
+
* field.updateComponentProps({
|
|
5094
5230
|
* placeholder: 'Enter email...',
|
|
5095
5231
|
* maxLength: 100,
|
|
5096
5232
|
* autoComplete: 'email'
|
|
@@ -5190,23 +5326,6 @@ console.log(field.valid.value); // true
|
|
|
5190
5326
|
|
|
5191
5327
|
_Source: src/form/nodes/field-node.ts_
|
|
5192
5328
|
|
|
5193
|
-
### FieldPathSegment
|
|
5194
|
-
|
|
5195
|
-
**Kind:** `type`
|
|
5196
|
-
|
|
5197
|
-
Тип для путей к полям (field paths)
|
|
5198
|
-
Используется в навигации по полям вместо any
|
|
5199
|
-
|
|
5200
|
-
**Signature:**
|
|
5201
|
-
```typescript
|
|
5202
|
-
export type FieldPathSegment = {
|
|
5203
|
-
key: string;
|
|
5204
|
-
index?: number;
|
|
5205
|
-
};
|
|
5206
|
-
```
|
|
5207
|
-
|
|
5208
|
-
_Source: src/form/types/index.ts_
|
|
5209
|
-
|
|
5210
5329
|
### FieldStatus
|
|
5211
5330
|
|
|
5212
5331
|
**Kind:** `type`
|
|
@@ -5220,70 +5339,6 @@ export type FieldStatus = 'valid' | 'invalid' | 'pending' | 'disabled';
|
|
|
5220
5339
|
|
|
5221
5340
|
_Source: src/form/types/contracts.ts_
|
|
5222
5341
|
|
|
5223
|
-
### FileLike
|
|
5224
|
-
|
|
5225
|
-
**Kind:** `interface`
|
|
5226
|
-
|
|
5227
|
-
Минимальный файлоподобный контракт, с которым работают file-валидаторы:
|
|
5228
|
-
нативный `File`, сериализуемый дескриптор загруженного файла и т.п.
|
|
5229
|
-
|
|
5230
|
-
**Signature:**
|
|
5231
|
-
```typescript
|
|
5232
|
-
export interface FileLike {
|
|
5233
|
-
name: string;
|
|
5234
|
-
size?: number;
|
|
5235
|
-
type?: string;
|
|
5236
|
-
}
|
|
5237
|
-
```
|
|
5238
|
-
|
|
5239
|
-
_Source: src/form/validation/validators/file-utils.ts_
|
|
5240
|
-
|
|
5241
|
-
### fileType
|
|
5242
|
-
|
|
5243
|
-
**Kind:** `function`
|
|
5244
|
-
|
|
5245
|
-
Фабрика валидатора типа файла.
|
|
5246
|
-
|
|
5247
|
-
Проверяет каждый файл против accept-строки в синтаксисе нативного атрибута
|
|
5248
|
-
`<input type="file" accept>`: расширения (`.pdf`), точные MIME (`image/png`),
|
|
5249
|
-
wildcard-категории (`image/*`), список через запятую. Матчинг регистронезависимый,
|
|
5250
|
-
по `type` и/или расширению из `name` ({@link matchesFileAccept}).
|
|
5251
|
-
|
|
5252
|
-
Нужен потому, что нативный `accept` — только подсказка пикеру: на drag-and-drop
|
|
5253
|
-
и «All files» он не действует. Пустые значения (`null`/`undefined`/`''`/`[]`)
|
|
5254
|
-
пропускаются (используйте {@link required} для обязательности).
|
|
5255
|
-
|
|
5256
|
-
**Signature:**
|
|
5257
|
-
```typescript
|
|
5258
|
-
export function fileType<TForm = unknown, TField = unknown>(
|
|
5259
|
-
accept: string,
|
|
5260
|
-
options?: ValidateOptions
|
|
5261
|
-
): Validator<TForm, TField>
|
|
5262
|
-
```
|
|
5263
|
-
|
|
5264
|
-
**Parameters:**
|
|
5265
|
-
- `accept` — - Accept-строка допустимых типов, например `'image/*,.pdf'`
|
|
5266
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
5267
|
-
попадают `accept` и `fileName` (первый нарушивший файл).
|
|
5268
|
-
|
|
5269
|
-
**Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
|
|
5270
|
-
|
|
5271
|
-
**Examples:**
|
|
5272
|
-
|
|
5273
|
-
Только изображения и PDF
|
|
5274
|
-
```typescript
|
|
5275
|
-
import { fileType } from '@reformer/core/validators';
|
|
5276
|
-
|
|
5277
|
-
// Внутри FieldConfig схемы формы:
|
|
5278
|
-
documents: {
|
|
5279
|
-
value: model.$.documents,
|
|
5280
|
-
component: FileUploadField,
|
|
5281
|
-
validators: [fileType('image/*,.pdf', { message: 'Только изображения или PDF' })],
|
|
5282
|
-
},
|
|
5283
|
-
```
|
|
5284
|
-
|
|
5285
|
-
_Source: src/form/validation/validators/file-type.ts_
|
|
5286
|
-
|
|
5287
5342
|
### FormArrayProxy
|
|
5288
5343
|
|
|
5289
5344
|
**Kind:** `type`
|
|
@@ -5664,19 +5719,25 @@ export interface FormSchemaNode {
|
|
|
5664
5719
|
component?: ElementType;
|
|
5665
5720
|
/** Props компонента. Также «клапан» для вложенности под-узлов (напр. steps визарда). */
|
|
5666
5721
|
componentProps?: Record<string, unknown>;
|
|
5667
|
-
validators?: SchemaValidator[];
|
|
5668
|
-
asyncValidators?: SchemaValidator[];
|
|
5669
5722
|
updateOn?: 'change' | 'blur' | 'submit';
|
|
5670
5723
|
disabled?: boolean;
|
|
5671
5724
|
/** Задержка (мс) перед запуском асинхронной валидации. */
|
|
5672
5725
|
debounce?: number;
|
|
5673
5726
|
/** Идентификатор узла (для wizard/tabs/renderBehavior). */
|
|
5674
5727
|
selector?: string;
|
|
5728
|
+
/**
|
|
5729
|
+
* ⚠️ Рантайм этого поля НЕ ЧИТАЕТ — `renderer-react` берёт testId из `componentProps.testId`
|
|
5730
|
+
* (иначе выводит из пути сигнала). Поле оставлено только потому, что `RenderSchemaNode`
|
|
5731
|
+
* рендерера объявляет свой одноимённый; пишите `componentProps: { testId: '…' }`.
|
|
5732
|
+
*/
|
|
5675
5733
|
testId?: string;
|
|
5676
|
-
/**
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5734
|
+
/**
|
|
5735
|
+
* Содержимое узла: под-узлы (даёт контекстную типизацию вложенным литералам — value/validators/when)
|
|
5736
|
+
* и текстовые части. Текст (литерал, число, сигнал модели) — такой же ребёнок, как узел: core его
|
|
5737
|
+
* не интерпретирует (обход пропускает примитивы и не спускается внутрь сигнала), а рендерер
|
|
5738
|
+
* выводит на своём месте в порядке следования.
|
|
5739
|
+
*/
|
|
5740
|
+
children?: readonly (FormSchemaNode | string | number | Signal<any>)[];
|
|
5680
5741
|
/** Реактивный массив модели (`model.<path>`) — маркер узла-массива (вместе с `item`). */
|
|
5681
5742
|
array?: SchemaArrayControl;
|
|
5682
5743
|
/** Схема элемента массива: под-модель элемента → узел поддерева. */
|
|
@@ -5694,43 +5755,6 @@ export interface FormSchemaNode {
|
|
|
5694
5755
|
|
|
5695
5756
|
_Source: src/form/types/schema-node.ts_
|
|
5696
5757
|
|
|
5697
|
-
### FormStatusMachine
|
|
5698
|
-
|
|
5699
|
-
**Kind:** `class`
|
|
5700
|
-
|
|
5701
|
-
FormStatusMachine - управляет состоянием поля формы
|
|
5702
|
-
|
|
5703
|
-
Предоставляет:
|
|
5704
|
-
- Единый источник истины для статуса
|
|
5705
|
-
- Computed signals для derived состояний (valid, invalid, pending, disabled)
|
|
5706
|
-
- Валидацию переходов между состояниями
|
|
5707
|
-
|
|
5708
|
-
**Signature:**
|
|
5709
|
-
```typescript
|
|
5710
|
-
export class FormStatusMachine {
|
|
5711
|
-
/** Внутренний сигнал статуса */ /* … */ }
|
|
5712
|
-
```
|
|
5713
|
-
|
|
5714
|
-
**Examples:**
|
|
5715
|
-
|
|
5716
|
-
```typescript
|
|
5717
|
-
const statusMachine = new FormStatusMachine('valid');
|
|
5718
|
-
|
|
5719
|
-
// Начало валидации
|
|
5720
|
-
statusMachine.startValidation();
|
|
5721
|
-
console.log(statusMachine.pending.value); // true
|
|
5722
|
-
|
|
5723
|
-
// Завершение валидации с ошибками
|
|
5724
|
-
statusMachine.completeValidation(true);
|
|
5725
|
-
console.log(statusMachine.invalid.value); // true
|
|
5726
|
-
|
|
5727
|
-
// Отключение поля
|
|
5728
|
-
statusMachine.disable();
|
|
5729
|
-
console.log(statusMachine.disabled.value); // true
|
|
5730
|
-
```
|
|
5731
|
-
|
|
5732
|
-
_Source: src/form/status-machine.ts_
|
|
5733
|
-
|
|
5734
5758
|
### FormSubmitter
|
|
5735
5759
|
|
|
5736
5760
|
**Kind:** `class`
|
|
@@ -5784,44 +5808,6 @@ export type FormValue =
|
|
|
5784
5808
|
|
|
5785
5809
|
_Source: src/form/types/contracts.ts_
|
|
5786
5810
|
|
|
5787
|
-
### futureDate
|
|
5788
|
-
|
|
5789
|
-
**Kind:** `function`
|
|
5790
|
-
|
|
5791
|
-
Фабрика валидатора, проверяющего что дата не в прошлом.
|
|
5792
|
-
|
|
5793
|
-
Дата не должна быть раньше сегодняшнего дня (сравнение по нормализованным датам).
|
|
5794
|
-
Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
|
|
5795
|
-
|
|
5796
|
-
**Signature:**
|
|
5797
|
-
```typescript
|
|
5798
|
-
export function futureDate<
|
|
5799
|
-
TForm = unknown,
|
|
5800
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
5801
|
-
>(options?: ValidateOptions): Validator<TForm, TField>
|
|
5802
|
-
```
|
|
5803
|
-
|
|
5804
|
-
**Parameters:**
|
|
5805
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
5806
|
-
|
|
5807
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
|
|
5808
|
-
|
|
5809
|
-
**Examples:**
|
|
5810
|
-
|
|
5811
|
-
Дата не в прошлом
|
|
5812
|
-
```typescript
|
|
5813
|
-
import { required, futureDate } from '@reformer/core/validators';
|
|
5814
|
-
|
|
5815
|
-
// Внутри FieldConfig схемы формы:
|
|
5816
|
-
appointmentDate: {
|
|
5817
|
-
value: model.$.appointmentDate,
|
|
5818
|
-
component: DatePicker,
|
|
5819
|
-
validators: [required(), futureDate({ message: 'Дата записи должна быть в будущем' })],
|
|
5820
|
-
},
|
|
5821
|
-
```
|
|
5822
|
-
|
|
5823
|
-
_Source: src/form/validation/validators/future-date.ts_
|
|
5824
|
-
|
|
5825
5811
|
### getNodeForSignal
|
|
5826
5812
|
|
|
5827
5813
|
**Kind:** `function`
|
|
@@ -5937,42 +5923,6 @@ export interface GroupNodeConfig<T> {
|
|
|
5937
5923
|
|
|
5938
5924
|
_Source: src/form/types/index.ts_
|
|
5939
5925
|
|
|
5940
|
-
### integer
|
|
5941
|
-
|
|
5942
|
-
**Kind:** `function`
|
|
5943
|
-
|
|
5944
|
-
Фабрика валидатора, проверяющего что число — целое.
|
|
5945
|
-
|
|
5946
|
-
Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
|
|
5947
|
-
|
|
5948
|
-
**Signature:**
|
|
5949
|
-
```typescript
|
|
5950
|
-
export function integer<TForm = unknown, TField extends number | null | undefined = number>(
|
|
5951
|
-
options?: ValidateOptions
|
|
5952
|
-
): Validator<TForm, TField>
|
|
5953
|
-
```
|
|
5954
|
-
|
|
5955
|
-
**Parameters:**
|
|
5956
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
5957
|
-
|
|
5958
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
5959
|
-
|
|
5960
|
-
**Examples:**
|
|
5961
|
-
|
|
5962
|
-
Проверка целого числа
|
|
5963
|
-
```typescript
|
|
5964
|
-
import { required, integer } from '@reformer/core/validators';
|
|
5965
|
-
|
|
5966
|
-
// Внутри FieldConfig схемы формы:
|
|
5967
|
-
count: {
|
|
5968
|
-
value: model.$.count,
|
|
5969
|
-
component: Input,
|
|
5970
|
-
validators: [required(), integer({ message: 'Должно быть целым числом' })],
|
|
5971
|
-
},
|
|
5972
|
-
```
|
|
5973
|
-
|
|
5974
|
-
_Source: src/form/validation/validators/integer.ts_
|
|
5975
|
-
|
|
5976
5926
|
### isArrayNode
|
|
5977
5927
|
|
|
5978
5928
|
**Kind:** `function`
|
|
@@ -6004,49 +5954,11 @@ if (isArrayNode(node)) {
|
|
|
6004
5954
|
|
|
6005
5955
|
_Source: src/form/type-guards.ts_
|
|
6006
5956
|
|
|
6007
|
-
###
|
|
5957
|
+
### isDerived
|
|
6008
5958
|
|
|
6009
5959
|
**Kind:** `function`
|
|
6010
5960
|
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
Принимает `Date` или строку, парсимую в дату. Пустые значения (`''`/`null`/`undefined`)
|
|
6014
|
-
пропускаются (используйте {@link required} для обязательности).
|
|
6015
|
-
|
|
6016
|
-
**Signature:**
|
|
6017
|
-
```typescript
|
|
6018
|
-
export function isDate<
|
|
6019
|
-
TForm = unknown,
|
|
6020
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
6021
|
-
>(options?: ValidateOptions): Validator<TForm, TField>
|
|
6022
|
-
```
|
|
6023
|
-
|
|
6024
|
-
**Parameters:**
|
|
6025
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
6026
|
-
|
|
6027
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
|
|
6028
|
-
|
|
6029
|
-
**Examples:**
|
|
6030
|
-
|
|
6031
|
-
Проверка валидности даты
|
|
6032
|
-
```typescript
|
|
6033
|
-
import { required, isDate } from '@reformer/core/validators';
|
|
6034
|
-
|
|
6035
|
-
// Внутри FieldConfig схемы формы:
|
|
6036
|
-
eventDate: {
|
|
6037
|
-
value: model.$.eventDate,
|
|
6038
|
-
component: DatePicker,
|
|
6039
|
-
validators: [required(), isDate({ message: 'Введите корректную дату' })],
|
|
6040
|
-
},
|
|
6041
|
-
```
|
|
6042
|
-
|
|
6043
|
-
_Source: src/form/validation/validators/is-date.ts_
|
|
6044
|
-
|
|
6045
|
-
### isDerived
|
|
6046
|
-
|
|
6047
|
-
**Kind:** `function`
|
|
6048
|
-
|
|
6049
|
-
Производный ли сигнал (помечен через {@link markDerived}).
|
|
5961
|
+
Производный ли сигнал (помечен через {@link markDerived}).
|
|
6050
5962
|
|
|
6051
5963
|
Читается bulk-сеттерами модели/группы, чтобы не затирать вычисляемые (`computeFrom`) поля
|
|
6052
5964
|
значениями из payload.
|
|
@@ -6087,733 +5999,119 @@ FieldNode представляет примитивное поле формы (s
|
|
|
6087
5999
|
|
|
6088
6000
|
**Signature:**
|
|
6089
6001
|
```typescript
|
|
6090
|
-
export function isFieldNode(value: unknown): value is FieldNode<FormValue>
|
|
6091
|
-
```
|
|
6092
|
-
|
|
6093
|
-
**Parameters:**
|
|
6094
|
-
- `value` — - Значение для проверки
|
|
6095
|
-
|
|
6096
|
-
**Returns:** true если value является FieldNode
|
|
6097
|
-
|
|
6098
|
-
**Examples:**
|
|
6099
|
-
|
|
6100
|
-
```typescript
|
|
6101
|
-
if (isFieldNode(node)) {
|
|
6102
|
-
node.validators; // OK
|
|
6103
|
-
node.asyncValidators; // OK
|
|
6104
|
-
node.markAsTouched(); // OK
|
|
6105
|
-
}
|
|
6106
|
-
```
|
|
6107
|
-
|
|
6108
|
-
_Source: src/form/type-guards.ts_
|
|
6109
|
-
|
|
6110
|
-
### isFileLike
|
|
6111
|
-
|
|
6112
|
-
**Kind:** `function`
|
|
6113
|
-
|
|
6114
|
-
Проверяет, что значение файлоподобно: объект со строковым `name` и опциональными
|
|
6115
|
-
числовым `size` / строковым `type`.
|
|
6116
|
-
|
|
6117
|
-
**Signature:**
|
|
6118
|
-
```typescript
|
|
6119
|
-
export function isFileLike(value: unknown): value is FileLike
|
|
6120
|
-
```
|
|
6121
|
-
|
|
6122
|
-
**Parameters:**
|
|
6123
|
-
- `value` — - Проверяемое значение
|
|
6124
|
-
|
|
6125
|
-
**Returns:** `true`, если значение соответствует {@link FileLike}
|
|
6126
|
-
|
|
6127
|
-
_Source: src/form/validation/validators/file-utils.ts_
|
|
6128
|
-
|
|
6129
|
-
### isFormNode
|
|
6130
|
-
|
|
6131
|
-
**Kind:** `function`
|
|
6132
|
-
|
|
6133
|
-
Проверить, является ли значение любым FormNode
|
|
6134
|
-
|
|
6135
|
-
Проверяет базовые свойства, общие для всех типов узлов
|
|
6136
|
-
|
|
6137
|
-
**Signature:**
|
|
6138
|
-
```typescript
|
|
6139
|
-
export function isFormNode(value: unknown): value is FormNode<FormValue>
|
|
6140
|
-
```
|
|
6141
|
-
|
|
6142
|
-
**Parameters:**
|
|
6143
|
-
- `value` — - Значение для проверки
|
|
6144
|
-
|
|
6145
|
-
**Returns:** true если value является FormNode
|
|
6146
|
-
|
|
6147
|
-
**Examples:**
|
|
6148
|
-
|
|
6149
|
-
```typescript
|
|
6150
|
-
if (isFormNode(value)) {
|
|
6151
|
-
value.setValue(newValue);
|
|
6152
|
-
value.validate();
|
|
6153
|
-
}
|
|
6154
|
-
```
|
|
6155
|
-
|
|
6156
|
-
_Source: src/form/type-guards.ts_
|
|
6157
|
-
|
|
6158
|
-
### isGroupNode
|
|
6159
|
-
|
|
6160
|
-
**Kind:** `function`
|
|
6161
|
-
|
|
6162
|
-
Проверить, является ли значение GroupNode (объект с вложенными полями)
|
|
6163
|
-
|
|
6164
|
-
GroupNode представляет объект с вложенными полями формы: имеет навигацию по полям
|
|
6165
|
-
(`getFieldByPath`/`fields`) и НЕ имеет array-методов (`items`/`push`/`removeAt`).
|
|
6166
|
-
|
|
6167
|
-
**Signature:**
|
|
6168
|
-
```typescript
|
|
6169
|
-
export function isGroupNode(value: unknown): value is GroupNode<object>
|
|
6170
|
-
```
|
|
6171
|
-
|
|
6172
|
-
**Parameters:**
|
|
6173
|
-
- `value` — - Значение для проверки
|
|
6174
|
-
|
|
6175
|
-
**Returns:** true если value является GroupNode
|
|
6176
|
-
|
|
6177
|
-
**Examples:**
|
|
6178
|
-
|
|
6179
|
-
```typescript
|
|
6180
|
-
if (isGroupNode(node)) {
|
|
6181
|
-
node.getFieldByPath('user.email'); // OK
|
|
6182
|
-
}
|
|
6183
|
-
```
|
|
6184
|
-
|
|
6185
|
-
_Source: src/form/type-guards.ts_
|
|
6186
|
-
|
|
6187
|
-
### isNumber
|
|
6188
|
-
|
|
6189
|
-
**Kind:** `function`
|
|
6190
|
-
|
|
6191
|
-
Фабрика валидатора, проверяющего что значение — конечное число (не NaN, не строка).
|
|
6192
|
-
|
|
6193
|
-
Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для
|
|
6194
|
-
обязательности). В отличие от других number-валидаторов, **не** пропускает не-числа
|
|
6195
|
-
и `NaN` — это его задача.
|
|
6196
|
-
|
|
6197
|
-
**Signature:**
|
|
6198
|
-
```typescript
|
|
6199
|
-
export function isNumber<TForm = unknown, TField extends number | null | undefined = number>(
|
|
6200
|
-
options?: ValidateOptions
|
|
6201
|
-
): Validator<TForm, TField>
|
|
6202
|
-
```
|
|
6203
|
-
|
|
6204
|
-
**Parameters:**
|
|
6205
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
6206
|
-
|
|
6207
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
6208
|
-
|
|
6209
|
-
**Examples:**
|
|
6210
|
-
|
|
6211
|
-
Проверка, что значение — число
|
|
6212
|
-
```typescript
|
|
6213
|
-
import { required, isNumber } from '@reformer/core/validators';
|
|
6214
|
-
|
|
6215
|
-
// Внутри FieldConfig схемы формы:
|
|
6216
|
-
amount: {
|
|
6217
|
-
value: model.$.amount,
|
|
6218
|
-
component: Input,
|
|
6219
|
-
validators: [required(), isNumber({ message: 'Введите число' })],
|
|
6220
|
-
},
|
|
6221
|
-
```
|
|
6222
|
-
|
|
6223
|
-
_Source: src/form/validation/validators/is-number.ts_
|
|
6224
|
-
|
|
6225
|
-
### markDerived
|
|
6226
|
-
|
|
6227
|
-
**Kind:** `function`
|
|
6228
|
-
|
|
6229
|
-
Пометить сигнал производным (вычисляемым).
|
|
6230
|
-
|
|
6231
|
-
Вызывается операторами {@link computeFrom}/`compute` для их сигнала-цели. После этого
|
|
6232
|
-
bulk-сеттеры (`model.set`/`model.patch`, `patchValue`/`setValue`) пропускают это поле, чтобы
|
|
6233
|
-
значение из payload не затирало вычисляемое. Прикладной код напрямую обычно не вызывает.
|
|
6234
|
-
|
|
6235
|
-
Идемпотентна на уровне флага: повторные вызовы наращивают счётчик ссылок, чтобы каждый оператор,
|
|
6236
|
-
пишущий в этот сигнал, был сбалансирован своим {@link unmarkDerived} при dispose.
|
|
6237
|
-
|
|
6238
|
-
**Signature:**
|
|
6239
|
-
```typescript
|
|
6240
|
-
export function markDerived(signal: Signal<any>): void
|
|
6241
|
-
```
|
|
6242
|
-
|
|
6243
|
-
**Parameters:**
|
|
6244
|
-
- `signal` — - Сигнал значения из {@link FormModel}, которым владеет compute
|
|
6245
|
-
|
|
6246
|
-
**Examples:**
|
|
6247
|
-
|
|
6248
|
-
```typescript
|
|
6249
|
-
import { markDerived } from '@reformer/core';
|
|
6250
|
-
|
|
6251
|
-
// Помечаем поле total как вычисляемое — bulk-set его не перезапишет
|
|
6252
|
-
markDerived(model.$.total);
|
|
6253
|
-
```
|
|
6254
|
-
|
|
6255
|
-
**See also:**
|
|
6256
|
-
- {@link isDerived} - проверка пометки
|
|
6257
|
-
- {@link unmarkDerived} - снять пометку при dispose оператора
|
|
6258
|
-
|
|
6259
|
-
_Source: src/state/derived-registry.ts_
|
|
6260
|
-
|
|
6261
|
-
### matchesFileAccept
|
|
6262
|
-
|
|
6263
|
-
**Kind:** `function`
|
|
6264
|
-
|
|
6265
|
-
Проверяет файл против accept-паттерна в синтаксисе нативного атрибута
|
|
6266
|
-
`<input type="file" accept>`: список через запятую из расширений (`.pdf`),
|
|
6267
|
-
точных MIME (`image/png`) и wildcard-категорий (`image/*`). Регистронезависимо.
|
|
6268
|
-
|
|
6269
|
-
Нужен собственный матчер, потому что `accept` у нативного input — только подсказка
|
|
6270
|
-
пикеру: на drag-and-drop и на программное значение он не действует.
|
|
6271
|
-
|
|
6272
|
-
**Signature:**
|
|
6273
|
-
```typescript
|
|
6274
|
-
export function matchesFileAccept(file: Pick<FileLike, 'name' | 'type'>, accept: string): boolean
|
|
6275
|
-
```
|
|
6276
|
-
|
|
6277
|
-
**Parameters:**
|
|
6278
|
-
- `file` — - Файлоподобное значение (`name` + опциональный `type`)
|
|
6279
|
-
- `accept` — - Accept-строка; пустая/пробельная строка матчит всё
|
|
6280
|
-
|
|
6281
|
-
**Returns:** `true`, если файл подходит хотя бы под один паттерн
|
|
6282
|
-
|
|
6283
|
-
_Source: src/form/validation/validators/file-utils.ts_
|
|
6284
|
-
|
|
6285
|
-
### max
|
|
6286
|
-
|
|
6287
|
-
**Kind:** `function`
|
|
6288
|
-
|
|
6289
|
-
Фабрика валидатора максимального числового значения.
|
|
6290
|
-
|
|
6291
|
-
Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
|
|
6292
|
-
|
|
6293
|
-
**Signature:**
|
|
6294
|
-
```typescript
|
|
6295
|
-
export function max<TForm = unknown, TField extends number | null | undefined = number>(
|
|
6296
|
-
maxValue: number,
|
|
6297
|
-
options?: ValidateOptions
|
|
6298
|
-
): Validator<TForm, TField>
|
|
6299
|
-
```
|
|
6300
|
-
|
|
6301
|
-
**Parameters:**
|
|
6302
|
-
- `maxValue` — - Максимально допустимое значение (включительно)
|
|
6303
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6304
|
-
попадают `max` и `actual`.
|
|
6305
|
-
|
|
6306
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
6307
|
-
|
|
6308
|
-
**Examples:**
|
|
6309
|
-
|
|
6310
|
-
Максимальное значение числового поля
|
|
6311
|
-
```typescript
|
|
6312
|
-
import { required, max } from '@reformer/core/validators';
|
|
6313
|
-
|
|
6314
|
-
// Внутри FieldConfig схемы формы:
|
|
6315
|
-
quantity: { value: model.$.quantity, component: Input, validators: [max(100)] },
|
|
6316
|
-
discount: {
|
|
6317
|
-
value: model.$.discount,
|
|
6318
|
-
component: Input,
|
|
6319
|
-
validators: [required(), max(50, { message: 'Не более 50%' })],
|
|
6320
|
-
},
|
|
6321
|
-
```
|
|
6322
|
-
|
|
6323
|
-
_Source: src/form/validation/validators/max.ts_
|
|
6324
|
-
|
|
6325
|
-
### maxAge
|
|
6326
|
-
|
|
6327
|
-
**Kind:** `function`
|
|
6328
|
-
|
|
6329
|
-
Фабрика валидатора максимального возраста (по дате рождения).
|
|
6330
|
-
|
|
6331
|
-
Возраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные
|
|
6332
|
-
даты пропускаются (используйте {@link required} и {@link isDate}).
|
|
6333
|
-
|
|
6334
|
-
**Signature:**
|
|
6335
|
-
```typescript
|
|
6336
|
-
export function maxAge<
|
|
6337
|
-
TForm = unknown,
|
|
6338
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
6339
|
-
>(maxAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>
|
|
6340
|
-
```
|
|
6341
|
-
|
|
6342
|
-
**Parameters:**
|
|
6343
|
-
- `maxAgeValue` — - Максимально допустимый возраст (в полных годах)
|
|
6344
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6345
|
-
попадают `maxAge` и `currentAge`.
|
|
6346
|
-
|
|
6347
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)
|
|
6348
|
-
|
|
6349
|
-
**Examples:**
|
|
6350
|
-
|
|
6351
|
-
Максимальный возраст
|
|
6352
|
-
```typescript
|
|
6353
|
-
import { maxAge } from '@reformer/core/validators';
|
|
6354
|
-
|
|
6355
|
-
// Внутри FieldConfig схемы формы:
|
|
6356
|
-
birthDate: {
|
|
6357
|
-
value: model.$.birthDate,
|
|
6358
|
-
component: DatePicker,
|
|
6359
|
-
validators: [maxAge(100, { message: 'Проверьте дату рождения' })],
|
|
6360
|
-
},
|
|
6361
|
-
```
|
|
6362
|
-
|
|
6363
|
-
_Source: src/form/validation/validators/max-age.ts_
|
|
6364
|
-
|
|
6365
|
-
### maxDate
|
|
6366
|
-
|
|
6367
|
-
**Kind:** `function`
|
|
6368
|
-
|
|
6369
|
-
Фабрика валидатора максимальной даты (включительно).
|
|
6370
|
-
|
|
6371
|
-
Сравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты
|
|
6372
|
-
пропускаются (используйте {@link required} и {@link isDate}).
|
|
6373
|
-
|
|
6374
|
-
**Signature:**
|
|
6375
|
-
```typescript
|
|
6376
|
-
export function maxDate<
|
|
6377
|
-
TForm = unknown,
|
|
6378
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
6379
|
-
>(maxDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>
|
|
6380
|
-
```
|
|
6381
|
-
|
|
6382
|
-
**Parameters:**
|
|
6383
|
-
- `maxDateValue` — - Максимально допустимая дата (включительно)
|
|
6384
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6385
|
-
попадает `maxDate`.
|
|
6386
|
-
|
|
6387
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
|
|
6388
|
-
|
|
6389
|
-
**Examples:**
|
|
6390
|
-
|
|
6391
|
-
Максимальная дата
|
|
6392
|
-
```typescript
|
|
6393
|
-
import { maxDate } from '@reformer/core/validators';
|
|
6394
|
-
|
|
6395
|
-
// Внутри FieldConfig схемы формы:
|
|
6396
|
-
birthDate: {
|
|
6397
|
-
value: model.$.birthDate,
|
|
6398
|
-
component: DatePicker,
|
|
6399
|
-
validators: [maxDate(new Date(), { message: 'Дата не может быть в будущем' })],
|
|
6400
|
-
},
|
|
6401
|
-
```
|
|
6402
|
-
|
|
6403
|
-
_Source: src/form/validation/validators/max-date.ts_
|
|
6404
|
-
|
|
6405
|
-
### maxFiles
|
|
6406
|
-
|
|
6407
|
-
**Kind:** `function`
|
|
6408
|
-
|
|
6409
|
-
Фабрика валидатора максимального количества файлов.
|
|
6410
|
-
|
|
6411
|
-
Работает с массивом файлов (одиночный файл считается как 1). Пустые значения
|
|
6412
|
-
(`null`/`undefined`/`''`/`[]`) пропускаются (используйте {@link required}
|
|
6413
|
-
для обязательности).
|
|
6414
|
-
|
|
6415
|
-
**Signature:**
|
|
6416
|
-
```typescript
|
|
6417
|
-
export function maxFiles<TForm = unknown, TField = unknown>(
|
|
6418
|
-
max: number,
|
|
6419
|
-
options?: ValidateOptions
|
|
6420
|
-
): Validator<TForm, TField>
|
|
6421
|
-
```
|
|
6422
|
-
|
|
6423
|
-
**Parameters:**
|
|
6424
|
-
- `max` — - Максимально допустимое количество файлов (включительно)
|
|
6425
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6426
|
-
попадают `maxFiles` и `actualCount`.
|
|
6427
|
-
|
|
6428
|
-
**Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
|
|
6429
|
-
|
|
6430
|
-
**Examples:**
|
|
6431
|
-
|
|
6432
|
-
Не более трёх вложений
|
|
6433
|
-
```typescript
|
|
6434
|
-
import { maxFiles } from '@reformer/core/validators';
|
|
6435
|
-
|
|
6436
|
-
// Внутри FieldConfig схемы формы:
|
|
6437
|
-
documents: {
|
|
6438
|
-
value: model.$.documents,
|
|
6439
|
-
component: FileUploadField,
|
|
6440
|
-
validators: [maxFiles(3, { message: 'Максимум 3 файла' })],
|
|
6441
|
-
},
|
|
6442
|
-
```
|
|
6443
|
-
|
|
6444
|
-
_Source: src/form/validation/validators/max-files.ts_
|
|
6445
|
-
|
|
6446
|
-
### maxFileSize
|
|
6447
|
-
|
|
6448
|
-
**Kind:** `function`
|
|
6449
|
-
|
|
6450
|
-
Фабрика валидатора максимального размера файла.
|
|
6451
|
-
|
|
6452
|
-
Работает с одиночным файлом или массивом (`File` либо файлоподобный дескриптор с
|
|
6453
|
-
`name`/`size`). Проверяется каждый файл; в ошибку попадает первый нарушивший.
|
|
6454
|
-
Пустые значения (`null`/`undefined`/`''`/`[]`) и элементы без числового `size`
|
|
6455
|
-
(например, дескриптор загруженного файла без размера) пропускаются
|
|
6456
|
-
(используйте {@link required} для обязательности).
|
|
6457
|
-
|
|
6458
|
-
**Signature:**
|
|
6459
|
-
```typescript
|
|
6460
|
-
export function maxFileSize<TForm = unknown, TField = unknown>(
|
|
6461
|
-
maxSize: number,
|
|
6462
|
-
options?: ValidateOptions
|
|
6463
|
-
): Validator<TForm, TField>
|
|
6464
|
-
```
|
|
6465
|
-
|
|
6466
|
-
**Parameters:**
|
|
6467
|
-
- `maxSize` — - Максимально допустимый размер файла в байтах (включительно)
|
|
6468
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6469
|
-
попадают `maxFileSize`, `fileName` и `actualSize`.
|
|
6470
|
-
|
|
6471
|
-
**Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
|
|
6472
|
-
|
|
6473
|
-
**Examples:**
|
|
6474
|
-
|
|
6475
|
-
Ограничение размера вложений
|
|
6476
|
-
```typescript
|
|
6477
|
-
import { maxFileSize } from '@reformer/core/validators';
|
|
6478
|
-
|
|
6479
|
-
// Внутри FieldConfig схемы формы:
|
|
6480
|
-
documents: {
|
|
6481
|
-
value: model.$.documents,
|
|
6482
|
-
component: FileUploadField,
|
|
6483
|
-
validators: [maxFileSize(5 * 1024 * 1024, { message: 'Файл больше 5 МБ' })],
|
|
6484
|
-
},
|
|
6485
|
-
```
|
|
6486
|
-
|
|
6487
|
-
_Source: src/form/validation/validators/max-file-size.ts_
|
|
6488
|
-
|
|
6489
|
-
### maxLength
|
|
6490
|
-
|
|
6491
|
-
**Kind:** `function`
|
|
6492
|
-
|
|
6493
|
-
Фабрика валидатора максимальной длины строки или массива.
|
|
6494
|
-
|
|
6495
|
-
Работает со строкой или массивом (проверяется `value.length`). Пустые значения
|
|
6496
|
-
(`null`/`undefined`/`''`) и значения без числового `length` пропускаются
|
|
6497
|
-
(используйте {@link required} для обязательности).
|
|
6498
|
-
|
|
6499
|
-
**Signature:**
|
|
6500
|
-
```typescript
|
|
6501
|
-
export function maxLength<TForm = unknown, TField = unknown>(
|
|
6502
|
-
maxLen: number,
|
|
6503
|
-
options?: ValidateOptions
|
|
6504
|
-
): Validator<TForm, TField>
|
|
6505
|
-
```
|
|
6506
|
-
|
|
6507
|
-
**Parameters:**
|
|
6508
|
-
- `maxLen` — - Максимально допустимая длина (включительно)
|
|
6509
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6510
|
-
попадают `maxLength` и `actualLength`.
|
|
6511
|
-
|
|
6512
|
-
**Returns:** Чистый валидатор {@link Validator} для строки или массива
|
|
6513
|
-
|
|
6514
|
-
**Examples:**
|
|
6515
|
-
|
|
6516
|
-
Максимальная длина строки
|
|
6517
|
-
```typescript
|
|
6518
|
-
import { maxLength } from '@reformer/core/validators';
|
|
6519
|
-
|
|
6520
|
-
// Внутри FieldConfig схемы формы:
|
|
6521
|
-
name: { value: model.$.name, component: Input, validators: [maxLength(50)] },
|
|
6522
|
-
bio: {
|
|
6523
|
-
value: model.$.bio,
|
|
6524
|
-
component: Textarea,
|
|
6525
|
-
validators: [maxLength(500, { message: 'Максимум 500 символов' })],
|
|
6526
|
-
},
|
|
6527
|
-
```
|
|
6528
|
-
|
|
6529
|
-
_Source: src/form/validation/validators/max-length.ts_
|
|
6530
|
-
|
|
6531
|
-
### maxTotalFileSize
|
|
6532
|
-
|
|
6533
|
-
**Kind:** `function`
|
|
6534
|
-
|
|
6535
|
-
Фабрика валидатора суммарного размера всех файлов.
|
|
6536
|
-
|
|
6537
|
-
Складывает `size` всех файлов значения (элементы без числового `size` в сумму
|
|
6538
|
-
не входят). Пустые значения (`null`/`undefined`/`''`/`[]`) пропускаются
|
|
6539
|
-
(используйте {@link required} для обязательности).
|
|
6540
|
-
|
|
6541
|
-
**Signature:**
|
|
6542
|
-
```typescript
|
|
6543
|
-
export function maxTotalFileSize<TForm = unknown, TField = unknown>(
|
|
6544
|
-
maxTotal: number,
|
|
6545
|
-
options?: ValidateOptions
|
|
6546
|
-
): Validator<TForm, TField>
|
|
6547
|
-
```
|
|
6548
|
-
|
|
6549
|
-
**Parameters:**
|
|
6550
|
-
- `maxTotal` — - Максимально допустимый суммарный размер в байтах (включительно)
|
|
6551
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6552
|
-
попадают `maxTotalFileSize` и `actualTotal`.
|
|
6553
|
-
|
|
6554
|
-
**Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
|
|
6555
|
-
|
|
6556
|
-
**Examples:**
|
|
6557
|
-
|
|
6558
|
-
Суммарно не более 20 МБ
|
|
6559
|
-
```typescript
|
|
6560
|
-
import { maxTotalFileSize } from '@reformer/core/validators';
|
|
6561
|
-
|
|
6562
|
-
// Внутри FieldConfig схемы формы:
|
|
6563
|
-
documents: {
|
|
6564
|
-
value: model.$.documents,
|
|
6565
|
-
component: FileUploadField,
|
|
6566
|
-
validators: [maxTotalFileSize(20 * 1024 * 1024, { message: 'Суммарно не более 20 МБ' })],
|
|
6567
|
-
},
|
|
6568
|
-
```
|
|
6569
|
-
|
|
6570
|
-
_Source: src/form/validation/validators/max-total-file-size.ts_
|
|
6571
|
-
|
|
6572
|
-
### min
|
|
6573
|
-
|
|
6574
|
-
**Kind:** `function`
|
|
6575
|
-
|
|
6576
|
-
Фабрика валидатора минимального числового значения.
|
|
6577
|
-
|
|
6578
|
-
Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
|
|
6579
|
-
|
|
6580
|
-
**Signature:**
|
|
6581
|
-
```typescript
|
|
6582
|
-
export function min<TForm = unknown, TField extends number | null | undefined = number>(
|
|
6583
|
-
minValue: number,
|
|
6584
|
-
options?: ValidateOptions
|
|
6585
|
-
): Validator<TForm, TField>
|
|
6586
|
-
```
|
|
6587
|
-
|
|
6588
|
-
**Parameters:**
|
|
6589
|
-
- `minValue` — - Минимально допустимое значение (включительно)
|
|
6590
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6591
|
-
попадают `min` и `actual`.
|
|
6592
|
-
|
|
6593
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
6594
|
-
|
|
6595
|
-
**Examples:**
|
|
6596
|
-
|
|
6597
|
-
Минимальное значение числового поля
|
|
6598
|
-
```typescript
|
|
6599
|
-
import { required, min } from '@reformer/core/validators';
|
|
6600
|
-
|
|
6601
|
-
// Внутри FieldConfig схемы формы:
|
|
6602
|
-
age: { value: model.$.age, component: Input, validators: [min(18)] },
|
|
6603
|
-
quantity: {
|
|
6604
|
-
value: model.$.quantity,
|
|
6605
|
-
component: Input,
|
|
6606
|
-
validators: [required(), min(1, { message: 'Минимум 1' })],
|
|
6607
|
-
},
|
|
6608
|
-
```
|
|
6609
|
-
|
|
6610
|
-
_Source: src/form/validation/validators/min.ts_
|
|
6611
|
-
|
|
6612
|
-
### minAge
|
|
6613
|
-
|
|
6614
|
-
**Kind:** `function`
|
|
6615
|
-
|
|
6616
|
-
Фабрика валидатора минимального возраста (по дате рождения).
|
|
6617
|
-
|
|
6618
|
-
Возраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные
|
|
6619
|
-
даты пропускаются (используйте {@link required} и {@link isDate}).
|
|
6620
|
-
|
|
6621
|
-
**Signature:**
|
|
6622
|
-
```typescript
|
|
6623
|
-
export function minAge<
|
|
6624
|
-
TForm = unknown,
|
|
6625
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
6626
|
-
>(minAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>
|
|
6627
|
-
```
|
|
6628
|
-
|
|
6629
|
-
**Parameters:**
|
|
6630
|
-
- `minAgeValue` — - Минимально допустимый возраст (в полных годах)
|
|
6631
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6632
|
-
попадают `minAge` и `currentAge`.
|
|
6633
|
-
|
|
6634
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)
|
|
6635
|
-
|
|
6636
|
-
**Examples:**
|
|
6637
|
-
|
|
6638
|
-
Минимальный возраст
|
|
6639
|
-
```typescript
|
|
6640
|
-
import { required, minAge } from '@reformer/core/validators';
|
|
6641
|
-
|
|
6642
|
-
// Внутри FieldConfig схемы формы:
|
|
6643
|
-
birthDate: {
|
|
6644
|
-
value: model.$.birthDate,
|
|
6645
|
-
component: DatePicker,
|
|
6646
|
-
validators: [required(), minAge(18, { message: 'Вам должно быть не менее 18 лет' })],
|
|
6647
|
-
},
|
|
6648
|
-
```
|
|
6649
|
-
|
|
6650
|
-
_Source: src/form/validation/validators/min-age.ts_
|
|
6651
|
-
|
|
6652
|
-
### minDate
|
|
6653
|
-
|
|
6654
|
-
**Kind:** `function`
|
|
6655
|
-
|
|
6656
|
-
Фабрика валидатора минимальной даты (включительно).
|
|
6657
|
-
|
|
6658
|
-
Сравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты
|
|
6659
|
-
пропускаются (используйте {@link required} и {@link isDate}).
|
|
6660
|
-
|
|
6661
|
-
**Signature:**
|
|
6662
|
-
```typescript
|
|
6663
|
-
export function minDate<
|
|
6664
|
-
TForm = unknown,
|
|
6665
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
6666
|
-
>(minDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>
|
|
6002
|
+
export function isFieldNode(value: unknown): value is FieldNode<FormValue>
|
|
6667
6003
|
```
|
|
6668
6004
|
|
|
6669
6005
|
**Parameters:**
|
|
6670
|
-
- `
|
|
6671
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6672
|
-
попадает `minDate`.
|
|
6006
|
+
- `value` — - Значение для проверки
|
|
6673
6007
|
|
|
6674
|
-
**Returns:**
|
|
6008
|
+
**Returns:** true если value является FieldNode
|
|
6675
6009
|
|
|
6676
6010
|
**Examples:**
|
|
6677
6011
|
|
|
6678
|
-
Минимальная дата
|
|
6679
6012
|
```typescript
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
//
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
component: DatePicker,
|
|
6686
|
-
validators: [required(), minDate(new Date(), { message: 'Дата не раньше сегодня' })],
|
|
6687
|
-
},
|
|
6013
|
+
if (isFieldNode(node)) {
|
|
6014
|
+
node.validators; // OK
|
|
6015
|
+
node.asyncValidators; // OK
|
|
6016
|
+
node.markAsTouched(); // OK
|
|
6017
|
+
}
|
|
6688
6018
|
```
|
|
6689
6019
|
|
|
6690
|
-
_Source: src/form/
|
|
6020
|
+
_Source: src/form/type-guards.ts_
|
|
6691
6021
|
|
|
6692
|
-
###
|
|
6022
|
+
### isFormNode
|
|
6693
6023
|
|
|
6694
6024
|
**Kind:** `function`
|
|
6695
6025
|
|
|
6696
|
-
|
|
6026
|
+
Проверить, является ли значение любым FormNode
|
|
6697
6027
|
|
|
6698
|
-
|
|
6699
|
-
(`null`/`undefined`/`''`/`[]`) пропускаются — «нужен хотя бы один файл» выражается
|
|
6700
|
-
связкой `required()` + `minFiles(n)`, как и у {@link minLength}.
|
|
6028
|
+
Проверяет базовые свойства, общие для всех типов узлов
|
|
6701
6029
|
|
|
6702
6030
|
**Signature:**
|
|
6703
6031
|
```typescript
|
|
6704
|
-
export function
|
|
6705
|
-
min: number,
|
|
6706
|
-
options?: ValidateOptions
|
|
6707
|
-
): Validator<TForm, TField>
|
|
6032
|
+
export function isFormNode(value: unknown): value is FormNode<FormValue>
|
|
6708
6033
|
```
|
|
6709
6034
|
|
|
6710
6035
|
**Parameters:**
|
|
6711
|
-
- `
|
|
6712
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6713
|
-
попадают `minFiles` и `actualCount`.
|
|
6036
|
+
- `value` — - Значение для проверки
|
|
6714
6037
|
|
|
6715
|
-
**Returns:**
|
|
6038
|
+
**Returns:** true если value является FormNode
|
|
6716
6039
|
|
|
6717
6040
|
**Examples:**
|
|
6718
6041
|
|
|
6719
|
-
Не менее двух документов
|
|
6720
6042
|
```typescript
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
value: model.$.documents,
|
|
6726
|
-
component: FileUploadField,
|
|
6727
|
-
validators: [required(), minFiles(2, { message: 'Приложите минимум 2 документа' })],
|
|
6728
|
-
},
|
|
6043
|
+
if (isFormNode(value)) {
|
|
6044
|
+
value.setValue(newValue);
|
|
6045
|
+
value.validate();
|
|
6046
|
+
}
|
|
6729
6047
|
```
|
|
6730
6048
|
|
|
6731
|
-
_Source: src/form/
|
|
6049
|
+
_Source: src/form/type-guards.ts_
|
|
6732
6050
|
|
|
6733
|
-
###
|
|
6051
|
+
### isGroupNode
|
|
6734
6052
|
|
|
6735
6053
|
**Kind:** `function`
|
|
6736
6054
|
|
|
6737
|
-
|
|
6055
|
+
Проверить, является ли значение GroupNode (объект с вложенными полями)
|
|
6738
6056
|
|
|
6739
|
-
|
|
6740
|
-
`
|
|
6741
|
-
Типовой сценарий — отсев пустых (0-байтовых) файлов: `minFileSize(1)`.
|
|
6742
|
-
Пустые значения (`null`/`undefined`/`''`/`[]`) и элементы без числового `size`
|
|
6743
|
-
пропускаются (используйте {@link required} для обязательности).
|
|
6057
|
+
GroupNode представляет объект с вложенными полями формы: имеет навигацию по полям
|
|
6058
|
+
(`getFieldByPath`/`fields`) и НЕ имеет array-методов (`items`/`push`/`removeAt`).
|
|
6744
6059
|
|
|
6745
6060
|
**Signature:**
|
|
6746
6061
|
```typescript
|
|
6747
|
-
export function
|
|
6748
|
-
minSize: number,
|
|
6749
|
-
options?: ValidateOptions
|
|
6750
|
-
): Validator<TForm, TField>
|
|
6062
|
+
export function isGroupNode(value: unknown): value is GroupNode<object>
|
|
6751
6063
|
```
|
|
6752
6064
|
|
|
6753
6065
|
**Parameters:**
|
|
6754
|
-
- `
|
|
6755
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6756
|
-
попадают `minFileSize`, `fileName` и `actualSize`.
|
|
6066
|
+
- `value` — - Значение для проверки
|
|
6757
6067
|
|
|
6758
|
-
**Returns:**
|
|
6068
|
+
**Returns:** true если value является GroupNode
|
|
6759
6069
|
|
|
6760
6070
|
**Examples:**
|
|
6761
6071
|
|
|
6762
|
-
Отсев пустых файлов
|
|
6763
6072
|
```typescript
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
documents: {
|
|
6768
|
-
value: model.$.documents,
|
|
6769
|
-
component: FileUploadField,
|
|
6770
|
-
validators: [minFileSize(1, { message: 'Файл пустой' })],
|
|
6771
|
-
},
|
|
6073
|
+
if (isGroupNode(node)) {
|
|
6074
|
+
node.getFieldByPath('user.email'); // OK
|
|
6075
|
+
}
|
|
6772
6076
|
```
|
|
6773
6077
|
|
|
6774
|
-
_Source: src/form/
|
|
6078
|
+
_Source: src/form/type-guards.ts_
|
|
6775
6079
|
|
|
6776
|
-
###
|
|
6080
|
+
### markDerived
|
|
6777
6081
|
|
|
6778
6082
|
**Kind:** `function`
|
|
6779
6083
|
|
|
6780
|
-
|
|
6084
|
+
Пометить сигнал производным (вычисляемым).
|
|
6085
|
+
|
|
6086
|
+
Вызывается операторами {@link computeFrom}/`compute` для их сигнала-цели. После этого
|
|
6087
|
+
bulk-сеттеры (`model.set`/`model.patch`, `patchValue`/`setValue`) пропускают это поле, чтобы
|
|
6088
|
+
значение из payload не затирало вычисляемое. Прикладной код напрямую обычно не вызывает.
|
|
6781
6089
|
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
(используйте {@link required} для обязательности).
|
|
6090
|
+
Идемпотентна на уровне флага: повторные вызовы наращивают счётчик ссылок, чтобы каждый оператор,
|
|
6091
|
+
пишущий в этот сигнал, был сбалансирован своим {@link unmarkDerived} при dispose.
|
|
6785
6092
|
|
|
6786
6093
|
**Signature:**
|
|
6787
6094
|
```typescript
|
|
6788
|
-
export function
|
|
6789
|
-
minLen: number,
|
|
6790
|
-
options?: ValidateOptions
|
|
6791
|
-
): Validator<TForm, TField>
|
|
6095
|
+
export function markDerived(signal: Signal<any>): void
|
|
6792
6096
|
```
|
|
6793
6097
|
|
|
6794
6098
|
**Parameters:**
|
|
6795
|
-
- `
|
|
6796
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
6797
|
-
попадают `minLength` и `actualLength`.
|
|
6798
|
-
|
|
6799
|
-
**Returns:** Чистый валидатор {@link Validator} для строки или массива
|
|
6099
|
+
- `signal` — - Сигнал значения из {@link FormModel}, которым владеет compute
|
|
6800
6100
|
|
|
6801
6101
|
**Examples:**
|
|
6802
6102
|
|
|
6803
|
-
Минимальная длина строки
|
|
6804
6103
|
```typescript
|
|
6805
|
-
import {
|
|
6104
|
+
import { markDerived } from '@reformer/core';
|
|
6806
6105
|
|
|
6807
|
-
//
|
|
6808
|
-
|
|
6809
|
-
password: {
|
|
6810
|
-
value: model.$.password,
|
|
6811
|
-
component: Input,
|
|
6812
|
-
validators: [required(), minLength(8, { message: 'Минимум 8 символов' })],
|
|
6813
|
-
},
|
|
6106
|
+
// Помечаем поле total как вычисляемое — bulk-set его не перезапишет
|
|
6107
|
+
markDerived(model.$.total);
|
|
6814
6108
|
```
|
|
6815
6109
|
|
|
6816
|
-
|
|
6110
|
+
**See also:**
|
|
6111
|
+
- {@link isDerived} - проверка пометки
|
|
6112
|
+
- {@link unmarkDerived} - снять пометку при dispose оператора
|
|
6113
|
+
|
|
6114
|
+
_Source: src/state/derived-registry.ts_
|
|
6817
6115
|
|
|
6818
6116
|
### ModelApi
|
|
6819
6117
|
|
|
@@ -7017,358 +6315,105 @@ _Source: src/state/types.ts_
|
|
|
7017
6315
|
- примитив → значение
|
|
7018
6316
|
|
|
7019
6317
|
**Signature:**
|
|
7020
|
-
```typescript
|
|
7021
|
-
export type ModelValue<V> =
|
|
7022
|
-
NonNullable<V> extends ReadonlyArray<infer U>
|
|
7023
|
-
? ModelArray<U>
|
|
7024
|
-
: NonNullable<V> extends Opaque
|
|
7025
|
-
? V
|
|
7026
|
-
: NonNullable<V> extends object
|
|
7027
|
-
? FormModel<NonNullable<V>>
|
|
7028
|
-
: V;
|
|
7029
|
-
```
|
|
7030
|
-
|
|
7031
|
-
_Source: src/state/types.ts_
|
|
7032
|
-
|
|
7033
|
-
### multipleOf
|
|
7034
|
-
|
|
7035
|
-
**Kind:** `function`
|
|
7036
|
-
|
|
7037
|
-
Фабрика валидатора, проверяющего что число кратно заданному.
|
|
7038
|
-
|
|
7039
|
-
Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
|
|
7040
|
-
|
|
7041
|
-
**Signature:**
|
|
7042
|
-
```typescript
|
|
7043
|
-
export function multipleOf<TForm = unknown, TField extends number | null | undefined = number>(
|
|
7044
|
-
divisor: number,
|
|
7045
|
-
options?: ValidateOptions
|
|
7046
|
-
): Validator<TForm, TField>
|
|
7047
|
-
```
|
|
7048
|
-
|
|
7049
|
-
**Parameters:**
|
|
7050
|
-
- `divisor` — - Делитель: значение должно быть кратно ему
|
|
7051
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
7052
|
-
попадает `multipleOf` (делитель).
|
|
7053
|
-
|
|
7054
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
7055
|
-
|
|
7056
|
-
**Examples:**
|
|
7057
|
-
|
|
7058
|
-
Проверка кратности
|
|
7059
|
-
```typescript
|
|
7060
|
-
import { multipleOf } from '@reformer/core/validators';
|
|
7061
|
-
|
|
7062
|
-
// Внутри FieldConfig схемы формы:
|
|
7063
|
-
rating: {
|
|
7064
|
-
value: model.$.rating,
|
|
7065
|
-
component: Input,
|
|
7066
|
-
validators: [multipleOf(0.5, { message: 'Только шаг 0.5' })],
|
|
7067
|
-
},
|
|
7068
|
-
```
|
|
7069
|
-
|
|
7070
|
-
_Source: src/form/validation/validators/multiple-of.ts_
|
|
7071
|
-
|
|
7072
|
-
### NodeFactory
|
|
7073
|
-
|
|
7074
|
-
**Kind:** `class`
|
|
7075
|
-
|
|
7076
|
-
Фабрика для создания узлов формы.
|
|
7077
|
-
|
|
7078
|
-
Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
|
|
7079
|
-
Используется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.
|
|
7080
|
-
|
|
7081
|
-
**Signature:**
|
|
7082
|
-
```typescript
|
|
7083
|
-
export class NodeFactory {
|
|
7084
|
-
/**
|
|
7085
|
-
* Создает узел формы на основе конфигурации
|
|
7086
|
-
*
|
|
7087
|
-
* ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую
|
|
7088
|
-
*
|
|
7089
|
-
* Автоматически определяет тип узла:
|
|
7090
|
-
* - FieldNode: имеет value и component
|
|
7091
|
-
* - ArrayNode: массив [schema, ...items] или { schema, initialItems }
|
|
7092
|
-
* - GroupNode: объект без value, component, schema
|
|
7093
|
-
*
|
|
7094
|
-
* @param config Конфигурация узла
|
|
7095
|
-
* @returns Экземпляр FieldNode, GroupNode или ArrayNode
|
|
7096
|
-
* @throws Error если конфиг не соответствует ни одному типу
|
|
7097
|
-
*
|
|
7098
|
-
* @example
|
|
7099
|
-
* ```typescript
|
|
7100
|
-
* const factory = new NodeFactory();
|
|
7101
|
-
*
|
|
7102
|
-
* // FieldNode
|
|
7103
|
-
* const field = factory.createNode({
|
|
7104
|
-
* value: 'test@mail.com',
|
|
7105
|
-
* component: Input,
|
|
7106
|
-
* validators: [required, email]
|
|
7107
|
-
* });
|
|
7108
|
-
*
|
|
7109
|
-
* // GroupNode
|
|
7110
|
-
* const group = factory.createNode({
|
|
7111
|
-
* email: { value: '', component: Input },
|
|
7112
|
-
* password: { value: '', component: Input }
|
|
7113
|
-
* });
|
|
7114
|
-
*
|
|
7115
|
-
* // ArrayNode (объект)
|
|
7116
|
-
* const array = factory.createNode({
|
|
7117
|
-
* schema: { title: { value: '', component: Input } },
|
|
7118
|
-
* initialItems: [{ title: 'Item 1' }]
|
|
7119
|
-
* });
|
|
7120
|
-
*
|
|
7121
|
-
* // ArrayNode (массив) - новый формат
|
|
7122
|
-
* const array2 = factory.createNode([
|
|
7123
|
-
* { title: { value: '', component: Input } }, // schema
|
|
7124
|
-
* { title: 'Item 1' }, // initial item 1
|
|
7125
|
-
* { title: 'Item 2' } // initial item 2
|
|
7126
|
-
* ]);
|
|
7127
|
-
* ```
|
|
7128
|
-
*/ /* … */ }
|
|
7129
|
-
```
|
|
7130
|
-
|
|
7131
|
-
**Examples:**
|
|
7132
|
-
|
|
7133
|
-
```typescript
|
|
7134
|
-
import { NodeFactory } from '@reformer/core';
|
|
7135
|
-
|
|
7136
|
-
const factory = new NodeFactory();
|
|
7137
|
-
const node = factory.createNode({ value: '', component: Input }); // → FieldNode<string>
|
|
7138
|
-
```
|
|
7139
|
-
|
|
7140
|
-
_Source: src/form/factories/node-factory.ts_
|
|
7141
|
-
|
|
7142
|
-
### nonNegative
|
|
7143
|
-
|
|
7144
|
-
**Kind:** `function`
|
|
7145
|
-
|
|
7146
|
-
Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).
|
|
7147
|
-
|
|
7148
|
-
Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
|
|
7149
|
-
|
|
7150
|
-
**Signature:**
|
|
7151
|
-
```typescript
|
|
7152
|
-
export function nonNegative<TForm = unknown, TField extends number | null | undefined = number>(
|
|
7153
|
-
options?: ValidateOptions
|
|
7154
|
-
): Validator<TForm, TField>
|
|
7155
|
-
```
|
|
7156
|
-
|
|
7157
|
-
**Parameters:**
|
|
7158
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
7159
|
-
|
|
7160
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
7161
|
-
|
|
7162
|
-
**Examples:**
|
|
7163
|
-
|
|
7164
|
-
Проверка неотрицательности
|
|
7165
|
-
```typescript
|
|
7166
|
-
import { nonNegative } from '@reformer/core/validators';
|
|
7167
|
-
|
|
7168
|
-
// Внутри FieldConfig схемы формы:
|
|
7169
|
-
balance: {
|
|
7170
|
-
value: model.$.balance,
|
|
7171
|
-
component: Input,
|
|
7172
|
-
validators: [nonNegative({ message: 'Баланс не может быть отрицательным' })],
|
|
7173
|
-
},
|
|
7174
|
-
```
|
|
7175
|
-
|
|
7176
|
-
_Source: src/form/validation/validators/non-negative.ts_
|
|
7177
|
-
|
|
7178
|
-
### nonZero
|
|
7179
|
-
|
|
7180
|
-
**Kind:** `function`
|
|
7181
|
-
|
|
7182
|
-
Фабрика валидатора, проверяющего что число не равно нулю.
|
|
7183
|
-
|
|
7184
|
-
Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
|
|
7185
|
-
|
|
7186
|
-
**Signature:**
|
|
7187
|
-
```typescript
|
|
7188
|
-
export function nonZero<TForm = unknown, TField extends number | null | undefined = number>(
|
|
7189
|
-
options?: ValidateOptions
|
|
7190
|
-
): Validator<TForm, TField>
|
|
7191
|
-
```
|
|
7192
|
-
|
|
7193
|
-
**Parameters:**
|
|
7194
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
7195
|
-
|
|
7196
|
-
**Returns:** Чистый валидатор {@link Validator} для числового поля
|
|
7197
|
-
|
|
7198
|
-
**Examples:**
|
|
7199
|
-
|
|
7200
|
-
Проверка «не ноль»
|
|
7201
|
-
```typescript
|
|
7202
|
-
import { nonZero } from '@reformer/core/validators';
|
|
7203
|
-
|
|
7204
|
-
// Внутри FieldConfig схемы формы:
|
|
7205
|
-
divisor: {
|
|
7206
|
-
value: model.$.divisor,
|
|
7207
|
-
component: Input,
|
|
7208
|
-
validators: [nonZero({ message: 'Не может быть нулём' })],
|
|
7209
|
-
},
|
|
7210
|
-
```
|
|
7211
|
-
|
|
7212
|
-
_Source: src/form/validation/validators/non-zero.ts_
|
|
7213
|
-
|
|
7214
|
-
### pastDate
|
|
7215
|
-
|
|
7216
|
-
**Kind:** `function`
|
|
7217
|
-
|
|
7218
|
-
Фабрика валидатора, проверяющего что дата не в будущем.
|
|
7219
|
-
|
|
7220
|
-
Дата не должна быть позже сегодняшнего дня (сравнение по нормализованным датам).
|
|
7221
|
-
Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
|
|
7222
|
-
|
|
7223
|
-
**Signature:**
|
|
7224
|
-
```typescript
|
|
7225
|
-
export function pastDate<
|
|
7226
|
-
TForm = unknown,
|
|
7227
|
-
TField extends string | Date | null | undefined = string | Date,
|
|
7228
|
-
>(options?: ValidateOptions): Validator<TForm, TField>
|
|
7229
|
-
```
|
|
7230
|
-
|
|
7231
|
-
**Parameters:**
|
|
7232
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
7233
|
-
|
|
7234
|
-
**Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
|
|
7235
|
-
|
|
7236
|
-
**Examples:**
|
|
7237
|
-
|
|
7238
|
-
Дата не в будущем
|
|
7239
|
-
```typescript
|
|
7240
|
-
import { required, pastDate } from '@reformer/core/validators';
|
|
7241
|
-
|
|
7242
|
-
// Внутри FieldConfig схемы формы:
|
|
7243
|
-
birthDate: {
|
|
7244
|
-
value: model.$.birthDate,
|
|
7245
|
-
component: DatePicker,
|
|
7246
|
-
validators: [required(), pastDate({ message: 'Дата рождения не может быть в будущем' })],
|
|
7247
|
-
},
|
|
7248
|
-
```
|
|
7249
|
-
|
|
7250
|
-
_Source: src/form/validation/validators/past-date.ts_
|
|
7251
|
-
|
|
7252
|
-
### PathAwareSignal
|
|
7253
|
-
|
|
7254
|
-
**Kind:** `type`
|
|
7255
|
-
|
|
7256
|
-
Сигнал, который знает свой путь в модели (`'personalData.lastName'`).
|
|
7257
|
-
Используется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.
|
|
7258
|
-
|
|
7259
|
-
**Signature:**
|
|
7260
|
-
```typescript
|
|
7261
|
-
export type PathAwareSignal<T> = Signal<T> & {
|
|
7262
|
-
/** Путь поля в модели (dot-нотация). На элементах массива включает индекс. */
|
|
7263
|
-
readonly __path: string;
|
|
7264
|
-
};
|
|
7265
|
-
```
|
|
7266
|
-
|
|
7267
|
-
_Source: src/state/types.ts_
|
|
7268
|
-
|
|
7269
|
-
### pattern
|
|
7270
|
-
|
|
7271
|
-
**Kind:** `function`
|
|
7272
|
-
|
|
7273
|
-
Фабрика валидатора регулярного выражения.
|
|
7274
|
-
|
|
7275
|
-
Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
|
|
7276
|
-
для обязательности).
|
|
7277
|
-
|
|
7278
|
-
**Signature:**
|
|
7279
|
-
```typescript
|
|
7280
|
-
export function pattern<TForm = unknown, TField extends string | null | undefined = string>(
|
|
7281
|
-
regex: RegExp,
|
|
7282
|
-
options?: ValidateOptions
|
|
7283
|
-
): Validator<TForm, TField>
|
|
7284
|
-
```
|
|
7285
|
-
|
|
7286
|
-
**Parameters:**
|
|
7287
|
-
- `regex` — - Регулярное выражение для проверки значения
|
|
7288
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
|
|
7289
|
-
попадает `pattern` (строка-источник regex).
|
|
7290
|
-
|
|
7291
|
-
**Returns:** Чистый валидатор {@link Validator} для строкового поля
|
|
7292
|
-
|
|
7293
|
-
**Examples:**
|
|
7294
|
-
|
|
7295
|
-
Проверка по регулярному выражению
|
|
7296
|
-
```typescript
|
|
7297
|
-
import { required, pattern } from '@reformer/core/validators';
|
|
7298
|
-
|
|
7299
|
-
// Внутри FieldConfig схемы формы:
|
|
7300
|
-
name: {
|
|
7301
|
-
value: model.$.name,
|
|
7302
|
-
component: Input,
|
|
7303
|
-
validators: [pattern(/^[a-zA-Zа-яА-Я]+$/, { message: 'Только буквы' })],
|
|
7304
|
-
},
|
|
7305
|
-
phone: {
|
|
7306
|
-
value: model.$.phone,
|
|
7307
|
-
component: InputMask,
|
|
7308
|
-
validators: [
|
|
7309
|
-
required(),
|
|
7310
|
-
pattern(/^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/, { message: 'Формат +7 (999) 123-45-67' }),
|
|
7311
|
-
],
|
|
7312
|
-
},
|
|
6318
|
+
```typescript
|
|
6319
|
+
export type ModelValue<V> =
|
|
6320
|
+
NonNullable<V> extends ReadonlyArray<infer U>
|
|
6321
|
+
? ModelArray<U>
|
|
6322
|
+
: NonNullable<V> extends Opaque
|
|
6323
|
+
? V
|
|
6324
|
+
: NonNullable<V> extends object
|
|
6325
|
+
? FormModel<NonNullable<V>>
|
|
6326
|
+
: V;
|
|
7313
6327
|
```
|
|
7314
6328
|
|
|
7315
|
-
_Source: src/
|
|
6329
|
+
_Source: src/state/types.ts_
|
|
7316
6330
|
|
|
7317
|
-
###
|
|
6331
|
+
### NodeFactory
|
|
7318
6332
|
|
|
7319
|
-
**Kind:** `
|
|
6333
|
+
**Kind:** `class`
|
|
7320
6334
|
|
|
7321
|
-
Фабрика
|
|
6335
|
+
Фабрика для создания узлов формы.
|
|
7322
6336
|
|
|
7323
|
-
|
|
7324
|
-
|
|
6337
|
+
Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
|
|
6338
|
+
Используется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.
|
|
7325
6339
|
|
|
7326
6340
|
**Signature:**
|
|
7327
6341
|
```typescript
|
|
7328
|
-
export
|
|
7329
|
-
|
|
7330
|
-
|
|
6342
|
+
export class NodeFactory {
|
|
6343
|
+
/**
|
|
6344
|
+
* Создает узел формы на основе конфигурации
|
|
6345
|
+
*
|
|
6346
|
+
* ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую
|
|
6347
|
+
*
|
|
6348
|
+
* Автоматически определяет тип узла:
|
|
6349
|
+
* - FieldNode: имеет value и component
|
|
6350
|
+
* - ArrayNode: массив [schema, ...items] или { schema, initialItems }
|
|
6351
|
+
* - GroupNode: объект без value, component, schema
|
|
6352
|
+
*
|
|
6353
|
+
* @param config Конфигурация узла
|
|
6354
|
+
* @returns Экземпляр FieldNode, GroupNode или ArrayNode
|
|
6355
|
+
* @throws Error если конфиг не соответствует ни одному типу
|
|
6356
|
+
*
|
|
6357
|
+
* @example
|
|
6358
|
+
* ```typescript
|
|
6359
|
+
* const factory = new NodeFactory();
|
|
6360
|
+
*
|
|
6361
|
+
* // FieldNode
|
|
6362
|
+
* const field = factory.createNode({
|
|
6363
|
+
* value: 'test@mail.com',
|
|
6364
|
+
* component: Input,
|
|
6365
|
+
* validators: [required, email]
|
|
6366
|
+
* });
|
|
6367
|
+
*
|
|
6368
|
+
* // GroupNode
|
|
6369
|
+
* const group = factory.createNode({
|
|
6370
|
+
* email: { value: '', component: Input },
|
|
6371
|
+
* password: { value: '', component: Input }
|
|
6372
|
+
* });
|
|
6373
|
+
*
|
|
6374
|
+
* // ArrayNode (объект)
|
|
6375
|
+
* const array = factory.createNode({
|
|
6376
|
+
* schema: { title: { value: '', component: Input } },
|
|
6377
|
+
* initialItems: [{ title: 'Item 1' }]
|
|
6378
|
+
* });
|
|
6379
|
+
*
|
|
6380
|
+
* // ArrayNode (массив) - новый формат
|
|
6381
|
+
* const array2 = factory.createNode([
|
|
6382
|
+
* { title: { value: '', component: Input } }, // schema
|
|
6383
|
+
* { title: 'Item 1' }, // initial item 1
|
|
6384
|
+
* { title: 'Item 2' } // initial item 2
|
|
6385
|
+
* ]);
|
|
6386
|
+
* ```
|
|
6387
|
+
*/ /* … */ }
|
|
7331
6388
|
```
|
|
7332
6389
|
|
|
7333
|
-
**Parameters:**
|
|
7334
|
-
- `options` — - Опции валидатора {@link PhoneValidatorOptions}. В `params` ошибки
|
|
7335
|
-
автоматически попадает выбранный `format`.
|
|
7336
|
-
|
|
7337
|
-
**Returns:** Чистый валидатор {@link Validator} для строкового поля
|
|
7338
|
-
|
|
7339
6390
|
**Examples:**
|
|
7340
6391
|
|
|
7341
|
-
Проверка номера телефона
|
|
7342
6392
|
```typescript
|
|
7343
|
-
import {
|
|
6393
|
+
import { NodeFactory } from '@reformer/core';
|
|
7344
6394
|
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
value: model.$.phone,
|
|
7348
|
-
component: Input,
|
|
7349
|
-
validators: [required(), phone({ format: 'ru' })],
|
|
7350
|
-
},
|
|
6395
|
+
const factory = new NodeFactory();
|
|
6396
|
+
const node = factory.createNode({ value: '', component: Input }); // → FieldNode<string>
|
|
7351
6397
|
```
|
|
7352
6398
|
|
|
7353
|
-
_Source: src/form/
|
|
6399
|
+
_Source: src/form/factories/node-factory.ts_
|
|
7354
6400
|
|
|
7355
|
-
###
|
|
6401
|
+
### PathAwareSignal
|
|
7356
6402
|
|
|
7357
6403
|
**Kind:** `type`
|
|
7358
6404
|
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
- `international` — международный формат E.164 (`+?[1-9]\d{1,14}`);
|
|
7362
|
-
- `ru` — российские номера (`+7`/`7`/`8`, коды `4`/`8`/`9`, с разделителями);
|
|
7363
|
-
- `us` — североамериканские номера (NANP);
|
|
7364
|
-
- `any` — свободный формат: цифры, скобки и разделители (по умолчанию).
|
|
6405
|
+
Сигнал, который знает свой путь в модели (`'personalData.lastName'`).
|
|
6406
|
+
Используется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.
|
|
7365
6407
|
|
|
7366
6408
|
**Signature:**
|
|
7367
6409
|
```typescript
|
|
7368
|
-
export type
|
|
6410
|
+
export type PathAwareSignal<T> = Signal<T> & {
|
|
6411
|
+
/** Путь поля в модели (dot-нотация). На элементах массива включает индекс. */
|
|
6412
|
+
readonly __path: string;
|
|
6413
|
+
};
|
|
7369
6414
|
```
|
|
7370
6415
|
|
|
7371
|
-
_Source: src/
|
|
6416
|
+
_Source: src/state/types.ts_
|
|
7372
6417
|
|
|
7373
6418
|
### registerSignalNode
|
|
7374
6419
|
|
|
@@ -7404,52 +6449,6 @@ if (sig && node) registerSignalNode(sig, node);
|
|
|
7404
6449
|
|
|
7405
6450
|
_Source: src/form/signal-node-registry.ts_
|
|
7406
6451
|
|
|
7407
|
-
### required
|
|
7408
|
-
|
|
7409
|
-
**Kind:** `function`
|
|
7410
|
-
|
|
7411
|
-
Фабрика валидатора обязательного поля.
|
|
7412
|
-
|
|
7413
|
-
Возвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.
|
|
7414
|
-
|
|
7415
|
-
Пустыми считаются: `null`, `undefined`, `''` (пустая строка), `[]` (пустой массив —
|
|
7416
|
-
обязательный multi-select / FormArray без выбранных элементов).
|
|
7417
|
-
Для boolean полей требуется значение `true`.
|
|
7418
|
-
|
|
7419
|
-
**Signature:**
|
|
7420
|
-
```typescript
|
|
7421
|
-
export function required<TForm = unknown, TField = unknown>(
|
|
7422
|
-
options?: ValidateOptions
|
|
7423
|
-
): Validator<TForm, TField>
|
|
7424
|
-
```
|
|
7425
|
-
|
|
7426
|
-
**Parameters:**
|
|
7427
|
-
- `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
|
|
7428
|
-
|
|
7429
|
-
**Returns:** Чистый валидатор {@link Validator} для поля схемы
|
|
7430
|
-
|
|
7431
|
-
**Examples:**
|
|
7432
|
-
|
|
7433
|
-
Обязательные поля в схеме формы
|
|
7434
|
-
```typescript
|
|
7435
|
-
import { required } from '@reformer/core/validators';
|
|
7436
|
-
|
|
7437
|
-
// Внутри FieldConfig схемы формы:
|
|
7438
|
-
email: { value: model.$.email, component: Input, validators: [required()] },
|
|
7439
|
-
phone: {
|
|
7440
|
-
value: model.$.phone,
|
|
7441
|
-
component: Input,
|
|
7442
|
-
validators: [required({ message: 'Укажите номер телефона' })],
|
|
7443
|
-
},
|
|
7444
|
-
agreeToTerms: {
|
|
7445
|
-
value: model.$.agreeToTerms,
|
|
7446
|
-
component: Checkbox,
|
|
7447
|
-
validators: [required({ message: 'Необходимо принять условия' })],
|
|
7448
|
-
},
|
|
7449
|
-
```
|
|
7450
|
-
|
|
7451
|
-
_Source: src/form/validation/validators/required.ts_
|
|
7452
|
-
|
|
7453
6452
|
### resetWhen
|
|
7454
6453
|
|
|
7455
6454
|
**Kind:** `function`
|
|
@@ -7473,19 +6472,6 @@ resetWhen(model.$.cardNumber, () => model.paymentType !== 'card', { resetValue:
|
|
|
7473
6472
|
|
|
7474
6473
|
_Source: src/state/behaviors-value.ts_
|
|
7475
6474
|
|
|
7476
|
-
### ResourceLoadResult
|
|
7477
|
-
|
|
7478
|
-
**Kind:** `type`
|
|
7479
|
-
|
|
7480
|
-
Тип для результатов загрузки ресурсов
|
|
7481
|
-
|
|
7482
|
-
**Signature:**
|
|
7483
|
-
```typescript
|
|
7484
|
-
export type ResourceLoadResult = unknown;
|
|
7485
|
-
```
|
|
7486
|
-
|
|
7487
|
-
_Source: src/form/types/index.ts_
|
|
7488
|
-
|
|
7489
6475
|
### revalidateWhen
|
|
7490
6476
|
|
|
7491
6477
|
**Kind:** `function`
|
|
@@ -7643,25 +6629,6 @@ export interface SchemaArrayControl {
|
|
|
7643
6629
|
|
|
7644
6630
|
_Source: src/form/types/schema-node.ts_
|
|
7645
6631
|
|
|
7646
|
-
### SchemaValidator
|
|
7647
|
-
|
|
7648
|
-
**Kind:** `type`
|
|
7649
|
-
|
|
7650
|
-
Валидатор поля схемы (legacy). Дерево-движок, вызывавший `validators` узла как
|
|
7651
|
-
`(value, scope, root)`, удалён — живые правила это `Rule<T>` в `validate(sig, [...])`
|
|
7652
|
-
(`@reformer/core/validation`). Тип остаётся широким по параметрам для совместимости
|
|
7653
|
-
узлов, всё ещё несущих `validators` (гетерогенные контракты `ValidatorFn`/`Validator`).
|
|
7654
|
-
|
|
7655
|
-
**Signature:**
|
|
7656
|
-
```typescript
|
|
7657
|
-
export type SchemaValidator = (
|
|
7658
|
-
value: any,
|
|
7659
|
-
...rest: any[]
|
|
7660
|
-
) => ValidationError | null | Promise<ValidationError | null>;
|
|
7661
|
-
```
|
|
7662
|
-
|
|
7663
|
-
_Source: src/form/types/schema-node.ts_
|
|
7664
|
-
|
|
7665
6632
|
### SetValueOptions
|
|
7666
6633
|
|
|
7667
6634
|
**Kind:** `interface`
|
|
@@ -7673,32 +6640,13 @@ _Source: src/form/types/schema-node.ts_
|
|
|
7673
6640
|
export interface SetValueOptions {
|
|
7674
6641
|
/** Не вызывать событие изменения (не триггерить валидацию) */
|
|
7675
6642
|
emitEvent?: boolean;
|
|
7676
|
-
|
|
7677
|
-
|
|
6643
|
+
// onlySelf удалён в 7.0: опция объявлялась, но не была реализована ни одной из четырёх
|
|
6644
|
+
// реализаций setValue — передача значения ни на что не влияла.
|
|
7678
6645
|
}
|
|
7679
6646
|
```
|
|
7680
6647
|
|
|
7681
6648
|
_Source: src/form/nodes/form-node.ts_
|
|
7682
6649
|
|
|
7683
|
-
### StatusEvent
|
|
7684
|
-
|
|
7685
|
-
**Kind:** `type`
|
|
7686
|
-
|
|
7687
|
-
События для State Machine
|
|
7688
|
-
|
|
7689
|
-
**Signature:**
|
|
7690
|
-
```typescript
|
|
7691
|
-
export type StatusEvent =
|
|
7692
|
-
| { type: 'START_VALIDATION' }
|
|
7693
|
-
| { type: 'VALIDATION_SUCCESS' }
|
|
7694
|
-
| { type: 'VALIDATION_FAILURE' }
|
|
7695
|
-
| { type: 'DISABLE' }
|
|
7696
|
-
| { type: 'ENABLE'; hasErrors?: boolean }
|
|
7697
|
-
| { type: 'SET_ERRORS'; hasErrors: boolean };
|
|
7698
|
-
```
|
|
7699
|
-
|
|
7700
|
-
_Source: src/form/status-machine.ts_
|
|
7701
|
-
|
|
7702
6650
|
### SubmitOptions
|
|
7703
6651
|
|
|
7704
6652
|
**Kind:** `interface`
|
|
@@ -7825,27 +6773,6 @@ syncFields(model.$.field1, model.$.field2);
|
|
|
7825
6773
|
|
|
7826
6774
|
_Source: src/state/behaviors-value.ts_
|
|
7827
6775
|
|
|
7828
|
-
### toFileArray
|
|
7829
|
-
|
|
7830
|
-
**Kind:** `function`
|
|
7831
|
-
|
|
7832
|
-
Нормализует значение file-поля в массив файлоподобных элементов.
|
|
7833
|
-
|
|
7834
|
-
Одиночный {@link FileLike} оборачивается в массив; из массива отбираются только
|
|
7835
|
-
файлоподобные элементы. Для прочих значений — `null` (валидатор пропускает).
|
|
7836
|
-
|
|
7837
|
-
**Signature:**
|
|
7838
|
-
```typescript
|
|
7839
|
-
export function toFileArray(value: unknown): FileLike[] | null
|
|
7840
|
-
```
|
|
7841
|
-
|
|
7842
|
-
**Parameters:**
|
|
7843
|
-
- `value` — - Значение поля (`FileLike`, `FileLike[]` или что-то ещё)
|
|
7844
|
-
|
|
7845
|
-
**Returns:** Массив файлоподобных элементов или `null`
|
|
7846
|
-
|
|
7847
|
-
_Source: src/form/validation/validators/file-utils.ts_
|
|
7848
|
-
|
|
7849
6776
|
### transformValue
|
|
7850
6777
|
|
|
7851
6778
|
**Kind:** `function`
|
|
@@ -7869,61 +6796,6 @@ transformValue(model.$.promoCode, (v) => (v ?? '').toUpperCase());
|
|
|
7869
6796
|
|
|
7870
6797
|
_Source: src/state/behaviors-value.ts_
|
|
7871
6798
|
|
|
7872
|
-
### uniqueId
|
|
7873
|
-
|
|
7874
|
-
**Kind:** `function`
|
|
7875
|
-
|
|
7876
|
-
Генерирует уникальный идентификатор с указанным префиксом.
|
|
7877
|
-
|
|
7878
|
-
**Signature:**
|
|
7879
|
-
```typescript
|
|
7880
|
-
export function uniqueId(prefix: SubscriptionKeyType): string
|
|
7881
|
-
```
|
|
7882
|
-
|
|
7883
|
-
**Parameters:**
|
|
7884
|
-
- `prefix` — - Префикс для идентификатора (используйте {@link SubscriptionKey}).
|
|
7885
|
-
|
|
7886
|
-
**Returns:** Уникальный идентификатор в формате `${prefix}-${counter}`.
|
|
7887
|
-
|
|
7888
|
-
**Examples:**
|
|
7889
|
-
|
|
7890
|
-
```typescript
|
|
7891
|
-
import { uniqueId, SubscriptionKey } from '@reformer/core';
|
|
7892
|
-
|
|
7893
|
-
uniqueId(SubscriptionKey.WatchField); // → 'watchField-1'
|
|
7894
|
-
uniqueId(SubscriptionKey.WatchField); // → 'watchField-2'
|
|
7895
|
-
```
|
|
7896
|
-
|
|
7897
|
-
_Source: src/form/unique-id.ts_
|
|
7898
|
-
|
|
7899
|
-
### UnknownCallback
|
|
7900
|
-
|
|
7901
|
-
**Kind:** `type`
|
|
7902
|
-
|
|
7903
|
-
Тип для коллбэков и обработчиков событий
|
|
7904
|
-
Используется вместо (...args: any[]) => any
|
|
7905
|
-
|
|
7906
|
-
**Signature:**
|
|
7907
|
-
```typescript
|
|
7908
|
-
export type UnknownCallback = (...args: unknown[]) => unknown;
|
|
7909
|
-
```
|
|
7910
|
-
|
|
7911
|
-
_Source: src/form/types/index.ts_
|
|
7912
|
-
|
|
7913
|
-
### UnknownFormValue
|
|
7914
|
-
|
|
7915
|
-
**Kind:** `type`
|
|
7916
|
-
|
|
7917
|
-
Type-safe alternative to 'any' for unknown form values
|
|
7918
|
-
Requires explicit type checking before use
|
|
7919
|
-
|
|
7920
|
-
**Signature:**
|
|
7921
|
-
```typescript
|
|
7922
|
-
export type UnknownFormValue = unknown;
|
|
7923
|
-
```
|
|
7924
|
-
|
|
7925
|
-
_Source: src/form/types/contracts.ts_
|
|
7926
|
-
|
|
7927
6799
|
### UnknownRecord
|
|
7928
6800
|
|
|
7929
6801
|
**Kind:** `type`
|
|
@@ -7974,50 +6846,6 @@ onDispose(() => unmarkDerived(model.$.total)); // при снятии compute с
|
|
|
7974
6846
|
|
|
7975
6847
|
_Source: src/state/derived-registry.ts_
|
|
7976
6848
|
|
|
7977
|
-
### url
|
|
7978
|
-
|
|
7979
|
-
**Kind:** `function`
|
|
7980
|
-
|
|
7981
|
-
Фабрика валидатора URL.
|
|
7982
|
-
|
|
7983
|
-
Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
|
|
7984
|
-
для обязательности). При `requireProtocol` протокол обязателен; `allowedProtocols`
|
|
7985
|
-
дополнительно ограничивает набор допустимых протоколов.
|
|
7986
|
-
|
|
7987
|
-
**Signature:**
|
|
7988
|
-
```typescript
|
|
7989
|
-
export function url<TForm = unknown, TField extends string | null | undefined = string>(
|
|
7990
|
-
options?: UrlValidatorOptions
|
|
7991
|
-
): Validator<TForm, TField>
|
|
7992
|
-
```
|
|
7993
|
-
|
|
7994
|
-
**Parameters:**
|
|
7995
|
-
- `options` — - Опции валидатора {@link UrlValidatorOptions}
|
|
7996
|
-
|
|
7997
|
-
**Returns:** Чистый валидатор {@link Validator} для строкового поля
|
|
7998
|
-
|
|
7999
|
-
**Examples:**
|
|
8000
|
-
|
|
8001
|
-
Проверка URL
|
|
8002
|
-
```typescript
|
|
8003
|
-
import { required, url } from '@reformer/core/validators';
|
|
8004
|
-
|
|
8005
|
-
// Внутри FieldConfig схемы формы:
|
|
8006
|
-
website: {
|
|
8007
|
-
value: model.$.website,
|
|
8008
|
-
component: Input,
|
|
8009
|
-
validators: [required(), url({ message: 'Введите корректный URL' })],
|
|
8010
|
-
},
|
|
8011
|
-
// Требовать протокол и ограничить схему только https:
|
|
8012
|
-
homepage: {
|
|
8013
|
-
value: model.$.homepage,
|
|
8014
|
-
component: Input,
|
|
8015
|
-
validators: [url({ requireProtocol: true, allowedProtocols: ['https'] })],
|
|
8016
|
-
},
|
|
8017
|
-
```
|
|
8018
|
-
|
|
8019
|
-
_Source: src/form/validation/validators/url.ts_
|
|
8020
|
-
|
|
8021
6849
|
### useArrayLength
|
|
8022
6850
|
|
|
8023
6851
|
**Kind:** `function`
|
|
@@ -8166,7 +6994,7 @@ onChange={e => control.setValue(e.target.checked)}
|
|
|
8166
6994
|
}
|
|
8167
6995
|
|
|
8168
6996
|
// Использование
|
|
8169
|
-
control.
|
|
6997
|
+
control.updateComponentProps({
|
|
8170
6998
|
label: 'Accept terms and conditions',
|
|
8171
6999
|
hint: 'Required to continue'
|
|
8172
7000
|
});
|
|
@@ -8222,7 +7050,7 @@ control.push({ street: '', city: '' });
|
|
|
8222
7050
|
};
|
|
8223
7051
|
|
|
8224
7052
|
const handleRemove = (index: number) => {
|
|
8225
|
-
control.
|
|
7053
|
+
control.removeAt(index);
|
|
8226
7054
|
};
|
|
8227
7055
|
|
|
8228
7056
|
return (
|
|
@@ -8471,23 +7299,80 @@ return (
|
|
|
8471
7299
|
|
|
8472
7300
|
_Source: src/form/hooks/useFormControlValue.ts_
|
|
8473
7301
|
|
|
8474
|
-
###
|
|
7302
|
+
### useFormValidation
|
|
7303
|
+
|
|
7304
|
+
**Kind:** `function`
|
|
7305
|
+
|
|
7306
|
+
Декларативный выбор стратегии валидации формы: одна точка вместо ручной разводки
|
|
7307
|
+
`validateModel`/`revalidateWhen`. Собирает стабильный {@link createFormValidation}-контроллер,
|
|
7308
|
+
армит реактивную стратегию на клиенте (`useEffect` → SSR-safe) и отдаёт `submit`/`isValidating`.
|
|
7309
|
+
|
|
7310
|
+
Схема-валидации — **стабильная ссылка** (обязанность вызывающего): контроллер мемоизируется по
|
|
7311
|
+
`[model, schema, strategy, debounce, liveAfterSubmit]`.
|
|
7312
|
+
|
|
7313
|
+
**Signature:**
|
|
7314
|
+
```typescript
|
|
7315
|
+
export function useFormValidation<T>(args: UseFormValidationArgs<T>): UseFormValidationResult
|
|
7316
|
+
```
|
|
7317
|
+
|
|
7318
|
+
**Examples:**
|
|
7319
|
+
|
|
7320
|
+
```tsx
|
|
7321
|
+
const validation = defineValidationSchema<Form>(({ model }) => { ... }); // module-level
|
|
7322
|
+
|
|
7323
|
+
function MyForm() {
|
|
7324
|
+
const { submit, isValidating } = useFormValidation({
|
|
7325
|
+
model, schema: validation, strategy: 'afterFirstSubmit', debounce: 300,
|
|
7326
|
+
});
|
|
7327
|
+
const onSubmit = async (e: React.FormEvent) => {
|
|
7328
|
+
e.preventDefault();
|
|
7329
|
+
if (await submit()) await api.save(model.get());
|
|
7330
|
+
};
|
|
7331
|
+
return <form onSubmit={onSubmit}>{ ... }<button disabled={isValidating}>Отправить</button></form>;
|
|
7332
|
+
}
|
|
7333
|
+
```
|
|
7334
|
+
|
|
7335
|
+
_Source: src/form/hooks/use-form-validation.ts_
|
|
7336
|
+
|
|
7337
|
+
### UseFormValidationArgs
|
|
8475
7338
|
|
|
8476
7339
|
**Kind:** `interface`
|
|
8477
7340
|
|
|
8478
7341
|
**Signature:**
|
|
8479
7342
|
```typescript
|
|
8480
|
-
export interface
|
|
8481
|
-
/**
|
|
7343
|
+
export interface UseFormValidationArgs<T> {
|
|
7344
|
+
/** Модель данных формы. */
|
|
7345
|
+
model: FormModel<T>;
|
|
7346
|
+
/** Схема валидации. **Стабильная ссылка** (module-level `const` / `useMemo`) — иначе ломается дедуп раннера. */
|
|
7347
|
+
schema: ValidationSchema<T>;
|
|
7348
|
+
/** Стратегия запуска. Default `'submit'`. */
|
|
7349
|
+
strategy?: ValidationStrategyKind;
|
|
7350
|
+
/** Debounce (мс) для live-фаз (`change` / live-часть `afterFirstSubmit`). */
|
|
8482
7351
|
debounce?: number;
|
|
7352
|
+
/** Режим live-фазы для `afterFirstSubmit`. Default `'change'`. */
|
|
7353
|
+
liveAfterSubmit?: 'change' | 'blur';
|
|
8483
7354
|
}
|
|
8484
7355
|
```
|
|
8485
7356
|
|
|
8486
|
-
|
|
8487
|
-
подключалась тем оператором, которого больше нет. Рантаймом не потребляется; экспортируется
|
|
8488
|
-
только ради обратной совместимости.
|
|
7357
|
+
_Source: src/form/hooks/use-form-validation.ts_
|
|
8489
7358
|
|
|
8490
|
-
|
|
7359
|
+
### UseFormValidationResult
|
|
7360
|
+
|
|
7361
|
+
**Kind:** `interface`
|
|
7362
|
+
|
|
7363
|
+
**Signature:**
|
|
7364
|
+
```typescript
|
|
7365
|
+
export interface UseFormValidationResult {
|
|
7366
|
+
/** Полный прогон + раскрытие ошибок (`touch:true`); для `onSubmit`. Стабильная ссылка. */
|
|
7367
|
+
submit: () => Promise<boolean>;
|
|
7368
|
+
/** Алиас `submit` для не-submit сценариев. */
|
|
7369
|
+
validate: () => Promise<boolean>;
|
|
7370
|
+
/** Идёт ли прогон (submit или live) — для блокировки кнопки. */
|
|
7371
|
+
isValidating: boolean;
|
|
7372
|
+
}
|
|
7373
|
+
```
|
|
7374
|
+
|
|
7375
|
+
_Source: src/form/hooks/use-form-validation.ts_
|
|
8491
7376
|
|
|
8492
7377
|
### ValidateOptions
|
|
8493
7378
|
|
|
@@ -8591,33 +7476,3 @@ watchField(model.$.country, async (country) => {
|
|
|
8591
7476
|
```
|
|
8592
7477
|
|
|
8593
7478
|
_Source: src/state/behaviors-value.ts_
|
|
8594
|
-
|
|
8595
|
-
### WithBehaviorSchema
|
|
8596
|
-
|
|
8597
|
-
**Kind:** `interface`
|
|
8598
|
-
|
|
8599
|
-
Интерфейс для узлов с методом applyBehaviorSchema
|
|
8600
|
-
|
|
8601
|
-
**Signature:**
|
|
8602
|
-
```typescript
|
|
8603
|
-
export interface WithBehaviorSchema {
|
|
8604
|
-
applyBehaviorSchema(schemaFn: unknown): void;
|
|
8605
|
-
}
|
|
8606
|
-
```
|
|
8607
|
-
|
|
8608
|
-
_Source: src/form/types/index.ts_
|
|
8609
|
-
|
|
8610
|
-
### WithValidationSchema
|
|
8611
|
-
|
|
8612
|
-
**Kind:** `interface`
|
|
8613
|
-
|
|
8614
|
-
Интерфейс для узлов с методом applyValidationSchema
|
|
8615
|
-
|
|
8616
|
-
**Signature:**
|
|
8617
|
-
```typescript
|
|
8618
|
-
export interface WithValidationSchema {
|
|
8619
|
-
applyValidationSchema(schemaFn: unknown): void;
|
|
8620
|
-
}
|
|
8621
|
-
```
|
|
8622
|
-
|
|
8623
|
-
_Source: src/form/types/index.ts_
|