@reformer/ui-kit 6.0.0 → 7.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.
@@ -1,6 +1,11 @@
1
1
  import { ComponentType, ReactNode } from 'react';
2
2
  import { ArrayNode, FormArrayProxy, FormProxy } from '@reformer/core';
3
3
  import { FieldWrapperProps } from '@reformer/renderer-react';
4
+ /**
5
+ * Пропсы {@link FormArraySection}.
6
+ *
7
+ * @typeParam T - Тип одного элемента массива (object).
8
+ */
4
9
  export interface FormArraySectionProps<T extends object> {
5
10
  /** Уже-резолвленный ArrayNode/ModelArrayNode/FormArrayProxy. */
6
11
  control: FormArrayProxy<T> | ArrayNode<T> | undefined;
@@ -59,4 +64,43 @@ export interface FormArraySectionProps<T extends object> {
59
64
  */
60
65
  fieldWrapper?: ComponentType<FieldWrapperProps>;
61
66
  }
67
+ /**
68
+ * Готовая UI-секция для динамического массива форм — стилизованная обёртка поверх
69
+ * headless-compound `@reformer/cdk/form-array`. Рендерит заголовок, кнопку
70
+ * «Добавить», карточку с меткой на каждый элемент (плюс опциональные кнопки
71
+ * удаления и перестановки ↑/↓) и сообщение пустого состояния.
72
+ *
73
+ * `control` принимает `FormArrayProxy<T>` или уже-резолвленный
74
+ * `ArrayNode<T>`/`ModelArrayNode<T>`. `itemComponent` — единственная форма
75
+ * рендера элемента: `ComponentType<{ control: FormProxy<T> }>` (тот же контракт,
76
+ * что у шага {@link FormWizardStep}). Внутри `RenderNodeComponent` проп `form`
77
+ * инъектится автоматически (маркер `__selfManagedChildren`).
78
+ *
79
+ * Проп `hasItems` удобен для toggle-чекбоксов («У меня есть имущество»): при
80
+ * `false` секция скрывается целиком.
81
+ *
82
+ * @typeParam T - Тип одного элемента массива (object).
83
+ *
84
+ * @example Массив «Имущество» под чекбоксом-переключателем
85
+ * ```tsx
86
+ * import { FormArraySection } from '@reformer/ui-kit/form-array';
87
+ *
88
+ * function AdditionalInfo({ control }: { control: FormProxy<CreditApplication> }) {
89
+ * const hasProperty = useFormControlValue(control.hasProperty) as boolean;
90
+ * return (
91
+ * <FormArraySection
92
+ * title="Имущество"
93
+ * control={control.properties}
94
+ * itemComponent={PropertyForm}
95
+ * itemLabel="Имущество"
96
+ * addButtonLabel="+ Добавить имущество"
97
+ * emptyMessage='Нажмите "Добавить имущество" для добавления информации'
98
+ * hasItems={hasProperty}
99
+ * initialValue={createBlankProperty()}
100
+ * reorderable
101
+ * />
102
+ * );
103
+ * }
104
+ * ```
105
+ */
62
106
  export declare function FormArraySection<T extends object>({ control, itemComponent: ItemComponent, title, itemLabel, addButtonLabel, removeButtonLabel, emptyMessage, emptyMessageHint, hasItems, initialValue, showRemoveOnSingle, reorderable, maxItems, className, cardClassName, }: FormArraySectionProps<T>): ReactNode;
@@ -1,11 +1,47 @@
1
1
  import { FC } from 'react';
2
2
  import { FormWizardActionsRenderProps } from '@reformer/cdk/form-wizard';
3
+ /**
4
+ * Пропсы {@link FormWizardActions}: render-props навигации из headless-слота
5
+ * `<FormWizard.Actions>` (`prev`, `next`, `submit`, `isFirstStep`, `isLastStep`,
6
+ * `isValidating`, `isSubmitting`) плюс переопределяемые подписи кнопок.
7
+ *
8
+ * Все `*Label`-пропсы опциональны и имеют русские дефолты.
9
+ */
3
10
  export interface FormWizardActionsProps extends FormWizardActionsRenderProps {
11
+ /** Внешний CSS-класс контейнера кнопок. */
4
12
  className?: string;
13
+ /** Подпись кнопки «Назад». По умолчанию `'← Назад'`. */
5
14
  prevLabel?: string;
15
+ /** Подпись кнопки «Далее». По умолчанию `'Далее →'`. */
6
16
  nextLabel?: string;
17
+ /** Подпись кнопки отправки на последнем шаге. По умолчанию `'Отправить заявку'`. */
7
18
  submitLabel?: string;
19
+ /** Подпись кнопки «Далее» во время валидации шага. По умолчанию `'Проверка...'`. */
8
20
  validatingLabel?: string;
21
+ /** Подпись кнопки отправки во время submit. По умолчанию `'Отправка...'`. */
9
22
  submittingLabel?: string;
10
23
  }
24
+ /**
25
+ * Кнопки навигации wizard'а: «Назад» / «Далее →» / «Отправить». На первом шаге
26
+ * скрывает «Назад», на последнем показывает «Отправить» вместо «Далее». Во время
27
+ * валидации/отправки показывает промежуточные подписи и блокирует кнопку.
28
+ *
29
+ * Рендерится из headless-слота `<FormWizard.Actions>` через render-prop, поэтому
30
+ * `prev`/`next`/`submit`/флаги приходят автоматически. Готовый {@link FormWizard}
31
+ * уже подключает этот компонент — использовать напрямую нужно только для кастомной
32
+ * раскладки.
33
+ *
34
+ * @example Кастомные подписи в слоте Actions
35
+ * ```tsx
36
+ * <FormWizard.Actions onSubmit={onSubmit}>
37
+ * {(actions) => (
38
+ * <FormWizardActions
39
+ * {...actions}
40
+ * submitLabel="Оформить заявку"
41
+ * className="mt-8"
42
+ * />
43
+ * )}
44
+ * </FormWizard.Actions>
45
+ * ```
46
+ */
11
47
  export declare const FormWizardActions: FC<FormWizardActionsProps>;
@@ -1,7 +1,37 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
  import { FormWizardProgressRenderProps } from '@reformer/cdk/form-wizard';
3
+ /**
4
+ * Пропсы {@link FormWizardProgress}: render-props прогресса из слота
5
+ * `<FormWizard.Progress>` (`current`, `total`, `percent`) плюс `className` и
6
+ * переопределяемый `format`.
7
+ */
3
8
  export interface FormWizardProgressProps extends FormWizardProgressRenderProps {
9
+ /** Внешний CSS-класс контейнера. */
4
10
  className?: string;
11
+ /**
12
+ * Кастомный форматтер строки прогресса. Получает `{ current, total, percent }`.
13
+ * По умолчанию — `'Шаг N из M • X% завершено'`.
14
+ */
5
15
  format?: (props: FormWizardProgressRenderProps) => ReactNode;
6
16
  }
17
+ /**
18
+ * Текстовый индикатор прогресса wizard'а — по умолчанию рендерит
19
+ * «Шаг N из M • X% завершено». Формат строки переопределяется пропом `format`.
20
+ *
21
+ * Рендерится из headless-слота `<FormWizard.Progress>` через render-prop
22
+ * (`current`/`total`/`percent` приходят автоматически). Готовый {@link FormWizard}
23
+ * уже подключает этот компонент; напрямую нужен только для кастомной раскладки.
24
+ *
25
+ * @example Свой формат строки прогресса
26
+ * ```tsx
27
+ * <FormWizard.Progress>
28
+ * {(progress) => (
29
+ * <FormWizardProgress
30
+ * {...progress}
31
+ * format={({ current, total }) => `${current} / ${total}`}
32
+ * />
33
+ * )}
34
+ * </FormWizard.Progress>
35
+ * ```
36
+ */
7
37
  export declare const FormWizardProgress: FC<FormWizardProgressProps>;
@@ -3,28 +3,75 @@ import { FormWizard as FormWizardHeadless, FormWizardActionsProps as HeadlessFor
3
3
  import { FormProxy } from '@reformer/core';
4
4
  import { RenderNode } from '@reformer/renderer-react';
5
5
  /**
6
- * Полиморфное тело шага.
6
+ * Полиморфное тело шага {@link FormWizardStep}. Один и тот же {@link FormWizard}
7
+ * покрывает TS-flow, renderer-react и renderer-json за счёт трёх допустимых форм
8
+ * `body`, дискриминация которых выполняется в рантайме по типу значения:
7
9
  *
8
- * - FC получает `control={form}`.
9
- * - ReactNode рендерится напрямую (статический JSX).
10
- * - RenderNode<T> рендерится через `<RenderNodeComponent>`.
10
+ * - `ComponentType<{ control: FormProxy<T> }>` — React-компонент; получает
11
+ * `control={form}` (корневой {@link FormProxy}) и сам обращается к нужным полям.
12
+ * - `ReactNode` готовый JSX или статический контент шага (текст, число и т.п.).
13
+ * - `RenderNode<T>` — RenderSchema-поддерево; рендерится через `RenderNodeComponent`
14
+ * для интеграции с `@reformer/renderer-react`.
15
+ *
16
+ * @typeParam T - Тип значения корневой формы (`FormProxy<T>`).
17
+ *
18
+ * @example Компонент шага получает control
19
+ * ```tsx
20
+ * function BasicInfoForm({ control }: { control: FormProxy<CreditApplication> }) {
21
+ * return <FormField control={control.loanAmount} testId="loanAmount" />;
22
+ * }
23
+ * const body: FormWizardStepBody<CreditApplication> = BasicInfoForm;
24
+ * ```
11
25
  */
12
26
  export type FormWizardStepBody<T> = ComponentType<{
13
27
  control: FormProxy<T>;
14
28
  }> | ReactNode | RenderNode<T>;
29
+ /**
30
+ * Описание одного шага {@link FormWizard}: порядковый номер, заголовок и иконка
31
+ * для индикатора, плюс полиморфное тело {@link FormWizardStepBody}.
32
+ *
33
+ * Массив `FormWizardStep<T>[]` передаётся в проп `steps`. Порядок и `number`
34
+ * задают последовательность навигации; `number` должен быть 1-based и уникальным.
35
+ *
36
+ * @typeParam T - Тип значения корневой формы (`FormProxy<T>`).
37
+ *
38
+ * @example Массив шагов кредитной заявки
39
+ * ```tsx
40
+ * const STEPS: FormWizardStep<CreditApplication>[] = [
41
+ * { number: 1, title: 'Кредит', icon: '💰', body: BasicInfoForm },
42
+ * { number: 2, title: 'Данные', icon: '👤', body: PersonalInfoForm },
43
+ * { number: 3, title: 'Подтверждение', icon: '✓', body: ConfirmationForm },
44
+ * ];
45
+ * ```
46
+ */
15
47
  export interface FormWizardStep<T> {
16
- /** Step number (1-based). */
48
+ /** Порядковый номер шага (1-based). Уникальный, задаёт порядок навигации. */
17
49
  number: number;
18
- /** Step title shown in indicator. */
50
+ /** Заголовок шага, показывается в {@link StepIndicator}. */
19
51
  title: string;
20
- /** Optional icon (string или ReactNode). Передаётся в headless Indicator. */
52
+ /** Иконка шага (эмодзи или строка). Передаётся в headless Indicator. */
21
53
  icon?: string;
22
- /** Body — FC | ReactNode | RenderNode<T>. */
54
+ /** Тело шага — FC | ReactNode | RenderNode<T> (см. {@link FormWizardStepBody}). */
23
55
  body: FormWizardStepBody<T>;
24
56
  }
57
+ /**
58
+ * Пропсы {@link FormWizard}. Расширяют headless-пропсы из
59
+ * `@reformer/cdk/form-wizard` (`form`, `config`, `onStepChange`, …), добавляя
60
+ * декларативный `steps` и колбэк `onSubmit`.
61
+ *
62
+ * @typeParam T - Тип значения корневой формы. Ограничение `Record<string, any>`
63
+ * синхронизировано с headless-cdk и нужно только как bound для инференции
64
+ * generic'а T в JSX (в т.ч. при nullable-числах вида `number | null`).
65
+ *
66
+ * @see {@link FormWizardStep} — форма элемента `steps`.
67
+ * @see FormWizardHandle — императивный handle через `ref` (submit/навигация).
68
+ */
25
69
  export interface FormWizardProps<T extends Record<string, any>> extends FormWizardHeadlessProps<T> {
70
+ /** Внешний CSS-класс корневого контейнера. */
26
71
  className?: string;
72
+ /** Декларативный список шагов (см. {@link FormWizardStep}). Порядок = порядок навигации. */
27
73
  steps: FormWizardStep<T>[];
74
+ /** Колбэк отправки формы на последнем шаге; вызывается после успешной валидации. */
28
75
  onSubmit: HeadlessFormWizardActionsProps['onSubmit'];
29
76
  }
30
77
  declare const FormWizardForwarded: <T extends Record<string, any>>(props: FormWizardProps<T> & {
@@ -36,5 +83,57 @@ type FormWizardCompound = typeof FormWizardForwarded & {
36
83
  Actions: typeof FormWizardHeadless.Actions;
37
84
  Progress: typeof FormWizardHeadless.Progress;
38
85
  };
86
+ /**
87
+ * Готовая многошаговая форма (multi-step wizard) — стилизованная обёртка поверх
88
+ * headless-compound `@reformer/cdk/form-wizard`. Собирает Indicator, тело шагов,
89
+ * Actions (Назад / Далее / Отправить) и Progress в единый layout, работает с
90
+ * одной {@link FormProxy} и декларативным списком {@link FormWizardStep}.
91
+ *
92
+ * Один компонент покрывает TS-flow, renderer-react и renderer-json за счёт
93
+ * полиморфного {@link FormWizardStepBody}. Валидация по шагам и submit-валидация
94
+ * задаются через `config` (`{ validateStep, validateAll }`, обычно из
95
+ * `validateFormModel`). Императивный доступ (submit/навигация снаружи дерева) —
96
+ * через `ref` типа `FormWizardHandle<T>`.
97
+ *
98
+ * Экспонирует compound-слоты `FormWizard.Indicator` / `.Step` / `.Actions` /
99
+ * `.Progress` для кастомной раскладки.
100
+ *
101
+ * @typeParam T - Тип значения корневой формы (`FormProxy<T>`).
102
+ *
103
+ * @example Кредитная заявка с 3 шагами и внешним submit
104
+ * ```tsx
105
+ * import { useMemo, useRef } from 'react';
106
+ * import { FormWizard, type FormWizardStep } from '@reformer/ui-kit/form-wizard';
107
+ * import type { FormWizardHandle } from '@reformer/cdk/form-wizard';
108
+ *
109
+ * const STEPS: FormWizardStep<CreditApplication>[] = [
110
+ * { number: 1, title: 'Кредит', icon: '💰', body: BasicInfoForm },
111
+ * { number: 2, title: 'Данные', icon: '👤', body: PersonalInfoForm },
112
+ * { number: 3, title: 'Подтверждение', icon: '✓', body: ConfirmationForm },
113
+ * ];
114
+ *
115
+ * function CreditForm() {
116
+ * const navRef = useRef<FormWizardHandle<CreditApplication>>(null);
117
+ * const { form, model } = useMemo(() => createCreditForm(), []);
118
+ * const config = useMemo(() => makeValidationConfig(model), [model]);
119
+ *
120
+ * const onSubmit = () =>
121
+ * navRef.current?.submit((values) => api.submit(values));
122
+ *
123
+ * return (
124
+ * <FormWizard
125
+ * ref={navRef}
126
+ * form={form}
127
+ * config={config}
128
+ * steps={STEPS}
129
+ * onSubmit={onSubmit}
130
+ * />
131
+ * );
132
+ * }
133
+ * ```
134
+ *
135
+ * @see {@link FormWizardStep} — форма элемента `steps`.
136
+ * @see {@link StepIndicator}, {@link FormWizardActions}, {@link FormWizardProgress} — слоты layout'а.
137
+ */
39
138
  declare const FormWizard: FormWizardCompound;
40
139
  export { FormWizard };
@@ -1,10 +1,37 @@
1
1
  import { FC } from 'react';
2
2
  import { FormWizardIndicatorStepWithState, FormWizardIndicatorRenderProps } from '@reformer/cdk/form-wizard';
3
+ /**
4
+ * Пропсы {@link StepIndicator}: render-props индикатора из слота
5
+ * `<FormWizard.Indicator>` (`steps` со статусами, `goToStep`) плюс `className`
6
+ * и настройка aria-меток.
7
+ */
3
8
  export interface StepIndicatorProps extends FormWizardIndicatorRenderProps {
9
+ /** Внешний CSS-класс контейнера. */
4
10
  className?: string;
5
11
  /** Aria-label контейнера навигации. По умолчанию «Шаги формы». */
6
12
  navAriaLabel?: string;
7
13
  /** Кастомный шаблон aria-label для шага. Получает {step}. */
8
14
  stepAriaLabel?: (step: FormWizardIndicatorStepWithState) => string;
9
15
  }
16
+ /**
17
+ * Визуальная цепочка шагов wizard'а — иконки, заголовки и соединительные линии
18
+ * с подсветкой текущего / завершённого шага. Клик (и Enter) по доступному шагу
19
+ * вызывает `goToStep`; недоступные шаги приглушены и не кликабельны. Разметка
20
+ * доступна для скринридеров (`role="navigation"`, `aria-current="step"`,
21
+ * настраиваемые aria-метки).
22
+ *
23
+ * Рендерится из headless-слота `<FormWizard.Indicator>` через render-prop
24
+ * (`steps` со статусами и `goToStep` приходят автоматически). Готовый
25
+ * {@link FormWizard} уже подключает этот компонент; напрямую нужен только для
26
+ * кастомной раскладки.
27
+ *
28
+ * @example Индикатор с кастомной aria-меткой контейнера
29
+ * ```tsx
30
+ * <FormWizard.Indicator steps={steps}>
31
+ * {(indicator) => (
32
+ * <StepIndicator {...indicator} navAriaLabel="Этапы заявки" className="mb-8" />
33
+ * )}
34
+ * </FormWizard.Indicator>
35
+ * ```
36
+ */
10
37
  export declare const StepIndicator: FC<StepIndicatorProps>;
@@ -1,10 +1,31 @@
1
1
  import { ReactNode } from 'react';
2
2
  interface ErrorStateProps {
3
+ /** Текст ошибки, показывается под заголовком. */
3
4
  error: string;
5
+ /** Заголовок блока ошибки. По умолчанию `'Ошибка загрузки'`. */
4
6
  title?: string;
7
+ /** Колбэк повторной попытки. Если задан — рендерится кнопка «Повторить». */
5
8
  onRetry?: () => void;
9
+ /** Подпись кнопки повтора. По умолчанию `'Повторить'`. */
6
10
  retryLabel?: string;
11
+ /** Внешний CSS-класс контейнера. По умолчанию `'w-full'`. */
7
12
  className?: string;
8
13
  }
14
+ /**
15
+ * Состояние ошибки — карточка с иконкой, заголовком, текстом ошибки и
16
+ * опциональной кнопкой повтора. Типовое применение — показать вместо формы,
17
+ * когда не удалось загрузить данные заявки.
18
+ *
19
+ * @param props - Пропсы: `error` (обязателен), `title`, `onRetry`, `retryLabel`, `className`.
20
+ * @returns Разметку блока ошибки.
21
+ *
22
+ * @example Ошибка загрузки с повтором
23
+ * ```tsx
24
+ * const { error } = useLoadCreditApplication(form, '1');
25
+ * if (error) {
26
+ * return <ErrorState error={error} onRetry={() => window.location.reload()} />;
27
+ * }
28
+ * ```
29
+ */
9
30
  export declare function ErrorState({ error, title, onRetry, retryLabel, className, }: ErrorStateProps): ReactNode;
10
31
  export {};
@@ -1,8 +1,26 @@
1
1
  import { ReactNode } from 'react';
2
2
  interface LoadingStateProps {
3
+ /** Основной текст. По умолчанию `'Загрузка данных...'`. */
3
4
  title?: string;
5
+ /** Вспомогательный текст под спиннером. По умолчанию `'Пожалуйста, подождите'`. */
4
6
  subtitle?: string;
7
+ /** Внешний CSS-класс контейнера. По умолчанию центрирует спиннер с отступами. */
5
8
  className?: string;
6
9
  }
10
+ /**
11
+ * Состояние загрузки — центрированный спиннер с заголовком и подзаголовком.
12
+ * Типовое применение — показать вместо формы, пока грузятся данные заявки.
13
+ *
14
+ * @param props - Пропсы: `title`, `subtitle`, `className` (все опциональны).
15
+ * @returns Разметку блока загрузки.
16
+ *
17
+ * @example Загрузка перед рендером формы
18
+ * ```tsx
19
+ * const { isLoading } = useLoadCreditApplication(form, '1');
20
+ * if (isLoading) {
21
+ * return <LoadingState />;
22
+ * }
23
+ * ```
24
+ */
7
25
  export declare function LoadingState({ title, subtitle, className, }: LoadingStateProps): ReactNode;
8
26
  export {};
@@ -49,13 +49,15 @@ export interface AsyncBoundaryProps {
49
49
  *
50
50
  * @example Внутри RenderSchema (статус подставляется через `patchProps`)
51
51
  * ```tsx
52
+ * import { createRenderSchema } from '@reformer/renderer-react';
52
53
  * import { AsyncBoundary } from '@reformer/ui-kit';
53
54
  *
54
- * createRenderSchema((path) => ({
55
+ * // M1: функция схемы не принимает аргументов — привязка к данным идёт через сигналы модели.
56
+ * const schema = createRenderSchema(() => ({
55
57
  * selector: 'data-boundary',
56
58
  * component: AsyncBoundary,
57
59
  * componentProps: { status: 'loading', LoadingComponent: Spinner },
58
- * children: [...],
60
+ * children: [{ value: model.$.email, component: Input }],
59
61
  * }));
60
62
  * // позже: schema.node('data-boundary').patchProps({ status: 'ready' });
61
63
  * ```
@@ -14,26 +14,30 @@ export interface BoxProps {
14
14
  * Простой `<div>` для группировки элементов в `RenderSchema`. Используйте
15
15
  * `className` для настройки layout через atomic CSS (Tailwind).
16
16
  *
17
- * @example Вертикальный список полей в RenderSchema
17
+ * @example Вертикальный список полей в RenderSchema (M1: лист = `value` + `component`)
18
18
  * ```typescript
19
+ * import { Box, Input, InputPassword } from '@reformer/ui-kit';
20
+ *
19
21
  * {
20
22
  * component: Box,
21
23
  * componentProps: { className: 'flex flex-col gap-4' },
22
24
  * children: [
23
- * { component: path.email },
24
- * { component: path.password },
25
+ * { value: model.$.email, component: Input },
26
+ * { value: model.$.password, component: InputPassword },
25
27
  * ],
26
28
  * }
27
29
  * ```
28
30
  *
29
31
  * @example Двухколоночная сетка
30
32
  * ```typescript
33
+ * import { Box, Input } from '@reformer/ui-kit';
34
+ *
31
35
  * {
32
36
  * component: Box,
33
37
  * componentProps: { className: 'grid grid-cols-2 gap-4' },
34
38
  * children: [
35
- * { component: path.firstName },
36
- * { component: path.lastName },
39
+ * { value: model.$.firstName, component: Input },
40
+ * { value: model.$.lastName, component: Input },
37
41
  * ],
38
42
  * }
39
43
  * ```
@@ -21,11 +21,13 @@ export interface CollapsibleProps {
21
21
  *
22
22
  * Заголовок-кнопка переключает видимость `children`. Состояние локальное
23
23
  * (`useState`), внешний control пока не поддерживается — для управляемого
24
- * варианта используй `RenderSchema.node('selector').setHidden(true)` поверх
25
- * обычного `Box`.
24
+ * извне варианта используй `createRenderSchema(...).node('selector').setHidden(true)`
25
+ * поверх обычного `Box`/`Section`.
26
26
  *
27
- * @example Свёрнута по умолчанию
27
+ * @example Свёрнута по умолчанию (M1: лист = `value` + `component`)
28
28
  * ```typescript
29
+ * import { Collapsible, Textarea, Input } from '@reformer/ui-kit';
30
+ *
29
31
  * {
30
32
  * component: Collapsible,
31
33
  * componentProps: {
@@ -35,14 +37,16 @@ export interface CollapsibleProps {
35
37
  * titleClassName: 'font-semibold w-full text-left',
36
38
  * },
37
39
  * children: [
38
- * { component: path.notes },
39
- * { component: path.tags },
40
+ * { value: model.$.notes, component: Textarea },
41
+ * { value: model.$.tags, component: Input },
40
42
  * ],
41
43
  * }
42
44
  * ```
43
45
  *
44
46
  * @example Развёрнута, со специальным фоном контента
45
47
  * ```typescript
48
+ * import { Collapsible, Textarea } from '@reformer/ui-kit';
49
+ *
46
50
  * {
47
51
  * component: Collapsible,
48
52
  * componentProps: {
@@ -51,7 +55,7 @@ export interface CollapsibleProps {
51
55
  * contentClassName: 'mt-2 bg-gray-50 p-3 rounded',
52
56
  * },
53
57
  * children: [
54
- * { component: path.deliveryAddress },
58
+ * { value: model.$.deliveryAddress, component: Textarea },
55
59
  * ],
56
60
  * }
57
61
  * ```
@@ -34,22 +34,31 @@ export interface FormFieldProps {
34
34
  * - Обёрнут в `React.memo` со сравнением по ссылке `control` — критично для
35
35
  * производительности больших форм.
36
36
  *
37
- * @example Standalone в обычной форме
37
+ * @example Standalone в обычной форме (M1: `createModel` + `createForm({ model, schema })`)
38
38
  * ```tsx
39
39
  * import { useMemo } from 'react';
40
- * import { createForm, type FormSchema } from '@reformer/core';
40
+ * import { createModel, createForm } from '@reformer/core';
41
+ * import { required } from '@reformer/core/validators';
41
42
  * import { Button, FormField, Input } from '@reformer/ui-kit';
42
43
  *
43
44
  * function RegistrationPage() {
44
- * const form = useMemo(
45
- * () => createForm<FormSchema<{ email: string }>>({
46
- * email: { component: Input, componentProps: { label: 'Email' } },
47
- * }),
48
- * []
49
- * );
45
+ * const { form } = useMemo(() => {
46
+ * const model = createModel<{ email: string }>({ email: '' });
47
+ * const schema = {
48
+ * children: [
49
+ * {
50
+ * value: model.$.email,
51
+ * component: Input,
52
+ * componentProps: { label: 'Email', type: 'email', testId: 'email' },
53
+ * validators: [required({ message: 'Email обязателен' })],
54
+ * },
55
+ * ],
56
+ * };
57
+ * return { form: createForm<{ email: string }>({ model, schema }) };
58
+ * }, []);
50
59
  * return (
51
60
  * <form>
52
- * <FormField control={form.email} testId="email" />
61
+ * <FormField control={form.email} />
53
62
  * <Button type="submit">OK</Button>
54
63
  * </form>
55
64
  * );
@@ -59,11 +68,15 @@ export interface FormFieldProps {
59
68
  * @example В качестве `fieldWrapper` для FormRenderer
60
69
  * ```tsx
61
70
  * import { FormRenderer, createRenderSchema } from '@reformer/renderer-react';
62
- * import { FormField } from '@reformer/ui-kit';
71
+ * import { Box, FormField, Input } from '@reformer/ui-kit';
63
72
  *
64
- * const schema = createRenderSchema<MyForm>((path) => ({
65
- * component: 'Box',
66
- * children: [{ component: path.email }, { component: path.phone }],
73
+ * // M1: узлы ссылаются на компоненты-значения, листья — на сигналы модели.
74
+ * const schema = createRenderSchema<MyForm>(() => ({
75
+ * component: Box,
76
+ * children: [
77
+ * { value: model.$.email, component: Input },
78
+ * { value: model.$.phone, component: Input },
79
+ * ],
67
80
  * }));
68
81
  *
69
82
  * <FormRenderer render={schema} settings={{ fieldWrapper: FormField }} />
@@ -49,6 +49,27 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
49
49
  * placeholder="Возраст"
50
50
  * />
51
51
  * ```
52
+ *
53
+ * @example Привязка к полю формы через `useFormControl`
54
+ * ```tsx
55
+ * import { useFormControl, type FieldNode } from '@reformer/core';
56
+ * import { Input } from '@reformer/ui-kit';
57
+ *
58
+ * function EmailField({ control }: { control: FieldNode<string> }) {
59
+ * const { value, disabled, errors, shouldShowError } = useFormControl(control);
60
+ * return (
61
+ * <Input
62
+ * type="email"
63
+ * value={value}
64
+ * disabled={disabled}
65
+ * onChange={(v) => control.setValue((v ?? '') as string)}
66
+ * onBlur={() => control.markAsTouched()}
67
+ * aria-invalid={shouldShowError}
68
+ * placeholder={shouldShowError ? errors[0]?.message : 'you@example.com'}
69
+ * />
70
+ * );
71
+ * }
72
+ * ```
52
73
  */
53
74
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
54
75
  export { Input };
@@ -20,8 +20,10 @@ export interface SectionProps {
20
20
  * Семантический `<section>`-контейнер для группировки связанных полей
21
21
  * с опциональным заголовком (`titleAs` управляет уровнем `h1`-`h6`).
22
22
  *
23
- * @example Заголовок h2 + сетка из двух колонок
23
+ * @example Заголовок h2 + сетка из двух колонок (M1: лист = `value` + `component`)
24
24
  * ```typescript
25
+ * import { Section, Input } from '@reformer/ui-kit';
26
+ *
25
27
  * {
26
28
  * component: Section,
27
29
  * componentProps: {
@@ -31,20 +33,22 @@ export interface SectionProps {
31
33
  * className: 'grid grid-cols-2 gap-4',
32
34
  * },
33
35
  * children: [
34
- * { component: path.firstName },
35
- * { component: path.lastName },
36
+ * { value: model.$.firstName, component: Input },
37
+ * { value: model.$.lastName, component: Input },
36
38
  * ],
37
39
  * }
38
40
  * ```
39
41
  *
40
42
  * @example Section без заголовка (только обёртка)
41
43
  * ```typescript
44
+ * import { Section, Input } from '@reformer/ui-kit';
45
+ *
42
46
  * {
43
47
  * component: Section,
44
48
  * componentProps: { className: 'space-y-4 mt-4' },
45
49
  * children: [
46
- * { component: path.address },
47
- * { component: path.city },
50
+ * { value: model.$.address, component: Input },
51
+ * { value: model.$.city, component: Input },
48
52
  * ],
49
53
  * }
50
54
  * ```