react-formsteps-core 0.1.0
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 +36 -0
- package/README.md +312 -0
- package/dist/index.d.mts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +185 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Copyright (c) 2025 Franxx
|
|
2
|
+
GitHub: https://github.com/franklinjunior23
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software to use it for personal, educational, or open source projects,
|
|
6
|
+
subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
1. ATTRIBUTION REQUIRED: The above copyright notice and this permission notice
|
|
9
|
+
must be included in all copies or substantial portions of the Software.
|
|
10
|
+
|
|
11
|
+
2. NON-COMMERCIAL: This software may not be sold, sublicensed, or used as part
|
|
12
|
+
of any commercial product or service without explicit written permission
|
|
13
|
+
from the original author (Franxx).
|
|
14
|
+
|
|
15
|
+
3. NO REBRANDING: You may not remove or alter the original authorship credits,
|
|
16
|
+
rename this library and republish it as your own, or claim original
|
|
17
|
+
authorship of this work.
|
|
18
|
+
|
|
19
|
+
4. NO REPUBLISHING: You may not publish this package or any modified version
|
|
20
|
+
of it to npm, GitHub Packages, or any other package registry under a
|
|
21
|
+
different name or ownership without explicit written permission from
|
|
22
|
+
the original author.
|
|
23
|
+
|
|
24
|
+
5. CONTRIBUTIONS WELCOME: Contributions via pull requests are welcome. By
|
|
25
|
+
submitting a contribution, you agree that the original author (Franxx)
|
|
26
|
+
retains full ownership and copyright of the project, including your
|
|
27
|
+
contributions.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
33
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
34
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
35
|
+
|
|
36
|
+
For commercial use or any other permissions contact the author directly.
|
package/README.md
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# react-formsteps
|
|
2
|
+
|
|
3
|
+
> Headless, type-safe multi-step form library for React — built on [react-hook-form](https://react-hook-form.com/) and [Zod](https://zod.dev/).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/react-formsteps-core)
|
|
6
|
+
[](https://www.npmjs.com/package/react-formsteps-ui)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Packages
|
|
13
|
+
|
|
14
|
+
| Package | Version | Description |
|
|
15
|
+
| ------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
16
|
+
| [`react-formsteps-core`](./packages/core) |  | Headless hooks + context. No UI, no styles. |
|
|
17
|
+
| [`react-formsteps-ui`](./packages/ui) |  | Optional pre-built React components. |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **Headless** — zero UI imposed. Works with any design system.
|
|
24
|
+
- **Per-step validation** — validates only the current step's Zod schema before advancing.
|
|
25
|
+
- **Type-safe** — strict TypeScript throughout. Types flow from Zod schemas into your fields.
|
|
26
|
+
- **Built on react-hook-form** — full compatibility with the RHF ecosystem.
|
|
27
|
+
- **Flexible** — use the hooks alone or drop in the ready-made components.
|
|
28
|
+
- **Tiny** — tree-shakeable, no CSS bundled.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
### Core only (headless)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# npm
|
|
38
|
+
npm install react-formsteps-core react-hook-form zod @hookform/resolvers
|
|
39
|
+
|
|
40
|
+
# pnpm
|
|
41
|
+
pnpm add react-formsteps-core react-hook-form zod @hookform/resolvers
|
|
42
|
+
|
|
43
|
+
# yarn
|
|
44
|
+
yarn add react-formsteps-core react-hook-form zod @hookform/resolvers
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### With UI components
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# npm
|
|
51
|
+
npm install react-formsteps-core react-formsteps-ui react-hook-form zod @hookform/resolvers
|
|
52
|
+
|
|
53
|
+
# pnpm
|
|
54
|
+
pnpm add react-formsteps-core react-formsteps-ui react-hook-form zod @hookform/resolvers
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Peer dependencies
|
|
58
|
+
|
|
59
|
+
| Dependency | Version |
|
|
60
|
+
| --------------------- | ------- |
|
|
61
|
+
| `react` | `>=18` |
|
|
62
|
+
| `react-dom` | `>=18` |
|
|
63
|
+
| `react-hook-form` | `>=7` |
|
|
64
|
+
| `zod` | `>=3` |
|
|
65
|
+
| `@hookform/resolvers` | `>=3` |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick start
|
|
70
|
+
|
|
71
|
+
### Headless — `useSteps` + `useStepForm`
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { useSteps, useStepForm } from 'react-formsteps-core';
|
|
75
|
+
import { z } from 'zod';
|
|
76
|
+
|
|
77
|
+
const schemas = [
|
|
78
|
+
z.object({ firstName: z.string().min(1, 'Required'), lastName: z.string().min(1, 'Required') }),
|
|
79
|
+
z.object({ email: z.string().email('Enter a valid email') }),
|
|
80
|
+
z.object({ password: z.string().min(8, 'Min. 8 characters') }),
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
export function RegistrationForm() {
|
|
84
|
+
const { currentStep, next, prev, isFirst, isLast, progress, totalSteps } = useSteps({
|
|
85
|
+
totalSteps: schemas.length,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const { form, nextWithValidation, isValidating } = useStepForm({
|
|
89
|
+
schema: schemas[currentStep],
|
|
90
|
+
onNext: (data) => console.log('Step data:', data),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const handleNext = async () => {
|
|
94
|
+
const ok = await nextWithValidation();
|
|
95
|
+
if (ok && !isLast) next();
|
|
96
|
+
if (ok && isLast) console.log('All done!', form.getValues());
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<form>
|
|
101
|
+
{/* Progress */}
|
|
102
|
+
<div>
|
|
103
|
+
Step {currentStep + 1} of {totalSteps} — {progress}%
|
|
104
|
+
</div>
|
|
105
|
+
<progress value={progress} max={100} />
|
|
106
|
+
|
|
107
|
+
{/* Step 1 */}
|
|
108
|
+
{currentStep === 0 && (
|
|
109
|
+
<>
|
|
110
|
+
<input {...form.register('firstName')} placeholder="First name" />
|
|
111
|
+
<input {...form.register('lastName')} placeholder="Last name" />
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
|
|
115
|
+
{/* Step 2 */}
|
|
116
|
+
{currentStep === 1 && <input {...form.register('email')} placeholder="Email" />}
|
|
117
|
+
|
|
118
|
+
{/* Step 3 */}
|
|
119
|
+
{currentStep === 2 && (
|
|
120
|
+
<input {...form.register('password')} type="password" placeholder="Password" />
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{/* Navigation */}
|
|
124
|
+
<button type="button" onClick={prev} disabled={isFirst}>
|
|
125
|
+
Back
|
|
126
|
+
</button>
|
|
127
|
+
<button type="button" onClick={handleNext} disabled={isValidating}>
|
|
128
|
+
{isLast ? 'Submit' : 'Next'}
|
|
129
|
+
</button>
|
|
130
|
+
</form>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### With UI components — `<Steps>` + `<Step>`
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { Steps, Step, StepBar, StepNav } from 'react-formsteps-ui';
|
|
141
|
+
import { z } from 'zod';
|
|
142
|
+
|
|
143
|
+
const schema1 = z.object({ name: z.string().min(1, 'Required') });
|
|
144
|
+
const schema2 = z.object({ email: z.string().email() });
|
|
145
|
+
const schema3 = z.object({ password: z.string().min(8) });
|
|
146
|
+
|
|
147
|
+
export function RegistrationForm() {
|
|
148
|
+
return (
|
|
149
|
+
<Steps
|
|
150
|
+
schemas={[schema1, schema2, schema3]}
|
|
151
|
+
onSubmit={(data) => console.log('Submitted:', data)}
|
|
152
|
+
>
|
|
153
|
+
<Step title="Personal info">{/* your fields */}</Step>
|
|
154
|
+
|
|
155
|
+
<Step title="Contact">{/* your fields */}</Step>
|
|
156
|
+
|
|
157
|
+
<Step title="Security">{/* your fields */}</Step>
|
|
158
|
+
</Steps>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## API
|
|
166
|
+
|
|
167
|
+
### `useSteps(options)`
|
|
168
|
+
|
|
169
|
+
Manages step navigation state.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const {
|
|
173
|
+
currentStep, // number — 0-indexed
|
|
174
|
+
totalSteps, // number
|
|
175
|
+
isFirst, // boolean
|
|
176
|
+
isLast, // boolean
|
|
177
|
+
next, // () => void
|
|
178
|
+
prev, // () => void
|
|
179
|
+
goTo, // (index: number) => void
|
|
180
|
+
progress, // number — 0 to 100
|
|
181
|
+
} = useSteps({ totalSteps: 3, initialStep?: 0, onComplete?: () => void });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| Option | Type | Default | Description |
|
|
185
|
+
| ------------- | ------------ | ------- | -------------------------------------------------------- |
|
|
186
|
+
| `totalSteps` | `number` | — | **Required.** Must be a positive integer |
|
|
187
|
+
| `initialStep` | `number` | `0` | Starting step index |
|
|
188
|
+
| `onComplete` | `() => void` | — | Called once when the user first arrives at the last step |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### `useStepForm(options)`
|
|
193
|
+
|
|
194
|
+
Integrates react-hook-form with per-step Zod validation.
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const {
|
|
198
|
+
form, // UseFormReturn<z.infer<typeof schema>>
|
|
199
|
+
nextWithValidation, // () => Promise<boolean>
|
|
200
|
+
isValidating, // boolean
|
|
201
|
+
} = useStepForm({ schema, defaultValues?, onNext? });
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
| Option | Type | Description |
|
|
205
|
+
| --------------- | --------------------------- | --------------------------------------------- |
|
|
206
|
+
| `schema` | `ZodType` | **Required.** Zod schema for the current step |
|
|
207
|
+
| `defaultValues` | `Partial<z.infer<TSchema>>` | Initial field values |
|
|
208
|
+
| `onNext` | `(data) => void` | Called with validated data when advancing |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### `useStepsContext()`
|
|
213
|
+
|
|
214
|
+
Access step state from any component inside a `<Steps>` or `<StepsProvider>`.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { useStepsContext } from 'react-formsteps-core';
|
|
218
|
+
|
|
219
|
+
const { currentStep, totalSteps, next, prev, goTo, formData } = useStepsContext();
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### `<StepsProvider>` — headless context
|
|
225
|
+
|
|
226
|
+
Use the context without the UI package.
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
import { StepsProvider, useStepsContext } from 'react-formsteps-core';
|
|
230
|
+
|
|
231
|
+
<StepsProvider schemas={[schema1, schema2]} onSubmit={handleSubmit}>
|
|
232
|
+
<MyCustomWizard />
|
|
233
|
+
</StepsProvider>;
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### Utilities
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { validateStep, mergeSchemas, validateAllSteps } from 'react-formsteps-core';
|
|
242
|
+
|
|
243
|
+
// Validate a single step — never throws
|
|
244
|
+
const result = await validateStep(schema, data);
|
|
245
|
+
// { success: boolean, data?, errors?: Record<string, string> }
|
|
246
|
+
|
|
247
|
+
// Merge multiple ZodObject schemas into one
|
|
248
|
+
const fullSchema = mergeSchemas([step1Schema, step2Schema, step3Schema]);
|
|
249
|
+
|
|
250
|
+
// Validate all accumulated data against merged schemas
|
|
251
|
+
const result = await validateAllSteps(schemas, allData);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### UI Components
|
|
257
|
+
|
|
258
|
+
| Component | Description |
|
|
259
|
+
| ----------- | ----------------------------------------------------------- |
|
|
260
|
+
| `<Steps>` | Root provider. Pass `schemas` and `onSubmit`. |
|
|
261
|
+
| `<Step>` | Wrapper for each step's content. Accepts optional `title`. |
|
|
262
|
+
| `<StepBar>` | Progress bar with optional step labels. |
|
|
263
|
+
| `<StepNav>` | Back / Next / Submit buttons with built-in validation gate. |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## TypeScript
|
|
268
|
+
|
|
269
|
+
All APIs are fully typed. Enable `strict: true` in your `tsconfig.json` for the best experience.
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"compilerOptions": {
|
|
274
|
+
"strict": true
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Import types directly:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import type {
|
|
283
|
+
StepSchema,
|
|
284
|
+
StepConfig,
|
|
285
|
+
StepsContextValue,
|
|
286
|
+
UseStepsOptions,
|
|
287
|
+
UseStepsReturn,
|
|
288
|
+
UseStepFormOptions,
|
|
289
|
+
UseStepFormReturn,
|
|
290
|
+
StepsProviderProps,
|
|
291
|
+
} from 'react-formsteps-core';
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Contributing
|
|
297
|
+
|
|
298
|
+
Contributions via pull requests are welcome. Please open an issue first to discuss significant changes.
|
|
299
|
+
|
|
300
|
+
By submitting a contribution you agree that the original author (Franxx) retains full ownership and copyright of the project, including your contributions.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
Copyright (c) 2025 Franxx — see [LICENSE](./LICENSE) for full terms.
|
|
307
|
+
|
|
308
|
+
This software is free for personal, educational, and open source use. **Commercial use requires explicit written permission from the author.** See the license for details.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
<p align="center">Made by <a href="https://github.com/franklinjunior23">Franxx</a></p>
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ZodType, z, ZodObject } from 'zod';
|
|
2
|
+
import { UseFormReturn, FieldValues } from 'react-hook-form';
|
|
3
|
+
import React$1 from 'react';
|
|
4
|
+
|
|
5
|
+
type StepSchema = ZodType<Record<string, unknown>>;
|
|
6
|
+
interface StepConfig {
|
|
7
|
+
id: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
schema?: StepSchema;
|
|
10
|
+
}
|
|
11
|
+
interface StepsContextValue {
|
|
12
|
+
currentStep: number;
|
|
13
|
+
totalSteps: number;
|
|
14
|
+
isFirst: boolean;
|
|
15
|
+
isLast: boolean;
|
|
16
|
+
next: () => void;
|
|
17
|
+
prev: () => void;
|
|
18
|
+
goTo: (index: number) => void;
|
|
19
|
+
formData: Record<string, unknown>;
|
|
20
|
+
setStepData: (step: number, data: Record<string, unknown>) => void;
|
|
21
|
+
schemas: StepSchema[];
|
|
22
|
+
}
|
|
23
|
+
interface UseStepsOptions {
|
|
24
|
+
totalSteps: number;
|
|
25
|
+
initialStep?: number;
|
|
26
|
+
onComplete?: () => void;
|
|
27
|
+
}
|
|
28
|
+
interface UseStepsReturn {
|
|
29
|
+
currentStep: number;
|
|
30
|
+
totalSteps: number;
|
|
31
|
+
isFirst: boolean;
|
|
32
|
+
isLast: boolean;
|
|
33
|
+
next: () => void;
|
|
34
|
+
prev: () => void;
|
|
35
|
+
goTo: (index: number) => void;
|
|
36
|
+
progress: number;
|
|
37
|
+
}
|
|
38
|
+
interface UseStepFormOptions<TSchema extends ZodType = ZodType> {
|
|
39
|
+
schema: TSchema;
|
|
40
|
+
defaultValues?: Partial<z.infer<TSchema>>;
|
|
41
|
+
onNext?: (data: z.infer<TSchema>) => void;
|
|
42
|
+
}
|
|
43
|
+
interface UseStepFormReturn<TSchema extends ZodType = ZodType> {
|
|
44
|
+
form: UseFormReturn<z.infer<TSchema> & FieldValues>;
|
|
45
|
+
nextWithValidation: () => Promise<boolean>;
|
|
46
|
+
isValidating: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface StepsProviderProps {
|
|
49
|
+
children: React.ReactNode;
|
|
50
|
+
schemas: StepSchema[];
|
|
51
|
+
onSubmit?: (data: Record<string, unknown>) => void;
|
|
52
|
+
initialStep?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare function useSteps({ totalSteps, initialStep, onComplete, }: UseStepsOptions): UseStepsReturn;
|
|
56
|
+
|
|
57
|
+
declare function useStepForm<TSchema extends ZodType>({ schema, defaultValues, onNext, }: UseStepFormOptions<TSchema>): UseStepFormReturn<TSchema>;
|
|
58
|
+
|
|
59
|
+
declare const StepsContext: React$1.Context<StepsContextValue | null>;
|
|
60
|
+
declare function useStepsContext(): StepsContextValue;
|
|
61
|
+
declare function StepsProvider({ children, schemas, initialStep }: StepsProviderProps): React$1.FunctionComponentElement<React$1.ProviderProps<StepsContextValue | null>>;
|
|
62
|
+
|
|
63
|
+
interface ValidateStepResult {
|
|
64
|
+
success: boolean;
|
|
65
|
+
errors?: Record<string, string>;
|
|
66
|
+
data?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
declare function validateStep(schema: ZodType, data: Record<string, unknown>): Promise<ValidateStepResult>;
|
|
69
|
+
|
|
70
|
+
type AnyZodObject = ZodObject<any, any, any>;
|
|
71
|
+
/**
|
|
72
|
+
* Merges multiple Zod schemas into a single ZodObject schema.
|
|
73
|
+
* Only merges ZodObject schemas; other schema types are skipped.
|
|
74
|
+
*/
|
|
75
|
+
declare function mergeSchemas(schemas: ZodType[]): AnyZodObject;
|
|
76
|
+
/**
|
|
77
|
+
* Validates all accumulated form data against the merged schema.
|
|
78
|
+
*/
|
|
79
|
+
declare function validateAllSteps(schemas: ZodType[], data: Record<string, unknown>): Promise<{
|
|
80
|
+
success: boolean;
|
|
81
|
+
data?: Record<string, unknown>;
|
|
82
|
+
errors?: Record<string, string>;
|
|
83
|
+
}>;
|
|
84
|
+
|
|
85
|
+
export { type StepConfig, type StepSchema, StepsContext, type StepsContextValue, StepsProvider, type StepsProviderProps, type UseStepFormOptions, type UseStepFormReturn, type UseStepsOptions, type UseStepsReturn, mergeSchemas, useStepForm, useSteps, useStepsContext, validateAllSteps, validateStep };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ZodType, z, ZodObject } from 'zod';
|
|
2
|
+
import { UseFormReturn, FieldValues } from 'react-hook-form';
|
|
3
|
+
import React$1 from 'react';
|
|
4
|
+
|
|
5
|
+
type StepSchema = ZodType<Record<string, unknown>>;
|
|
6
|
+
interface StepConfig {
|
|
7
|
+
id: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
schema?: StepSchema;
|
|
10
|
+
}
|
|
11
|
+
interface StepsContextValue {
|
|
12
|
+
currentStep: number;
|
|
13
|
+
totalSteps: number;
|
|
14
|
+
isFirst: boolean;
|
|
15
|
+
isLast: boolean;
|
|
16
|
+
next: () => void;
|
|
17
|
+
prev: () => void;
|
|
18
|
+
goTo: (index: number) => void;
|
|
19
|
+
formData: Record<string, unknown>;
|
|
20
|
+
setStepData: (step: number, data: Record<string, unknown>) => void;
|
|
21
|
+
schemas: StepSchema[];
|
|
22
|
+
}
|
|
23
|
+
interface UseStepsOptions {
|
|
24
|
+
totalSteps: number;
|
|
25
|
+
initialStep?: number;
|
|
26
|
+
onComplete?: () => void;
|
|
27
|
+
}
|
|
28
|
+
interface UseStepsReturn {
|
|
29
|
+
currentStep: number;
|
|
30
|
+
totalSteps: number;
|
|
31
|
+
isFirst: boolean;
|
|
32
|
+
isLast: boolean;
|
|
33
|
+
next: () => void;
|
|
34
|
+
prev: () => void;
|
|
35
|
+
goTo: (index: number) => void;
|
|
36
|
+
progress: number;
|
|
37
|
+
}
|
|
38
|
+
interface UseStepFormOptions<TSchema extends ZodType = ZodType> {
|
|
39
|
+
schema: TSchema;
|
|
40
|
+
defaultValues?: Partial<z.infer<TSchema>>;
|
|
41
|
+
onNext?: (data: z.infer<TSchema>) => void;
|
|
42
|
+
}
|
|
43
|
+
interface UseStepFormReturn<TSchema extends ZodType = ZodType> {
|
|
44
|
+
form: UseFormReturn<z.infer<TSchema> & FieldValues>;
|
|
45
|
+
nextWithValidation: () => Promise<boolean>;
|
|
46
|
+
isValidating: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface StepsProviderProps {
|
|
49
|
+
children: React.ReactNode;
|
|
50
|
+
schemas: StepSchema[];
|
|
51
|
+
onSubmit?: (data: Record<string, unknown>) => void;
|
|
52
|
+
initialStep?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare function useSteps({ totalSteps, initialStep, onComplete, }: UseStepsOptions): UseStepsReturn;
|
|
56
|
+
|
|
57
|
+
declare function useStepForm<TSchema extends ZodType>({ schema, defaultValues, onNext, }: UseStepFormOptions<TSchema>): UseStepFormReturn<TSchema>;
|
|
58
|
+
|
|
59
|
+
declare const StepsContext: React$1.Context<StepsContextValue | null>;
|
|
60
|
+
declare function useStepsContext(): StepsContextValue;
|
|
61
|
+
declare function StepsProvider({ children, schemas, initialStep }: StepsProviderProps): React$1.FunctionComponentElement<React$1.ProviderProps<StepsContextValue | null>>;
|
|
62
|
+
|
|
63
|
+
interface ValidateStepResult {
|
|
64
|
+
success: boolean;
|
|
65
|
+
errors?: Record<string, string>;
|
|
66
|
+
data?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
declare function validateStep(schema: ZodType, data: Record<string, unknown>): Promise<ValidateStepResult>;
|
|
69
|
+
|
|
70
|
+
type AnyZodObject = ZodObject<any, any, any>;
|
|
71
|
+
/**
|
|
72
|
+
* Merges multiple Zod schemas into a single ZodObject schema.
|
|
73
|
+
* Only merges ZodObject schemas; other schema types are skipped.
|
|
74
|
+
*/
|
|
75
|
+
declare function mergeSchemas(schemas: ZodType[]): AnyZodObject;
|
|
76
|
+
/**
|
|
77
|
+
* Validates all accumulated form data against the merged schema.
|
|
78
|
+
*/
|
|
79
|
+
declare function validateAllSteps(schemas: ZodType[], data: Record<string, unknown>): Promise<{
|
|
80
|
+
success: boolean;
|
|
81
|
+
data?: Record<string, unknown>;
|
|
82
|
+
errors?: Record<string, string>;
|
|
83
|
+
}>;
|
|
84
|
+
|
|
85
|
+
export { type StepConfig, type StepSchema, StepsContext, type StepsContextValue, StepsProvider, type StepsProviderProps, type UseStepFormOptions, type UseStepFormReturn, type UseStepsOptions, type UseStepsReturn, mergeSchemas, useStepForm, useSteps, useStepsContext, validateAllSteps, validateStep };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
StepsContext: () => StepsContext,
|
|
34
|
+
StepsProvider: () => StepsProvider,
|
|
35
|
+
mergeSchemas: () => mergeSchemas,
|
|
36
|
+
useStepForm: () => useStepForm,
|
|
37
|
+
useSteps: () => useSteps,
|
|
38
|
+
useStepsContext: () => useStepsContext,
|
|
39
|
+
validateAllSteps: () => validateAllSteps,
|
|
40
|
+
validateStep: () => validateStep
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(index_exports);
|
|
43
|
+
|
|
44
|
+
// src/hooks/useSteps.ts
|
|
45
|
+
var import_react = require("react");
|
|
46
|
+
function useSteps({
|
|
47
|
+
totalSteps,
|
|
48
|
+
initialStep = 0,
|
|
49
|
+
onComplete
|
|
50
|
+
}) {
|
|
51
|
+
if (totalSteps <= 0) {
|
|
52
|
+
throw new Error("[useSteps] totalSteps must be a positive integer");
|
|
53
|
+
}
|
|
54
|
+
const [currentStep, setCurrentStep] = (0, import_react.useState)(initialStep);
|
|
55
|
+
const next = (0, import_react.useCallback)(() => {
|
|
56
|
+
setCurrentStep((prev2) => {
|
|
57
|
+
const nextStep = Math.min(prev2 + 1, totalSteps - 1);
|
|
58
|
+
if (nextStep === totalSteps - 1 && prev2 !== totalSteps - 1) {
|
|
59
|
+
onComplete?.();
|
|
60
|
+
}
|
|
61
|
+
return nextStep;
|
|
62
|
+
});
|
|
63
|
+
}, [totalSteps, onComplete]);
|
|
64
|
+
const prev = (0, import_react.useCallback)(() => {
|
|
65
|
+
setCurrentStep((prev2) => Math.max(prev2 - 1, 0));
|
|
66
|
+
}, []);
|
|
67
|
+
const goTo = (0, import_react.useCallback)(
|
|
68
|
+
(index) => {
|
|
69
|
+
if (index >= 0 && index < totalSteps) {
|
|
70
|
+
setCurrentStep(index);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
[totalSteps]
|
|
74
|
+
);
|
|
75
|
+
const progress = totalSteps > 1 ? Math.round(currentStep / (totalSteps - 1) * 100) : 100;
|
|
76
|
+
return {
|
|
77
|
+
currentStep,
|
|
78
|
+
totalSteps,
|
|
79
|
+
isFirst: currentStep === 0,
|
|
80
|
+
isLast: currentStep === totalSteps - 1,
|
|
81
|
+
next,
|
|
82
|
+
prev,
|
|
83
|
+
goTo,
|
|
84
|
+
progress
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/hooks/useStepForm.ts
|
|
89
|
+
var import_react2 = require("react");
|
|
90
|
+
var import_react_hook_form = require("react-hook-form");
|
|
91
|
+
var import_zod = require("@hookform/resolvers/zod");
|
|
92
|
+
function useStepForm({
|
|
93
|
+
schema,
|
|
94
|
+
defaultValues,
|
|
95
|
+
onNext
|
|
96
|
+
}) {
|
|
97
|
+
const [isValidating, setIsValidating] = (0, import_react2.useState)(false);
|
|
98
|
+
const form = (0, import_react_hook_form.useForm)({
|
|
99
|
+
resolver: (0, import_zod.zodResolver)(schema),
|
|
100
|
+
// Cast needed: react-hook-form expects FieldValues but z.infer<TSchema> satisfies it at runtime
|
|
101
|
+
defaultValues,
|
|
102
|
+
mode: "onSubmit"
|
|
103
|
+
});
|
|
104
|
+
const nextWithValidation = (0, import_react2.useCallback)(async () => {
|
|
105
|
+
setIsValidating(true);
|
|
106
|
+
try {
|
|
107
|
+
const isValid = await form.trigger();
|
|
108
|
+
if (isValid) {
|
|
109
|
+
const data = form.getValues();
|
|
110
|
+
onNext?.(data);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
} finally {
|
|
115
|
+
setIsValidating(false);
|
|
116
|
+
}
|
|
117
|
+
}, [form, onNext]);
|
|
118
|
+
return {
|
|
119
|
+
form,
|
|
120
|
+
nextWithValidation,
|
|
121
|
+
isValidating
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/context/StepsContext.ts
|
|
126
|
+
var import_react3 = __toESM(require("react"));
|
|
127
|
+
var StepsContext = (0, import_react3.createContext)(null);
|
|
128
|
+
function useStepsContext() {
|
|
129
|
+
const ctx = (0, import_react3.useContext)(StepsContext);
|
|
130
|
+
if (!ctx) {
|
|
131
|
+
throw new Error("useStepsContext must be used within a StepsProvider");
|
|
132
|
+
}
|
|
133
|
+
return ctx;
|
|
134
|
+
}
|
|
135
|
+
function StepsProvider({ children, schemas, initialStep = 0 }) {
|
|
136
|
+
const totalSteps = schemas.length;
|
|
137
|
+
const [currentStep, setCurrentStep] = (0, import_react3.useState)(initialStep);
|
|
138
|
+
const [formData, setFormData] = (0, import_react3.useState)({});
|
|
139
|
+
const next = (0, import_react3.useCallback)(
|
|
140
|
+
() => setCurrentStep((s) => Math.min(s + 1, totalSteps - 1)),
|
|
141
|
+
[totalSteps]
|
|
142
|
+
);
|
|
143
|
+
const prev = (0, import_react3.useCallback)(() => setCurrentStep((s) => Math.max(s - 1, 0)), []);
|
|
144
|
+
const goTo = (0, import_react3.useCallback)(
|
|
145
|
+
(index) => {
|
|
146
|
+
if (index >= 0 && index < totalSteps) setCurrentStep(index);
|
|
147
|
+
},
|
|
148
|
+
[totalSteps]
|
|
149
|
+
);
|
|
150
|
+
const setStepData = (0, import_react3.useCallback)((_step, data) => {
|
|
151
|
+
setFormData((prev2) => ({ ...prev2, ...data }));
|
|
152
|
+
}, []);
|
|
153
|
+
const contextValue = (0, import_react3.useMemo)(
|
|
154
|
+
() => ({
|
|
155
|
+
currentStep,
|
|
156
|
+
totalSteps,
|
|
157
|
+
isFirst: currentStep === 0,
|
|
158
|
+
isLast: currentStep === totalSteps - 1,
|
|
159
|
+
next,
|
|
160
|
+
prev,
|
|
161
|
+
goTo,
|
|
162
|
+
formData,
|
|
163
|
+
setStepData,
|
|
164
|
+
schemas
|
|
165
|
+
}),
|
|
166
|
+
[currentStep, totalSteps, next, prev, goTo, formData, setStepData, schemas]
|
|
167
|
+
);
|
|
168
|
+
return import_react3.default.createElement(StepsContext.Provider, { value: contextValue }, children);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/utils/validateStep.ts
|
|
172
|
+
var import_zod2 = require("zod");
|
|
173
|
+
async function validateStep(schema, data) {
|
|
174
|
+
try {
|
|
175
|
+
const parsed = await schema.parseAsync(data);
|
|
176
|
+
return { success: true, data: parsed };
|
|
177
|
+
} catch (err) {
|
|
178
|
+
if (err instanceof import_zod2.ZodError) {
|
|
179
|
+
const errors = {};
|
|
180
|
+
for (const issue of err.issues) {
|
|
181
|
+
const path = issue.path.join(".");
|
|
182
|
+
errors[path] = issue.message;
|
|
183
|
+
}
|
|
184
|
+
return { success: false, errors };
|
|
185
|
+
}
|
|
186
|
+
return { success: false, errors: { _root: "Validation failed" } };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/utils/mergeSchemas.ts
|
|
191
|
+
var import_zod3 = require("zod");
|
|
192
|
+
function mergeSchemas(schemas) {
|
|
193
|
+
let merged = import_zod3.z.object({});
|
|
194
|
+
for (const schema of schemas) {
|
|
195
|
+
if (schema instanceof import_zod3.ZodObject) {
|
|
196
|
+
merged = merged.merge(schema);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return merged;
|
|
200
|
+
}
|
|
201
|
+
async function validateAllSteps(schemas, data) {
|
|
202
|
+
const mergedSchema = mergeSchemas(schemas);
|
|
203
|
+
try {
|
|
204
|
+
const parsed = await mergedSchema.parseAsync(data);
|
|
205
|
+
return { success: true, data: parsed };
|
|
206
|
+
} catch (err) {
|
|
207
|
+
const { ZodError: ZodError2 } = await import("zod");
|
|
208
|
+
if (err instanceof ZodError2) {
|
|
209
|
+
const errors = {};
|
|
210
|
+
for (const issue of err.issues) {
|
|
211
|
+
errors[issue.path.join(".")] = issue.message;
|
|
212
|
+
}
|
|
213
|
+
return { success: false, errors };
|
|
214
|
+
}
|
|
215
|
+
return { success: false };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
219
|
+
0 && (module.exports = {
|
|
220
|
+
StepsContext,
|
|
221
|
+
StepsProvider,
|
|
222
|
+
mergeSchemas,
|
|
223
|
+
useStepForm,
|
|
224
|
+
useSteps,
|
|
225
|
+
useStepsContext,
|
|
226
|
+
validateAllSteps,
|
|
227
|
+
validateStep
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/useSteps.ts","../src/hooks/useStepForm.ts","../src/context/StepsContext.ts","../src/utils/validateStep.ts","../src/utils/mergeSchemas.ts"],"sourcesContent":["// Hooks\nexport { useSteps } from './hooks/useSteps';\nexport { useStepForm } from './hooks/useStepForm';\n\n// Context\nexport { StepsContext, useStepsContext, StepsProvider } from './context/StepsContext';\n\n// Utils\nexport { validateStep } from './utils/validateStep';\nexport { mergeSchemas, validateAllSteps } from './utils/mergeSchemas';\n\n// Types\nexport type {\n StepConfig,\n StepSchema,\n StepsContextValue,\n UseStepsOptions,\n UseStepsReturn,\n UseStepFormOptions,\n UseStepFormReturn,\n StepsProviderProps,\n} from './types';\n","import { useState, useCallback } from 'react';\nimport { UseStepsOptions, UseStepsReturn } from '../types';\n\nexport function useSteps({\n totalSteps,\n initialStep = 0,\n onComplete,\n}: UseStepsOptions): UseStepsReturn {\n if (totalSteps <= 0) {\n throw new Error('[useSteps] totalSteps must be a positive integer');\n }\n\n const [currentStep, setCurrentStep] = useState(initialStep);\n\n const next = useCallback(() => {\n setCurrentStep((prev) => {\n const nextStep = Math.min(prev + 1, totalSteps - 1);\n if (nextStep === totalSteps - 1 && prev !== totalSteps - 1) {\n onComplete?.();\n }\n return nextStep;\n });\n }, [totalSteps, onComplete]);\n\n const prev = useCallback(() => {\n setCurrentStep((prev) => Math.max(prev - 1, 0));\n }, []);\n\n const goTo = useCallback(\n (index: number) => {\n if (index >= 0 && index < totalSteps) {\n setCurrentStep(index);\n }\n },\n [totalSteps]\n );\n\n const progress = totalSteps > 1 ? Math.round((currentStep / (totalSteps - 1)) * 100) : 100;\n\n return {\n currentStep,\n totalSteps,\n isFirst: currentStep === 0,\n isLast: currentStep === totalSteps - 1,\n next,\n prev,\n goTo,\n progress,\n };\n}\n","import { useState, useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { ZodType, z } from 'zod';\nimport { UseStepFormOptions, UseStepFormReturn } from '../types';\n\nexport function useStepForm<TSchema extends ZodType>({\n schema,\n defaultValues,\n onNext,\n}: UseStepFormOptions<TSchema>): UseStepFormReturn<TSchema> {\n const [isValidating, setIsValidating] = useState(false);\n\n const form = useForm<z.infer<TSchema>>({\n resolver: zodResolver(schema),\n // Cast needed: react-hook-form expects FieldValues but z.infer<TSchema> satisfies it at runtime\n defaultValues: defaultValues as z.infer<TSchema>,\n mode: 'onSubmit',\n });\n\n const nextWithValidation = useCallback(async (): Promise<boolean> => {\n setIsValidating(true);\n try {\n const isValid = await form.trigger();\n if (isValid) {\n const data = form.getValues();\n onNext?.(data);\n return true;\n }\n return false;\n } finally {\n setIsValidating(false);\n }\n }, [form, onNext]);\n\n return {\n form,\n nextWithValidation,\n isValidating,\n };\n}\n","import React, { createContext, useContext, useState, useCallback, useMemo } from 'react';\nimport { StepsContextValue, StepsProviderProps } from '../types';\n\nexport const StepsContext = createContext<StepsContextValue | null>(null);\n\nexport function useStepsContext(): StepsContextValue {\n const ctx = useContext(StepsContext);\n if (!ctx) {\n throw new Error('useStepsContext must be used within a StepsProvider');\n }\n return ctx;\n}\n\nexport function StepsProvider({ children, schemas, initialStep = 0 }: StepsProviderProps) {\n // We derive totalSteps from schemas length for headless usage\n const totalSteps = schemas.length;\n const [currentStep, setCurrentStep] = useState(initialStep);\n const [formData, setFormData] = useState<Record<string, unknown>>({});\n\n const next = useCallback(\n () => setCurrentStep((s) => Math.min(s + 1, totalSteps - 1)),\n [totalSteps]\n );\n const prev = useCallback(() => setCurrentStep((s) => Math.max(s - 1, 0)), []);\n const goTo = useCallback(\n (index: number) => {\n if (index >= 0 && index < totalSteps) setCurrentStep(index);\n },\n [totalSteps]\n );\n\n const setStepData = useCallback((_step: number, data: Record<string, unknown>) => {\n setFormData((prev) => ({ ...prev, ...data }));\n }, []);\n\n const contextValue: StepsContextValue = useMemo(\n () => ({\n currentStep,\n totalSteps,\n isFirst: currentStep === 0,\n isLast: currentStep === totalSteps - 1,\n next,\n prev,\n goTo,\n formData,\n setStepData,\n schemas,\n }),\n [currentStep, totalSteps, next, prev, goTo, formData, setStepData, schemas]\n );\n\n return React.createElement(StepsContext.Provider, { value: contextValue }, children);\n}\n","import { ZodType, ZodError } from 'zod';\n\nexport interface ValidateStepResult {\n success: boolean;\n errors?: Record<string, string>;\n data?: Record<string, unknown>;\n}\n\nexport async function validateStep(\n schema: ZodType,\n data: Record<string, unknown>\n): Promise<ValidateStepResult> {\n try {\n const parsed = await schema.parseAsync(data);\n return { success: true, data: parsed as Record<string, unknown> };\n } catch (err) {\n if (err instanceof ZodError) {\n const errors: Record<string, string> = {};\n for (const issue of err.issues) {\n const path = issue.path.join('.');\n errors[path] = issue.message;\n }\n return { success: false, errors };\n }\n return { success: false, errors: { _root: 'Validation failed' } };\n }\n}\n","import { z, ZodType, ZodObject, ZodTypeAny } from 'zod';\n\n// ZodObject generics (shape, unknownKeys, catchall) vary across schemas after `.merge()`,\n// making a precise generic type impractical here. `any` is intentional and safe.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyZodObject = ZodObject<any, any, any>;\n\n/**\n * Merges multiple Zod schemas into a single ZodObject schema.\n * Only merges ZodObject schemas; other schema types are skipped.\n */\nexport function mergeSchemas(schemas: ZodType[]): AnyZodObject {\n let merged: AnyZodObject = z.object({});\n\n for (const schema of schemas) {\n if (schema instanceof ZodObject) {\n merged = merged.merge(schema as ZodObject<Record<string, ZodTypeAny>>);\n }\n }\n\n return merged;\n}\n\n/**\n * Validates all accumulated form data against the merged schema.\n */\nexport async function validateAllSteps(\n schemas: ZodType[],\n data: Record<string, unknown>\n): Promise<{ success: boolean; data?: Record<string, unknown>; errors?: Record<string, string> }> {\n const mergedSchema = mergeSchemas(schemas);\n try {\n const parsed = await mergedSchema.parseAsync(data);\n return { success: true, data: parsed as Record<string, unknown> };\n } catch (err) {\n const { ZodError } = await import('zod');\n if (err instanceof ZodError) {\n const errors: Record<string, string> = {};\n for (const issue of err.issues) {\n errors[issue.path.join('.')] = issue.message;\n }\n return { success: false, errors };\n }\n return { success: false };\n }\n}\n"],"mappings":"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","names":["prev","import_react","import_react","prev","React","import_zod","import_zod","ZodError"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// src/hooks/useSteps.ts
|
|
2
|
+
import { useState, useCallback } from "react";
|
|
3
|
+
function useSteps({
|
|
4
|
+
totalSteps,
|
|
5
|
+
initialStep = 0,
|
|
6
|
+
onComplete
|
|
7
|
+
}) {
|
|
8
|
+
if (totalSteps <= 0) {
|
|
9
|
+
throw new Error("[useSteps] totalSteps must be a positive integer");
|
|
10
|
+
}
|
|
11
|
+
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
12
|
+
const next = useCallback(() => {
|
|
13
|
+
setCurrentStep((prev2) => {
|
|
14
|
+
const nextStep = Math.min(prev2 + 1, totalSteps - 1);
|
|
15
|
+
if (nextStep === totalSteps - 1 && prev2 !== totalSteps - 1) {
|
|
16
|
+
onComplete?.();
|
|
17
|
+
}
|
|
18
|
+
return nextStep;
|
|
19
|
+
});
|
|
20
|
+
}, [totalSteps, onComplete]);
|
|
21
|
+
const prev = useCallback(() => {
|
|
22
|
+
setCurrentStep((prev2) => Math.max(prev2 - 1, 0));
|
|
23
|
+
}, []);
|
|
24
|
+
const goTo = useCallback(
|
|
25
|
+
(index) => {
|
|
26
|
+
if (index >= 0 && index < totalSteps) {
|
|
27
|
+
setCurrentStep(index);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
[totalSteps]
|
|
31
|
+
);
|
|
32
|
+
const progress = totalSteps > 1 ? Math.round(currentStep / (totalSteps - 1) * 100) : 100;
|
|
33
|
+
return {
|
|
34
|
+
currentStep,
|
|
35
|
+
totalSteps,
|
|
36
|
+
isFirst: currentStep === 0,
|
|
37
|
+
isLast: currentStep === totalSteps - 1,
|
|
38
|
+
next,
|
|
39
|
+
prev,
|
|
40
|
+
goTo,
|
|
41
|
+
progress
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/hooks/useStepForm.ts
|
|
46
|
+
import { useState as useState2, useCallback as useCallback2 } from "react";
|
|
47
|
+
import { useForm } from "react-hook-form";
|
|
48
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
49
|
+
function useStepForm({
|
|
50
|
+
schema,
|
|
51
|
+
defaultValues,
|
|
52
|
+
onNext
|
|
53
|
+
}) {
|
|
54
|
+
const [isValidating, setIsValidating] = useState2(false);
|
|
55
|
+
const form = useForm({
|
|
56
|
+
resolver: zodResolver(schema),
|
|
57
|
+
// Cast needed: react-hook-form expects FieldValues but z.infer<TSchema> satisfies it at runtime
|
|
58
|
+
defaultValues,
|
|
59
|
+
mode: "onSubmit"
|
|
60
|
+
});
|
|
61
|
+
const nextWithValidation = useCallback2(async () => {
|
|
62
|
+
setIsValidating(true);
|
|
63
|
+
try {
|
|
64
|
+
const isValid = await form.trigger();
|
|
65
|
+
if (isValid) {
|
|
66
|
+
const data = form.getValues();
|
|
67
|
+
onNext?.(data);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
} finally {
|
|
72
|
+
setIsValidating(false);
|
|
73
|
+
}
|
|
74
|
+
}, [form, onNext]);
|
|
75
|
+
return {
|
|
76
|
+
form,
|
|
77
|
+
nextWithValidation,
|
|
78
|
+
isValidating
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/context/StepsContext.ts
|
|
83
|
+
import React, { createContext, useContext, useState as useState3, useCallback as useCallback3, useMemo } from "react";
|
|
84
|
+
var StepsContext = createContext(null);
|
|
85
|
+
function useStepsContext() {
|
|
86
|
+
const ctx = useContext(StepsContext);
|
|
87
|
+
if (!ctx) {
|
|
88
|
+
throw new Error("useStepsContext must be used within a StepsProvider");
|
|
89
|
+
}
|
|
90
|
+
return ctx;
|
|
91
|
+
}
|
|
92
|
+
function StepsProvider({ children, schemas, initialStep = 0 }) {
|
|
93
|
+
const totalSteps = schemas.length;
|
|
94
|
+
const [currentStep, setCurrentStep] = useState3(initialStep);
|
|
95
|
+
const [formData, setFormData] = useState3({});
|
|
96
|
+
const next = useCallback3(
|
|
97
|
+
() => setCurrentStep((s) => Math.min(s + 1, totalSteps - 1)),
|
|
98
|
+
[totalSteps]
|
|
99
|
+
);
|
|
100
|
+
const prev = useCallback3(() => setCurrentStep((s) => Math.max(s - 1, 0)), []);
|
|
101
|
+
const goTo = useCallback3(
|
|
102
|
+
(index) => {
|
|
103
|
+
if (index >= 0 && index < totalSteps) setCurrentStep(index);
|
|
104
|
+
},
|
|
105
|
+
[totalSteps]
|
|
106
|
+
);
|
|
107
|
+
const setStepData = useCallback3((_step, data) => {
|
|
108
|
+
setFormData((prev2) => ({ ...prev2, ...data }));
|
|
109
|
+
}, []);
|
|
110
|
+
const contextValue = useMemo(
|
|
111
|
+
() => ({
|
|
112
|
+
currentStep,
|
|
113
|
+
totalSteps,
|
|
114
|
+
isFirst: currentStep === 0,
|
|
115
|
+
isLast: currentStep === totalSteps - 1,
|
|
116
|
+
next,
|
|
117
|
+
prev,
|
|
118
|
+
goTo,
|
|
119
|
+
formData,
|
|
120
|
+
setStepData,
|
|
121
|
+
schemas
|
|
122
|
+
}),
|
|
123
|
+
[currentStep, totalSteps, next, prev, goTo, formData, setStepData, schemas]
|
|
124
|
+
);
|
|
125
|
+
return React.createElement(StepsContext.Provider, { value: contextValue }, children);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/utils/validateStep.ts
|
|
129
|
+
import { ZodError } from "zod";
|
|
130
|
+
async function validateStep(schema, data) {
|
|
131
|
+
try {
|
|
132
|
+
const parsed = await schema.parseAsync(data);
|
|
133
|
+
return { success: true, data: parsed };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
if (err instanceof ZodError) {
|
|
136
|
+
const errors = {};
|
|
137
|
+
for (const issue of err.issues) {
|
|
138
|
+
const path = issue.path.join(".");
|
|
139
|
+
errors[path] = issue.message;
|
|
140
|
+
}
|
|
141
|
+
return { success: false, errors };
|
|
142
|
+
}
|
|
143
|
+
return { success: false, errors: { _root: "Validation failed" } };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/utils/mergeSchemas.ts
|
|
148
|
+
import { z, ZodObject } from "zod";
|
|
149
|
+
function mergeSchemas(schemas) {
|
|
150
|
+
let merged = z.object({});
|
|
151
|
+
for (const schema of schemas) {
|
|
152
|
+
if (schema instanceof ZodObject) {
|
|
153
|
+
merged = merged.merge(schema);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return merged;
|
|
157
|
+
}
|
|
158
|
+
async function validateAllSteps(schemas, data) {
|
|
159
|
+
const mergedSchema = mergeSchemas(schemas);
|
|
160
|
+
try {
|
|
161
|
+
const parsed = await mergedSchema.parseAsync(data);
|
|
162
|
+
return { success: true, data: parsed };
|
|
163
|
+
} catch (err) {
|
|
164
|
+
const { ZodError: ZodError2 } = await import("zod");
|
|
165
|
+
if (err instanceof ZodError2) {
|
|
166
|
+
const errors = {};
|
|
167
|
+
for (const issue of err.issues) {
|
|
168
|
+
errors[issue.path.join(".")] = issue.message;
|
|
169
|
+
}
|
|
170
|
+
return { success: false, errors };
|
|
171
|
+
}
|
|
172
|
+
return { success: false };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
StepsContext,
|
|
177
|
+
StepsProvider,
|
|
178
|
+
mergeSchemas,
|
|
179
|
+
useStepForm,
|
|
180
|
+
useSteps,
|
|
181
|
+
useStepsContext,
|
|
182
|
+
validateAllSteps,
|
|
183
|
+
validateStep
|
|
184
|
+
};
|
|
185
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useSteps.ts","../src/hooks/useStepForm.ts","../src/context/StepsContext.ts","../src/utils/validateStep.ts","../src/utils/mergeSchemas.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { UseStepsOptions, UseStepsReturn } from '../types';\n\nexport function useSteps({\n totalSteps,\n initialStep = 0,\n onComplete,\n}: UseStepsOptions): UseStepsReturn {\n if (totalSteps <= 0) {\n throw new Error('[useSteps] totalSteps must be a positive integer');\n }\n\n const [currentStep, setCurrentStep] = useState(initialStep);\n\n const next = useCallback(() => {\n setCurrentStep((prev) => {\n const nextStep = Math.min(prev + 1, totalSteps - 1);\n if (nextStep === totalSteps - 1 && prev !== totalSteps - 1) {\n onComplete?.();\n }\n return nextStep;\n });\n }, [totalSteps, onComplete]);\n\n const prev = useCallback(() => {\n setCurrentStep((prev) => Math.max(prev - 1, 0));\n }, []);\n\n const goTo = useCallback(\n (index: number) => {\n if (index >= 0 && index < totalSteps) {\n setCurrentStep(index);\n }\n },\n [totalSteps]\n );\n\n const progress = totalSteps > 1 ? Math.round((currentStep / (totalSteps - 1)) * 100) : 100;\n\n return {\n currentStep,\n totalSteps,\n isFirst: currentStep === 0,\n isLast: currentStep === totalSteps - 1,\n next,\n prev,\n goTo,\n progress,\n };\n}\n","import { useState, useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { ZodType, z } from 'zod';\nimport { UseStepFormOptions, UseStepFormReturn } from '../types';\n\nexport function useStepForm<TSchema extends ZodType>({\n schema,\n defaultValues,\n onNext,\n}: UseStepFormOptions<TSchema>): UseStepFormReturn<TSchema> {\n const [isValidating, setIsValidating] = useState(false);\n\n const form = useForm<z.infer<TSchema>>({\n resolver: zodResolver(schema),\n // Cast needed: react-hook-form expects FieldValues but z.infer<TSchema> satisfies it at runtime\n defaultValues: defaultValues as z.infer<TSchema>,\n mode: 'onSubmit',\n });\n\n const nextWithValidation = useCallback(async (): Promise<boolean> => {\n setIsValidating(true);\n try {\n const isValid = await form.trigger();\n if (isValid) {\n const data = form.getValues();\n onNext?.(data);\n return true;\n }\n return false;\n } finally {\n setIsValidating(false);\n }\n }, [form, onNext]);\n\n return {\n form,\n nextWithValidation,\n isValidating,\n };\n}\n","import React, { createContext, useContext, useState, useCallback, useMemo } from 'react';\nimport { StepsContextValue, StepsProviderProps } from '../types';\n\nexport const StepsContext = createContext<StepsContextValue | null>(null);\n\nexport function useStepsContext(): StepsContextValue {\n const ctx = useContext(StepsContext);\n if (!ctx) {\n throw new Error('useStepsContext must be used within a StepsProvider');\n }\n return ctx;\n}\n\nexport function StepsProvider({ children, schemas, initialStep = 0 }: StepsProviderProps) {\n // We derive totalSteps from schemas length for headless usage\n const totalSteps = schemas.length;\n const [currentStep, setCurrentStep] = useState(initialStep);\n const [formData, setFormData] = useState<Record<string, unknown>>({});\n\n const next = useCallback(\n () => setCurrentStep((s) => Math.min(s + 1, totalSteps - 1)),\n [totalSteps]\n );\n const prev = useCallback(() => setCurrentStep((s) => Math.max(s - 1, 0)), []);\n const goTo = useCallback(\n (index: number) => {\n if (index >= 0 && index < totalSteps) setCurrentStep(index);\n },\n [totalSteps]\n );\n\n const setStepData = useCallback((_step: number, data: Record<string, unknown>) => {\n setFormData((prev) => ({ ...prev, ...data }));\n }, []);\n\n const contextValue: StepsContextValue = useMemo(\n () => ({\n currentStep,\n totalSteps,\n isFirst: currentStep === 0,\n isLast: currentStep === totalSteps - 1,\n next,\n prev,\n goTo,\n formData,\n setStepData,\n schemas,\n }),\n [currentStep, totalSteps, next, prev, goTo, formData, setStepData, schemas]\n );\n\n return React.createElement(StepsContext.Provider, { value: contextValue }, children);\n}\n","import { ZodType, ZodError } from 'zod';\n\nexport interface ValidateStepResult {\n success: boolean;\n errors?: Record<string, string>;\n data?: Record<string, unknown>;\n}\n\nexport async function validateStep(\n schema: ZodType,\n data: Record<string, unknown>\n): Promise<ValidateStepResult> {\n try {\n const parsed = await schema.parseAsync(data);\n return { success: true, data: parsed as Record<string, unknown> };\n } catch (err) {\n if (err instanceof ZodError) {\n const errors: Record<string, string> = {};\n for (const issue of err.issues) {\n const path = issue.path.join('.');\n errors[path] = issue.message;\n }\n return { success: false, errors };\n }\n return { success: false, errors: { _root: 'Validation failed' } };\n }\n}\n","import { z, ZodType, ZodObject, ZodTypeAny } from 'zod';\n\n// ZodObject generics (shape, unknownKeys, catchall) vary across schemas after `.merge()`,\n// making a precise generic type impractical here. `any` is intentional and safe.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyZodObject = ZodObject<any, any, any>;\n\n/**\n * Merges multiple Zod schemas into a single ZodObject schema.\n * Only merges ZodObject schemas; other schema types are skipped.\n */\nexport function mergeSchemas(schemas: ZodType[]): AnyZodObject {\n let merged: AnyZodObject = z.object({});\n\n for (const schema of schemas) {\n if (schema instanceof ZodObject) {\n merged = merged.merge(schema as ZodObject<Record<string, ZodTypeAny>>);\n }\n }\n\n return merged;\n}\n\n/**\n * Validates all accumulated form data against the merged schema.\n */\nexport async function validateAllSteps(\n schemas: ZodType[],\n data: Record<string, unknown>\n): Promise<{ success: boolean; data?: Record<string, unknown>; errors?: Record<string, string> }> {\n const mergedSchema = mergeSchemas(schemas);\n try {\n const parsed = await mergedSchema.parseAsync(data);\n return { success: true, data: parsed as Record<string, unknown> };\n } catch (err) {\n const { ZodError } = await import('zod');\n if (err instanceof ZodError) {\n const errors: Record<string, string> = {};\n for (const issue of err.issues) {\n errors[issue.path.join('.')] = issue.message;\n }\n return { success: false, errors };\n }\n return { success: false };\n }\n}\n"],"mappings":"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","names":["prev","useState","useCallback","useState","useCallback","prev","ZodError"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-formsteps-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Headless multi-step form logic for React",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"form",
|
|
8
|
+
"wizard",
|
|
9
|
+
"steps",
|
|
10
|
+
"headless"
|
|
11
|
+
],
|
|
12
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"module": "./dist/index.mjs",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.mjs",
|
|
20
|
+
"require": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@hookform/resolvers": ">=3",
|
|
34
|
+
"react": ">=18",
|
|
35
|
+
"react-dom": ">=18",
|
|
36
|
+
"react-hook-form": ">=7",
|
|
37
|
+
"zod": ">=3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@hookform/resolvers": "^3.3.4",
|
|
41
|
+
"@testing-library/react": "^14.2.2",
|
|
42
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
43
|
+
"@types/react": "^18.2.73",
|
|
44
|
+
"@types/react-dom": "^18.2.23",
|
|
45
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
46
|
+
"jsdom": "^29.0.1",
|
|
47
|
+
"react": "^18.2.0",
|
|
48
|
+
"react-dom": "^18.2.0",
|
|
49
|
+
"react-hook-form": "^7.51.2",
|
|
50
|
+
"tsup": "^8.0.2",
|
|
51
|
+
"typescript": "^5.4.5",
|
|
52
|
+
"vitest": "^1.4.0",
|
|
53
|
+
"zod": "^3.22.4"
|
|
54
|
+
}
|
|
55
|
+
}
|