@reformer/ui-kit 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/components/form-array/form-array-section.d.ts +60 -0
- package/dist/components/form-array/index.d.ts +2 -0
- package/dist/components/form-wizard/form-wizard-actions.d.ts +11 -0
- package/dist/components/form-wizard/form-wizard-progress.d.ts +7 -0
- package/dist/components/form-wizard/form-wizard.d.ts +40 -0
- package/dist/components/form-wizard/index.d.ts +8 -0
- package/dist/components/form-wizard/step-indicator.d.ts +10 -0
- package/dist/components/state/error-state.d.ts +10 -0
- package/dist/components/state/index.d.ts +2 -0
- package/dist/components/state/loading-state.d.ts +8 -0
- package/dist/components/ui/async-boundary.d.ts +63 -0
- package/dist/components/ui/box.d.ts +41 -0
- package/dist/components/ui/button.d.ts +35 -0
- package/dist/components/ui/checkbox.d.ts +48 -0
- package/dist/components/ui/collapsible.d.ts +59 -0
- package/dist/components/ui/example-card.d.ts +57 -0
- package/dist/components/ui/form-field.d.ts +72 -0
- package/dist/components/ui/input-mask.d.ts +52 -0
- package/dist/components/ui/input-password.d.ts +51 -0
- package/dist/components/ui/input.d.ts +54 -0
- package/dist/components/ui/radio-group.d.ts +60 -0
- package/dist/components/ui/section.d.ts +52 -0
- package/dist/components/ui/select.d.ts +316 -0
- package/dist/components/ui/textarea.d.ts +53 -0
- package/dist/form-array-section-CItAR061.js +92 -0
- package/dist/form-array.d.ts +2 -0
- package/dist/form-array.js +4 -0
- package/dist/form-wizard-C-yRYqTI.js +118 -0
- package/dist/form-wizard.d.ts +2 -0
- package/dist/form-wizard.js +7 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +170 -0
- package/dist/lib/utils.d.ts +29 -0
- package/dist/loading-state-4VeOE6iN.js +38 -0
- package/dist/state.d.ts +2 -0
- package/dist/state.js +5 -0
- package/dist/ui/async-boundary.d.ts +2 -0
- package/dist/ui/async-boundary.js +12 -0
- package/dist/ui/box.d.ts +2 -0
- package/dist/ui/box.js +7 -0
- package/dist/ui/button.d.ts +2 -0
- package/dist/ui/button.js +78 -0
- package/dist/ui/checkbox.d.ts +2 -0
- package/dist/ui/checkbox.js +35 -0
- package/dist/ui/collapsible.d.ts +2 -0
- package/dist/ui/collapsible.js +31 -0
- package/dist/ui/form-field.d.ts +2 -0
- package/dist/ui/form-field.js +217 -0
- package/dist/ui/input-mask.d.ts +2 -0
- package/dist/ui/input-mask.js +36 -0
- package/dist/ui/input-password.d.ts +2 -0
- package/dist/ui/input-password.js +72 -0
- package/dist/ui/input.d.ts +2 -0
- package/dist/ui/input.js +48 -0
- package/dist/ui/radio-group.d.ts +2 -0
- package/dist/ui/radio-group.js +53 -0
- package/dist/ui/section.d.ts +2 -0
- package/dist/ui/section.js +16 -0
- package/dist/ui/select.d.ts +2 -0
- package/dist/ui/select.js +241 -0
- package/dist/ui/textarea.d.ts +2 -0
- package/dist/ui/textarea.js +38 -0
- package/dist/utils-DtaLkIY8.js +2776 -0
- package/llms.txt +3652 -0
- package/package.json +161 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alexandr Bukhtatyy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @reformer/ui-kit
|
|
2
|
+
|
|
3
|
+
Headless UI components for `@reformer/core` - build accessible, fully customizable form interfaces.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Headless** - No default styles, complete design freedom
|
|
8
|
+
- **Compound Components** - Declarative, composable API
|
|
9
|
+
- **Render Props** - Full control over rendering
|
|
10
|
+
- **TypeScript** - Fully typed with generics support
|
|
11
|
+
- **Tree-shakable** - Import only what you need
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @reformer/cdk @reformer/core
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Components
|
|
20
|
+
|
|
21
|
+
### FormArray
|
|
22
|
+
|
|
23
|
+
Manage dynamic form arrays with add/remove functionality.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { FormArray } from '@reformer/cdk/form-array';
|
|
27
|
+
|
|
28
|
+
<FormArray.Root control={form.items}>
|
|
29
|
+
<FormArray.Empty>
|
|
30
|
+
<p>No items yet</p>
|
|
31
|
+
</FormArray.Empty>
|
|
32
|
+
|
|
33
|
+
<FormArray.List>
|
|
34
|
+
{({ control, index, remove }) => (
|
|
35
|
+
<div>
|
|
36
|
+
<span>Item #{index + 1}</span>
|
|
37
|
+
<ItemForm control={control} />
|
|
38
|
+
<button onClick={remove}>Remove</button>
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
41
|
+
</FormArray.List>
|
|
42
|
+
|
|
43
|
+
<FormArray.AddButton>Add Item</FormArray.AddButton>
|
|
44
|
+
</FormArray.Root>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### FormWizard
|
|
48
|
+
|
|
49
|
+
Build multi-step form wizards with validation.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { FormWizard } from '@reformer/cdk/form-wizard';
|
|
53
|
+
|
|
54
|
+
<FormWizard form={form} config={config}>
|
|
55
|
+
<FormWizard.Indicator steps={STEPS}>
|
|
56
|
+
{({ steps, goToStep }) => (
|
|
57
|
+
<nav>
|
|
58
|
+
{steps.map((step) => (
|
|
59
|
+
<button
|
|
60
|
+
key={step.number}
|
|
61
|
+
onClick={() => goToStep(step.number)}
|
|
62
|
+
disabled={!step.canNavigate}
|
|
63
|
+
>
|
|
64
|
+
{step.title}
|
|
65
|
+
</button>
|
|
66
|
+
))}
|
|
67
|
+
</nav>
|
|
68
|
+
)}
|
|
69
|
+
</FormWizard.Indicator>
|
|
70
|
+
|
|
71
|
+
<FormWizard.Step component={Step1} control={form} />
|
|
72
|
+
<FormWizard.Step component={Step2} control={form} />
|
|
73
|
+
|
|
74
|
+
<FormWizard.Actions onSubmit={handleSubmit}>
|
|
75
|
+
{({ prev, next, submit, isFirstStep, isLastStep }) => (
|
|
76
|
+
<div>
|
|
77
|
+
{!isFirstStep && <button {...prev}>Back</button>}
|
|
78
|
+
{!isLastStep ? <button {...next}>Next</button> : <button {...submit}>Submit</button>}
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</FormWizard.Actions>
|
|
82
|
+
</FormWizard>;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Hooks
|
|
86
|
+
|
|
87
|
+
For full customization, use the hooks directly:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { useFormArray } from '@reformer/cdk/form-array';
|
|
91
|
+
import { useFormWizard } from '@reformer/cdk/form-wizard';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
import { ArrayNode, FieldPathNode, FormArrayProxy, FormFields, FormProxy } from '@reformer/core';
|
|
3
|
+
import { FieldWrapperProps } from '@reformer/renderer-react';
|
|
4
|
+
export interface FormArraySectionProps<T extends FormFields> {
|
|
5
|
+
/**
|
|
6
|
+
* Резолвится автоматически: уже-резолвленный ArrayNode/FormArrayProxy ИЛИ
|
|
7
|
+
* FieldPathNode (path.<arrayField>) — в этом случае через `form` + navigator.
|
|
8
|
+
*/
|
|
9
|
+
control: FormArrayProxy<T> | ArrayNode<T> | FieldPathNode<unknown, unknown> | undefined;
|
|
10
|
+
/** React FC получает `control: FormProxy<T>` для каждого элемента. */
|
|
11
|
+
itemComponent: ComponentType<{
|
|
12
|
+
control: FormProxy<T>;
|
|
13
|
+
}>;
|
|
14
|
+
/** Заголовок секции (рендерится h3). */
|
|
15
|
+
title?: string;
|
|
16
|
+
/** Метка для каждого item — строка-префикс или функция. */
|
|
17
|
+
itemLabel?: string | ((control: FormProxy<T>, index: number) => string);
|
|
18
|
+
/** Текст кнопки добавления. По умолчанию `'+ Добавить'`. */
|
|
19
|
+
addButtonLabel?: string;
|
|
20
|
+
/** Текст кнопки удаления. По умолчанию `'Удалить'`. */
|
|
21
|
+
removeButtonLabel?: string;
|
|
22
|
+
/** Сообщение пустого состояния. */
|
|
23
|
+
emptyMessage?: string;
|
|
24
|
+
/** Подсказка под пустым состоянием. */
|
|
25
|
+
emptyMessageHint?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Условие видимости секции. Если `false` — секция полностью скрыта.
|
|
28
|
+
* Удобно для toggle-чекбоксов вида «У меня есть имущество».
|
|
29
|
+
*/
|
|
30
|
+
hasItems?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Plain-leaf значения для новых items (передаётся в `FormArray.AddButton`).
|
|
33
|
+
* НЕ FieldConfig — только примитивы по форме item-типа `T`.
|
|
34
|
+
*
|
|
35
|
+
* Тип `Partial<T>` — TS проверит, что initialValue совместим с типом элемента.
|
|
36
|
+
* Передавайте generic явно для лучшей type-safety:
|
|
37
|
+
* `<FormArraySection<PropertyItem> initialValue={createPropertyItem()} ...>`.
|
|
38
|
+
*/
|
|
39
|
+
initialValue?: Partial<T>;
|
|
40
|
+
/** Показывать «Удалить» когда остался один элемент. По умолчанию `false`. */
|
|
41
|
+
showRemoveOnSingle?: boolean;
|
|
42
|
+
/** Максимум items — AddButton отключается при достижении. */
|
|
43
|
+
maxItems?: number;
|
|
44
|
+
/** Внешний className секции. */
|
|
45
|
+
className?: string;
|
|
46
|
+
/** Класс card-обёртки каждого item. */
|
|
47
|
+
cardClassName?: string;
|
|
48
|
+
/**
|
|
49
|
+
* FormProxy. Авто-инъектится `RenderNodeComponent` через
|
|
50
|
+
* `__selfManagedChildren` маркер. Передавать вручную — только при
|
|
51
|
+
* использовании вне стандартного render-tree.
|
|
52
|
+
*/
|
|
53
|
+
form?: FormProxy<unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Field wrapper для дочерних полей. Авто-инъектится `RenderNodeComponent`;
|
|
56
|
+
* переопределить для использования другого wrapper в этой секции.
|
|
57
|
+
*/
|
|
58
|
+
fieldWrapper?: ComponentType<FieldWrapperProps>;
|
|
59
|
+
}
|
|
60
|
+
export declare function FormArraySection<T extends FormFields>({ control, itemComponent: ItemComponent, title, itemLabel, addButtonLabel, removeButtonLabel, emptyMessage, emptyMessageHint, hasItems, initialValue, showRemoveOnSingle, maxItems, className, cardClassName, form, }: FormArraySectionProps<T>): ReactNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { FormWizardActionsRenderProps } from '@reformer/cdk/form-wizard';
|
|
3
|
+
export interface FormWizardActionsProps extends FormWizardActionsRenderProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
prevLabel?: string;
|
|
6
|
+
nextLabel?: string;
|
|
7
|
+
submitLabel?: string;
|
|
8
|
+
validatingLabel?: string;
|
|
9
|
+
submittingLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const FormWizardActions: FC<FormWizardActionsProps>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
import { FormWizardProgressRenderProps } from '@reformer/cdk/form-wizard';
|
|
3
|
+
export interface FormWizardProgressProps extends FormWizardProgressRenderProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
format?: (props: FormWizardProgressRenderProps) => ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare const FormWizardProgress: FC<FormWizardProgressProps>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ComponentType, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FormWizard as FormWizardHeadless, FormWizardActionsProps as HeadlessFormWizardActionsProps, FormWizardHandle, FormWizardProps as FormWizardHeadlessProps } from '@reformer/cdk/form-wizard';
|
|
3
|
+
import { FormProxy } from '@reformer/core';
|
|
4
|
+
import { RenderNode } from '@reformer/renderer-react';
|
|
5
|
+
/**
|
|
6
|
+
* Полиморфное тело шага.
|
|
7
|
+
*
|
|
8
|
+
* - FC получает `control={form}`.
|
|
9
|
+
* - ReactNode рендерится напрямую (статический JSX).
|
|
10
|
+
* - RenderNode<T> рендерится через `<RenderNodeComponent>`.
|
|
11
|
+
*/
|
|
12
|
+
export type FormWizardStepBody<T> = ComponentType<{
|
|
13
|
+
control: FormProxy<T>;
|
|
14
|
+
}> | ReactNode | RenderNode<T>;
|
|
15
|
+
export interface FormWizardStep<T> {
|
|
16
|
+
/** Step number (1-based). */
|
|
17
|
+
number: number;
|
|
18
|
+
/** Step title shown in indicator. */
|
|
19
|
+
title: string;
|
|
20
|
+
/** Optional icon (string или ReactNode). Передаётся в headless Indicator. */
|
|
21
|
+
icon?: string;
|
|
22
|
+
/** Body — FC | ReactNode | RenderNode<T>. */
|
|
23
|
+
body: FormWizardStepBody<T>;
|
|
24
|
+
}
|
|
25
|
+
export interface FormWizardProps<T extends Record<string, any>> extends FormWizardHeadlessProps<T> {
|
|
26
|
+
className?: string;
|
|
27
|
+
steps: FormWizardStep<T>[];
|
|
28
|
+
onSubmit: HeadlessFormWizardActionsProps['onSubmit'];
|
|
29
|
+
}
|
|
30
|
+
declare const FormWizardForwarded: <T extends Record<string, any>>(props: FormWizardProps<T> & {
|
|
31
|
+
ref?: React.Ref<FormWizardHandle<T>>;
|
|
32
|
+
}) => ReactElement | null;
|
|
33
|
+
type FormWizardCompound = typeof FormWizardForwarded & {
|
|
34
|
+
Indicator: typeof FormWizardHeadless.Indicator;
|
|
35
|
+
Step: typeof FormWizardHeadless.Step;
|
|
36
|
+
Actions: typeof FormWizardHeadless.Actions;
|
|
37
|
+
Progress: typeof FormWizardHeadless.Progress;
|
|
38
|
+
};
|
|
39
|
+
declare const FormWizard: FormWizardCompound;
|
|
40
|
+
export { FormWizard };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { FormWizard } from './form-wizard';
|
|
2
|
+
export type { FormWizardProps, FormWizardStep, FormWizardStepBody } from './form-wizard';
|
|
3
|
+
export { StepIndicator } from './step-indicator';
|
|
4
|
+
export type { StepIndicatorProps } from './step-indicator';
|
|
5
|
+
export { FormWizardActions } from './form-wizard-actions';
|
|
6
|
+
export type { FormWizardActionsProps } from './form-wizard-actions';
|
|
7
|
+
export { FormWizardProgress } from './form-wizard-progress';
|
|
8
|
+
export type { FormWizardProgressProps } from './form-wizard-progress';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { FormWizardIndicatorStepWithState, FormWizardIndicatorRenderProps } from '@reformer/cdk/form-wizard';
|
|
3
|
+
export interface StepIndicatorProps extends FormWizardIndicatorRenderProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
/** Aria-label контейнера навигации. По умолчанию «Шаги формы». */
|
|
6
|
+
navAriaLabel?: string;
|
|
7
|
+
/** Кастомный шаблон aria-label для шага. Получает {step}. */
|
|
8
|
+
stepAriaLabel?: (step: FormWizardIndicatorStepWithState) => string;
|
|
9
|
+
}
|
|
10
|
+
export declare const StepIndicator: FC<StepIndicatorProps>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface ErrorStateProps {
|
|
3
|
+
error: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
onRetry?: () => void;
|
|
6
|
+
retryLabel?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function ErrorState({ error, title, onRetry, retryLabel, className, }: ErrorStateProps): ReactNode;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
/** Состояние асинхронной операции, ожидаемое {@link AsyncBoundary}. */
|
|
3
|
+
export type AsyncStatus = 'loading' | 'error' | 'ready';
|
|
4
|
+
/** Props компонента {@link AsyncBoundary}. */
|
|
5
|
+
export interface AsyncBoundaryProps {
|
|
6
|
+
/** Текущее состояние асинхронной операции. Управляется снаружи. */
|
|
7
|
+
status: AsyncStatus;
|
|
8
|
+
/** Компонент, рендерящийся при `status === 'loading'`. Без props. Если не передан — `null`. */
|
|
9
|
+
LoadingComponent?: ComponentType;
|
|
10
|
+
/** Компонент, рендерящийся при `status === 'error'`. Без props. Если не передан — `null`. */
|
|
11
|
+
ErrorComponent?: ComponentType;
|
|
12
|
+
/** Контент, рендерящийся при `status === 'ready'`. */
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Контейнер с тремя состояниями (`loading`/`error`/`ready`). В состоянии `ready`
|
|
17
|
+
* отображает `children`. Для loading/error используются переданные slot-компоненты
|
|
18
|
+
* (`ComponentType`, без props — для кастомизации передай тонкую обёртку).
|
|
19
|
+
*
|
|
20
|
+
* Это не Suspense-boundary: ничего не throw'ится, состоянием управляешь сам.
|
|
21
|
+
*
|
|
22
|
+
* @example Загрузка списка с обработкой ошибки
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { useEffect, useState } from 'react';
|
|
25
|
+
* import { AsyncBoundary, type AsyncStatus } from '@reformer/ui-kit';
|
|
26
|
+
*
|
|
27
|
+
* function CountriesPage() {
|
|
28
|
+
* const [status, setStatus] = useState<AsyncStatus>('loading');
|
|
29
|
+
* const [countries, setCountries] = useState<string[]>([]);
|
|
30
|
+
*
|
|
31
|
+
* useEffect(() => {
|
|
32
|
+
* fetch('/api/countries')
|
|
33
|
+
* .then((r) => r.json())
|
|
34
|
+
* .then((d) => { setCountries(d); setStatus('ready'); })
|
|
35
|
+
* .catch(() => setStatus('error'));
|
|
36
|
+
* }, []);
|
|
37
|
+
*
|
|
38
|
+
* return (
|
|
39
|
+
* <AsyncBoundary
|
|
40
|
+
* status={status}
|
|
41
|
+
* LoadingComponent={() => <p>Загружаем страны...</p>}
|
|
42
|
+
* ErrorComponent={() => <p>Ошибка загрузки</p>}
|
|
43
|
+
* >
|
|
44
|
+
* <ul>{countries.map((c) => <li key={c}>{c}</li>)}</ul>
|
|
45
|
+
* </AsyncBoundary>
|
|
46
|
+
* );
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example Внутри RenderSchema (статус подставляется через `patchProps`)
|
|
51
|
+
* ```tsx
|
|
52
|
+
* import { AsyncBoundary } from '@reformer/ui-kit';
|
|
53
|
+
*
|
|
54
|
+
* createRenderSchema((path) => ({
|
|
55
|
+
* selector: 'data-boundary',
|
|
56
|
+
* component: AsyncBoundary,
|
|
57
|
+
* componentProps: { status: 'loading', LoadingComponent: Spinner },
|
|
58
|
+
* children: [...],
|
|
59
|
+
* }));
|
|
60
|
+
* // позже: schema.node('data-boundary').patchProps({ status: 'ready' });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function AsyncBoundary({ status, LoadingComponent, ErrorComponent, children, }: AsyncBoundaryProps): ReactNode;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props компонента Box
|
|
4
|
+
*/
|
|
5
|
+
export interface BoxProps {
|
|
6
|
+
/** CSS класс для стилизации */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** Дочерние элементы */
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Box - базовый контейнер-обёртка.
|
|
13
|
+
*
|
|
14
|
+
* Простой `<div>` для группировки элементов в `RenderSchema`. Используйте
|
|
15
|
+
* `className` для настройки layout через atomic CSS (Tailwind).
|
|
16
|
+
*
|
|
17
|
+
* @example Вертикальный список полей в RenderSchema
|
|
18
|
+
* ```typescript
|
|
19
|
+
* {
|
|
20
|
+
* component: Box,
|
|
21
|
+
* componentProps: { className: 'flex flex-col gap-4' },
|
|
22
|
+
* children: [
|
|
23
|
+
* { component: path.email },
|
|
24
|
+
* { component: path.password },
|
|
25
|
+
* ],
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Двухколоночная сетка
|
|
30
|
+
* ```typescript
|
|
31
|
+
* {
|
|
32
|
+
* component: Box,
|
|
33
|
+
* componentProps: { className: 'grid grid-cols-2 gap-4' },
|
|
34
|
+
* children: [
|
|
35
|
+
* { component: path.firstName },
|
|
36
|
+
* { component: path.lastName },
|
|
37
|
+
* ],
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function Box({ className, children }: BoxProps): ReactNode;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Базовая кнопка на shadcn/Radix `Slot`. Поддерживает 6 вариантов
|
|
9
|
+
* (`default`/`destructive`/`outline`/`secondary`/`ghost`/`link`), 6 размеров
|
|
10
|
+
* (`default`/`sm`/`lg`/`icon`/`icon-sm`/`icon-lg`) и `asChild` для замены
|
|
11
|
+
* корневого DOM-узла на дочерний элемент (например, `<Link>` из роутера).
|
|
12
|
+
*
|
|
13
|
+
* @example Variants matrix (для design-system документации)
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { Button } from '@reformer/ui-kit';
|
|
16
|
+
*
|
|
17
|
+
* {(['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'] as const).map(
|
|
18
|
+
* (v) => <Button key={v} variant={v}>{v}</Button>
|
|
19
|
+
* )}
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example asChild + react-router Link (стили кнопки на анкоре)
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { Link } from 'react-router-dom';
|
|
25
|
+
* import { Button } from '@reformer/ui-kit';
|
|
26
|
+
*
|
|
27
|
+
* <Button asChild variant="outline" size="lg">
|
|
28
|
+
* <Link to="/dashboard">Открыть дашборд</Link>
|
|
29
|
+
* </Button>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
|
33
|
+
asChild?: boolean;
|
|
34
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export { Button };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** Props компонента {@link Checkbox}. */
|
|
3
|
+
export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type'> {
|
|
4
|
+
/** Дополнительный CSS-класс для самого input. */
|
|
5
|
+
className?: string;
|
|
6
|
+
/** Состояние чекбокса. `undefined` рендерится как `false`. */
|
|
7
|
+
value?: boolean;
|
|
8
|
+
/** Вызывается при изменении. Получает `event.target.checked`. */
|
|
9
|
+
onChange?: (value: boolean) => void;
|
|
10
|
+
/** Срабатывает при потере фокуса. */
|
|
11
|
+
onBlur?: () => void;
|
|
12
|
+
/** Подпись справа от чекбокса. Если опущена — рендерится только сам контрол. */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Блокирует переключение. */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
/** Test-id для e2e (используется как `data-testid` на input). */
|
|
17
|
+
'data-testid'?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Чекбокс с опциональной подписью справа. Контракт `value`/`onChange` —
|
|
21
|
+
* `boolean`, не строка.
|
|
22
|
+
*
|
|
23
|
+
* `FormField` из `@reformer/ui-kit` детектит `Checkbox` и не рендерит верхний
|
|
24
|
+
* `Label`, чтобы не дублировать подпись.
|
|
25
|
+
*
|
|
26
|
+
* @example Согласие с условиями
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { Checkbox } from '@reformer/ui-kit';
|
|
29
|
+
*
|
|
30
|
+
* <Checkbox
|
|
31
|
+
* value={agree}
|
|
32
|
+
* onChange={setAgree}
|
|
33
|
+
* label="Согласен с условиями обработки персональных данных"
|
|
34
|
+
* />
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Без подписи (label справа добавляется снаружи)
|
|
38
|
+
* ```tsx
|
|
39
|
+
* import { Checkbox } from '@reformer/ui-kit';
|
|
40
|
+
*
|
|
41
|
+
* <div className="flex items-center gap-2">
|
|
42
|
+
* <Checkbox value={hasMortgage} onChange={setHasMortgage} />
|
|
43
|
+
* <span>У меня уже есть ипотека</span>
|
|
44
|
+
* </div>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
|
|
48
|
+
export { Checkbox };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props компонента Collapsible
|
|
4
|
+
*/
|
|
5
|
+
export interface CollapsibleProps {
|
|
6
|
+
/** Заголовок секции */
|
|
7
|
+
title: string;
|
|
8
|
+
/** Начальное состояние (развёрнуто по умолчанию) */
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
/** CSS класс для контейнера */
|
|
11
|
+
className?: string;
|
|
12
|
+
/** CSS класс для заголовка */
|
|
13
|
+
titleClassName?: string;
|
|
14
|
+
/** CSS класс для контента */
|
|
15
|
+
contentClassName?: string;
|
|
16
|
+
/** Дочерние элементы */
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Collapsible - сворачиваемая секция формы.
|
|
21
|
+
*
|
|
22
|
+
* Заголовок-кнопка переключает видимость `children`. Состояние локальное
|
|
23
|
+
* (`useState`), внешний control пока не поддерживается — для управляемого
|
|
24
|
+
* варианта используй `RenderSchema.node('selector').setHidden(true)` поверх
|
|
25
|
+
* обычного `Box`.
|
|
26
|
+
*
|
|
27
|
+
* @example Свёрнута по умолчанию
|
|
28
|
+
* ```typescript
|
|
29
|
+
* {
|
|
30
|
+
* component: Collapsible,
|
|
31
|
+
* componentProps: {
|
|
32
|
+
* title: 'Дополнительные параметры',
|
|
33
|
+
* defaultOpen: false,
|
|
34
|
+
* className: 'border rounded p-4',
|
|
35
|
+
* titleClassName: 'font-semibold w-full text-left',
|
|
36
|
+
* },
|
|
37
|
+
* children: [
|
|
38
|
+
* { component: path.notes },
|
|
39
|
+
* { component: path.tags },
|
|
40
|
+
* ],
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example Развёрнута, со специальным фоном контента
|
|
45
|
+
* ```typescript
|
|
46
|
+
* {
|
|
47
|
+
* component: Collapsible,
|
|
48
|
+
* componentProps: {
|
|
49
|
+
* title: 'Адрес доставки',
|
|
50
|
+
* defaultOpen: true,
|
|
51
|
+
* contentClassName: 'mt-2 bg-gray-50 p-3 rounded',
|
|
52
|
+
* },
|
|
53
|
+
* children: [
|
|
54
|
+
* { component: path.deliveryAddress },
|
|
55
|
+
* ],
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function Collapsible({ title, defaultOpen, className, titleClassName, contentClassName, children, }: CollapsibleProps): ReactNode;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** Props компонента {@link ExampleCard}. */
|
|
3
|
+
export interface ExampleCardProps {
|
|
4
|
+
/** Заголовок карточки (обязательный). */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Описание под заголовком. */
|
|
7
|
+
description?: string;
|
|
8
|
+
/** Контент примера, отображаемый в режиме «пример». */
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
/** Текст исходного кода, копируемый в clipboard в режиме «код». */
|
|
11
|
+
code: string;
|
|
12
|
+
/** Дополнительный CSS-класс контейнера. */
|
|
13
|
+
className?: string;
|
|
14
|
+
/** Tailwind-класс фона карточки. По умолчанию `'bg-white'`. */
|
|
15
|
+
bgColor?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Карточка-обёртка для демонстрации компонентов в playground: заголовок,
|
|
19
|
+
* описание, область с примером и кнопка переключения исходного кода с
|
|
20
|
+
* copy-to-clipboard.
|
|
21
|
+
*
|
|
22
|
+
* Утилита для playground/документации, не для продакшена.
|
|
23
|
+
*
|
|
24
|
+
* @example Базовое использование
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { ExampleCard, Input } from '@reformer/ui-kit';
|
|
27
|
+
* import { useState } from 'react';
|
|
28
|
+
*
|
|
29
|
+
* function Demo() {
|
|
30
|
+
* const [v, setV] = useState<string | null>(null);
|
|
31
|
+
* return (
|
|
32
|
+
* <ExampleCard
|
|
33
|
+
* title="Input — базовый"
|
|
34
|
+
* description="Однострочное поле с placeholder"
|
|
35
|
+
* code={`<Input value={v} onChange={setV} placeholder="Email" />`}
|
|
36
|
+
* >
|
|
37
|
+
* <Input value={v} onChange={setV} placeholder="Email" />
|
|
38
|
+
* </ExampleCard>
|
|
39
|
+
* );
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example С кастомным фоном (для подсветки группы)
|
|
44
|
+
* ```tsx
|
|
45
|
+
* import { ExampleCard, Button } from '@reformer/ui-kit';
|
|
46
|
+
*
|
|
47
|
+
* <ExampleCard
|
|
48
|
+
* title="Destructive button"
|
|
49
|
+
* description="Кнопка опасного действия"
|
|
50
|
+
* bgColor="bg-red-50"
|
|
51
|
+
* code={`<Button variant="destructive">Delete</Button>`}
|
|
52
|
+
* >
|
|
53
|
+
* <Button variant="destructive">Delete</Button>
|
|
54
|
+
* </ExampleCard>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function ExampleCard({ title, description, children, code, className, bgColor, }: ExampleCardProps): import("react/jsx-runtime").JSX.Element;
|