@reformer/core 10.2.0 → 11.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/behaviors.js +134 -134
  2. package/dist/form/form-submitter.d.ts +0 -4
  3. package/dist/form/hooks/types.d.ts +3 -3
  4. package/dist/form/index.d.ts +0 -3
  5. package/dist/form/nodes/array-node.d.ts +0 -84
  6. package/dist/form/nodes/form-node.d.ts +0 -14
  7. package/dist/form/nodes/group-node.d.ts +0 -4
  8. package/dist/form/status-machine.d.ts +0 -38
  9. package/dist/form/types/contracts.d.ts +0 -6
  10. package/dist/form/types/deep-schema.d.ts +0 -9
  11. package/dist/form/types/index.d.ts +4 -38
  12. package/dist/form/types/schema-node.d.ts +13 -16
  13. package/dist/form/types/validation-schema.d.ts +0 -25
  14. package/dist/form/unique-id.d.ts +3 -11
  15. package/dist/form/validators.d.ts +8 -3
  16. package/dist/form-model-DhW2HZOB.js +323 -0
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +448 -636
  19. package/dist/runtime-token.d.ts +23 -0
  20. package/dist/state/form-model.d.ts +14 -0
  21. package/dist/state/index.d.ts +2 -1
  22. package/dist/state/types.d.ts +39 -11
  23. package/dist/state.js +18 -18
  24. package/dist/validation.js +1 -1
  25. package/dist/validators.d.ts +0 -4
  26. package/dist/validators.js +88 -122
  27. package/docs/llms/01-api-reference.md +63 -0
  28. package/docs/llms/02-quick-start.md +143 -0
  29. package/docs/llms/03-api-signatures.md +273 -0
  30. package/docs/llms/04-common-patterns.md +202 -0
  31. package/docs/llms/05-common-mistakes.md +167 -0
  32. package/docs/llms/06-troubleshooting.md +11 -0
  33. package/docs/llms/07-complete-import.md +99 -0
  34. package/docs/llms/08-form-types.md +47 -0
  35. package/docs/llms/09-formschema.md +143 -0
  36. package/docs/llms/10-arrays.md +161 -0
  37. package/docs/llms/11-async-watchfield.md +53 -0
  38. package/docs/llms/12-array-cleanup.md +31 -0
  39. package/docs/llms/13-multi-step.md +91 -0
  40. package/docs/llms/14-extended-mistakes.md +98 -0
  41. package/docs/llms/15-project-structure.md +125 -0
  42. package/docs/llms/16-ui-components.md +189 -0
  43. package/docs/llms/17-nonexistent-api.md +93 -0
  44. package/docs/llms/18-conditional-fields.md +183 -0
  45. package/docs/llms/19-reading-values.md +88 -0
  46. package/docs/llms/20-compute-vs-watch.md +147 -0
  47. package/docs/llms/21-array-operations.md +113 -0
  48. package/docs/llms/22-cycle-detection.md +86 -0
  49. package/docs/llms/23-copy-from.md +141 -0
  50. package/docs/llms/24-sync-fields.md +114 -0
  51. package/docs/llms/25-reset-when.md +115 -0
  52. package/docs/llms/26-transform-value.md +136 -0
  53. package/docs/llms/27-revalidate-when.md +132 -0
  54. package/docs/llms/28-submit-and-reset.md +259 -0
  55. package/docs/llms/29-async-preload.md +193 -0
  56. package/docs/llms/30-type-safety-recipes.md +159 -0
  57. package/docs/llms/31-async-validator-debounce.md +135 -0
  58. package/docs/llms/32-async-options-loading.md +108 -0
  59. package/docs/llms/33-validation-strategy.md +193 -0
  60. package/llms.txt +219 -1533
  61. package/package.json +33 -10
  62. package/dist/derived-registry-CluZCQ7U.js +0 -16
  63. package/dist/form-model-DYCzGGKF.js +0 -286
package/llms.txt CHANGED
@@ -2259,9 +2259,38 @@ model.$.email.peek(); // нереактивный снимок
2259
2259
  model.$.address.city.value; // сигнал вложенного поля (≡ model.address.$.city у под-модели)
2260
2260
 
2261
2261
  // весь объект
2262
- model.get(); // снимок { email, address: { city }, ... } — для submit
2262
+ model.get(); // НЕреактивный снимок { email, address: { city }, ... } — для submit
2263
2263
  ```
2264
2264
 
2265
+ > ⚠️ `model.get()` и `model.isDirty()` читают через `peek()` — внутри `effect`/`computed` они НЕ
2266
+ > создают зависимостей. `computed(() => model.get())` никогда не пересчитается. Для реактивного
2267
+ > чтения всего объекта — узел дерева `$` (ниже).
2268
+
2269
+ ### Подписка на группу и на модель целиком
2270
+
2271
+ Каждый узел дерева `$` — сигнал: лист отдаёт `PathAwareSignal`, а корень, вложенные объекты-группы
2272
+ и массивы — `ReadonlySignal` агрегированного значения поддерева. Поэтому подписаться можно на любом
2273
+ уровне, а не только на конкретном поле.
2274
+
2275
+ ```typescript
2276
+ model.$.subscribe((all) => autosave(all)); // любое изменение модели; all: T целиком
2277
+ model.$.address.subscribe((addr) => ...); // только поддерево address
2278
+ model.$.address.value; // реактивный снимок группы
2279
+ model.$.address.peek(); // нереактивный снимок группы
2280
+ model.$.items.subscribe((rows) => ...); // массив: и правка элемента, и push/removeAt/move
2281
+
2282
+ // узел — обычный ReadonlySignal, поэтому принимается операциями слоя данных
2283
+ watchField(model.$.address, (addr) => geocode(addr));
2284
+ ```
2285
+
2286
+ Дети узла доступны как раньше — `model.$.address.city` по-прежнему сигнал поля. Подписчик вызывается
2287
+ сразу с текущим значением (семантика `Signal.subscribe`), а `model.set(...)`/`model.reset()`
2288
+ уведомляют один раз, а не по разу на поле.
2289
+
2290
+ > ⚠️ Доступ к полю выигрывает у свойства сигнала: если в форме есть поле с именем `value`, `peek`,
2291
+ > `subscribe`, `valueOf`, `toString`, `toJSON` или `brand`, то `model.$.<группа>.<это имя>` вернёт
2292
+ > сигнал поля. `subscribe` при этом продолжает работать.
2293
+
2265
2294
  ### В behaviors — читаем model напрямую
2266
2295
 
2267
2296
  `compute`/`onChange`/условия `when` читают значения из value-модели (`model.field`) —
@@ -2411,6 +2440,14 @@ import { watchField } from '@reformer/core';
2411
2440
  const stop = watchField(model.$.country, () => { model.city = ''; });
2412
2441
  ```
2413
2442
 
2443
+ Источником может быть не только поле: узлы-контейнеры дерева `$` (корень, группы, массивы) — тоже
2444
+ `ReadonlySignal`, поэтому за поддеревом целиком следят без перечисления полей.
2445
+
2446
+ ```typescript
2447
+ watchField(model.$.address, (addr) => geocode(addr)); // любое поле address
2448
+ watchField(model.$, (all) => autosave(all)); // любое поле формы
2449
+ ```
2450
+
2414
2451
  ### Rule of Thumb
2415
2452
 
2416
2453
  | Scenario | Use |
@@ -2419,6 +2456,7 @@ const stop = watchField(model.$.country, () => { model.city = ''; });
2419
2456
  | Производное с явными зависимостями | `computeFrom` |
2420
2457
  | Async-реакция, обновление componentProps | `onChange` (debounce + AbortSignal) |
2421
2458
  | Простая синхронная реакция (примитив) | `watchField` |
2459
+ | Реакция на любое изменение группы/формы | `watchField(model.$.<группа>)` или `.subscribe` |
2422
2460
 
2423
2461
  ### Chained computeds
2424
2462
 
@@ -4324,22 +4362,6 @@ export type AnyFunction = (...args: never[]) => unknown;
4324
4362
 
4325
4363
  _Source: src/form/types/index.ts_
4326
4364
 
4327
- ### ArrayConfig
4328
-
4329
- **Kind:** `interface`
4330
-
4331
- Конфигурация массива
4332
-
4333
- **Signature:**
4334
- ```typescript
4335
- export interface ArrayConfig<T extends object> {
4336
- itemSchema: FormSchema<T>;
4337
- initial?: Partial<T>[];
4338
- }
4339
- ```
4340
-
4341
- _Source: src/form/types/deep-schema.ts_
4342
-
4343
4365
  ### ArrayControlState
4344
4366
 
4345
4367
  **Kind:** `interface`
@@ -4484,7 +4506,7 @@ return (
4484
4506
  <PhoneItem
4485
4507
  key={item.id}
4486
4508
  control={item}
4487
- onRemove={() => control.remove(index)}
4509
+ onRemove={() => control.removeAt(index)}
4488
4510
  />
4489
4511
  ))}
4490
4512
 
@@ -4552,28 +4574,6 @@ export interface ArrayNodeLike {
4552
4574
 
4553
4575
  _Source: src/form/types/index.ts_
4554
4576
 
4555
- ### AsyncValidator
4556
-
4557
- **Kind:** `type`
4558
-
4559
- Чистый асинхронный валидатор поля. Та же тройка аргументов `(value, scope, root)`, что у
4560
- {@link Validator}, но возвращает `Promise`.
4561
-
4562
- **Signature:**
4563
- ```typescript
4564
- export type AsyncValidator<TForm, TField> = (
4565
- value: TField,
4566
- scope: unknown,
4567
- root: FormModel<TForm>
4568
- ) => Promise<ValidationError | null>;
4569
- ```
4570
-
4571
- **Deprecated:** Осиротевший остаток удалённого оператора `validateAsync` (Ф7). Рантаймом не
4572
- потребляется — живой async-путь узла поля использует `AsyncValidatorFn` `(value, { signal })`.
4573
- Экспортируется только ради обратной совместимости.
4574
-
4575
- _Source: src/form/types/validation-schema.ts_
4576
-
4577
4577
  ### AsyncValidatorFn
4578
4578
 
4579
4579
  **Kind:** `type`
@@ -4677,22 +4677,6 @@ computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price *
4677
4677
 
4678
4678
  _Source: src/state/behaviors-value.ts_
4679
4679
 
4680
- ### ConditionFn
4681
-
4682
- **Kind:** `type`
4683
-
4684
- Функция-предикат `(value) => boolean`.
4685
-
4686
- **Signature:**
4687
- ```typescript
4688
- export type ConditionFn<T> = (value: T) => boolean;
4689
- ```
4690
-
4691
- **Deprecated:** Осиротевший остаток удалённого оператора `applyWhen` (Ф7). Рантаймом не
4692
- потребляется; экспортируется только ради обратной совместимости.
4693
-
4694
- _Source: src/form/types/validation-schema.ts_
4695
-
4696
4680
  ### ConfigWithSchema
4697
4681
 
4698
4682
  **Kind:** `interface`
@@ -4747,6 +4731,40 @@ copyFrom(model.$.email, model.$.emailAdditional, { when: () => model.sameEmail }
4747
4731
 
4748
4732
  _Source: src/state/behaviors-value.ts_
4749
4733
 
4734
+ ### CORE_RUNTIME_TOKEN
4735
+
4736
+ **Kind:** `const`
4737
+
4738
+ Штамп копии рантайма ядра.
4739
+
4740
+ Единственное назначение — быть объектом, уникальным в пределах ОДНОЙ копии модуля. Две
4741
+ независимо загруженные копии `@reformer/core` дадут два разных объекта, и по их несовпадению
4742
+ guard распознаёт дубль рантайма.
4743
+
4744
+ Почему именно объект, а не строка с версией: две копии ОДНОЙ версии ломают всё ровно так же,
4745
+ как две копии разных версий, — раздваиваются модульные `WeakMap` (`derived-registry`,
4746
+ `signal-node-registry`) и перестают работать проверки `instanceof Signal`. Сравнение версий
4747
+ такой случай пропустило бы.
4748
+
4749
+ **Signature:**
4750
+ ```typescript
4751
+ export const CORE_RUNTIME_TOKEN: object
4752
+ ```
4753
+
4754
+ **Examples:**
4755
+
4756
+ ```ts
4757
+ import { CORE_RUNTIME_TOKEN } from '@reformer/core';
4758
+ import { stampRuntime } from '@reformer/form-registry/guard';
4759
+
4760
+ stampRuntime('@reformer/core', CORE_RUNTIME_TOKEN);
4761
+ ```
4762
+
4763
+ **See also:**
4764
+ - `@reformer/form-registry/guard`
4765
+
4766
+ _Source: src/runtime-token.ts_
4767
+
4750
4768
  ### createForm
4751
4769
 
4752
4770
  **Kind:** `function`
@@ -4952,43 +4970,6 @@ disableWhen(model.$.discount, () => model.plan !== 'promo', { resetOnDisable: tr
4952
4970
 
4953
4971
  _Source: src/form/behaviors-node.ts_
4954
4972
 
4955
- ### email
4956
-
4957
- **Kind:** `function`
4958
-
4959
- Фабрика валидатора формата email.
4960
-
4961
- Проверяет по упрощённому regex `^[^\s@]+@[^\s@]+\.[^\s@]+$`. Пустые значения
4962
- (`''`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
4963
-
4964
- **Signature:**
4965
- ```typescript
4966
- export function email<TForm = unknown, TField extends string | null | undefined = string>(
4967
- options?: ValidateOptions
4968
- ): Validator<TForm, TField>
4969
- ```
4970
-
4971
- **Parameters:**
4972
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
4973
-
4974
- **Returns:** Чистый валидатор {@link Validator} для строкового поля
4975
-
4976
- **Examples:**
4977
-
4978
- Проверка формата email
4979
- ```typescript
4980
- import { required, email } from '@reformer/core/validators';
4981
-
4982
- // Внутри FieldConfig схемы формы:
4983
- email: {
4984
- value: model.$.email,
4985
- component: Input,
4986
- validators: [required(), email({ message: 'Введите корректный email' })],
4987
- },
4988
- ```
4989
-
4990
- _Source: src/form/validation/validators/email.ts_
4991
-
4992
4973
  ### enableWhen
4993
4974
 
4994
4975
  **Kind:** `function`
@@ -5278,12 +5259,12 @@ export interface FieldControlState<T> {
5278
5259
 
5279
5260
  /**
5280
5261
  * Пользовательские props для передачи в UI-компоненты.
5281
- * Устанавливаются через {@link FieldNode.setComponentProps}.
5262
+ * Устанавливаются через {@link FieldNode.updateComponentProps}.
5282
5263
  *
5283
5264
  * @example
5284
5265
  * ```tsx
5285
5266
  * // Установка props
5286
- * field.setComponentProps({
5267
+ * field.updateComponentProps({
5287
5268
  * placeholder: 'Enter email...',
5288
5269
  * maxLength: 100,
5289
5270
  * autoComplete: 'email'
@@ -5383,23 +5364,6 @@ console.log(field.valid.value); // true
5383
5364
 
5384
5365
  _Source: src/form/nodes/field-node.ts_
5385
5366
 
5386
- ### FieldPathSegment
5387
-
5388
- **Kind:** `type`
5389
-
5390
- Тип для путей к полям (field paths)
5391
- Используется в навигации по полям вместо any
5392
-
5393
- **Signature:**
5394
- ```typescript
5395
- export type FieldPathSegment = {
5396
- key: string;
5397
- index?: number;
5398
- };
5399
- ```
5400
-
5401
- _Source: src/form/types/index.ts_
5402
-
5403
5367
  ### FieldStatus
5404
5368
 
5405
5369
  **Kind:** `type`
@@ -5413,70 +5377,6 @@ export type FieldStatus = 'valid' | 'invalid' | 'pending' | 'disabled';
5413
5377
 
5414
5378
  _Source: src/form/types/contracts.ts_
5415
5379
 
5416
- ### FileLike
5417
-
5418
- **Kind:** `interface`
5419
-
5420
- Минимальный файлоподобный контракт, с которым работают file-валидаторы:
5421
- нативный `File`, сериализуемый дескриптор загруженного файла и т.п.
5422
-
5423
- **Signature:**
5424
- ```typescript
5425
- export interface FileLike {
5426
- name: string;
5427
- size?: number;
5428
- type?: string;
5429
- }
5430
- ```
5431
-
5432
- _Source: src/form/validation/validators/file-utils.ts_
5433
-
5434
- ### fileType
5435
-
5436
- **Kind:** `function`
5437
-
5438
- Фабрика валидатора типа файла.
5439
-
5440
- Проверяет каждый файл против accept-строки в синтаксисе нативного атрибута
5441
- `<input type="file" accept>`: расширения (`.pdf`), точные MIME (`image/png`),
5442
- wildcard-категории (`image/*`), список через запятую. Матчинг регистронезависимый,
5443
- по `type` и/или расширению из `name` ({@link matchesFileAccept}).
5444
-
5445
- Нужен потому, что нативный `accept` — только подсказка пикеру: на drag-and-drop
5446
- и «All files» он не действует. Пустые значения (`null`/`undefined`/`''`/`[]`)
5447
- пропускаются (используйте {@link required} для обязательности).
5448
-
5449
- **Signature:**
5450
- ```typescript
5451
- export function fileType<TForm = unknown, TField = unknown>(
5452
- accept: string,
5453
- options?: ValidateOptions
5454
- ): Validator<TForm, TField>
5455
- ```
5456
-
5457
- **Parameters:**
5458
- - `accept` — - Accept-строка допустимых типов, например `'image/*,.pdf'`
5459
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
5460
- попадают `accept` и `fileName` (первый нарушивший файл).
5461
-
5462
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
5463
-
5464
- **Examples:**
5465
-
5466
- Только изображения и PDF
5467
- ```typescript
5468
- import { fileType } from '@reformer/core/validators';
5469
-
5470
- // Внутри FieldConfig схемы формы:
5471
- documents: {
5472
- value: model.$.documents,
5473
- component: FileUploadField,
5474
- validators: [fileType('image/*,.pdf', { message: 'Только изображения или PDF' })],
5475
- },
5476
- ```
5477
-
5478
- _Source: src/form/validation/validators/file-type.ts_
5479
-
5480
5380
  ### FormArrayProxy
5481
5381
 
5482
5382
  **Kind:** `type`
@@ -5857,19 +5757,25 @@ export interface FormSchemaNode {
5857
5757
  component?: ElementType;
5858
5758
  /** Props компонента. Также «клапан» для вложенности под-узлов (напр. steps визарда). */
5859
5759
  componentProps?: Record<string, unknown>;
5860
- validators?: SchemaValidator[];
5861
- asyncValidators?: SchemaValidator[];
5862
5760
  updateOn?: 'change' | 'blur' | 'submit';
5863
5761
  disabled?: boolean;
5864
5762
  /** Задержка (мс) перед запуском асинхронной валидации. */
5865
5763
  debounce?: number;
5866
5764
  /** Идентификатор узла (для wizard/tabs/renderBehavior). */
5867
5765
  selector?: string;
5766
+ /**
5767
+ * ⚠️ Рантайм этого поля НЕ ЧИТАЕТ — `renderer-react` берёт testId из `componentProps.testId`
5768
+ * (иначе выводит из пути сигнала). Поле оставлено только потому, что `RenderSchemaNode`
5769
+ * рендерера объявляет свой одноимённый; пишите `componentProps: { testId: '…' }`.
5770
+ */
5868
5771
  testId?: string;
5869
- /** Дочерние узлы (даёт контекстную типизацию вложенным литералам — value/validators/when). */
5870
- children?: readonly FormSchemaNode[];
5871
- /** Условие включения поддерева (branch-узел `{ when, children }`). */
5872
- when?: (scope: any, root: any) => boolean;
5772
+ /**
5773
+ * Содержимое узла: под-узлы (даёт контекстную типизацию вложенным литералам — value/validators/when)
5774
+ * и текстовые части. Текст (литерал, число, сигнал модели) — такой же ребёнок, как узел: core его
5775
+ * не интерпретирует (обход пропускает примитивы и не спускается внутрь сигнала), а рендерер
5776
+ * выводит на своём месте в порядке следования.
5777
+ */
5778
+ children?: readonly (FormSchemaNode | string | number | Signal<any>)[];
5873
5779
  /** Реактивный массив модели (`model.<path>`) — маркер узла-массива (вместе с `item`). */
5874
5780
  array?: SchemaArrayControl;
5875
5781
  /** Схема элемента массива: под-модель элемента → узел поддерева. */
@@ -5887,43 +5793,6 @@ export interface FormSchemaNode {
5887
5793
 
5888
5794
  _Source: src/form/types/schema-node.ts_
5889
5795
 
5890
- ### FormStatusMachine
5891
-
5892
- **Kind:** `class`
5893
-
5894
- FormStatusMachine - управляет состоянием поля формы
5895
-
5896
- Предоставляет:
5897
- - Единый источник истины для статуса
5898
- - Computed signals для derived состояний (valid, invalid, pending, disabled)
5899
- - Валидацию переходов между состояниями
5900
-
5901
- **Signature:**
5902
- ```typescript
5903
- export class FormStatusMachine {
5904
- /** Внутренний сигнал статуса */ /* … */ }
5905
- ```
5906
-
5907
- **Examples:**
5908
-
5909
- ```typescript
5910
- const statusMachine = new FormStatusMachine('valid');
5911
-
5912
- // Начало валидации
5913
- statusMachine.startValidation();
5914
- console.log(statusMachine.pending.value); // true
5915
-
5916
- // Завершение валидации с ошибками
5917
- statusMachine.completeValidation(true);
5918
- console.log(statusMachine.invalid.value); // true
5919
-
5920
- // Отключение поля
5921
- statusMachine.disable();
5922
- console.log(statusMachine.disabled.value); // true
5923
- ```
5924
-
5925
- _Source: src/form/status-machine.ts_
5926
-
5927
5796
  ### FormSubmitter
5928
5797
 
5929
5798
  **Kind:** `class`
@@ -5977,44 +5846,6 @@ export type FormValue =
5977
5846
 
5978
5847
  _Source: src/form/types/contracts.ts_
5979
5848
 
5980
- ### futureDate
5981
-
5982
- **Kind:** `function`
5983
-
5984
- Фабрика валидатора, проверяющего что дата не в прошлом.
5985
-
5986
- Дата не должна быть раньше сегодняшнего дня (сравнение по нормализованным датам).
5987
- Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
5988
-
5989
- **Signature:**
5990
- ```typescript
5991
- export function futureDate<
5992
- TForm = unknown,
5993
- TField extends string | Date | null | undefined = string | Date,
5994
- >(options?: ValidateOptions): Validator<TForm, TField>
5995
- ```
5996
-
5997
- **Parameters:**
5998
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
5999
-
6000
- **Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
6001
-
6002
- **Examples:**
6003
-
6004
- Дата не в прошлом
6005
- ```typescript
6006
- import { required, futureDate } from '@reformer/core/validators';
6007
-
6008
- // Внутри FieldConfig схемы формы:
6009
- appointmentDate: {
6010
- value: model.$.appointmentDate,
6011
- component: DatePicker,
6012
- validators: [required(), futureDate({ message: 'Дата записи должна быть в будущем' })],
6013
- },
6014
- ```
6015
-
6016
- _Source: src/form/validation/validators/future-date.ts_
6017
-
6018
5849
  ### getNodeForSignal
6019
5850
 
6020
5851
  **Kind:** `function`
@@ -6130,42 +5961,6 @@ export interface GroupNodeConfig<T> {
6130
5961
 
6131
5962
  _Source: src/form/types/index.ts_
6132
5963
 
6133
- ### integer
6134
-
6135
- **Kind:** `function`
6136
-
6137
- Фабрика валидатора, проверяющего что число — целое.
6138
-
6139
- Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6140
-
6141
- **Signature:**
6142
- ```typescript
6143
- export function integer<TForm = unknown, TField extends number | null | undefined = number>(
6144
- options?: ValidateOptions
6145
- ): Validator<TForm, TField>
6146
- ```
6147
-
6148
- **Parameters:**
6149
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
6150
-
6151
- **Returns:** Чистый валидатор {@link Validator} для числового поля
6152
-
6153
- **Examples:**
6154
-
6155
- Проверка целого числа
6156
- ```typescript
6157
- import { required, integer } from '@reformer/core/validators';
6158
-
6159
- // Внутри FieldConfig схемы формы:
6160
- count: {
6161
- value: model.$.count,
6162
- component: Input,
6163
- validators: [required(), integer({ message: 'Должно быть целым числом' })],
6164
- },
6165
- ```
6166
-
6167
- _Source: src/form/validation/validators/integer.ts_
6168
-
6169
5964
  ### isArrayNode
6170
5965
 
6171
5966
  **Kind:** `function`
@@ -6197,44 +5992,6 @@ if (isArrayNode(node)) {
6197
5992
 
6198
5993
  _Source: src/form/type-guards.ts_
6199
5994
 
6200
- ### isDate
6201
-
6202
- **Kind:** `function`
6203
-
6204
- Фабрика валидатора, проверяющего что значение — валидная дата.
6205
-
6206
- Принимает `Date` или строку, парсимую в дату. Пустые значения (`''`/`null`/`undefined`)
6207
- пропускаются (используйте {@link required} для обязательности).
6208
-
6209
- **Signature:**
6210
- ```typescript
6211
- export function isDate<
6212
- TForm = unknown,
6213
- TField extends string | Date | null | undefined = string | Date,
6214
- >(options?: ValidateOptions): Validator<TForm, TField>
6215
- ```
6216
-
6217
- **Parameters:**
6218
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
6219
-
6220
- **Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
6221
-
6222
- **Examples:**
6223
-
6224
- Проверка валидности даты
6225
- ```typescript
6226
- import { required, isDate } from '@reformer/core/validators';
6227
-
6228
- // Внутри FieldConfig схемы формы:
6229
- eventDate: {
6230
- value: model.$.eventDate,
6231
- component: DatePicker,
6232
- validators: [required(), isDate({ message: 'Введите корректную дату' })],
6233
- },
6234
- ```
6235
-
6236
- _Source: src/form/validation/validators/is-date.ts_
6237
-
6238
5995
  ### isDerived
6239
5996
 
6240
5997
  **Kind:** `function`
@@ -6300,25 +6057,6 @@ if (isFieldNode(node)) {
6300
6057
 
6301
6058
  _Source: src/form/type-guards.ts_
6302
6059
 
6303
- ### isFileLike
6304
-
6305
- **Kind:** `function`
6306
-
6307
- Проверяет, что значение файлоподобно: объект со строковым `name` и опциональными
6308
- числовым `size` / строковым `type`.
6309
-
6310
- **Signature:**
6311
- ```typescript
6312
- export function isFileLike(value: unknown): value is FileLike
6313
- ```
6314
-
6315
- **Parameters:**
6316
- - `value` — - Проверяемое значение
6317
-
6318
- **Returns:** `true`, если значение соответствует {@link FileLike}
6319
-
6320
- _Source: src/form/validation/validators/file-utils.ts_
6321
-
6322
6060
  ### isFormNode
6323
6061
 
6324
6062
  **Kind:** `function`
@@ -6377,43 +6115,28 @@ if (isGroupNode(node)) {
6377
6115
 
6378
6116
  _Source: src/form/type-guards.ts_
6379
6117
 
6380
- ### isNumber
6118
+ ### isModelContainerSignal
6381
6119
 
6382
6120
  **Kind:** `function`
6383
6121
 
6384
- Фабрика валидатора, проверяющего что значение — конечное число (не NaN, не строка).
6122
+ Узел дерева `model.$` — контейнер (группа/массив), а не лист?
6385
6123
 
6386
- Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для
6387
- обязательности). В отличие от других number-валидаторов, **не** пропускает не-числа
6388
- и `NaN` — это его задача.
6124
+ Контейнерный узел структурно совместим с `ReadonlySignal` (`peek`/`value`/`subscribe`), поэтому
6125
+ duck-typing «есть `peek` ⇒ это лист» на нём даёт ложное срабатывание. Этот guard — надёжный
6126
+ способ различить: обходчикам дерева нужно спускаться в контейнер, а не читать его целиком.
6389
6127
 
6390
6128
  **Signature:**
6391
6129
  ```typescript
6392
- export function isNumber<TForm = unknown, TField extends number | null | undefined = number>(
6393
- options?: ValidateOptions
6394
- ): Validator<TForm, TField>
6130
+ export function isModelContainerSignal(value: unknown): boolean
6395
6131
  ```
6396
6132
 
6397
- **Parameters:**
6398
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
6399
-
6400
- **Returns:** Чистый валидатор {@link Validator} для числового поля
6401
-
6402
6133
  **Examples:**
6403
6134
 
6404
- Проверка, что значение — число
6405
6135
  ```typescript
6406
- import { required, isNumber } from '@reformer/core/validators';
6407
-
6408
- // Внутри FieldConfig схемы формы:
6409
- amount: {
6410
- value: model.$.amount,
6411
- component: Input,
6412
- validators: [required(), isNumber({ message: 'Введите число' })],
6413
- },
6136
+ const isLeaf = (v: unknown) => isSignalLike(v) && !isModelContainerSignal(v);
6414
6137
  ```
6415
6138
 
6416
- _Source: src/form/validation/validators/is-number.ts_
6139
+ _Source: src/state/form-model.ts_
6417
6140
 
6418
6141
  ### markDerived
6419
6142
 
@@ -6451,577 +6174,23 @@ markDerived(model.$.total);
6451
6174
 
6452
6175
  _Source: src/state/derived-registry.ts_
6453
6176
 
6454
- ### matchesFileAccept
6455
-
6456
- **Kind:** `function`
6457
-
6458
- Проверяет файл против accept-паттерна в синтаксисе нативного атрибута
6459
- `<input type="file" accept>`: список через запятую из расширений (`.pdf`),
6460
- точных MIME (`image/png`) и wildcard-категорий (`image/*`). Регистронезависимо.
6461
-
6462
- Нужен собственный матчер, потому что `accept` у нативного input — только подсказка
6463
- пикеру: на drag-and-drop и на программное значение он не действует.
6464
-
6465
- **Signature:**
6466
- ```typescript
6467
- export function matchesFileAccept(file: Pick<FileLike, 'name' | 'type'>, accept: string): boolean
6468
- ```
6469
-
6470
- **Parameters:**
6471
- - `file` — - Файлоподобное значение (`name` + опциональный `type`)
6472
- - `accept` — - Accept-строка; пустая/пробельная строка матчит всё
6473
-
6474
- **Returns:** `true`, если файл подходит хотя бы под один паттерн
6475
-
6476
- _Source: src/form/validation/validators/file-utils.ts_
6477
-
6478
- ### max
6177
+ ### ModelApi
6479
6178
 
6480
- **Kind:** `function`
6179
+ **Kind:** `interface`
6481
6180
 
6482
- Фабрика валидатора максимального числового значения.
6181
+ API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).
6483
6182
 
6484
- Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
6485
-
6486
- **Signature:**
6487
- ```typescript
6488
- export function max<TForm = unknown, TField extends number | null | undefined = number>(
6489
- maxValue: number,
6490
- options?: ValidateOptions
6491
- ): Validator<TForm, TField>
6492
- ```
6493
-
6494
- **Parameters:**
6495
- - `maxValue` — - Максимально допустимое значение (включительно)
6496
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6497
- попадают `max` и `actual`.
6498
-
6499
- **Returns:** Чистый валидатор {@link Validator} для числового поля
6500
-
6501
- **Examples:**
6502
-
6503
- Максимальное значение числового поля
6504
- ```typescript
6505
- import { required, max } from '@reformer/core/validators';
6506
-
6507
- // Внутри FieldConfig схемы формы:
6508
- quantity: { value: model.$.quantity, component: Input, validators: [max(100)] },
6509
- discount: {
6510
- value: model.$.discount,
6511
- component: Input,
6512
- validators: [required(), max(50, { message: 'Не более 50%' })],
6513
- },
6514
- ```
6515
-
6516
- _Source: src/form/validation/validators/max.ts_
6517
-
6518
- ### maxAge
6519
-
6520
- **Kind:** `function`
6521
-
6522
- Фабрика валидатора максимального возраста (по дате рождения).
6523
-
6524
- Возраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные
6525
- даты пропускаются (используйте {@link required} и {@link isDate}).
6526
-
6527
- **Signature:**
6528
- ```typescript
6529
- export function maxAge<
6530
- TForm = unknown,
6531
- TField extends string | Date | null | undefined = string | Date,
6532
- >(maxAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>
6533
- ```
6534
-
6535
- **Parameters:**
6536
- - `maxAgeValue` — - Максимально допустимый возраст (в полных годах)
6537
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6538
- попадают `maxAge` и `currentAge`.
6539
-
6540
- **Returns:** Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)
6541
-
6542
- **Examples:**
6543
-
6544
- Максимальный возраст
6545
- ```typescript
6546
- import { maxAge } from '@reformer/core/validators';
6547
-
6548
- // Внутри FieldConfig схемы формы:
6549
- birthDate: {
6550
- value: model.$.birthDate,
6551
- component: DatePicker,
6552
- validators: [maxAge(100, { message: 'Проверьте дату рождения' })],
6553
- },
6554
- ```
6555
-
6556
- _Source: src/form/validation/validators/max-age.ts_
6557
-
6558
- ### maxDate
6559
-
6560
- **Kind:** `function`
6561
-
6562
- Фабрика валидатора максимальной даты (включительно).
6563
-
6564
- Сравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты
6565
- пропускаются (используйте {@link required} и {@link isDate}).
6566
-
6567
- **Signature:**
6568
- ```typescript
6569
- export function maxDate<
6570
- TForm = unknown,
6571
- TField extends string | Date | null | undefined = string | Date,
6572
- >(maxDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>
6573
- ```
6574
-
6575
- **Parameters:**
6576
- - `maxDateValue` — - Максимально допустимая дата (включительно)
6577
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6578
- попадает `maxDate`.
6579
-
6580
- **Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
6581
-
6582
- **Examples:**
6583
-
6584
- Максимальная дата
6585
- ```typescript
6586
- import { maxDate } from '@reformer/core/validators';
6587
-
6588
- // Внутри FieldConfig схемы формы:
6589
- birthDate: {
6590
- value: model.$.birthDate,
6591
- component: DatePicker,
6592
- validators: [maxDate(new Date(), { message: 'Дата не может быть в будущем' })],
6593
- },
6594
- ```
6595
-
6596
- _Source: src/form/validation/validators/max-date.ts_
6597
-
6598
- ### maxFiles
6599
-
6600
- **Kind:** `function`
6601
-
6602
- Фабрика валидатора максимального количества файлов.
6603
-
6604
- Работает с массивом файлов (одиночный файл считается как 1). Пустые значения
6605
- (`null`/`undefined`/`''`/`[]`) пропускаются (используйте {@link required}
6606
- для обязательности).
6607
-
6608
- **Signature:**
6609
- ```typescript
6610
- export function maxFiles<TForm = unknown, TField = unknown>(
6611
- max: number,
6612
- options?: ValidateOptions
6613
- ): Validator<TForm, TField>
6614
- ```
6615
-
6616
- **Parameters:**
6617
- - `max` — - Максимально допустимое количество файлов (включительно)
6618
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6619
- попадают `maxFiles` и `actualCount`.
6620
-
6621
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
6622
-
6623
- **Examples:**
6624
-
6625
- Не более трёх вложений
6626
- ```typescript
6627
- import { maxFiles } from '@reformer/core/validators';
6628
-
6629
- // Внутри FieldConfig схемы формы:
6630
- documents: {
6631
- value: model.$.documents,
6632
- component: FileUploadField,
6633
- validators: [maxFiles(3, { message: 'Максимум 3 файла' })],
6634
- },
6635
- ```
6636
-
6637
- _Source: src/form/validation/validators/max-files.ts_
6638
-
6639
- ### maxFileSize
6640
-
6641
- **Kind:** `function`
6642
-
6643
- Фабрика валидатора максимального размера файла.
6644
-
6645
- Работает с одиночным файлом или массивом (`File` либо файлоподобный дескриптор с
6646
- `name`/`size`). Проверяется каждый файл; в ошибку попадает первый нарушивший.
6647
- Пустые значения (`null`/`undefined`/`''`/`[]`) и элементы без числового `size`
6648
- (например, дескриптор загруженного файла без размера) пропускаются
6649
- (используйте {@link required} для обязательности).
6650
-
6651
- **Signature:**
6652
- ```typescript
6653
- export function maxFileSize<TForm = unknown, TField = unknown>(
6654
- maxSize: number,
6655
- options?: ValidateOptions
6656
- ): Validator<TForm, TField>
6657
- ```
6658
-
6659
- **Parameters:**
6660
- - `maxSize` — - Максимально допустимый размер файла в байтах (включительно)
6661
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6662
- попадают `maxFileSize`, `fileName` и `actualSize`.
6663
-
6664
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
6665
-
6666
- **Examples:**
6667
-
6668
- Ограничение размера вложений
6669
- ```typescript
6670
- import { maxFileSize } from '@reformer/core/validators';
6671
-
6672
- // Внутри FieldConfig схемы формы:
6673
- documents: {
6674
- value: model.$.documents,
6675
- component: FileUploadField,
6676
- validators: [maxFileSize(5 * 1024 * 1024, { message: 'Файл больше 5 МБ' })],
6677
- },
6678
- ```
6679
-
6680
- _Source: src/form/validation/validators/max-file-size.ts_
6681
-
6682
- ### maxLength
6683
-
6684
- **Kind:** `function`
6685
-
6686
- Фабрика валидатора максимальной длины строки или массива.
6687
-
6688
- Работает со строкой или массивом (проверяется `value.length`). Пустые значения
6689
- (`null`/`undefined`/`''`) и значения без числового `length` пропускаются
6690
- (используйте {@link required} для обязательности).
6691
-
6692
- **Signature:**
6693
- ```typescript
6694
- export function maxLength<TForm = unknown, TField = unknown>(
6695
- maxLen: number,
6696
- options?: ValidateOptions
6697
- ): Validator<TForm, TField>
6698
- ```
6699
-
6700
- **Parameters:**
6701
- - `maxLen` — - Максимально допустимая длина (включительно)
6702
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6703
- попадают `maxLength` и `actualLength`.
6704
-
6705
- **Returns:** Чистый валидатор {@link Validator} для строки или массива
6706
-
6707
- **Examples:**
6708
-
6709
- Максимальная длина строки
6710
- ```typescript
6711
- import { maxLength } from '@reformer/core/validators';
6712
-
6713
- // Внутри FieldConfig схемы формы:
6714
- name: { value: model.$.name, component: Input, validators: [maxLength(50)] },
6715
- bio: {
6716
- value: model.$.bio,
6717
- component: Textarea,
6718
- validators: [maxLength(500, { message: 'Максимум 500 символов' })],
6719
- },
6720
- ```
6721
-
6722
- _Source: src/form/validation/validators/max-length.ts_
6723
-
6724
- ### maxTotalFileSize
6725
-
6726
- **Kind:** `function`
6727
-
6728
- Фабрика валидатора суммарного размера всех файлов.
6729
-
6730
- Складывает `size` всех файлов значения (элементы без числового `size` в сумму
6731
- не входят). Пустые значения (`null`/`undefined`/`''`/`[]`) пропускаются
6732
- (используйте {@link required} для обязательности).
6733
-
6734
- **Signature:**
6735
- ```typescript
6736
- export function maxTotalFileSize<TForm = unknown, TField = unknown>(
6737
- maxTotal: number,
6738
- options?: ValidateOptions
6739
- ): Validator<TForm, TField>
6740
- ```
6741
-
6742
- **Parameters:**
6743
- - `maxTotal` — - Максимально допустимый суммарный размер в байтах (включительно)
6744
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6745
- попадают `maxTotalFileSize` и `actualTotal`.
6746
-
6747
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
6748
-
6749
- **Examples:**
6750
-
6751
- Суммарно не более 20 МБ
6752
- ```typescript
6753
- import { maxTotalFileSize } from '@reformer/core/validators';
6754
-
6755
- // Внутри FieldConfig схемы формы:
6756
- documents: {
6757
- value: model.$.documents,
6758
- component: FileUploadField,
6759
- validators: [maxTotalFileSize(20 * 1024 * 1024, { message: 'Суммарно не более 20 МБ' })],
6760
- },
6761
- ```
6762
-
6763
- _Source: src/form/validation/validators/max-total-file-size.ts_
6764
-
6765
- ### min
6766
-
6767
- **Kind:** `function`
6768
-
6769
- Фабрика валидатора минимального числового значения.
6770
-
6771
- Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
6772
-
6773
- **Signature:**
6774
- ```typescript
6775
- export function min<TForm = unknown, TField extends number | null | undefined = number>(
6776
- minValue: number,
6777
- options?: ValidateOptions
6778
- ): Validator<TForm, TField>
6779
- ```
6780
-
6781
- **Parameters:**
6782
- - `minValue` — - Минимально допустимое значение (включительно)
6783
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6784
- попадают `min` и `actual`.
6785
-
6786
- **Returns:** Чистый валидатор {@link Validator} для числового поля
6787
-
6788
- **Examples:**
6789
-
6790
- Минимальное значение числового поля
6791
- ```typescript
6792
- import { required, min } from '@reformer/core/validators';
6793
-
6794
- // Внутри FieldConfig схемы формы:
6795
- age: { value: model.$.age, component: Input, validators: [min(18)] },
6796
- quantity: {
6797
- value: model.$.quantity,
6798
- component: Input,
6799
- validators: [required(), min(1, { message: 'Минимум 1' })],
6800
- },
6801
- ```
6802
-
6803
- _Source: src/form/validation/validators/min.ts_
6804
-
6805
- ### minAge
6806
-
6807
- **Kind:** `function`
6808
-
6809
- Фабрика валидатора минимального возраста (по дате рождения).
6810
-
6811
- Возраст вычисляется по дате рождения относительно сегодняшнего дня. Пустые и невалидные
6812
- даты пропускаются (используйте {@link required} и {@link isDate}).
6813
-
6814
- **Signature:**
6815
- ```typescript
6816
- export function minAge<
6817
- TForm = unknown,
6818
- TField extends string | Date | null | undefined = string | Date,
6819
- >(minAgeValue: number, options?: ValidateOptions): Validator<TForm, TField>
6820
- ```
6821
-
6822
- **Parameters:**
6823
- - `minAgeValue` — - Минимально допустимый возраст (в полных годах)
6824
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6825
- попадают `minAge` и `currentAge`.
6826
-
6827
- **Returns:** Чистый валидатор {@link Validator} для поля даты рождения (`string | Date`)
6828
-
6829
- **Examples:**
6830
-
6831
- Минимальный возраст
6832
- ```typescript
6833
- import { required, minAge } from '@reformer/core/validators';
6834
-
6835
- // Внутри FieldConfig схемы формы:
6836
- birthDate: {
6837
- value: model.$.birthDate,
6838
- component: DatePicker,
6839
- validators: [required(), minAge(18, { message: 'Вам должно быть не менее 18 лет' })],
6840
- },
6841
- ```
6842
-
6843
- _Source: src/form/validation/validators/min-age.ts_
6844
-
6845
- ### minDate
6846
-
6847
- **Kind:** `function`
6848
-
6849
- Фабрика валидатора минимальной даты (включительно).
6850
-
6851
- Сравнение по нормализованным датам (время обнуляется). Пустые и невалидные даты
6852
- пропускаются (используйте {@link required} и {@link isDate}).
6853
-
6854
- **Signature:**
6855
- ```typescript
6856
- export function minDate<
6857
- TForm = unknown,
6858
- TField extends string | Date | null | undefined = string | Date,
6859
- >(minDateValue: Date, options?: ValidateOptions): Validator<TForm, TField>
6860
- ```
6861
-
6862
- **Parameters:**
6863
- - `minDateValue` — - Минимально допустимая дата (включительно)
6864
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6865
- попадает `minDate`.
6866
-
6867
- **Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
6868
-
6869
- **Examples:**
6870
-
6871
- Минимальная дата
6872
- ```typescript
6873
- import { required, minDate } from '@reformer/core/validators';
6874
-
6875
- // Внутри FieldConfig схемы формы:
6876
- startDate: {
6877
- value: model.$.startDate,
6878
- component: DatePicker,
6879
- validators: [required(), minDate(new Date(), { message: 'Дата не раньше сегодня' })],
6880
- },
6881
- ```
6882
-
6883
- _Source: src/form/validation/validators/min-date.ts_
6884
-
6885
- ### minFiles
6886
-
6887
- **Kind:** `function`
6888
-
6889
- Фабрика валидатора минимального количества файлов.
6890
-
6891
- Работает с массивом файлов (одиночный файл считается как 1). Пустые значения
6892
- (`null`/`undefined`/`''`/`[]`) пропускаются — «нужен хотя бы один файл» выражается
6893
- связкой `required()` + `minFiles(n)`, как и у {@link minLength}.
6894
-
6895
- **Signature:**
6896
- ```typescript
6897
- export function minFiles<TForm = unknown, TField = unknown>(
6898
- min: number,
6899
- options?: ValidateOptions
6900
- ): Validator<TForm, TField>
6901
- ```
6902
-
6903
- **Parameters:**
6904
- - `min` — - Минимально допустимое количество файлов (включительно)
6905
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6906
- попадают `minFiles` и `actualCount`.
6907
-
6908
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
6909
-
6910
- **Examples:**
6911
-
6912
- Не менее двух документов
6913
- ```typescript
6914
- import { required, minFiles } from '@reformer/core/validators';
6915
-
6916
- // Внутри FieldConfig схемы формы:
6917
- documents: {
6918
- value: model.$.documents,
6919
- component: FileUploadField,
6920
- validators: [required(), minFiles(2, { message: 'Приложите минимум 2 документа' })],
6921
- },
6922
- ```
6923
-
6924
- _Source: src/form/validation/validators/min-files.ts_
6925
-
6926
- ### minFileSize
6927
-
6928
- **Kind:** `function`
6929
-
6930
- Фабрика валидатора минимального размера файла.
6931
-
6932
- Работает с одиночным файлом или массивом (`File` либо файлоподобный дескриптор с
6933
- `name`/`size`). Проверяется каждый файл; в ошибку попадает первый нарушивший.
6934
- Типовой сценарий — отсев пустых (0-байтовых) файлов: `minFileSize(1)`.
6935
- Пустые значения (`null`/`undefined`/`''`/`[]`) и элементы без числового `size`
6936
- пропускаются (используйте {@link required} для обязательности).
6937
-
6938
- **Signature:**
6939
- ```typescript
6940
- export function minFileSize<TForm = unknown, TField = unknown>(
6941
- minSize: number,
6942
- options?: ValidateOptions
6943
- ): Validator<TForm, TField>
6944
- ```
6945
-
6946
- **Parameters:**
6947
- - `minSize` — - Минимально допустимый размер файла в байтах (включительно)
6948
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6949
- попадают `minFileSize`, `fileName` и `actualSize`.
6950
-
6951
- **Returns:** Чистый валидатор {@link Validator} для файла или массива файлов
6952
-
6953
- **Examples:**
6954
-
6955
- Отсев пустых файлов
6956
- ```typescript
6957
- import { minFileSize } from '@reformer/core/validators';
6958
-
6959
- // Внутри FieldConfig схемы формы:
6960
- documents: {
6961
- value: model.$.documents,
6962
- component: FileUploadField,
6963
- validators: [minFileSize(1, { message: 'Файл пустой' })],
6964
- },
6965
- ```
6966
-
6967
- _Source: src/form/validation/validators/min-file-size.ts_
6968
-
6969
- ### minLength
6970
-
6971
- **Kind:** `function`
6972
-
6973
- Фабрика валидатора минимальной длины строки или массива.
6974
-
6975
- Работает со строкой или массивом (проверяется `value.length`). Пустые значения
6976
- (`null`/`undefined`/`''`) и значения без числового `length` пропускаются
6977
- (используйте {@link required} для обязательности).
6978
-
6979
- **Signature:**
6980
- ```typescript
6981
- export function minLength<TForm = unknown, TField = unknown>(
6982
- minLen: number,
6983
- options?: ValidateOptions
6984
- ): Validator<TForm, TField>
6985
- ```
6986
-
6987
- **Parameters:**
6988
- - `minLen` — - Минимально допустимая длина (включительно)
6989
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
6990
- попадают `minLength` и `actualLength`.
6991
-
6992
- **Returns:** Чистый валидатор {@link Validator} для строки или массива
6993
-
6994
- **Examples:**
6995
-
6996
- Минимальная длина строки
6997
- ```typescript
6998
- import { required, minLength } from '@reformer/core/validators';
6999
-
7000
- // Внутри FieldConfig схемы формы:
7001
- name: { value: model.$.name, component: Input, validators: [minLength(2)] },
7002
- password: {
7003
- value: model.$.password,
7004
- component: Input,
7005
- validators: [required(), minLength(8, { message: 'Минимум 8 символов' })],
7006
- },
7007
- ```
7008
-
7009
- _Source: src/form/validation/validators/min-length.ts_
7010
-
7011
- ### ModelApi
7012
-
7013
- **Kind:** `interface`
7014
-
7015
- API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).
7016
-
7017
- ⚠️ Имена методов (`$`/`get`/`set`/`patch`/`isDirty`/`reset`/`signalAt`/`captureInitial`)
7018
- зарезервированы: одноимённое поле формы их затеняет (редкий краевой случай).
6183
+ ⚠️ Имена методов (`$`/`get`/`set`/`patch`/`isDirty`/`reset`/`signalAt`/`captureInitial`)
6184
+ зарезервированы: одноимённое поле формы их затеняет (редкий краевой случай).
7019
6185
 
7020
6186
  **Signature:**
7021
6187
  ```typescript
7022
6188
  export interface ModelApi<T> {
7023
- /** Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`. */
7024
- readonly $: ModelSignals<T>;
6189
+ /**
6190
+ * Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`.
6191
+ * Сам узел — {@link ReadonlySignal} модели целиком: `model.$.subscribe(v => …)`.
6192
+ */
6193
+ readonly $: ModelGroupSignals<T>;
7025
6194
  /** Снимок значений (без подписки) — для submit. */
7026
6195
  get(): T;
7027
6196
  /**
@@ -7165,403 +6334,185 @@ rows.length.value; // 1 (реактивная длина)
7165
6334
 
7166
6335
  _Source: src/form/nodes/model-array-node.ts_
7167
6336
 
7168
- ### ModelObject
6337
+ ### ModelArraySignals
7169
6338
 
7170
6339
  **Kind:** `type`
7171
6340
 
7172
- Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства
7173
- (чтение реактивно внутри `effect`/`computed`, запись — присваиванием). Вложенные объекты-поля
7174
- резолвятся в под-модели {@link FormModel} (см. {@link ModelValue}), массивы — в {@link ModelArray}.
6341
+ Узел-массив дерева `model.$`: индексируемый доступ к под-сигналам элементов, реактивная `length`
6342
+ и {@link ReadonlySignal} значения массива целиком (реагирует и на правку элемента, и на изменение
6343
+ состава — push/removeAt/move).
7175
6344
 
7176
6345
  **Signature:**
7177
6346
  ```typescript
7178
- export type ModelObject<T> = {
7179
- [K in keyof T]: ModelValue<T[K]>;
6347
+ export type ModelArraySignals<U, V> = ContainerSignal<V, 'length'> & {
6348
+ readonly length: number;
6349
+ readonly [index: number]: ModelSignalNode<U>;
7180
6350
  };
7181
6351
  ```
7182
6352
 
7183
6353
  _Source: src/state/types.ts_
7184
6354
 
7185
- ### ModelSignals
6355
+ ### ModelGroupSignals
7186
6356
 
7187
6357
  **Kind:** `type`
7188
6358
 
7189
- Дерево сигналов (escape-hatch `model.$`): листья → {@link PathAwareSignal},
7190
- объекты → вложенное дерево, массивы → индексируемое дерево под-сигналов.
6359
+ Узел-группа дерева `model.$`: доступ к под-сигналам полей ({@link ModelSignals}) И одновременно
6360
+ {@link ReadonlySignal} агрегированного значения группы — `.value`/`.peek()`/`.subscribe()`.
7191
6361
 
7192
- **Signature:**
7193
- ```typescript
7194
- export type ModelSignals<T> = {
7195
- [K in keyof T]: ModelSignalNode<T[K]>;
7196
- };
7197
- ```
7198
-
7199
- _Source: src/state/types.ts_
7200
-
7201
- ### ModelValue
7202
-
7203
- **Kind:** `type`
7204
-
7205
- Значение поля в value-доступе модели:
7206
- - массив → {@link ModelArray}
7207
- - спец-объект (Date/File/Blob) → как есть
7208
- - объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…);
7209
- промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>`
7210
- - примитив → значение
6362
+ ⚠️ Поле формы с именем `value`/`peek`/`subscribe`/`valueOf`/`toString`/`toJSON`/`brand` затеняет
6363
+ одноимённое свойство сигнала (редкий краевой случай); `subscribe` при этом продолжает работать.
7211
6364
 
7212
6365
  **Signature:**
7213
6366
  ```typescript
7214
- export type ModelValue<V> =
7215
- NonNullable<V> extends ReadonlyArray<infer U>
7216
- ? ModelArray<U>
7217
- : NonNullable<V> extends Opaque
7218
- ? V
7219
- : NonNullable<V> extends object
7220
- ? FormModel<NonNullable<V>>
7221
- : V;
6367
+ export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;
7222
6368
  ```
7223
6369
 
7224
6370
  _Source: src/state/types.ts_
7225
6371
 
7226
- ### multipleOf
7227
-
7228
- **Kind:** `function`
7229
-
7230
- Фабрика валидатора, проверяющего что число кратно заданному.
7231
-
7232
- Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
7233
-
7234
- **Signature:**
7235
- ```typescript
7236
- export function multipleOf<TForm = unknown, TField extends number | null | undefined = number>(
7237
- divisor: number,
7238
- options?: ValidateOptions
7239
- ): Validator<TForm, TField>
7240
- ```
7241
-
7242
- **Parameters:**
7243
- - `divisor` — - Делитель: значение должно быть кратно ему
7244
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
7245
- попадает `multipleOf` (делитель).
7246
-
7247
- **Returns:** Чистый валидатор {@link Validator} для числового поля
7248
-
7249
- **Examples:**
7250
-
7251
- Проверка кратности
7252
- ```typescript
7253
- import { multipleOf } from '@reformer/core/validators';
7254
-
7255
- // Внутри FieldConfig схемы формы:
7256
- rating: {
7257
- value: model.$.rating,
7258
- component: Input,
7259
- validators: [multipleOf(0.5, { message: 'Только шаг 0.5' })],
7260
- },
7261
- ```
7262
-
7263
- _Source: src/form/validation/validators/multiple-of.ts_
7264
-
7265
- ### NodeFactory
7266
-
7267
- **Kind:** `class`
7268
-
7269
- Фабрика для создания узлов формы.
7270
-
7271
- Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
7272
- Используется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.
7273
-
7274
- **Signature:**
7275
- ```typescript
7276
- export class NodeFactory {
7277
- /**
7278
- * Создает узел формы на основе конфигурации
7279
- *
7280
- * ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую
7281
- *
7282
- * Автоматически определяет тип узла:
7283
- * - FieldNode: имеет value и component
7284
- * - ArrayNode: массив [schema, ...items] или { schema, initialItems }
7285
- * - GroupNode: объект без value, component, schema
7286
- *
7287
- * @param config Конфигурация узла
7288
- * @returns Экземпляр FieldNode, GroupNode или ArrayNode
7289
- * @throws Error если конфиг не соответствует ни одному типу
7290
- *
7291
- * @example
7292
- * ```typescript
7293
- * const factory = new NodeFactory();
7294
- *
7295
- * // FieldNode
7296
- * const field = factory.createNode({
7297
- * value: 'test@mail.com',
7298
- * component: Input,
7299
- * validators: [required, email]
7300
- * });
7301
- *
7302
- * // GroupNode
7303
- * const group = factory.createNode({
7304
- * email: { value: '', component: Input },
7305
- * password: { value: '', component: Input }
7306
- * });
7307
- *
7308
- * // ArrayNode (объект)
7309
- * const array = factory.createNode({
7310
- * schema: { title: { value: '', component: Input } },
7311
- * initialItems: [{ title: 'Item 1' }]
7312
- * });
7313
- *
7314
- * // ArrayNode (массив) - новый формат
7315
- * const array2 = factory.createNode([
7316
- * { title: { value: '', component: Input } }, // schema
7317
- * { title: 'Item 1' }, // initial item 1
7318
- * { title: 'Item 2' } // initial item 2
7319
- * ]);
7320
- * ```
7321
- */ /* … */ }
7322
- ```
7323
-
7324
- **Examples:**
7325
-
7326
- ```typescript
7327
- import { NodeFactory } from '@reformer/core';
7328
-
7329
- const factory = new NodeFactory();
7330
- const node = factory.createNode({ value: '', component: Input }); // → FieldNode<string>
7331
- ```
7332
-
7333
- _Source: src/form/factories/node-factory.ts_
7334
-
7335
- ### nonNegative
7336
-
7337
- **Kind:** `function`
7338
-
7339
- Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).
7340
-
7341
- Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
7342
-
7343
- **Signature:**
7344
- ```typescript
7345
- export function nonNegative<TForm = unknown, TField extends number | null | undefined = number>(
7346
- options?: ValidateOptions
7347
- ): Validator<TForm, TField>
7348
- ```
7349
-
7350
- **Parameters:**
7351
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
7352
-
7353
- **Returns:** Чистый валидатор {@link Validator} для числового поля
7354
-
7355
- **Examples:**
7356
-
7357
- Проверка неотрицательности
7358
- ```typescript
7359
- import { nonNegative } from '@reformer/core/validators';
7360
-
7361
- // Внутри FieldConfig схемы формы:
7362
- balance: {
7363
- value: model.$.balance,
7364
- component: Input,
7365
- validators: [nonNegative({ message: 'Баланс не может быть отрицательным' })],
7366
- },
7367
- ```
7368
-
7369
- _Source: src/form/validation/validators/non-negative.ts_
7370
-
7371
- ### nonZero
7372
-
7373
- **Kind:** `function`
7374
-
7375
- Фабрика валидатора, проверяющего что число не равно нулю.
7376
-
7377
- Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
7378
-
7379
- **Signature:**
7380
- ```typescript
7381
- export function nonZero<TForm = unknown, TField extends number | null | undefined = number>(
7382
- options?: ValidateOptions
7383
- ): Validator<TForm, TField>
7384
- ```
7385
-
7386
- **Parameters:**
7387
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
7388
-
7389
- **Returns:** Чистый валидатор {@link Validator} для числового поля
7390
-
7391
- **Examples:**
7392
-
7393
- Проверка «не ноль»
7394
- ```typescript
7395
- import { nonZero } from '@reformer/core/validators';
7396
-
7397
- // Внутри FieldConfig схемы формы:
7398
- divisor: {
7399
- value: model.$.divisor,
7400
- component: Input,
7401
- validators: [nonZero({ message: 'Не может быть нулём' })],
7402
- },
7403
- ```
7404
-
7405
- _Source: src/form/validation/validators/non-zero.ts_
7406
-
7407
- ### pastDate
7408
-
7409
- **Kind:** `function`
7410
-
7411
- Фабрика валидатора, проверяющего что дата не в будущем.
7412
-
7413
- Дата не должна быть позже сегодняшнего дня (сравнение по нормализованным датам).
7414
- Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
7415
-
7416
- **Signature:**
7417
- ```typescript
7418
- export function pastDate<
7419
- TForm = unknown,
7420
- TField extends string | Date | null | undefined = string | Date,
7421
- >(options?: ValidateOptions): Validator<TForm, TField>
7422
- ```
7423
-
7424
- **Parameters:**
7425
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
7426
-
7427
- **Returns:** Чистый валидатор {@link Validator} для поля даты (`string | Date`)
7428
-
7429
- **Examples:**
7430
-
7431
- Дата не в будущем
7432
- ```typescript
7433
- import { required, pastDate } from '@reformer/core/validators';
7434
-
7435
- // Внутри FieldConfig схемы формы:
7436
- birthDate: {
7437
- value: model.$.birthDate,
7438
- component: DatePicker,
7439
- validators: [required(), pastDate({ message: 'Дата рождения не может быть в будущем' })],
7440
- },
7441
- ```
7442
-
7443
- _Source: src/form/validation/validators/past-date.ts_
7444
-
7445
- ### PathAwareSignal
6372
+ ### ModelObject
7446
6373
 
7447
6374
  **Kind:** `type`
7448
6375
 
7449
- Сигнал, который знает свой путь в модели (`'personalData.lastName'`).
7450
- Используется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.
6376
+ Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства
6377
+ (чтение реактивно внутри `effect`/`computed`, запись — присваиванием). Вложенные объекты-поля
6378
+ резолвятся в под-модели {@link FormModel} (см. {@link ModelValue}), массивы — в {@link ModelArray}.
7451
6379
 
7452
6380
  **Signature:**
7453
6381
  ```typescript
7454
- export type PathAwareSignal<T> = Signal<T> & {
7455
- /** Путь поля в модели (dot-нотация). На элементах массива включает индекс. */
7456
- readonly __path: string;
6382
+ export type ModelObject<T> = {
6383
+ [K in keyof T]: ModelValue<T[K]>;
7457
6384
  };
7458
6385
  ```
7459
6386
 
7460
6387
  _Source: src/state/types.ts_
7461
6388
 
7462
- ### pattern
7463
-
7464
- **Kind:** `function`
6389
+ ### ModelSignals
7465
6390
 
7466
- Фабрика валидатора регулярного выражения.
6391
+ **Kind:** `type`
7467
6392
 
7468
- Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
7469
- для обязательности).
6393
+ Карта под-сигналов объекта в дереве `model.$` (без свойств самого узла — их добавляет
6394
+ {@link ModelGroupSignals}).
7470
6395
 
7471
6396
  **Signature:**
7472
6397
  ```typescript
7473
- export function pattern<TForm = unknown, TField extends string | null | undefined = string>(
7474
- regex: RegExp,
7475
- options?: ValidateOptions
7476
- ): Validator<TForm, TField>
6398
+ export type ModelSignals<T> = {
6399
+ [K in keyof T]: ModelSignalNode<T[K]>;
6400
+ };
7477
6401
  ```
7478
6402
 
7479
- **Parameters:**
7480
- - `regex` — - Регулярное выражение для проверки значения
7481
- - `options` — - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
7482
- попадает `pattern` (строка-источник regex).
6403
+ _Source: src/state/types.ts_
7483
6404
 
7484
- **Returns:** Чистый валидатор {@link Validator} для строкового поля
6405
+ ### ModelValue
7485
6406
 
7486
- **Examples:**
6407
+ **Kind:** `type`
7487
6408
 
7488
- Проверка по регулярному выражению
7489
- ```typescript
7490
- import { required, pattern } from '@reformer/core/validators';
6409
+ Значение поля в value-доступе модели:
6410
+ - массив → {@link ModelArray}
6411
+ - спец-объект (Date/File/Blob) → как есть
6412
+ - объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…);
6413
+ промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>`
6414
+ - примитив → значение
7491
6415
 
7492
- // Внутри FieldConfig схемы формы:
7493
- name: {
7494
- value: model.$.name,
7495
- component: Input,
7496
- validators: [pattern(/^[a-zA-Zа-яА-Я]+$/, { message: 'Только буквы' })],
7497
- },
7498
- phone: {
7499
- value: model.$.phone,
7500
- component: InputMask,
7501
- validators: [
7502
- required(),
7503
- pattern(/^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/, { message: 'Формат +7 (999) 123-45-67' }),
7504
- ],
7505
- },
6416
+ **Signature:**
6417
+ ```typescript
6418
+ export type ModelValue<V> =
6419
+ NonNullable<V> extends ReadonlyArray<infer U>
6420
+ ? ModelArray<U>
6421
+ : NonNullable<V> extends Opaque
6422
+ ? V
6423
+ : NonNullable<V> extends object
6424
+ ? FormModel<NonNullable<V>>
6425
+ : V;
7506
6426
  ```
7507
6427
 
7508
- _Source: src/form/validation/validators/pattern.ts_
6428
+ _Source: src/state/types.ts_
7509
6429
 
7510
- ### phone
6430
+ ### NodeFactory
7511
6431
 
7512
- **Kind:** `function`
6432
+ **Kind:** `class`
7513
6433
 
7514
- Фабрика валидатора номера телефона.
6434
+ Фабрика для создания узлов формы.
7515
6435
 
7516
- Проверяет значение по regex выбранного {@link PhoneFormat}. Пустые значения
7517
- (`''`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
6436
+ Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
6437
+ Используется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.
7518
6438
 
7519
6439
  **Signature:**
7520
6440
  ```typescript
7521
- export function phone<TForm = unknown, TField extends string | null | undefined = string>(
7522
- options?: PhoneValidatorOptions
7523
- ): Validator<TForm, TField>
6441
+ export class NodeFactory {
6442
+ /**
6443
+ * Создает узел формы на основе конфигурации
6444
+ *
6445
+ * ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую
6446
+ *
6447
+ * Автоматически определяет тип узла:
6448
+ * - FieldNode: имеет value и component
6449
+ * - ArrayNode: массив [schema, ...items] или { schema, initialItems }
6450
+ * - GroupNode: объект без value, component, schema
6451
+ *
6452
+ * @param config Конфигурация узла
6453
+ * @returns Экземпляр FieldNode, GroupNode или ArrayNode
6454
+ * @throws Error если конфиг не соответствует ни одному типу
6455
+ *
6456
+ * @example
6457
+ * ```typescript
6458
+ * const factory = new NodeFactory();
6459
+ *
6460
+ * // FieldNode
6461
+ * const field = factory.createNode({
6462
+ * value: 'test@mail.com',
6463
+ * component: Input,
6464
+ * validators: [required, email]
6465
+ * });
6466
+ *
6467
+ * // GroupNode
6468
+ * const group = factory.createNode({
6469
+ * email: { value: '', component: Input },
6470
+ * password: { value: '', component: Input }
6471
+ * });
6472
+ *
6473
+ * // ArrayNode (объект)
6474
+ * const array = factory.createNode({
6475
+ * schema: { title: { value: '', component: Input } },
6476
+ * initialItems: [{ title: 'Item 1' }]
6477
+ * });
6478
+ *
6479
+ * // ArrayNode (массив) - новый формат
6480
+ * const array2 = factory.createNode([
6481
+ * { title: { value: '', component: Input } }, // schema
6482
+ * { title: 'Item 1' }, // initial item 1
6483
+ * { title: 'Item 2' } // initial item 2
6484
+ * ]);
6485
+ * ```
6486
+ */ /* … */ }
7524
6487
  ```
7525
6488
 
7526
- **Parameters:**
7527
- - `options` — - Опции валидатора {@link PhoneValidatorOptions}. В `params` ошибки
7528
- автоматически попадает выбранный `format`.
7529
-
7530
- **Returns:** Чистый валидатор {@link Validator} для строкового поля
7531
-
7532
6489
  **Examples:**
7533
6490
 
7534
- Проверка номера телефона
7535
6491
  ```typescript
7536
- import { required, phone } from '@reformer/core/validators';
6492
+ import { NodeFactory } from '@reformer/core';
7537
6493
 
7538
- // Внутри FieldConfig схемы формы:
7539
- phone: {
7540
- value: model.$.phone,
7541
- component: Input,
7542
- validators: [required(), phone({ format: 'ru' })],
7543
- },
6494
+ const factory = new NodeFactory();
6495
+ const node = factory.createNode({ value: '', component: Input }); // → FieldNode<string>
7544
6496
  ```
7545
6497
 
7546
- _Source: src/form/validation/validators/phone.ts_
6498
+ _Source: src/form/factories/node-factory.ts_
7547
6499
 
7548
- ### PhoneFormat
6500
+ ### PathAwareSignal
7549
6501
 
7550
6502
  **Kind:** `type`
7551
6503
 
7552
- Формат проверки номера телефона для валидатора {@link phone}.
7553
-
7554
- - `international` — международный формат E.164 (`+?[1-9]\d{1,14}`);
7555
- - `ru` — российские номера (`+7`/`7`/`8`, коды `4`/`8`/`9`, с разделителями);
7556
- - `us` — североамериканские номера (NANP);
7557
- - `any` — свободный формат: цифры, скобки и разделители (по умолчанию).
6504
+ Сигнал, который знает свой путь в модели (`'personalData.lastName'`).
6505
+ Используется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.
7558
6506
 
7559
6507
  **Signature:**
7560
6508
  ```typescript
7561
- export type PhoneFormat = 'international' | 'ru' | 'us' | 'any';
6509
+ export type PathAwareSignal<T> = Signal<T> & {
6510
+ /** Путь поля в модели (dot-нотация). На элементах массива включает индекс. */
6511
+ readonly __path: string;
6512
+ };
7562
6513
  ```
7563
6514
 
7564
- _Source: src/form/validation/validators/phone.ts_
6515
+ _Source: src/state/types.ts_
7565
6516
 
7566
6517
  ### registerSignalNode
7567
6518
 
@@ -7597,52 +6548,6 @@ if (sig && node) registerSignalNode(sig, node);
7597
6548
 
7598
6549
  _Source: src/form/signal-node-registry.ts_
7599
6550
 
7600
- ### required
7601
-
7602
- **Kind:** `function`
7603
-
7604
- Фабрика валидатора обязательного поля.
7605
-
7606
- Возвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.
7607
-
7608
- Пустыми считаются: `null`, `undefined`, `''` (пустая строка), `[]` (пустой массив —
7609
- обязательный multi-select / FormArray без выбранных элементов).
7610
- Для boolean полей требуется значение `true`.
7611
-
7612
- **Signature:**
7613
- ```typescript
7614
- export function required<TForm = unknown, TField = unknown>(
7615
- options?: ValidateOptions
7616
- ): Validator<TForm, TField>
7617
- ```
7618
-
7619
- **Parameters:**
7620
- - `options` — - Опции валидатора ({@link ValidateOptions}): `message`, `params`
7621
-
7622
- **Returns:** Чистый валидатор {@link Validator} для поля схемы
7623
-
7624
- **Examples:**
7625
-
7626
- Обязательные поля в схеме формы
7627
- ```typescript
7628
- import { required } from '@reformer/core/validators';
7629
-
7630
- // Внутри FieldConfig схемы формы:
7631
- email: { value: model.$.email, component: Input, validators: [required()] },
7632
- phone: {
7633
- value: model.$.phone,
7634
- component: Input,
7635
- validators: [required({ message: 'Укажите номер телефона' })],
7636
- },
7637
- agreeToTerms: {
7638
- value: model.$.agreeToTerms,
7639
- component: Checkbox,
7640
- validators: [required({ message: 'Необходимо принять условия' })],
7641
- },
7642
- ```
7643
-
7644
- _Source: src/form/validation/validators/required.ts_
7645
-
7646
6551
  ### resetWhen
7647
6552
 
7648
6553
  **Kind:** `function`
@@ -7666,19 +6571,6 @@ resetWhen(model.$.cardNumber, () => model.paymentType !== 'card', { resetValue:
7666
6571
 
7667
6572
  _Source: src/state/behaviors-value.ts_
7668
6573
 
7669
- ### ResourceLoadResult
7670
-
7671
- **Kind:** `type`
7672
-
7673
- Тип для результатов загрузки ресурсов
7674
-
7675
- **Signature:**
7676
- ```typescript
7677
- export type ResourceLoadResult = unknown;
7678
- ```
7679
-
7680
- _Source: src/form/types/index.ts_
7681
-
7682
6574
  ### revalidateWhen
7683
6575
 
7684
6576
  **Kind:** `function`
@@ -7836,25 +6728,6 @@ export interface SchemaArrayControl {
7836
6728
 
7837
6729
  _Source: src/form/types/schema-node.ts_
7838
6730
 
7839
- ### SchemaValidator
7840
-
7841
- **Kind:** `type`
7842
-
7843
- Валидатор поля схемы (legacy). Дерево-движок, вызывавший `validators` узла как
7844
- `(value, scope, root)`, удалён — живые правила это `Rule<T>` в `validate(sig, [...])`
7845
- (`@reformer/core/validation`). Тип остаётся широким по параметрам для совместимости
7846
- узлов, всё ещё несущих `validators` (гетерогенные контракты `ValidatorFn`/`Validator`).
7847
-
7848
- **Signature:**
7849
- ```typescript
7850
- export type SchemaValidator = (
7851
- value: any,
7852
- ...rest: any[]
7853
- ) => ValidationError | null | Promise<ValidationError | null>;
7854
- ```
7855
-
7856
- _Source: src/form/types/schema-node.ts_
7857
-
7858
6731
  ### SetValueOptions
7859
6732
 
7860
6733
  **Kind:** `interface`
@@ -7866,32 +6739,13 @@ _Source: src/form/types/schema-node.ts_
7866
6739
  export interface SetValueOptions {
7867
6740
  /** Не вызывать событие изменения (не триггерить валидацию) */
7868
6741
  emitEvent?: boolean;
7869
- /** Обновить только этот узел, не распространять на родителей */
7870
- onlySelf?: boolean;
6742
+ // onlySelf удалён в 7.0: опция объявлялась, но не была реализована ни одной из четырёх
6743
+ // реализаций setValue — передача значения ни на что не влияла.
7871
6744
  }
7872
6745
  ```
7873
6746
 
7874
6747
  _Source: src/form/nodes/form-node.ts_
7875
6748
 
7876
- ### StatusEvent
7877
-
7878
- **Kind:** `type`
7879
-
7880
- События для State Machine
7881
-
7882
- **Signature:**
7883
- ```typescript
7884
- export type StatusEvent =
7885
- | { type: 'START_VALIDATION' }
7886
- | { type: 'VALIDATION_SUCCESS' }
7887
- | { type: 'VALIDATION_FAILURE' }
7888
- | { type: 'DISABLE' }
7889
- | { type: 'ENABLE'; hasErrors?: boolean }
7890
- | { type: 'SET_ERRORS'; hasErrors: boolean };
7891
- ```
7892
-
7893
- _Source: src/form/status-machine.ts_
7894
-
7895
6749
  ### SubmitOptions
7896
6750
 
7897
6751
  **Kind:** `interface`
@@ -8018,27 +6872,6 @@ syncFields(model.$.field1, model.$.field2);
8018
6872
 
8019
6873
  _Source: src/state/behaviors-value.ts_
8020
6874
 
8021
- ### toFileArray
8022
-
8023
- **Kind:** `function`
8024
-
8025
- Нормализует значение file-поля в массив файлоподобных элементов.
8026
-
8027
- Одиночный {@link FileLike} оборачивается в массив; из массива отбираются только
8028
- файлоподобные элементы. Для прочих значений — `null` (валидатор пропускает).
8029
-
8030
- **Signature:**
8031
- ```typescript
8032
- export function toFileArray(value: unknown): FileLike[] | null
8033
- ```
8034
-
8035
- **Parameters:**
8036
- - `value` — - Значение поля (`FileLike`, `FileLike[]` или что-то ещё)
8037
-
8038
- **Returns:** Массив файлоподобных элементов или `null`
8039
-
8040
- _Source: src/form/validation/validators/file-utils.ts_
8041
-
8042
6875
  ### transformValue
8043
6876
 
8044
6877
  **Kind:** `function`
@@ -8062,61 +6895,6 @@ transformValue(model.$.promoCode, (v) => (v ?? '').toUpperCase());
8062
6895
 
8063
6896
  _Source: src/state/behaviors-value.ts_
8064
6897
 
8065
- ### uniqueId
8066
-
8067
- **Kind:** `function`
8068
-
8069
- Генерирует уникальный идентификатор с указанным префиксом.
8070
-
8071
- **Signature:**
8072
- ```typescript
8073
- export function uniqueId(prefix: SubscriptionKeyType): string
8074
- ```
8075
-
8076
- **Parameters:**
8077
- - `prefix` — - Префикс для идентификатора (используйте {@link SubscriptionKey}).
8078
-
8079
- **Returns:** Уникальный идентификатор в формате `${prefix}-${counter}`.
8080
-
8081
- **Examples:**
8082
-
8083
- ```typescript
8084
- import { uniqueId, SubscriptionKey } from '@reformer/core';
8085
-
8086
- uniqueId(SubscriptionKey.WatchField); // → 'watchField-1'
8087
- uniqueId(SubscriptionKey.WatchField); // → 'watchField-2'
8088
- ```
8089
-
8090
- _Source: src/form/unique-id.ts_
8091
-
8092
- ### UnknownCallback
8093
-
8094
- **Kind:** `type`
8095
-
8096
- Тип для коллбэков и обработчиков событий
8097
- Используется вместо (...args: any[]) => any
8098
-
8099
- **Signature:**
8100
- ```typescript
8101
- export type UnknownCallback = (...args: unknown[]) => unknown;
8102
- ```
8103
-
8104
- _Source: src/form/types/index.ts_
8105
-
8106
- ### UnknownFormValue
8107
-
8108
- **Kind:** `type`
8109
-
8110
- Type-safe alternative to 'any' for unknown form values
8111
- Requires explicit type checking before use
8112
-
8113
- **Signature:**
8114
- ```typescript
8115
- export type UnknownFormValue = unknown;
8116
- ```
8117
-
8118
- _Source: src/form/types/contracts.ts_
8119
-
8120
6898
  ### UnknownRecord
8121
6899
 
8122
6900
  **Kind:** `type`
@@ -8167,50 +6945,6 @@ onDispose(() => unmarkDerived(model.$.total)); // при снятии compute с
8167
6945
 
8168
6946
  _Source: src/state/derived-registry.ts_
8169
6947
 
8170
- ### url
8171
-
8172
- **Kind:** `function`
8173
-
8174
- Фабрика валидатора URL.
8175
-
8176
- Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
8177
- для обязательности). При `requireProtocol` протокол обязателен; `allowedProtocols`
8178
- дополнительно ограничивает набор допустимых протоколов.
8179
-
8180
- **Signature:**
8181
- ```typescript
8182
- export function url<TForm = unknown, TField extends string | null | undefined = string>(
8183
- options?: UrlValidatorOptions
8184
- ): Validator<TForm, TField>
8185
- ```
8186
-
8187
- **Parameters:**
8188
- - `options` — - Опции валидатора {@link UrlValidatorOptions}
8189
-
8190
- **Returns:** Чистый валидатор {@link Validator} для строкового поля
8191
-
8192
- **Examples:**
8193
-
8194
- Проверка URL
8195
- ```typescript
8196
- import { required, url } from '@reformer/core/validators';
8197
-
8198
- // Внутри FieldConfig схемы формы:
8199
- website: {
8200
- value: model.$.website,
8201
- component: Input,
8202
- validators: [required(), url({ message: 'Введите корректный URL' })],
8203
- },
8204
- // Требовать протокол и ограничить схему только https:
8205
- homepage: {
8206
- value: model.$.homepage,
8207
- component: Input,
8208
- validators: [url({ requireProtocol: true, allowedProtocols: ['https'] })],
8209
- },
8210
- ```
8211
-
8212
- _Source: src/form/validation/validators/url.ts_
8213
-
8214
6948
  ### useArrayLength
8215
6949
 
8216
6950
  **Kind:** `function`
@@ -8359,7 +7093,7 @@ onChange={e => control.setValue(e.target.checked)}
8359
7093
  }
8360
7094
 
8361
7095
  // Использование
8362
- control.setComponentProps({
7096
+ control.updateComponentProps({
8363
7097
  label: 'Accept terms and conditions',
8364
7098
  hint: 'Required to continue'
8365
7099
  });
@@ -8415,7 +7149,7 @@ control.push({ street: '', city: '' });
8415
7149
  };
8416
7150
 
8417
7151
  const handleRemove = (index: number) => {
8418
- control.remove(index);
7152
+ control.removeAt(index);
8419
7153
  };
8420
7154
 
8421
7155
  return (
@@ -8739,24 +7473,6 @@ export interface UseFormValidationResult {
8739
7473
 
8740
7474
  _Source: src/form/hooks/use-form-validation.ts_
8741
7475
 
8742
- ### ValidateAsyncOptions
8743
-
8744
- **Kind:** `interface`
8745
-
8746
- **Signature:**
8747
- ```typescript
8748
- export interface ValidateAsyncOptions extends ValidateOptions {
8749
- /** Задержка перед выполнением валидации (в мс). */
8750
- debounce?: number;
8751
- }
8752
- ```
8753
-
8754
- **Deprecated:** Осиротевший остаток удалённого оператора `validateAsync` (Ф7): опция `debounce`
8755
- подключалась тем оператором, которого больше нет. Рантаймом не потребляется; экспортируется
8756
- только ради обратной совместимости.
8757
-
8758
- _Source: src/form/types/validation-schema.ts_
8759
-
8760
7476
  ### ValidateOptions
8761
7477
 
8762
7478
  **Kind:** `interface`
@@ -8859,33 +7575,3 @@ watchField(model.$.country, async (country) => {
8859
7575
  ```
8860
7576
 
8861
7577
  _Source: src/state/behaviors-value.ts_
8862
-
8863
- ### WithBehaviorSchema
8864
-
8865
- **Kind:** `interface`
8866
-
8867
- Интерфейс для узлов с методом applyBehaviorSchema
8868
-
8869
- **Signature:**
8870
- ```typescript
8871
- export interface WithBehaviorSchema {
8872
- applyBehaviorSchema(schemaFn: unknown): void;
8873
- }
8874
- ```
8875
-
8876
- _Source: src/form/types/index.ts_
8877
-
8878
- ### WithValidationSchema
8879
-
8880
- **Kind:** `interface`
8881
-
8882
- Интерфейс для узлов с методом applyValidationSchema
8883
-
8884
- **Signature:**
8885
- ```typescript
8886
- export interface WithValidationSchema {
8887
- applyValidationSchema(schemaFn: unknown): void;
8888
- }
8889
- ```
8890
-
8891
- _Source: src/form/types/index.ts_