@reformer/ui 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 +100 -0
- package/dist/FormArray-K2YVvq1u.js +101 -0
- package/dist/FormNavigation-3rg4tJyl.js +227 -0
- package/dist/form-array/FormArray.d.ts +170 -0
- package/dist/form-array/FormArrayAddButton.d.ts +19 -0
- package/dist/form-array/FormArrayContext.d.ts +46 -0
- package/dist/form-array/FormArrayCount.d.ts +17 -0
- package/dist/form-array/FormArrayEmpty.d.ts +22 -0
- package/dist/form-array/FormArrayItemIndex.d.ts +24 -0
- package/dist/form-array/FormArrayList.d.ts +26 -0
- package/dist/form-array/FormArrayRemoveButton.d.ts +19 -0
- package/dist/form-array/index.d.ts +13 -0
- package/dist/form-array/types.d.ts +72 -0
- package/dist/form-array/useFormArray.d.ts +66 -0
- package/dist/form-array.d.ts +2 -0
- package/dist/form-array.js +15 -0
- package/dist/form-navigation/FormNavigation.d.ts +16 -0
- package/dist/form-navigation/FormNavigationActions.d.ts +113 -0
- package/dist/form-navigation/FormNavigationContext.d.ts +42 -0
- package/dist/form-navigation/FormNavigationIndicator.d.ts +113 -0
- package/dist/form-navigation/FormNavigationProgress.d.ts +83 -0
- package/dist/form-navigation/FormNavigationStep.d.ts +37 -0
- package/dist/form-navigation/index.d.ts +12 -0
- package/dist/form-navigation/types.d.ts +52 -0
- package/dist/form-navigation.d.ts +2 -0
- package/dist/form-navigation.js +10 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +23 -0
- package/llms.txt +343 -0
- package/package.json +85 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { FormNavigation } from './FormNavigation';
|
|
2
|
+
export { FormNavigationStep } from './FormNavigationStep';
|
|
3
|
+
export { FormNavigationIndicator } from './FormNavigationIndicator';
|
|
4
|
+
export { FormNavigationActions } from './FormNavigationActions';
|
|
5
|
+
export { FormNavigationProgress } from './FormNavigationProgress';
|
|
6
|
+
export { useFormNavigation, FormNavigationContext } from './FormNavigationContext';
|
|
7
|
+
export type { FormNavigationHandle, FormNavigationProps, FormNavigationConfig } from './types';
|
|
8
|
+
export type { FormNavigationStepProps } from './FormNavigationStep';
|
|
9
|
+
export type { FormNavigationContextValue } from './FormNavigationContext';
|
|
10
|
+
export type { FormNavigationIndicatorProps, FormNavigationIndicatorStep, FormNavigationIndicatorStepWithState, FormNavigationIndicatorRenderProps, } from './FormNavigationIndicator';
|
|
11
|
+
export type { FormNavigationActionsProps, FormNavigationActionsRenderProps, FormNavigationButtonProps, FormNavigationSubmitProps, } from './FormNavigationActions';
|
|
12
|
+
export type { FormNavigationProgressProps, FormNavigationProgressRenderProps, } from './FormNavigationProgress';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { GroupNodeWithControls, ValidationSchemaFn } from '@reformer/core';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for multi-step form navigation
|
|
5
|
+
* Note: totalSteps is inferred from children count
|
|
6
|
+
*/
|
|
7
|
+
export interface FormNavigationConfig<T extends Record<string, any>> {
|
|
8
|
+
/** Validation schemas per step (1-based indexing) */
|
|
9
|
+
stepValidations: Record<number, ValidationSchemaFn<T>>;
|
|
10
|
+
/** Full validation schema for submit */
|
|
11
|
+
fullValidation: ValidationSchemaFn<T>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Handle for external access to FormNavigation methods via ref
|
|
15
|
+
*/
|
|
16
|
+
export interface FormNavigationHandle<T extends Record<string, any>> {
|
|
17
|
+
/** Current step (1-based) */
|
|
18
|
+
currentStep: number;
|
|
19
|
+
/** Completed steps */
|
|
20
|
+
completedSteps: number[];
|
|
21
|
+
/** Validate current step */
|
|
22
|
+
validateCurrentStep: () => Promise<boolean>;
|
|
23
|
+
/** Go to next step (with validation) */
|
|
24
|
+
goToNextStep: () => Promise<boolean>;
|
|
25
|
+
/** Go to previous step */
|
|
26
|
+
goToPreviousStep: () => void;
|
|
27
|
+
/** Go to specific step */
|
|
28
|
+
goToStep: (step: number) => boolean;
|
|
29
|
+
/** Submit form (with full validation) */
|
|
30
|
+
submit: <R>(onSubmit: (values: T) => Promise<R> | R) => Promise<R | null>;
|
|
31
|
+
/** Is this the first step */
|
|
32
|
+
isFirstStep: boolean;
|
|
33
|
+
/** Is this the last step */
|
|
34
|
+
isLastStep: boolean;
|
|
35
|
+
/** Is validation in progress */
|
|
36
|
+
isValidating: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Props for FormNavigation component
|
|
40
|
+
*/
|
|
41
|
+
export interface FormNavigationProps<T extends Record<string, any>> {
|
|
42
|
+
/** Form instance */
|
|
43
|
+
form: GroupNodeWithControls<T>;
|
|
44
|
+
/** Step configuration (validation schemas) */
|
|
45
|
+
config: FormNavigationConfig<T>;
|
|
46
|
+
/** Children (Step components, Indicator, Actions, Progress, or any ReactNode) */
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
/** Callback when step changes */
|
|
49
|
+
onStepChange?: (step: number) => void;
|
|
50
|
+
/** Scroll to top on step change */
|
|
51
|
+
scrollToTop?: boolean;
|
|
52
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { F as i, c as t, e as r, b as s, d as n, a as g, u as m } from "./FormNavigation-3rg4tJyl.js";
|
|
2
|
+
export {
|
|
3
|
+
i as FormNavigation,
|
|
4
|
+
t as FormNavigationActions,
|
|
5
|
+
r as FormNavigationContext,
|
|
6
|
+
s as FormNavigationIndicator,
|
|
7
|
+
n as FormNavigationProgress,
|
|
8
|
+
g as FormNavigationStep,
|
|
9
|
+
m as useFormNavigation
|
|
10
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FormArray, FormArrayList, FormArrayAddButton, FormArrayRemoveButton, FormArrayEmpty, FormArrayCount, FormArrayItemIndex, useFormArray, FormArrayContext, FormArrayItemContext, useFormArrayContext, useFormArrayItemContext, } from './form-array';
|
|
2
|
+
export type { FormArrayHandle, FormArrayItem, UseFormArrayReturn, FormArrayRootProps, FormArrayListProps, FormArrayItemRenderProps, FormArrayAddButtonProps, FormArrayRemoveButtonProps, FormArrayEmptyProps, FormArrayCountProps, FormArrayItemIndexProps, FormArrayContextValue, FormArrayItemContextValue, } from './form-array';
|
|
3
|
+
export { FormNavigation, FormNavigationStep, FormNavigationIndicator, FormNavigationActions, FormNavigationProgress, useFormNavigation, FormNavigationContext, } from './form-navigation';
|
|
4
|
+
export type { FormNavigationHandle, FormNavigationProps, FormNavigationConfig, FormNavigationStepProps, FormNavigationContextValue, FormNavigationIndicatorProps, FormNavigationIndicatorStep, FormNavigationIndicatorStepWithState, FormNavigationIndicatorRenderProps, FormNavigationActionsProps, FormNavigationActionsRenderProps, FormNavigationButtonProps, FormNavigationSubmitProps, FormNavigationProgressProps, FormNavigationProgressRenderProps, } from './form-navigation';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { F as o, b as t, g as s, e as m, d as e, h as F, f as i, a as n, c as A, u as y, i as g, j as u } from "./FormArray-K2YVvq1u.js";
|
|
2
|
+
import { F as x, c as N, e as d, b as C, d as I, a as c, u as p } from "./FormNavigation-3rg4tJyl.js";
|
|
3
|
+
export {
|
|
4
|
+
o as FormArray,
|
|
5
|
+
t as FormArrayAddButton,
|
|
6
|
+
s as FormArrayContext,
|
|
7
|
+
m as FormArrayCount,
|
|
8
|
+
e as FormArrayEmpty,
|
|
9
|
+
F as FormArrayItemContext,
|
|
10
|
+
i as FormArrayItemIndex,
|
|
11
|
+
n as FormArrayList,
|
|
12
|
+
A as FormArrayRemoveButton,
|
|
13
|
+
x as FormNavigation,
|
|
14
|
+
N as FormNavigationActions,
|
|
15
|
+
d as FormNavigationContext,
|
|
16
|
+
C as FormNavigationIndicator,
|
|
17
|
+
I as FormNavigationProgress,
|
|
18
|
+
c as FormNavigationStep,
|
|
19
|
+
y as useFormArray,
|
|
20
|
+
g as useFormArrayContext,
|
|
21
|
+
u as useFormArrayItemContext,
|
|
22
|
+
p as useFormNavigation
|
|
23
|
+
};
|
package/llms.txt
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# @reformer/ui - LLM Integration Guide
|
|
2
|
+
|
|
3
|
+
Headless UI components for @reformer/core forms.
|
|
4
|
+
|
|
5
|
+
# Overview
|
|
6
|
+
|
|
7
|
+
`@reformer/ui` provides headless UI components for `@reformer/core` forms.
|
|
8
|
+
|
|
9
|
+
## Key Concepts
|
|
10
|
+
|
|
11
|
+
- **Headless**: No default UI or styles - you build the interface
|
|
12
|
+
- **Compound Components**: Composable, declarative API
|
|
13
|
+
- **Render Props**: Children as function for full control
|
|
14
|
+
- **Context-based**: State shared via React Context
|
|
15
|
+
|
|
16
|
+
## Components
|
|
17
|
+
|
|
18
|
+
| Component | Purpose |
|
|
19
|
+
|-----------|---------|
|
|
20
|
+
| `FormArray` | Manage dynamic form arrays |
|
|
21
|
+
| `FormNavigation` | Multi-step form wizard |
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @reformer/ui @reformer/core
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Import Patterns
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// All components
|
|
33
|
+
import { FormArray, FormNavigation } from '@reformer/ui';
|
|
34
|
+
|
|
35
|
+
// Tree-shaking (recommended)
|
|
36
|
+
import { FormArray, useFormArray } from '@reformer/ui/form-array';
|
|
37
|
+
import { FormNavigation, useFormNavigation } from '@reformer/ui/form-navigation';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
# FormArray
|
|
41
|
+
|
|
42
|
+
Headless compound component for managing form arrays.
|
|
43
|
+
|
|
44
|
+
## Basic Usage
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { FormArray } from '@reformer/ui/form-array';
|
|
48
|
+
|
|
49
|
+
<FormArray.Root control={form.items}>
|
|
50
|
+
<FormArray.Empty>
|
|
51
|
+
<p>No items added</p>
|
|
52
|
+
</FormArray.Empty>
|
|
53
|
+
|
|
54
|
+
<FormArray.List>
|
|
55
|
+
{({ control, index, remove }) => (
|
|
56
|
+
<div key={control.id}>
|
|
57
|
+
<h4>Item #{index + 1}</h4>
|
|
58
|
+
<ItemForm control={control} />
|
|
59
|
+
<button onClick={remove}>Remove</button>
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
</FormArray.List>
|
|
63
|
+
|
|
64
|
+
<FormArray.AddButton>Add Item</FormArray.AddButton>
|
|
65
|
+
</FormArray.Root>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Sub-components
|
|
69
|
+
|
|
70
|
+
| Component | Props | Purpose |
|
|
71
|
+
|-----------|-------|---------|
|
|
72
|
+
| `FormArray.Root` | `control: ArrayNode<T>` | Context provider |
|
|
73
|
+
| `FormArray.List` | `children: (item) => ReactNode` | Iterates items (render props) |
|
|
74
|
+
| `FormArray.AddButton` | `initialValue?: Partial<T>` | Adds new item |
|
|
75
|
+
| `FormArray.RemoveButton` | - | Removes current item (inside List) |
|
|
76
|
+
| `FormArray.Empty` | `children: ReactNode` | Shows when array is empty |
|
|
77
|
+
| `FormArray.Count` | `render?: (count) => ReactNode` | Displays item count |
|
|
78
|
+
| `FormArray.ItemIndex` | `render?: (index) => ReactNode` | Displays current index |
|
|
79
|
+
|
|
80
|
+
## List Render Props
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
interface FormArrayItemRenderProps<T> {
|
|
84
|
+
control: GroupNodeWithControls<T>; // Form control for item
|
|
85
|
+
index: number; // Zero-based index
|
|
86
|
+
id: string | number; // Unique key
|
|
87
|
+
remove: () => void; // Remove this item
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## External Control via Ref
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { useRef } from 'react';
|
|
95
|
+
import { FormArray, FormArrayHandle } from '@reformer/ui/form-array';
|
|
96
|
+
|
|
97
|
+
const arrayRef = useRef<FormArrayHandle<ItemType>>(null);
|
|
98
|
+
|
|
99
|
+
// Control from outside
|
|
100
|
+
arrayRef.current?.add({ name: 'New' });
|
|
101
|
+
arrayRef.current?.removeAt(0);
|
|
102
|
+
arrayRef.current?.clear();
|
|
103
|
+
|
|
104
|
+
<FormArray.Root ref={arrayRef} control={form.items}>
|
|
105
|
+
...
|
|
106
|
+
</FormArray.Root>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## FormArrayHandle API
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
interface FormArrayHandle<T> {
|
|
113
|
+
add: (value?: Partial<T>) => void;
|
|
114
|
+
clear: () => void;
|
|
115
|
+
insert: (index: number, value?: Partial<T>) => void;
|
|
116
|
+
removeAt: (index: number) => void;
|
|
117
|
+
length: number;
|
|
118
|
+
isEmpty: boolean;
|
|
119
|
+
at: (index: number) => GroupNodeWithControls<T> | undefined;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## useFormArray Hook
|
|
124
|
+
|
|
125
|
+
For full customization without compound components:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import { useFormArray } from '@reformer/ui/form-array';
|
|
129
|
+
|
|
130
|
+
function CustomList() {
|
|
131
|
+
const { items, add, isEmpty, length } = useFormArray(form.items);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div>
|
|
135
|
+
<span>Total: {length}</span>
|
|
136
|
+
{items.map(({ control, id, remove }) => (
|
|
137
|
+
<div key={id}>
|
|
138
|
+
<ItemForm control={control} />
|
|
139
|
+
<button onClick={remove}>X</button>
|
|
140
|
+
</div>
|
|
141
|
+
))}
|
|
142
|
+
{isEmpty && <p>Empty</p>}
|
|
143
|
+
<button onClick={() => add()}>Add</button>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
# FormNavigation
|
|
150
|
+
|
|
151
|
+
Headless compound component for multi-step form wizards.
|
|
152
|
+
|
|
153
|
+
## Basic Usage
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { FormNavigation } from '@reformer/ui/form-navigation';
|
|
157
|
+
|
|
158
|
+
const config = {
|
|
159
|
+
stepValidations: {
|
|
160
|
+
1: step1Schema,
|
|
161
|
+
2: step2Schema,
|
|
162
|
+
},
|
|
163
|
+
fullValidation: fullFormSchema,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
<FormNavigation form={form} config={config}>
|
|
167
|
+
<FormNavigation.Step component={Step1Form} control={form} />
|
|
168
|
+
<FormNavigation.Step component={Step2Form} control={form} />
|
|
169
|
+
|
|
170
|
+
<FormNavigation.Actions onSubmit={handleSubmit}>
|
|
171
|
+
{({ prev, next, submit, isFirstStep, isLastStep }) => (
|
|
172
|
+
<div>
|
|
173
|
+
{!isFirstStep && <button {...prev}>Back</button>}
|
|
174
|
+
{!isLastStep ? (
|
|
175
|
+
<button {...next}>Next</button>
|
|
176
|
+
) : (
|
|
177
|
+
<button {...submit}>Submit</button>
|
|
178
|
+
)}
|
|
179
|
+
</div>
|
|
180
|
+
)}
|
|
181
|
+
</FormNavigation.Actions>
|
|
182
|
+
</FormNavigation>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Sub-components
|
|
186
|
+
|
|
187
|
+
| Component | Purpose |
|
|
188
|
+
|-----------|---------|
|
|
189
|
+
| `FormNavigation` | Root provider |
|
|
190
|
+
| `FormNavigation.Step` | Renders component when step is current |
|
|
191
|
+
| `FormNavigation.Indicator` | Headless step indicator (render props) |
|
|
192
|
+
| `FormNavigation.Actions` | Headless navigation buttons (render props) |
|
|
193
|
+
| `FormNavigation.Progress` | Headless progress display (render props) |
|
|
194
|
+
|
|
195
|
+
## FormNavigation.Indicator
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
<FormNavigation.Indicator steps={STEPS}>
|
|
199
|
+
{({ steps, goToStep, currentStep }) => (
|
|
200
|
+
<nav>
|
|
201
|
+
{steps.map((step) => (
|
|
202
|
+
<button
|
|
203
|
+
key={step.number}
|
|
204
|
+
onClick={() => goToStep(step.number)}
|
|
205
|
+
disabled={!step.canNavigate}
|
|
206
|
+
aria-current={step.isCurrent ? 'step' : undefined}
|
|
207
|
+
>
|
|
208
|
+
{step.isCompleted ? '✓' : step.number} {step.title}
|
|
209
|
+
</button>
|
|
210
|
+
))}
|
|
211
|
+
</nav>
|
|
212
|
+
)}
|
|
213
|
+
</FormNavigation.Indicator>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Step Definition
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface FormNavigationIndicatorStep {
|
|
220
|
+
number: number; // 1-based step number
|
|
221
|
+
title: string;
|
|
222
|
+
icon?: string;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Render Props
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
interface FormNavigationIndicatorRenderProps {
|
|
230
|
+
steps: FormNavigationIndicatorStepWithState[];
|
|
231
|
+
goToStep: (step: number) => boolean;
|
|
232
|
+
currentStep: number;
|
|
233
|
+
totalSteps: number;
|
|
234
|
+
completedSteps: number[];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
interface FormNavigationIndicatorStepWithState {
|
|
238
|
+
number: number;
|
|
239
|
+
title: string;
|
|
240
|
+
icon?: string;
|
|
241
|
+
isCurrent: boolean;
|
|
242
|
+
isCompleted: boolean;
|
|
243
|
+
canNavigate: boolean;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## FormNavigation.Actions
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<FormNavigation.Actions onSubmit={handleSubmit}>
|
|
251
|
+
{({ prev, next, submit, isFirstStep, isLastStep, isValidating }) => (
|
|
252
|
+
<div>
|
|
253
|
+
{!isFirstStep && (
|
|
254
|
+
<button onClick={prev.onClick} disabled={prev.disabled}>
|
|
255
|
+
Back
|
|
256
|
+
</button>
|
|
257
|
+
)}
|
|
258
|
+
{!isLastStep ? (
|
|
259
|
+
<button onClick={next.onClick} disabled={next.disabled}>
|
|
260
|
+
{isValidating ? 'Validating...' : 'Next'}
|
|
261
|
+
</button>
|
|
262
|
+
) : (
|
|
263
|
+
<button onClick={submit.onClick} disabled={submit.disabled}>
|
|
264
|
+
{submit.isSubmitting ? 'Submitting...' : 'Submit'}
|
|
265
|
+
</button>
|
|
266
|
+
)}
|
|
267
|
+
</div>
|
|
268
|
+
)}
|
|
269
|
+
</FormNavigation.Actions>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Render Props
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
interface FormNavigationActionsRenderProps {
|
|
276
|
+
prev: { onClick: () => void; disabled: boolean };
|
|
277
|
+
next: { onClick: () => void; disabled: boolean };
|
|
278
|
+
submit: { onClick: () => void; disabled: boolean; isSubmitting: boolean };
|
|
279
|
+
isFirstStep: boolean;
|
|
280
|
+
isLastStep: boolean;
|
|
281
|
+
isValidating: boolean;
|
|
282
|
+
isSubmitting: boolean;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## FormNavigation.Progress
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
<FormNavigation.Progress>
|
|
290
|
+
{({ current, total, percent }) => (
|
|
291
|
+
<div>
|
|
292
|
+
Step {current} of {total} ({percent}%)
|
|
293
|
+
<div style={{ width: `${percent}%` }} />
|
|
294
|
+
</div>
|
|
295
|
+
)}
|
|
296
|
+
</FormNavigation.Progress>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Render Props
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
interface FormNavigationProgressRenderProps {
|
|
303
|
+
current: number;
|
|
304
|
+
total: number;
|
|
305
|
+
percent: number;
|
|
306
|
+
completedCount: number;
|
|
307
|
+
isFirstStep: boolean;
|
|
308
|
+
isLastStep: boolean;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## External Control via Ref
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
const navRef = useRef<FormNavigationHandle<FormType>>(null);
|
|
316
|
+
|
|
317
|
+
// Programmatic navigation
|
|
318
|
+
navRef.current?.goToStep(2);
|
|
319
|
+
navRef.current?.goToNextStep();
|
|
320
|
+
navRef.current?.goToPreviousStep();
|
|
321
|
+
|
|
322
|
+
// Submit with validation
|
|
323
|
+
const result = await navRef.current?.submit(async (values) => {
|
|
324
|
+
return api.submit(values);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
<FormNavigation ref={navRef} form={form} config={config}>
|
|
328
|
+
...
|
|
329
|
+
</FormNavigation>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Configuration
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
interface FormNavigationConfig<T> {
|
|
336
|
+
stepValidations: Record<number, ValidationSchemaFn<T>>;
|
|
337
|
+
fullValidation: ValidationSchemaFn<T>;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Validation happens automatically:
|
|
342
|
+
- On `next.onClick`: validates current step
|
|
343
|
+
- On `submit.onClick`: validates entire form
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reformer/ui",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "Headless UI components for @reformer/core - form arrays, multi-step wizards, and more",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./form-array": {
|
|
15
|
+
"types": "./dist/form-array.d.ts",
|
|
16
|
+
"import": "./dist/form-array.js"
|
|
17
|
+
},
|
|
18
|
+
"./form-navigation": {
|
|
19
|
+
"types": "./dist/form-navigation.d.ts",
|
|
20
|
+
"import": "./dist/form-navigation.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"scripts": {
|
|
25
|
+
"generate:llms": "npx tsx scripts/generate-llms.ts",
|
|
26
|
+
"build": "npm run generate:llms && vite build && tsc -p tsconfig.json",
|
|
27
|
+
"dev": "vite",
|
|
28
|
+
"test": "vitest",
|
|
29
|
+
"test:watch": "vitest watch"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"react",
|
|
33
|
+
"forms",
|
|
34
|
+
"headless-ui",
|
|
35
|
+
"compound-components",
|
|
36
|
+
"form-array",
|
|
37
|
+
"multi-step-form",
|
|
38
|
+
"wizard",
|
|
39
|
+
"reformer",
|
|
40
|
+
"typescript"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"author": "Alexandr Bukhtatyy",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "https://github.com/AlexandrBukhtatyy/ReFormer.git",
|
|
50
|
+
"directory": "packages/reformer-ui"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://alexandrbukhtatyy.github.io/ReFormer/",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/AlexandrBukhtatyy/ReFormer/issues"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"files": [
|
|
60
|
+
"dist",
|
|
61
|
+
"README.md",
|
|
62
|
+
"LICENSE",
|
|
63
|
+
"llms.txt"
|
|
64
|
+
],
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"@reformer/core": "^1.0.0",
|
|
67
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
68
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@reformer/core": "*",
|
|
72
|
+
"@types/node": "^24.10.1",
|
|
73
|
+
"@types/react": "^19.2.7",
|
|
74
|
+
"@types/react-dom": "^19.2.3",
|
|
75
|
+
"@vitejs/plugin-react": "^5.1.0",
|
|
76
|
+
"@vitest/utils": "^4.0.8",
|
|
77
|
+
"react": "^19.2.1",
|
|
78
|
+
"react-dom": "^19.2.1",
|
|
79
|
+
"tsx": "^4.19.2",
|
|
80
|
+
"typescript": "^5.9.3",
|
|
81
|
+
"vite": "^7.2.2",
|
|
82
|
+
"vite-plugin-dts": "^4.5.4",
|
|
83
|
+
"vitest": "^4.0.8"
|
|
84
|
+
}
|
|
85
|
+
}
|