@reformer/ui-kit 7.0.0-beta.1 → 7.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/form-array/form-array-section.d.ts +44 -0
- package/dist/components/form-wizard/form-wizard-actions.d.ts +36 -0
- package/dist/components/form-wizard/form-wizard-progress.d.ts +30 -0
- package/dist/components/form-wizard/form-wizard.d.ts +107 -8
- package/dist/components/form-wizard/step-indicator.d.ts +27 -0
- package/dist/components/state/error-state.d.ts +21 -0
- package/dist/components/state/loading-state.d.ts +18 -0
- package/dist/components/ui/async-boundary.d.ts +4 -2
- package/dist/components/ui/box.d.ts +9 -5
- package/dist/components/ui/collapsible.d.ts +10 -6
- package/dist/components/ui/form-field.d.ts +26 -13
- package/dist/components/ui/input.d.ts +21 -0
- package/dist/components/ui/section.d.ts +9 -5
- package/dist/components/ui/select-resource.d.ts +176 -0
- package/dist/components/ui/select-resource.test.d.ts +1 -0
- package/dist/components/ui/select.d.ts +59 -60
- package/dist/index.d.ts +1 -1
- package/dist/ui/select.js +294 -141
- package/llms.txt +774 -251
- package/package.json +1 -1
|
@@ -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
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
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
|
-
/**
|
|
48
|
+
/** Порядковый номер шага (1-based). Уникальный, задаёт порядок навигации. */
|
|
17
49
|
number: number;
|
|
18
|
-
/**
|
|
50
|
+
/** Заголовок шага, показывается в {@link StepIndicator}. */
|
|
19
51
|
title: string;
|
|
20
|
-
/**
|
|
52
|
+
/** Иконка шага (эмодзи или строка). Передаётся в headless Indicator. */
|
|
21
53
|
icon?: string;
|
|
22
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
* {
|
|
24
|
-
* {
|
|
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
|
-
* {
|
|
36
|
-
* {
|
|
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
|
-
* варианта используй `
|
|
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
|
-
* {
|
|
39
|
-
* {
|
|
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
|
-
* {
|
|
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 {
|
|
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
|
-
*
|
|
46
|
-
*
|
|
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}
|
|
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
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
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
|
-
* {
|
|
35
|
-
* {
|
|
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
|
-
* {
|
|
47
|
-
* {
|
|
50
|
+
* { value: model.$.address, component: Input },
|
|
51
|
+
* { value: model.$.city, component: Input },
|
|
48
52
|
* ],
|
|
49
53
|
* }
|
|
50
54
|
* ```
|