@reformer/core 11.0.0-beta.2 → 11.0.0-beta.4
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.d.ts +1 -1
- package/dist/behaviors.js +37 -37
- package/dist/create-model-Dxh9cfLp.js +97 -0
- package/dist/form/behaviors/collections.d.ts +50 -0
- package/dist/form/behaviors/context.d.ts +23 -0
- package/dist/form/behaviors/index.d.ts +28 -0
- package/dist/form/behaviors/internals.d.ts +26 -0
- package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +3 -3
- package/dist/form/behaviors/operators.d.ts +51 -0
- package/dist/form/behaviors/types.d.ts +17 -0
- package/dist/form/create-core-form.d.ts +70 -0
- package/dist/form/create-form.d.ts +1 -1
- package/dist/form/index.d.ts +12 -12
- package/dist/form/nodes/model-array-node.d.ts +1 -1
- package/dist/form/types/contracts.d.ts +9 -6
- package/dist/form/types/validation-schema.d.ts +1 -1
- package/dist/form/validation/config.d.ts +73 -0
- package/dist/form/validation/context.d.ts +27 -0
- package/dist/form/{error-handler.d.ts → validation/error-handler.d.ts} +1 -1
- package/dist/form/validation/index.d.ts +23 -28
- package/dist/form/validation/operators.d.ts +42 -0
- package/dist/form/validation/run.d.ts +45 -0
- package/dist/form/{validation-strategy.d.ts → validation/strategy.d.ts} +10 -4
- package/dist/form/validation/types.d.ts +28 -0
- package/dist/form/{validation/validators → validators}/date-utils.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/email.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/file-type.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/file-utils.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/future-date.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/index.d.ts +6 -4
- package/dist/form/{validation/validators → validators}/integer.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/is-date.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/is-number.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-age.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-date.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-file-size.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-files.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-length.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max-total-file-size.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/max.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min-age.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min-date.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min-file-size.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min-files.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min-length.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/min.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/multiple-of.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/non-negative.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/non-zero.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/past-date.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/pattern.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/phone.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/required.d.ts +1 -1
- package/dist/form/{validation/validators → validators}/url.d.ts +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +708 -479
- package/dist/{state/form-model.d.ts → model/create-model.d.ts} +0 -14
- package/dist/{state → model}/index.d.ts +10 -11
- package/dist/model/model-nodes.d.ts +60 -0
- package/dist/model/model-signals-proxy.d.ts +32 -0
- package/dist/model/model-value-proxy.d.ts +3 -0
- package/dist/{state → model}/safe-effect.d.ts +1 -1
- package/dist/model-signals-proxy-mV3WGdlO.js +233 -0
- package/dist/model.d.ts +2 -0
- package/dist/model.js +21 -0
- package/dist/{form → platforms/react}/hooks/types.d.ts +1 -1
- package/dist/platforms/react/hooks/use-form-bundle.d.ts +26 -0
- package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +3 -3
- package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +1 -1
- package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +3 -3
- package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +2 -2
- package/dist/platforms/react/index.d.ts +23 -0
- package/dist/signals.d.ts +1 -1
- package/dist/strategy-DA3JwxsR.js +170 -0
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +10 -165
- package/dist/validators/email.d.ts +1 -1
- package/dist/validators/future-date.d.ts +1 -1
- package/dist/validators/integer.d.ts +1 -1
- package/dist/validators/is-date.d.ts +1 -1
- package/dist/validators/is-number.d.ts +1 -1
- package/dist/validators/max-age.d.ts +1 -1
- package/dist/validators/max-date.d.ts +1 -1
- package/dist/validators/max-length.d.ts +1 -1
- package/dist/validators/max.d.ts +1 -1
- package/dist/validators/min-age.d.ts +1 -1
- package/dist/validators/min-date.d.ts +1 -1
- package/dist/validators/min-length.d.ts +1 -1
- package/dist/validators/min.d.ts +1 -1
- package/dist/validators/multiple-of.d.ts +1 -1
- package/dist/validators/non-negative.d.ts +1 -1
- package/dist/validators/non-zero.d.ts +1 -1
- package/dist/validators/past-date.d.ts +1 -1
- package/dist/validators/pattern.d.ts +1 -1
- package/dist/validators/phone.d.ts +1 -1
- package/dist/validators/required.d.ts +1 -1
- package/dist/validators/url.d.ts +1 -1
- package/dist/validators.d.ts +1 -1
- package/docs/llms/02-quick-start.md +14 -7
- package/docs/llms/15-project-structure.md +12 -8
- package/llms.txt +329 -53
- package/package.json +4 -4
- package/dist/form/behaviors.d.ts +0 -133
- package/dist/form/validation-schema.d.ts +0 -106
- package/dist/form/validators.d.ts +0 -11
- package/dist/form-model-DhW2HZOB.js +0 -323
- package/dist/state.d.ts +0 -2
- package/dist/state.js +0 -21
- package/dist/subscription-manager-705bls97.js +0 -171
- /package/dist/{state → form/nodes}/subscription-manager.d.ts +0 -0
- /package/dist/{state → model}/behaviors-value.d.ts +0 -0
- /package/dist/{state → model}/derived-registry.d.ts +0 -0
- /package/dist/{state → model}/types.d.ts +0 -0
- /package/dist/{behaviors-node-DGEFMTQu.js → node-DGEFMTQu.js} +0 -0
- /package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +0 -0
package/llms.txt
CHANGED
|
@@ -113,14 +113,15 @@ const { value, errors, disabled } = useFormControl(control.loanType);
|
|
|
113
113
|
> `Checkbox`-обёртки с `label`-prop'ами — это anti-pattern. См.
|
|
114
114
|
> `find_recipe(package="@reformer/ui-kit", topic="form-field-integration")`.
|
|
115
115
|
|
|
116
|
-
Архитектура M1:
|
|
117
|
-
(`
|
|
118
|
-
|
|
116
|
+
Архитектура M1: **модель данных** — источник истины, схема привязывает поля к её сигналам
|
|
117
|
+
(`model.$.field`), а сборка идёт ОДНИМ вызовом `createCoreForm` (для рендера ui-kit;
|
|
118
|
+
в рендерерах — `createReactForm` / `createJsonForm`), который создаёт модель, строит форму,
|
|
119
|
+
запускает поведение и собирает валидацию. Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной
|
|
119
120
|
схеме `defineValidationSchema` из `@reformer/core/validation` и запускается внешним
|
|
120
121
|
раннером `validateModel(model, schema)`.
|
|
121
122
|
|
|
122
123
|
```typescript
|
|
123
|
-
import { createModel,
|
|
124
|
+
import { createCoreForm, createModel, useFormBundle, type FormProxy } from '@reformer/core';
|
|
124
125
|
import { defineValidationSchema, validate, validateModel } from '@reformer/core/validation';
|
|
125
126
|
import { required, email } from '@reformer/core/validators';
|
|
126
127
|
import { FormField, Input, Button } from '@reformer/ui-kit';
|
|
@@ -155,8 +156,14 @@ const contactValidation = defineValidationSchema<ContactForm>(({ model }) => {
|
|
|
155
156
|
validate(model.$.email, [required({ message: 'Email is required' }), email({ message: 'Invalid email' })]);
|
|
156
157
|
});
|
|
157
158
|
|
|
158
|
-
// 5.
|
|
159
|
-
|
|
159
|
+
// 5. Сборка ОДНИМ вызовом: модель + ноды поверх её сигналов + валидация.
|
|
160
|
+
// В React оборачивают в useFormBundle — ленивый useState, фабрика зовётся один раз.
|
|
161
|
+
const contact = createCoreForm<ContactForm>({
|
|
162
|
+
model,
|
|
163
|
+
schema: buildSchema, // билдер (model) => tree
|
|
164
|
+
validation: contactValidation,
|
|
165
|
+
});
|
|
166
|
+
const form = contact.form;
|
|
160
167
|
|
|
161
168
|
// 6. Use in React component — thin JSX, FormField does ALL heavy lifting
|
|
162
169
|
function ContactFormComponent() {
|
|
@@ -227,7 +234,7 @@ const schema = {
|
|
|
227
234
|
properties: { array: model.properties, item: propertyItem },
|
|
228
235
|
};
|
|
229
236
|
|
|
230
|
-
const form =
|
|
237
|
+
const { form } = createCoreForm<MyForm>({ model, schema: () => schema });
|
|
231
238
|
|
|
232
239
|
// Операции над массивом — на модели:
|
|
233
240
|
model.properties.push({ type: 'apartment', description: '', estimatedValue: 0 });
|
|
@@ -1653,7 +1660,7 @@ src/
|
|
|
1653
1660
|
│
|
|
1654
1661
|
├── forms/
|
|
1655
1662
|
│ └── [form-name]/ # Form module — flat, one file per concern
|
|
1656
|
-
│ ├── index.tsx # entry + whole form:
|
|
1663
|
+
│ ├── index.tsx # entry + whole form: ONE createCoreForm call → <FormWizard> with all steps inline; arrays via FormArraySection
|
|
1657
1664
|
│ ├── types.ts # form type + enums + { value, label } option type + constant dictionaries
|
|
1658
1665
|
│ ├── model.ts # createModel + initial values + empty-array-element factories
|
|
1659
1666
|
│ ├── form.schema.ts # FormSchema: { value: model.$.x, component, componentProps }
|
|
@@ -1698,11 +1705,15 @@ export const creditApplicationBehavior = defineFormBehavior<CreditApplicationFor
|
|
|
1698
1705
|
});
|
|
1699
1706
|
|
|
1700
1707
|
// forms/credit-application/index.tsx — entry: assembles the form, renders <FormWizard> with all steps inline
|
|
1701
|
-
import {
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1708
|
+
import { createCoreForm } from '@reformer/core';
|
|
1709
|
+
// ONE call: model + form + behavior + validation. In the page: useFormBundle(createCreditApplicationForm).
|
|
1710
|
+
export const createCreditApplicationForm = () =>
|
|
1711
|
+
createCoreForm({
|
|
1712
|
+
model: createCreditApplicationModel(),
|
|
1713
|
+
schema: creditApplicationSchema, // builder (model) => tree
|
|
1714
|
+
behavior: creditApplicationBehavior,
|
|
1715
|
+
validation: creditApplicationValidation, // { steps, extras } → bundle.validation
|
|
1716
|
+
});
|
|
1706
1717
|
```
|
|
1707
1718
|
|
|
1708
1719
|
### Scaling up: folders (large forms)
|
|
@@ -1728,10 +1739,10 @@ forms/
|
|
|
1728
1739
|
│
|
|
1729
1740
|
├── schema/ # The form definition
|
|
1730
1741
|
│ ├── model.ts # createModel factory + initial values + array-element factories
|
|
1731
|
-
│ ├── schema.ts #
|
|
1742
|
+
│ ├── schema.ts # schema builder (model) => tree ({ value: model.$.x, component })
|
|
1732
1743
|
│ ├── validation.ts # defineValidationSchema + validateModel config ({ validateStep, validateAll })
|
|
1733
1744
|
│ ├── behavior.ts # defineFormBehavior(...)
|
|
1734
|
-
│ └── create-form.ts # Assembly:
|
|
1745
|
+
│ └── create-form.ts # Assembly: createCoreForm({ model, schema, behavior, validation })
|
|
1735
1746
|
│
|
|
1736
1747
|
└── components/
|
|
1737
1748
|
├── steps/ # One component per wizard step
|
|
@@ -4526,7 +4537,7 @@ Add Phone
|
|
|
4526
4537
|
- {@link useFormControl} - хук для получения состояния
|
|
4527
4538
|
- {@link FieldControlState} - состояние для полей
|
|
4528
4539
|
|
|
4529
|
-
_Source: src/
|
|
4540
|
+
_Source: src/platforms/react/hooks/types.ts_
|
|
4530
4541
|
|
|
4531
4542
|
### ArrayNode
|
|
4532
4543
|
|
|
@@ -4644,7 +4655,44 @@ _Source: src/form/types/contracts.ts_
|
|
|
4644
4655
|
export type BehaviorCleanup = () => void;
|
|
4645
4656
|
```
|
|
4646
4657
|
|
|
4647
|
-
_Source: src/
|
|
4658
|
+
_Source: src/model/behaviors-value.ts_
|
|
4659
|
+
|
|
4660
|
+
### buildValidation
|
|
4661
|
+
|
|
4662
|
+
**Kind:** `function`
|
|
4663
|
+
|
|
4664
|
+
Собрать {@link FormValidationBundle} из правил. Принимает либо готовую схему (сахар для простых
|
|
4665
|
+
форм), либо {@link FormValidation} с шагами и стратегией.
|
|
4666
|
+
|
|
4667
|
+
Схема для `validateAll` собирается ОДИН раз на бандл — иначе ломается дедупликация прогонов.
|
|
4668
|
+
|
|
4669
|
+
**Signature:**
|
|
4670
|
+
```typescript
|
|
4671
|
+
export function buildValidation<T>(
|
|
4672
|
+
model: FormModel<T>,
|
|
4673
|
+
validation?: FormValidation<T> | ValidationSchema<T>
|
|
4674
|
+
): FormValidationBundle<T> | undefined
|
|
4675
|
+
```
|
|
4676
|
+
|
|
4677
|
+
**Parameters:**
|
|
4678
|
+
- `model` — - Модель, по которой идут прогоны.
|
|
4679
|
+
- `validation` — - Правила; `undefined` — валидации у формы нет.
|
|
4680
|
+
|
|
4681
|
+
**Returns:** Бандл валидации либо `undefined`, если правила не заданы.
|
|
4682
|
+
|
|
4683
|
+
**Examples:**
|
|
4684
|
+
|
|
4685
|
+
```ts
|
|
4686
|
+
const v = buildValidation(model, {
|
|
4687
|
+
steps: { loan: loanRules, applicant: applicantRules, confirm: null },
|
|
4688
|
+
extras: crossFieldRules,
|
|
4689
|
+
strategy: 'blur',
|
|
4690
|
+
});
|
|
4691
|
+
await v!.validateStep(1); // правила шага `loan`
|
|
4692
|
+
await v!.validateAll(); // все шаги + extras
|
|
4693
|
+
```
|
|
4694
|
+
|
|
4695
|
+
_Source: src/form/validation/config.ts_
|
|
4648
4696
|
|
|
4649
4697
|
### computeFrom
|
|
4650
4698
|
|
|
@@ -4675,7 +4723,7 @@ export function computeFrom<R>(
|
|
|
4675
4723
|
computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price * qty);
|
|
4676
4724
|
```
|
|
4677
4725
|
|
|
4678
|
-
_Source: src/
|
|
4726
|
+
_Source: src/model/behaviors-value.ts_
|
|
4679
4727
|
|
|
4680
4728
|
### ConfigWithSchema
|
|
4681
4729
|
|
|
@@ -4729,7 +4777,7 @@ export function copyFrom<T>(
|
|
|
4729
4777
|
copyFrom(model.$.email, model.$.emailAdditional, { when: () => model.sameEmail });
|
|
4730
4778
|
```
|
|
4731
4779
|
|
|
4732
|
-
_Source: src/
|
|
4780
|
+
_Source: src/model/behaviors-value.ts_
|
|
4733
4781
|
|
|
4734
4782
|
### CORE_RUNTIME_TOKEN
|
|
4735
4783
|
|
|
@@ -4765,6 +4813,75 @@ stampRuntime('@reformer/core', CORE_RUNTIME_TOKEN);
|
|
|
4765
4813
|
|
|
4766
4814
|
_Source: src/runtime-token.ts_
|
|
4767
4815
|
|
|
4816
|
+
### CoreForm
|
|
4817
|
+
|
|
4818
|
+
**Kind:** `interface`
|
|
4819
|
+
|
|
4820
|
+
Результат {@link createCoreForm}: модель, форма и (если заданы правила) собранная валидация.
|
|
4821
|
+
|
|
4822
|
+
**Signature:**
|
|
4823
|
+
```typescript
|
|
4824
|
+
export interface CoreForm<T> {
|
|
4825
|
+
model: FormModel<T>;
|
|
4826
|
+
form: FormProxy<T>;
|
|
4827
|
+
validation?: FormValidationBundle<T>;
|
|
4828
|
+
}
|
|
4829
|
+
```
|
|
4830
|
+
|
|
4831
|
+
_Source: src/form/create-core-form.ts_
|
|
4832
|
+
|
|
4833
|
+
### createCoreForm
|
|
4834
|
+
|
|
4835
|
+
**Kind:** `function`
|
|
4836
|
+
|
|
4837
|
+
Собрать модель, форму и валидацию за один проход.
|
|
4838
|
+
|
|
4839
|
+
**Signature:**
|
|
4840
|
+
```typescript
|
|
4841
|
+
export function createCoreForm<T extends object>(config: CreateCoreFormConfig<T>): CoreForm<T>
|
|
4842
|
+
```
|
|
4843
|
+
|
|
4844
|
+
**Parameters:**
|
|
4845
|
+
- `config` — - {@link CreateCoreFormConfig}: (`initial` | `model`) + опц. `schema`, `behavior`,
|
|
4846
|
+
`validation`, `seed`, `setup`.
|
|
4847
|
+
|
|
4848
|
+
**Returns:**
|
|
4849
|
+
|
|
4850
|
+
**Examples:**
|
|
4851
|
+
|
|
4852
|
+
```tsx
|
|
4853
|
+
const credit = useFormBundle(() =>
|
|
4854
|
+
createCoreForm<CreditForm>({
|
|
4855
|
+
model: createCreditModel(),
|
|
4856
|
+
schema: buildCreditSchema,
|
|
4857
|
+
behavior: creditBehavior,
|
|
4858
|
+
validation: { steps: { loan: loanRules, confirm: null }, extras: crossRules },
|
|
4859
|
+
})
|
|
4860
|
+
);
|
|
4861
|
+
return <FormWizard form={credit.form} config={credit.validation} steps={STEPS} />;
|
|
4862
|
+
```
|
|
4863
|
+
|
|
4864
|
+
_Source: src/form/create-core-form.ts_
|
|
4865
|
+
|
|
4866
|
+
### CreateCoreFormConfig
|
|
4867
|
+
|
|
4868
|
+
**Kind:** `interface`
|
|
4869
|
+
|
|
4870
|
+
Конфиг {@link createCoreForm}.
|
|
4871
|
+
|
|
4872
|
+
**Signature:**
|
|
4873
|
+
```typescript
|
|
4874
|
+
export interface CreateCoreFormConfig<T> extends CreateFormConfigBase<T, CoreForm<T>> {
|
|
4875
|
+
/**
|
|
4876
|
+
* Билдер схемы формы. Именно функция, а не готовое дерево: листья схемы держат сами сигналы
|
|
4877
|
+
* модели (`value: model.$.email`), поэтому построить дерево до модели нечем.
|
|
4878
|
+
*/
|
|
4879
|
+
schema?: (model: FormModel<T>) => FormSchemaNode;
|
|
4880
|
+
}
|
|
4881
|
+
```
|
|
4882
|
+
|
|
4883
|
+
_Source: src/form/create-core-form.ts_
|
|
4884
|
+
|
|
4768
4885
|
### createForm
|
|
4769
4886
|
|
|
4770
4887
|
**Kind:** `function`
|
|
@@ -4817,6 +4934,40 @@ const ok = await validateModel(model, validation);
|
|
|
4817
4934
|
|
|
4818
4935
|
_Source: src/form/create-form.ts_
|
|
4819
4936
|
|
|
4937
|
+
### CreateFormConfigBase
|
|
4938
|
+
|
|
4939
|
+
**Kind:** `interface`
|
|
4940
|
+
|
|
4941
|
+
Общая часть конфига всех фабрик формы.
|
|
4942
|
+
|
|
4943
|
+
**Signature:**
|
|
4944
|
+
```typescript
|
|
4945
|
+
export interface CreateFormConfigBase<T, B> {
|
|
4946
|
+
/** Начальные значения — из них создаётся модель. Взаимоисключимо с `model`. */
|
|
4947
|
+
initial?: T;
|
|
4948
|
+
/** Готовая модель (если создана отдельной фабрикой). Приоритетнее `initial`. */
|
|
4949
|
+
model?: FormModel<T>;
|
|
4950
|
+
/** Декларативное поведение модели (compute/copyFrom/enableWhen/onChange). */
|
|
4951
|
+
behavior?: FormBehavior<T>;
|
|
4952
|
+
/** Правила валидации: готовая схема либо {@link FormValidation} со стратегией и шагами. */
|
|
4953
|
+
validation?: FormValidation<T> | ValidationSchema<T>;
|
|
4954
|
+
/**
|
|
4955
|
+
* Правка модели ДО сборки формы. Нужна там, где значение обязано существовать к моменту
|
|
4956
|
+
* построения нод — например, массив, наполняемый из вычислений (реактивные `onChange` на
|
|
4957
|
+
* инициализации не срабатывают).
|
|
4958
|
+
*/
|
|
4959
|
+
seed?: (model: FormModel<T>) => void;
|
|
4960
|
+
/**
|
|
4961
|
+
* Донастройка ПОСЛЕ сборки. Единственное место для правок, которые обязаны идти следом за
|
|
4962
|
+
* `createForm`: поле, чьё значение уже массив, ноды не получает (см. `buildModelConfig`),
|
|
4963
|
+
* поэтому такой префилл выполняется здесь.
|
|
4964
|
+
*/
|
|
4965
|
+
setup?: (bundle: B) => void;
|
|
4966
|
+
}
|
|
4967
|
+
```
|
|
4968
|
+
|
|
4969
|
+
_Source: src/form/create-core-form.ts_
|
|
4970
|
+
|
|
4820
4971
|
### createFormFromModel
|
|
4821
4972
|
|
|
4822
4973
|
**Kind:** `function`
|
|
@@ -4936,7 +5087,7 @@ model.tags.push('x');
|
|
|
4936
5087
|
model.get(); // { email: 'a@b.c', profile: { name: 'Ada' }, tags: ['x'] }
|
|
4937
5088
|
```
|
|
4938
5089
|
|
|
4939
|
-
_Source: src/
|
|
5090
|
+
_Source: src/model/create-model.ts_
|
|
4940
5091
|
|
|
4941
5092
|
### disableWhen
|
|
4942
5093
|
|
|
@@ -4968,7 +5119,28 @@ export function disableWhen(
|
|
|
4968
5119
|
disableWhen(model.$.discount, () => model.plan !== 'promo', { resetOnDisable: true });
|
|
4969
5120
|
```
|
|
4970
5121
|
|
|
4971
|
-
_Source: src/form/behaviors
|
|
5122
|
+
_Source: src/form/behaviors/node.ts_
|
|
5123
|
+
|
|
5124
|
+
### eachLeafSignal
|
|
5125
|
+
|
|
5126
|
+
**Kind:** `function`
|
|
5127
|
+
|
|
5128
|
+
Обойти ВСЕ листовые сигналы модели (включая элементы массивов), вызвав `visit` на каждом.
|
|
5129
|
+
|
|
5130
|
+
Внутри реактивного `effect` служит подпиской «любое поле изменилось»: `visit(sig => void sig.value)`
|
|
5131
|
+
подписывает на значения листьев, а обход массивов через `items.value` — на их состав. Так строятся
|
|
5132
|
+
триггеры `change`/`blur` стратегий валидации (см. `createFormValidation`), тем же паттерном, что
|
|
5133
|
+
`revalidateWhen`, но без ручного перечисления зависимостей.
|
|
5134
|
+
|
|
5135
|
+
**Signature:**
|
|
5136
|
+
```typescript
|
|
5137
|
+
export function eachLeafSignal<T>(
|
|
5138
|
+
model: FormModel<T>,
|
|
5139
|
+
visit: (signal: PathAwareSignal<unknown>) => void
|
|
5140
|
+
): void
|
|
5141
|
+
```
|
|
5142
|
+
|
|
5143
|
+
_Source: src/model/create-model.ts_
|
|
4972
5144
|
|
|
4973
5145
|
### enableWhen
|
|
4974
5146
|
|
|
@@ -5012,7 +5184,7 @@ compute(model.$.initialPayment, () => model.propertyValue * 0.2, {
|
|
|
5012
5184
|
});
|
|
5013
5185
|
```
|
|
5014
5186
|
|
|
5015
|
-
_Source: src/form/behaviors
|
|
5187
|
+
_Source: src/form/behaviors/node.ts_
|
|
5016
5188
|
|
|
5017
5189
|
### ErrorFilterOptions
|
|
5018
5190
|
|
|
@@ -5070,7 +5242,7 @@ export enum ErrorStrategy {
|
|
|
5070
5242
|
}
|
|
5071
5243
|
```
|
|
5072
5244
|
|
|
5073
|
-
_Source: src/form/error-handler.ts_
|
|
5245
|
+
_Source: src/form/validation/error-handler.ts_
|
|
5074
5246
|
|
|
5075
5247
|
### FieldConfig
|
|
5076
5248
|
|
|
@@ -5332,7 +5504,7 @@ onChange={e => control.setValue(e.target.value)}
|
|
|
5332
5504
|
- {@link useFormControl} - хук для получения состояния
|
|
5333
5505
|
- {@link ArrayControlState} - состояние для массивов
|
|
5334
5506
|
|
|
5335
|
-
_Source: src/
|
|
5507
|
+
_Source: src/platforms/react/hooks/types.ts_
|
|
5336
5508
|
|
|
5337
5509
|
### FieldNode
|
|
5338
5510
|
|
|
@@ -5431,6 +5603,21 @@ todos.forEach((item, i) => {
|
|
|
5431
5603
|
|
|
5432
5604
|
_Source: src/form/types/form-proxy.ts_
|
|
5433
5605
|
|
|
5606
|
+
### FormBundleLike
|
|
5607
|
+
|
|
5608
|
+
**Kind:** `interface`
|
|
5609
|
+
|
|
5610
|
+
Минимум, который хук ожидает от бандла: опциональный контроллер живой валидации.
|
|
5611
|
+
|
|
5612
|
+
**Signature:**
|
|
5613
|
+
```typescript
|
|
5614
|
+
export interface FormBundleLike {
|
|
5615
|
+
validation?: { controller: FormValidationController };
|
|
5616
|
+
}
|
|
5617
|
+
```
|
|
5618
|
+
|
|
5619
|
+
_Source: src/platforms/react/hooks/use-form-bundle.ts_
|
|
5620
|
+
|
|
5434
5621
|
### FormControlsProxy
|
|
5435
5622
|
|
|
5436
5623
|
**Kind:** `type`
|
|
@@ -5543,7 +5730,7 @@ try {
|
|
|
5543
5730
|
}
|
|
5544
5731
|
```
|
|
5545
5732
|
|
|
5546
|
-
_Source: src/form/error-handler.ts_
|
|
5733
|
+
_Source: src/form/validation/error-handler.ts_
|
|
5547
5734
|
|
|
5548
5735
|
### FormModel
|
|
5549
5736
|
|
|
@@ -5558,7 +5745,7 @@ FormModel — под-модель объекта `T`: value-доступ ({@link
|
|
|
5558
5745
|
export type FormModel<T> = ModelObject<T> & ModelApi<T>;
|
|
5559
5746
|
```
|
|
5560
5747
|
|
|
5561
|
-
_Source: src/
|
|
5748
|
+
_Source: src/model/types.ts_
|
|
5562
5749
|
|
|
5563
5750
|
### FormNode
|
|
5564
5751
|
|
|
@@ -5823,6 +6010,70 @@ if (submitter.submitting.value) {
|
|
|
5823
6010
|
|
|
5824
6011
|
_Source: src/form/form-submitter.ts_
|
|
5825
6012
|
|
|
6013
|
+
### FormValidation
|
|
6014
|
+
|
|
6015
|
+
**Kind:** `interface`
|
|
6016
|
+
|
|
6017
|
+
Правила валидации формы — ДАННЫЕ (без привязки к рендеру).
|
|
6018
|
+
|
|
6019
|
+
⚠️ `schema` и значения `steps` обязаны быть **стабильными ссылками**: отмена устаревших прогонов
|
|
6020
|
+
ключуется по паре `(model, schema)` через `WeakMap`, поэтому инлайн-стрелка ломает дедупликацию —
|
|
6021
|
+
валидация начнёт возвращать `false` от уже отменённых прогонов. Держите их
|
|
6022
|
+
module-level-константами (`defineValidationSchema`).
|
|
6023
|
+
|
|
6024
|
+
**Signature:**
|
|
6025
|
+
```typescript
|
|
6026
|
+
export interface FormValidation<T> {
|
|
6027
|
+
/** Полный набор правил — для submit и `validateAll`. Без него собирается из `steps` + `extras`. */
|
|
6028
|
+
schema?: ValidationSchema<T>;
|
|
6029
|
+
/**
|
|
6030
|
+
* Пошаговая валидация визарда: ключ = `selector` шага. `null` означает «шаг без правил» ЯВНО —
|
|
6031
|
+
* чтобы опечатка в ключе не выглядела как пустой шаг.
|
|
6032
|
+
*/
|
|
6033
|
+
steps?: Record<string, ValidationSchema<T> | null>;
|
|
6034
|
+
/** Cross-field правила, которые проверяются только целиком (в `validateAll`), но не по шагам. */
|
|
6035
|
+
extras?: ValidationSchema<T>;
|
|
6036
|
+
/** Когда запускать живую валидацию. По умолчанию `'submit'` (реактивно молчит). */
|
|
6037
|
+
strategy?: ValidationStrategyKind;
|
|
6038
|
+
debounce?: number;
|
|
6039
|
+
/** Режим live-фазы для `afterFirstSubmit`. По умолчанию `'change'`. */
|
|
6040
|
+
liveAfterSubmit?: 'change' | 'blur';
|
|
6041
|
+
}
|
|
6042
|
+
```
|
|
6043
|
+
|
|
6044
|
+
_Source: src/form/validation/config.ts_
|
|
6045
|
+
|
|
6046
|
+
### FormValidationBundle
|
|
6047
|
+
|
|
6048
|
+
**Kind:** `interface`
|
|
6049
|
+
|
|
6050
|
+
Собранная валидация формы. Структурно совместима с `FormWizardConfig` и `StepValidationConfig`
|
|
6051
|
+
из `@reformer/cdk`, поэтому уходит в визард как есть: `config={bundle.validation}` либо
|
|
6052
|
+
`patchProps({ form, ...bundle.validation })`.
|
|
6053
|
+
|
|
6054
|
+
**Signature:**
|
|
6055
|
+
```typescript
|
|
6056
|
+
export interface FormValidationBundle<T> {
|
|
6057
|
+
/** Полная схема (стабильная ссылка) — та, по которой идёт `validateAll`. */
|
|
6058
|
+
readonly schema: ValidationSchema<T>;
|
|
6059
|
+
/** Селекторы шагов в порядке объявления. Пусто, если `steps` не заданы. */
|
|
6060
|
+
readonly stepSelectors: readonly string[];
|
|
6061
|
+
/** Полный прогон с раскрытием ошибок. Синоним {@link FormValidationBundle.validateAll}. */
|
|
6062
|
+
validate(): Promise<boolean>;
|
|
6063
|
+
validateAll(): Promise<boolean>;
|
|
6064
|
+
/** Прогон правил одного шага: по номеру (1-based, как у визарда) или по селектору. */
|
|
6065
|
+
validateStep(step: number | string): Promise<boolean>;
|
|
6066
|
+
/** Контроллер живой валидации ШАГА; `null` — у шага нет правил либо стратегия `submit`. */
|
|
6067
|
+
createStepController(step: number | string): FormValidationController | null;
|
|
6068
|
+
/** Контроллер живой валидации ФОРМЫ. Армится хуком (`useFormBundle`), не фабрикой. */
|
|
6069
|
+
readonly controller: FormValidationController;
|
|
6070
|
+
/** Идёт ли прогон — реактивный сигнал (для тонкой подписки в UI). */
|
|
6071
|
+
readonly validating: ReadonlySignal<boolean>;
|
|
6072
|
+
}
|
|
6073
|
+
```
|
|
6074
|
+
|
|
6075
|
+
_Source: src/form/validation/config.ts_
|
|
6076
|
+
|
|
5826
6077
|
### FormValue
|
|
5827
6078
|
|
|
5828
6079
|
**Kind:** `type`
|
|
@@ -6024,7 +6275,7 @@ if (!isDerived(model.$.total)) {
|
|
|
6024
6275
|
**See also:**
|
|
6025
6276
|
- {@link markDerived} - пометить сигнал производным
|
|
6026
6277
|
|
|
6027
|
-
_Source: src/
|
|
6278
|
+
_Source: src/model/derived-registry.ts_
|
|
6028
6279
|
|
|
6029
6280
|
### isFieldNode
|
|
6030
6281
|
|
|
@@ -6136,7 +6387,7 @@ export function isModelContainerSignal(value: unknown): boolean
|
|
|
6136
6387
|
const isLeaf = (v: unknown) => isSignalLike(v) && !isModelContainerSignal(v);
|
|
6137
6388
|
```
|
|
6138
6389
|
|
|
6139
|
-
_Source: src/
|
|
6390
|
+
_Source: src/model/model-signals-proxy.ts_
|
|
6140
6391
|
|
|
6141
6392
|
### markDerived
|
|
6142
6393
|
|
|
@@ -6172,7 +6423,7 @@ markDerived(model.$.total);
|
|
|
6172
6423
|
- {@link isDerived} - проверка пометки
|
|
6173
6424
|
- {@link unmarkDerived} - снять пометку при dispose оператора
|
|
6174
6425
|
|
|
6175
|
-
_Source: src/
|
|
6426
|
+
_Source: src/model/derived-registry.ts_
|
|
6176
6427
|
|
|
6177
6428
|
### ModelApi
|
|
6178
6429
|
|
|
@@ -6215,7 +6466,7 @@ export interface ModelApi<T> {
|
|
|
6215
6466
|
}
|
|
6216
6467
|
```
|
|
6217
6468
|
|
|
6218
|
-
_Source: src/
|
|
6469
|
+
_Source: src/model/types.ts_
|
|
6219
6470
|
|
|
6220
6471
|
### ModelArray
|
|
6221
6472
|
|
|
@@ -6261,7 +6512,7 @@ export interface ModelArray<U> {
|
|
|
6261
6512
|
}
|
|
6262
6513
|
```
|
|
6263
6514
|
|
|
6264
|
-
_Source: src/
|
|
6515
|
+
_Source: src/model/types.ts_
|
|
6265
6516
|
|
|
6266
6517
|
### ModelArrayControl
|
|
6267
6518
|
|
|
@@ -6350,7 +6601,7 @@ export type ModelArraySignals<U, V> = ContainerSignal<V, 'length'> & {
|
|
|
6350
6601
|
};
|
|
6351
6602
|
```
|
|
6352
6603
|
|
|
6353
|
-
_Source: src/
|
|
6604
|
+
_Source: src/model/types.ts_
|
|
6354
6605
|
|
|
6355
6606
|
### ModelGroupSignals
|
|
6356
6607
|
|
|
@@ -6367,7 +6618,7 @@ _Source: src/state/types.ts_
|
|
|
6367
6618
|
export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;
|
|
6368
6619
|
```
|
|
6369
6620
|
|
|
6370
|
-
_Source: src/
|
|
6621
|
+
_Source: src/model/types.ts_
|
|
6371
6622
|
|
|
6372
6623
|
### ModelObject
|
|
6373
6624
|
|
|
@@ -6384,7 +6635,7 @@ export type ModelObject<T> = {
|
|
|
6384
6635
|
};
|
|
6385
6636
|
```
|
|
6386
6637
|
|
|
6387
|
-
_Source: src/
|
|
6638
|
+
_Source: src/model/types.ts_
|
|
6388
6639
|
|
|
6389
6640
|
### ModelSignals
|
|
6390
6641
|
|
|
@@ -6400,7 +6651,7 @@ export type ModelSignals<T> = {
|
|
|
6400
6651
|
};
|
|
6401
6652
|
```
|
|
6402
6653
|
|
|
6403
|
-
_Source: src/
|
|
6654
|
+
_Source: src/model/types.ts_
|
|
6404
6655
|
|
|
6405
6656
|
### ModelValue
|
|
6406
6657
|
|
|
@@ -6425,7 +6676,7 @@ export type ModelValue<V> =
|
|
|
6425
6676
|
: V;
|
|
6426
6677
|
```
|
|
6427
6678
|
|
|
6428
|
-
_Source: src/
|
|
6679
|
+
_Source: src/model/types.ts_
|
|
6429
6680
|
|
|
6430
6681
|
### NodeFactory
|
|
6431
6682
|
|
|
@@ -6512,7 +6763,7 @@ export type PathAwareSignal<T> = Signal<T> & {
|
|
|
6512
6763
|
};
|
|
6513
6764
|
```
|
|
6514
6765
|
|
|
6515
|
-
_Source: src/
|
|
6766
|
+
_Source: src/model/types.ts_
|
|
6516
6767
|
|
|
6517
6768
|
### registerSignalNode
|
|
6518
6769
|
|
|
@@ -6569,7 +6820,7 @@ export function resetWhen<T>(
|
|
|
6569
6820
|
resetWhen(model.$.cardNumber, () => model.paymentType !== 'card', { resetValue: '' });
|
|
6570
6821
|
```
|
|
6571
6822
|
|
|
6572
|
-
_Source: src/
|
|
6823
|
+
_Source: src/model/behaviors-value.ts_
|
|
6573
6824
|
|
|
6574
6825
|
### revalidateWhen
|
|
6575
6826
|
|
|
@@ -6592,7 +6843,7 @@ export function revalidateWhen(
|
|
|
6592
6843
|
revalidateWhen([model.$.maxAmount], () => void validateModel(model, schema));
|
|
6593
6844
|
```
|
|
6594
6845
|
|
|
6595
|
-
_Source: src/
|
|
6846
|
+
_Source: src/model/behaviors-value.ts_
|
|
6596
6847
|
|
|
6597
6848
|
### runOutsideEffect
|
|
6598
6849
|
|
|
@@ -6626,7 +6877,7 @@ effect(() => {
|
|
|
6626
6877
|
});
|
|
6627
6878
|
```
|
|
6628
6879
|
|
|
6629
|
-
_Source: src/
|
|
6880
|
+
_Source: src/model/safe-effect.ts_
|
|
6630
6881
|
|
|
6631
6882
|
### safeCallback
|
|
6632
6883
|
|
|
@@ -6665,7 +6916,7 @@ effect(() => {
|
|
|
6665
6916
|
});
|
|
6666
6917
|
```
|
|
6667
6918
|
|
|
6668
|
-
_Source: src/
|
|
6919
|
+
_Source: src/model/safe-effect.ts_
|
|
6669
6920
|
|
|
6670
6921
|
### safeDebouncedCallback
|
|
6671
6922
|
|
|
@@ -6703,7 +6954,7 @@ return effect(() => {
|
|
|
6703
6954
|
});
|
|
6704
6955
|
```
|
|
6705
6956
|
|
|
6706
|
-
_Source: src/
|
|
6957
|
+
_Source: src/model/safe-effect.ts_
|
|
6707
6958
|
|
|
6708
6959
|
### SchemaArrayControl
|
|
6709
6960
|
|
|
@@ -6846,7 +7097,7 @@ class FieldNode {
|
|
|
6846
7097
|
}
|
|
6847
7098
|
```
|
|
6848
7099
|
|
|
6849
|
-
_Source: src/
|
|
7100
|
+
_Source: src/form/nodes/subscription-manager.ts_
|
|
6850
7101
|
|
|
6851
7102
|
### syncFields
|
|
6852
7103
|
|
|
@@ -6870,7 +7121,7 @@ export function syncFields<T>(
|
|
|
6870
7121
|
syncFields(model.$.field1, model.$.field2);
|
|
6871
7122
|
```
|
|
6872
7123
|
|
|
6873
|
-
_Source: src/
|
|
7124
|
+
_Source: src/model/behaviors-value.ts_
|
|
6874
7125
|
|
|
6875
7126
|
### transformValue
|
|
6876
7127
|
|
|
@@ -6893,7 +7144,7 @@ export function transformValue<T>(
|
|
|
6893
7144
|
transformValue(model.$.promoCode, (v) => (v ?? '').toUpperCase());
|
|
6894
7145
|
```
|
|
6895
7146
|
|
|
6896
|
-
_Source: src/
|
|
7147
|
+
_Source: src/model/behaviors-value.ts_
|
|
6897
7148
|
|
|
6898
7149
|
### UnknownRecord
|
|
6899
7150
|
|
|
@@ -6943,7 +7194,7 @@ onDispose(() => unmarkDerived(model.$.total)); // при снятии compute с
|
|
|
6943
7194
|
**See also:**
|
|
6944
7195
|
- {@link markDerived} - пометить сигнал производным
|
|
6945
7196
|
|
|
6946
|
-
_Source: src/
|
|
7197
|
+
_Source: src/model/derived-registry.ts_
|
|
6947
7198
|
|
|
6948
7199
|
### useArrayLength
|
|
6949
7200
|
|
|
@@ -6981,7 +7232,32 @@ function ArrayRenderer({ arrayNode }) {
|
|
|
6981
7232
|
}
|
|
6982
7233
|
```
|
|
6983
7234
|
|
|
6984
|
-
_Source: src/
|
|
7235
|
+
_Source: src/platforms/react/hooks/useArrayLength.ts_
|
|
7236
|
+
|
|
7237
|
+
### useFormBundle
|
|
7238
|
+
|
|
7239
|
+
**Kind:** `function`
|
|
7240
|
+
|
|
7241
|
+
Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте
|
|
7242
|
+
(не при SSR — там эффекты не выполняются).
|
|
7243
|
+
|
|
7244
|
+
**Signature:**
|
|
7245
|
+
```typescript
|
|
7246
|
+
export function useFormBundle<B extends FormBundleLike>(factory: () => B): B
|
|
7247
|
+
```
|
|
7248
|
+
|
|
7249
|
+
**Parameters:**
|
|
7250
|
+
- `factory` — - Фабрика бандла, обычно `() => createCoreForm({…})`.
|
|
7251
|
+
|
|
7252
|
+
**Returns:** Стабильный бандл.
|
|
7253
|
+
|
|
7254
|
+
**Examples:**
|
|
7255
|
+
|
|
7256
|
+
```tsx
|
|
7257
|
+
const credit = useFormBundle(() => createCoreForm<CreditForm>({ model: createCreditModel() }));
|
|
7258
|
+
```
|
|
7259
|
+
|
|
7260
|
+
_Source: src/platforms/react/hooks/use-form-bundle.ts_
|
|
6985
7261
|
|
|
6986
7262
|
### useFormControl
|
|
6987
7263
|
|
|
@@ -7215,7 +7491,7 @@ return <div>Items: {length}</div>;
|
|
|
7215
7491
|
- {@link FieldControlState} - тип состояния для FieldNode
|
|
7216
7492
|
- {@link ArrayControlState} - тип состояния для ArrayNode
|
|
7217
7493
|
|
|
7218
|
-
_Source: src/
|
|
7494
|
+
_Source: src/platforms/react/hooks/useFormControl.ts_
|
|
7219
7495
|
|
|
7220
7496
|
### useFormControlValue
|
|
7221
7497
|
|
|
@@ -7396,7 +7672,7 @@ return (
|
|
|
7396
7672
|
- {@link useFormControl} - для полного состояния поля
|
|
7397
7673
|
- {@link FieldNode} - тип контрола поля
|
|
7398
7674
|
|
|
7399
|
-
_Source: src/
|
|
7675
|
+
_Source: src/platforms/react/hooks/useFormControlValue.ts_
|
|
7400
7676
|
|
|
7401
7677
|
### useFormValidation
|
|
7402
7678
|
|
|
@@ -7431,7 +7707,7 @@ function MyForm() {
|
|
|
7431
7707
|
}
|
|
7432
7708
|
```
|
|
7433
7709
|
|
|
7434
|
-
_Source: src/
|
|
7710
|
+
_Source: src/platforms/react/hooks/use-form-validation.ts_
|
|
7435
7711
|
|
|
7436
7712
|
### UseFormValidationArgs
|
|
7437
7713
|
|
|
@@ -7453,7 +7729,7 @@ export interface UseFormValidationArgs<T> {
|
|
|
7453
7729
|
}
|
|
7454
7730
|
```
|
|
7455
7731
|
|
|
7456
|
-
_Source: src/
|
|
7732
|
+
_Source: src/platforms/react/hooks/use-form-validation.ts_
|
|
7457
7733
|
|
|
7458
7734
|
### UseFormValidationResult
|
|
7459
7735
|
|
|
@@ -7471,7 +7747,7 @@ export interface UseFormValidationResult {
|
|
|
7471
7747
|
}
|
|
7472
7748
|
```
|
|
7473
7749
|
|
|
7474
|
-
_Source: src/
|
|
7750
|
+
_Source: src/platforms/react/hooks/use-form-validation.ts_
|
|
7475
7751
|
|
|
7476
7752
|
### ValidateOptions
|
|
7477
7753
|
|
|
@@ -7574,4 +7850,4 @@ watchField(model.$.country, async (country) => {
|
|
|
7574
7850
|
});
|
|
7575
7851
|
```
|
|
7576
7852
|
|
|
7577
|
-
_Source: src/
|
|
7853
|
+
_Source: src/model/behaviors-value.ts_
|