@ttoss/react-wizard 0.2.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024, Terezinha Tech Operations (ttoss)
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,399 @@
1
+ # @ttoss/react-wizard
2
+
3
+ A React wizard component for guiding users through multi-step flows with configurable step list layouts.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @ttoss/react-wizard
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { Wizard } from '@ttoss/react-wizard';
15
+
16
+ const steps = [
17
+ {
18
+ title: 'Personal Info',
19
+ description: 'Enter your details',
20
+ content: <PersonalInfoForm />,
21
+ onNext: () => validatePersonalInfo(),
22
+ },
23
+ {
24
+ title: 'Address',
25
+ content: <AddressForm />,
26
+ },
27
+ {
28
+ title: 'Review',
29
+ content: <ReviewStep />,
30
+ },
31
+ ];
32
+
33
+ const MyWizard = () => {
34
+ return (
35
+ <Wizard
36
+ steps={steps}
37
+ layout="top"
38
+ onComplete={() => console.log('Done!')}
39
+ onCancel={() => console.log('Cancelled')}
40
+ />
41
+ );
42
+ };
43
+ ```
44
+
45
+ ## Props
46
+
47
+ | Prop | Type | Default | Description |
48
+ | ---------------- | ----------------------------------------- | ------- | ------------------------------------------------------ |
49
+ | `steps` | `WizardStep[]` | — | Array of step definitions. |
50
+ | `layout` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Position of the step list relative to content. |
51
+ | `onComplete` | `() => void` | — | Called when the user finishes the last step. |
52
+ | `onCancel` | `() => void` | — | Called on cancel. If omitted, cancel button is hidden. |
53
+ | `onStepChange` | `(params: { stepIndex: number }) => void` | — | Called when the active step changes. |
54
+ | `initialStep` | `number` | `0` | The initially active step index. |
55
+ | `allowStepClick` | `boolean` | `true` | Allow clicking completed steps to navigate back. |
56
+
57
+ ## WizardStep
58
+
59
+ | Property | Type | Description |
60
+ | ------------- | ----------------------------------- | --------------------------------------------------------- |
61
+ | `title` | `string` | Title displayed in the step list. |
62
+ | `description` | `string` | Optional description below the title. |
63
+ | `content` | `ReactNode` | Content rendered when the step is active. |
64
+ | `onNext` | `() => boolean \| Promise<boolean>` | Validation callback. Return `false` to prevent advancing. |
65
+
66
+ ## Layouts
67
+
68
+ The `layout` prop controls where the step list appears:
69
+
70
+ - **`top`** — Horizontal step list above the content (default).
71
+ - **`bottom`** — Horizontal step list below the content.
72
+ - **`left`** — Vertical step list on the left side.
73
+ - **`right`** — Vertical step list on the right side.
74
+
75
+ ## useWizard Hook
76
+
77
+ Access the wizard context from within step content:
78
+
79
+ ```tsx
80
+ import { useWizard } from '@ttoss/react-wizard';
81
+
82
+ const StepContent = () => {
83
+ const {
84
+ currentStep,
85
+ totalSteps,
86
+ goToNext,
87
+ goToPrevious,
88
+ isLastStep,
89
+ setStepValidation,
90
+ } = useWizard();
91
+
92
+ return (
93
+ <div>
94
+ Step {currentStep + 1} of {totalSteps}
95
+ </div>
96
+ );
97
+ };
98
+ ```
99
+
100
+ ### useWizard Return Value
101
+
102
+ | Property | Type | Description |
103
+ | ------------------- | ------------------------------------------------------- | ------------------------------------------------------------ |
104
+ | `currentStep` | `number` | Current active step index. |
105
+ | `totalSteps` | `number` | Total number of steps. |
106
+ | `goToNext` | `() => Promise<void>` | Navigate to the next step. |
107
+ | `goToPrevious` | `() => void` | Navigate to the previous step. |
108
+ | `goToStep` | `(params: { stepIndex: number }) => void` | Navigate to a specific step. |
109
+ | `isFirstStep` | `boolean` | Whether the wizard is on the first step. |
110
+ | `isLastStep` | `boolean` | Whether the wizard is on the last step. |
111
+ | `getStepStatus` | `(params: { stepIndex: number }) => WizardStepStatus` | Get the status of a step by index. |
112
+ | `setStepValidation` | `(validate: () => boolean \| Promise<boolean>) => void` | Register a validation function for the current step content. |
113
+
114
+ ## Example: Form with Step-by-Step Validation
115
+
116
+ This example demonstrates using a single form across all wizard steps, with each step validating only its relevant fields using Zod:
117
+
118
+ ```tsx
119
+ import { Wizard } from '@ttoss/react-wizard';
120
+ import {
121
+ Form,
122
+ FormFieldInput,
123
+ FormFieldSelect,
124
+ FormFieldTextarea,
125
+ useForm,
126
+ z,
127
+ zodResolver,
128
+ } from '@ttoss/forms';
129
+ import { Button, Box, Text } from '@ttoss/ui';
130
+
131
+ // Define the complete Zod schema for all steps
132
+ const schema = z.object({
133
+ // Step 1: Personal Information
134
+ firstName: z.string().min(1, 'First name is required'),
135
+ lastName: z.string().min(1, 'Last name is required'),
136
+ email: z.string().email('Invalid email address'),
137
+
138
+ // Step 2: Address
139
+ street: z.string().min(1, 'Street is required'),
140
+ city: z.string().min(1, 'City is required'),
141
+ country: z.string().min(1, 'Country is required'),
142
+
143
+ // Step 3: Additional Info
144
+ phone: z.string().min(10, 'Phone must be at least 10 digits'),
145
+ comments: z.string().optional(),
146
+ });
147
+
148
+ type FormData = z.infer<typeof schema>;
149
+
150
+ const RegistrationWizard = () => {
151
+ const formMethods = useForm<FormData>({
152
+ mode: 'onChange',
153
+ resolver: zodResolver(schema),
154
+ });
155
+
156
+ const { trigger, handleSubmit } = formMethods;
157
+
158
+ const handleComplete = handleSubmit((data) => {
159
+ console.log('Form submitted:', data);
160
+ // Handle final submission
161
+ });
162
+
163
+ const steps = [
164
+ {
165
+ title: 'Personal Info',
166
+ description: 'Basic information',
167
+ content: (
168
+ <Box>
169
+ <FormFieldInput
170
+ name="firstName"
171
+ label="First Name"
172
+ placeholder="Enter your first name"
173
+ />
174
+ <FormFieldInput
175
+ name="lastName"
176
+ label="Last Name"
177
+ placeholder="Enter your last name"
178
+ />
179
+ <FormFieldInput
180
+ name="email"
181
+ label="Email"
182
+ type="email"
183
+ placeholder="Enter your email"
184
+ />
185
+ </Box>
186
+ ),
187
+ onNext: async () => {
188
+ // Validate only Step 1 fields
189
+ return await trigger(['firstName', 'lastName', 'email']);
190
+ },
191
+ },
192
+ {
193
+ title: 'Address',
194
+ description: 'Location details',
195
+ content: (
196
+ <Box>
197
+ <FormFieldInput
198
+ name="street"
199
+ label="Street"
200
+ placeholder="Enter your street"
201
+ />
202
+ <FormFieldInput
203
+ name="city"
204
+ label="City"
205
+ placeholder="Enter your city"
206
+ />
207
+ <FormFieldSelect
208
+ name="country"
209
+ label="Country"
210
+ placeholder="Select your country"
211
+ options={[
212
+ { value: 'us', label: 'United States' },
213
+ { value: 'br', label: 'Brazil' },
214
+ { value: 'uk', label: 'United Kingdom' },
215
+ ]}
216
+ />
217
+ </Box>
218
+ ),
219
+ onNext: async () => {
220
+ // Validate only Step 2 fields
221
+ return await trigger(['street', 'city', 'country']);
222
+ },
223
+ },
224
+ {
225
+ title: 'Additional Info',
226
+ description: 'Final details',
227
+ content: (
228
+ <Box>
229
+ <FormFieldInput
230
+ name="phone"
231
+ label="Phone"
232
+ placeholder="Enter your phone number"
233
+ />
234
+ <FormFieldTextarea
235
+ name="comments"
236
+ label="Comments (Optional)"
237
+ placeholder="Any additional comments"
238
+ />
239
+ </Box>
240
+ ),
241
+ onNext: async () => {
242
+ // Validate only Step 3 fields
243
+ return await trigger(['phone', 'comments']);
244
+ },
245
+ },
246
+ {
247
+ title: 'Review',
248
+ description: 'Confirm details',
249
+ content: (
250
+ <Box>
251
+ <Text variant="heading">Review Your Information</Text>
252
+ {/* Display summary of all form data */}
253
+ </Box>
254
+ ),
255
+ },
256
+ ];
257
+
258
+ return (
259
+ <Form {...formMethods} onSubmit={handleComplete}>
260
+ <Wizard
261
+ steps={steps}
262
+ layout="top"
263
+ onComplete={handleComplete}
264
+ onCancel={() => console.log('Wizard cancelled')}
265
+ />
266
+ </Form>
267
+ );
268
+ };
269
+ ```
270
+
271
+ **Key Points:**
272
+
273
+ - **Single Form**: The `<Form>` component wraps the entire wizard, maintaining form state across all steps
274
+ - **Step-by-Step Validation**: Each step's `onNext` callback uses `trigger()` to validate only the fields relevant to that step
275
+ - **Zod Schema**: Define the complete schema upfront with all fields from all steps
276
+ - **Form Methods**: Access `trigger` from `useForm` to programmatically validate specific fields
277
+ - **Progressive Flow**: Users can only advance to the next step after passing validation for current step fields
278
+
279
+ ## Example: Complex Component with Internal Validation
280
+
281
+ This example shows how a complex component can use `useWizard` to handle its own validation directly:
282
+
283
+ ```tsx
284
+ import { Wizard, useWizard } from '@ttoss/react-wizard';
285
+ import { Box, Text } from '@ttoss/ui';
286
+ import { useState, useEffect } from 'react';
287
+
288
+ // Complex component with internal validation using useWizard
289
+ const ComplexForm = () => {
290
+ const { setStepValidation } = useWizard();
291
+
292
+ const [formData, setFormData] = useState({
293
+ username: '',
294
+ password: '',
295
+ confirmPassword: '',
296
+ });
297
+ const [errors, setErrors] = useState<Record<string, string>>({});
298
+
299
+ // Register validation function with the wizard
300
+ useEffect(() => {
301
+ const validate = async () => {
302
+ const newErrors: Record<string, string> = {};
303
+
304
+ // Complex validation logic
305
+ if (!formData.username || formData.username.length < 3) {
306
+ newErrors.username = 'Username must be at least 3 characters';
307
+ }
308
+
309
+ if (!formData.password || formData.password.length < 8) {
310
+ newErrors.password = 'Password must be at least 8 characters';
311
+ }
312
+
313
+ if (formData.password !== formData.confirmPassword) {
314
+ newErrors.confirmPassword = 'Passwords do not match';
315
+ }
316
+
317
+ setErrors(newErrors);
318
+ return Object.keys(newErrors).length === 0;
319
+ };
320
+
321
+ setStepValidation(validate);
322
+ }, [formData, setStepValidation]);
323
+
324
+ return (
325
+ <Box>
326
+ <Box>
327
+ <Text>Username</Text>
328
+ <input
329
+ value={formData.username}
330
+ onChange={(e) =>
331
+ setFormData({ ...formData, username: e.target.value })
332
+ }
333
+ />
334
+ {errors.username && <Text color="red">{errors.username}</Text>}
335
+ </Box>
336
+
337
+ <Box>
338
+ <Text>Password</Text>
339
+ <input
340
+ type="password"
341
+ value={formData.password}
342
+ onChange={(e) =>
343
+ setFormData({ ...formData, password: e.target.value })
344
+ }
345
+ />
346
+ {errors.password && <Text color="red">{errors.password}</Text>}
347
+ </Box>
348
+
349
+ <Box>
350
+ <Text>Confirm Password</Text>
351
+ <input
352
+ type="password"
353
+ value={formData.confirmPassword}
354
+ onChange={(e) =>
355
+ setFormData({ ...formData, confirmPassword: e.target.value })
356
+ }
357
+ />
358
+ {errors.confirmPassword && (
359
+ <Text color="red">{errors.confirmPassword}</Text>
360
+ )}
361
+ </Box>
362
+ </Box>
363
+ );
364
+ };
365
+
366
+ const WizardWithComplexComponent = () => {
367
+ const steps = [
368
+ {
369
+ title: 'Account Setup',
370
+ description: 'Create your account',
371
+ content: <ComplexForm />,
372
+ },
373
+ {
374
+ title: 'Profile',
375
+ content: <Box>Profile information...</Box>,
376
+ },
377
+ {
378
+ title: 'Complete',
379
+ content: <Box>Setup complete!</Box>,
380
+ },
381
+ ];
382
+
383
+ return (
384
+ <Wizard
385
+ steps={steps}
386
+ layout="top"
387
+ onComplete={() => console.log('Wizard complete!')}
388
+ />
389
+ );
390
+ };
391
+ ```
392
+
393
+ **Key Points:**
394
+
395
+ - **useWizard Hook**: The complex component uses `setStepValidation` from `useWizard` to register its validation function
396
+ - **Automatic Integration**: The wizard automatically calls the registered validation when the user tries to advance
397
+ - **No Refs Needed**: Simpler than using refs and forwardRef patterns
398
+ - **Self-Contained**: The component manages its own state and validation logic
399
+ - **Dynamic Updates**: The validation function updates when formData changes
@@ -0,0 +1,295 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import * as React from 'react';
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", {
5
+ value,
6
+ configurable: true
7
+ });
8
+
9
+ // src/Wizard.tsx
10
+ import { defineMessages, useI18n } from "@ttoss/react-i18n";
11
+ import { Box as Box2, Button, Flex as Flex2 } from "@ttoss/ui";
12
+ import * as React3 from "react";
13
+
14
+ // src/WizardContext.ts
15
+ import * as React2 from "react";
16
+ var WizardContext = React2.createContext(null);
17
+ var useWizard = /* @__PURE__ */__name(() => {
18
+ const context = React2.useContext(WizardContext);
19
+ if (!context) {
20
+ throw new Error("useWizard must be used within a Wizard component.");
21
+ }
22
+ return context;
23
+ }, "useWizard");
24
+
25
+ // src/WizardStepList.tsx
26
+ import { Steps } from "@chakra-ui/react";
27
+ import { Box, Flex } from "@ttoss/ui";
28
+ var WizardStepList = /* @__PURE__ */__name(({
29
+ steps,
30
+ currentStep,
31
+ layout,
32
+ allowStepClick,
33
+ getStepStatus,
34
+ onStepClick
35
+ }) => {
36
+ const isHorizontal = layout === "top" || layout === "bottom";
37
+ const orientation = isHorizontal ? "horizontal" : "vertical";
38
+ return /* @__PURE__ */React.createElement(Flex, {
39
+ role: "navigation",
40
+ "aria-label": "Wizard steps",
41
+ sx: {
42
+ padding: "6",
43
+ backgroundColor: "navigation.background.muted.default",
44
+ ...(isHorizontal ? {
45
+ width: "100%",
46
+ borderBottom: layout === "top" ? "1px solid" : void 0,
47
+ borderTop: layout === "bottom" ? "1px solid" : void 0,
48
+ borderColor: "display.border.muted.default"
49
+ } : {
50
+ minWidth: "200px",
51
+ borderRight: layout === "left" ? "1px solid" : void 0,
52
+ borderLeft: layout === "right" ? "1px solid" : void 0,
53
+ borderColor: "display.border.muted.default"
54
+ })
55
+ }
56
+ }, /* @__PURE__ */React.createElement(Steps.Root, {
57
+ step: currentStep,
58
+ count: steps.length,
59
+ orientation
60
+ }, /* @__PURE__ */React.createElement(Steps.List, null, steps.map((step, index) => {
61
+ const status = getStepStatus({
62
+ stepIndex: index
63
+ });
64
+ const isClickable = allowStepClick && status === "completed" && index !== currentStep;
65
+ return /* @__PURE__ */React.createElement(Steps.Item, {
66
+ key: index,
67
+ index
68
+ }, /* @__PURE__ */React.createElement(Flex, {
69
+ sx: {
70
+ flexDirection: isHorizontal ? "column" : "row",
71
+ alignItems: "center",
72
+ gap: "2"
73
+ }
74
+ }, /* @__PURE__ */React.createElement(Box, {
75
+ role: "button",
76
+ tabIndex: isClickable ? 0 : -1,
77
+ onClick: /* @__PURE__ */__name(() => {
78
+ if (isClickable) {
79
+ onStepClick({
80
+ stepIndex: index
81
+ });
82
+ }
83
+ }, "onClick"),
84
+ onKeyDown: /* @__PURE__ */__name(e => {
85
+ if (isClickable && (e.key === "Enter" || e.key === " ")) {
86
+ e.preventDefault();
87
+ onStepClick({
88
+ stepIndex: index
89
+ });
90
+ }
91
+ }, "onKeyDown"),
92
+ "aria-current": status === "active" ? "step" : void 0,
93
+ sx: {
94
+ cursor: isClickable ? "pointer" : "default"
95
+ }
96
+ }, /* @__PURE__ */React.createElement(Steps.Indicator, null, /* @__PURE__ */React.createElement(Steps.Status, {
97
+ complete: "\u2713",
98
+ incomplete: /* @__PURE__ */React.createElement(Steps.Number, null)
99
+ }))), (step.title || step.description) && /* @__PURE__ */React.createElement(Box, null, step.title && /* @__PURE__ */React.createElement(Steps.Title, null, step.title), step.description && /* @__PURE__ */React.createElement(Steps.Description, null, step.description))), index < steps.length - 1 && /* @__PURE__ */React.createElement(Steps.Separator, null));
100
+ }))));
101
+ }, "WizardStepList");
102
+
103
+ // src/Wizard.tsx
104
+ var messages = defineMessages({
105
+ previous: {
106
+ id: "60eH0J",
107
+ defaultMessage: [{
108
+ "type": 0,
109
+ "value": "Previous"
110
+ }]
111
+ },
112
+ next: {
113
+ id: "FmaVut",
114
+ defaultMessage: [{
115
+ "type": 0,
116
+ "value": "Next"
117
+ }]
118
+ },
119
+ finish: {
120
+ id: "5lZ8VT",
121
+ defaultMessage: [{
122
+ "type": 0,
123
+ "value": "Finish"
124
+ }]
125
+ },
126
+ cancel: {
127
+ id: "6I9gjk",
128
+ defaultMessage: [{
129
+ "type": 0,
130
+ "value": "Cancel"
131
+ }]
132
+ }
133
+ });
134
+ var getFlexDirection = /* @__PURE__ */__name(layout => {
135
+ switch (layout) {
136
+ case "top":
137
+ return "column";
138
+ case "bottom":
139
+ return "column-reverse";
140
+ case "left":
141
+ return "row";
142
+ case "right":
143
+ return "row-reverse";
144
+ }
145
+ }, "getFlexDirection");
146
+ var Wizard = /* @__PURE__ */__name(({
147
+ steps,
148
+ layout = "top",
149
+ onComplete,
150
+ onCancel,
151
+ onStepChange,
152
+ initialStep = 0,
153
+ allowStepClick = true
154
+ }) => {
155
+ const {
156
+ intl
157
+ } = useI18n();
158
+ const [currentStep, setCurrentStep] = React3.useState(initialStep);
159
+ const stepValidationRef = React3.useRef(null);
160
+ const totalSteps = steps.length;
161
+ const isFirstStep = currentStep === 0;
162
+ const isLastStep = currentStep === totalSteps - 1;
163
+ const getStepStatus = React3.useCallback(({
164
+ stepIndex
165
+ }) => {
166
+ if (stepIndex < currentStep) {
167
+ return "completed";
168
+ }
169
+ if (stepIndex === currentStep) {
170
+ return "active";
171
+ }
172
+ return "upcoming";
173
+ }, [currentStep]);
174
+ const goToNext = React3.useCallback(async () => {
175
+ const step = steps[currentStep];
176
+ if (stepValidationRef.current) {
177
+ const canProceed = await stepValidationRef.current();
178
+ if (!canProceed) {
179
+ return;
180
+ }
181
+ }
182
+ if (step.onNext) {
183
+ const canProceed = await step.onNext();
184
+ if (!canProceed) {
185
+ return;
186
+ }
187
+ }
188
+ if (isLastStep) {
189
+ onComplete?.();
190
+ } else {
191
+ const nextStep = currentStep + 1;
192
+ stepValidationRef.current = null;
193
+ setCurrentStep(nextStep);
194
+ onStepChange?.({
195
+ stepIndex: nextStep
196
+ });
197
+ }
198
+ }, [currentStep, steps, isLastStep, onComplete, onStepChange]);
199
+ const goToPrevious = React3.useCallback(() => {
200
+ if (!isFirstStep) {
201
+ const prevStep = currentStep - 1;
202
+ stepValidationRef.current = null;
203
+ setCurrentStep(prevStep);
204
+ onStepChange?.({
205
+ stepIndex: prevStep
206
+ });
207
+ }
208
+ }, [currentStep, isFirstStep, onStepChange]);
209
+ const goToStep = React3.useCallback(({
210
+ stepIndex
211
+ }) => {
212
+ if (stepIndex >= 0 && stepIndex < totalSteps && stepIndex <= currentStep) {
213
+ stepValidationRef.current = null;
214
+ setCurrentStep(stepIndex);
215
+ onStepChange?.({
216
+ stepIndex
217
+ });
218
+ }
219
+ }, [currentStep, totalSteps, onStepChange]);
220
+ const setStepValidation = React3.useCallback(validate => {
221
+ stepValidationRef.current = validate;
222
+ }, []);
223
+ const contextValue = React3.useMemo(() => {
224
+ return {
225
+ currentStep,
226
+ totalSteps,
227
+ goToNext,
228
+ goToPrevious,
229
+ goToStep,
230
+ isFirstStep,
231
+ isLastStep,
232
+ getStepStatus,
233
+ setStepValidation
234
+ };
235
+ }, [currentStep, totalSteps, goToNext, goToPrevious, goToStep, isFirstStep, isLastStep, getStepStatus, setStepValidation]);
236
+ return /* @__PURE__ */React3.createElement(WizardContext.Provider, {
237
+ value: contextValue
238
+ }, /* @__PURE__ */React3.createElement(Flex2, {
239
+ sx: {
240
+ flexDirection: getFlexDirection(layout),
241
+ width: "100%",
242
+ minHeight: "300px",
243
+ border: "1px solid",
244
+ borderColor: "display.border.muted.default",
245
+ borderRadius: "8px",
246
+ overflow: "hidden"
247
+ }
248
+ }, /* @__PURE__ */React3.createElement(WizardStepList, {
249
+ steps,
250
+ currentStep,
251
+ layout,
252
+ allowStepClick,
253
+ getStepStatus,
254
+ onStepClick: goToStep
255
+ }), /* @__PURE__ */React3.createElement(Flex2, {
256
+ sx: {
257
+ flexDirection: "column",
258
+ flex: 1,
259
+ padding: "6"
260
+ }
261
+ }, /* @__PURE__ */React3.createElement(Box2, {
262
+ sx: {
263
+ flex: 1,
264
+ marginBottom: "4"
265
+ }
266
+ }, steps[currentStep].content), /* @__PURE__ */React3.createElement(Flex2, {
267
+ sx: {
268
+ justifyContent: "space-between",
269
+ alignItems: "center",
270
+ gap: "3"
271
+ }
272
+ }, /* @__PURE__ */React3.createElement(Flex2, {
273
+ sx: {
274
+ gap: "3"
275
+ }
276
+ }, onCancel && /* @__PURE__ */React3.createElement(Button, {
277
+ variant: "secondary",
278
+ onClick: onCancel,
279
+ "aria-label": intl.formatMessage(messages.cancel)
280
+ }, intl.formatMessage(messages.cancel))), /* @__PURE__ */React3.createElement(Flex2, {
281
+ sx: {
282
+ gap: "3"
283
+ }
284
+ }, /* @__PURE__ */React3.createElement(Button, {
285
+ variant: "secondary",
286
+ onClick: goToPrevious,
287
+ disabled: isFirstStep,
288
+ "aria-label": intl.formatMessage(messages.previous)
289
+ }, intl.formatMessage(messages.previous)), /* @__PURE__ */React3.createElement(Button, {
290
+ onClick: goToNext,
291
+ "aria-label": isLastStep ? intl.formatMessage(messages.finish) : intl.formatMessage(messages.next)
292
+ }, isLastStep ? intl.formatMessage(messages.finish) : intl.formatMessage(messages.next)))))));
293
+ }, "Wizard");
294
+ Wizard.displayName = "Wizard";
295
+ export { Wizard, useWizard };
@@ -0,0 +1,128 @@
1
+ import * as React from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+
4
+ /**
5
+ * Position of the step list relative to the wizard content.
6
+ */
7
+ type WizardLayout = 'top' | 'right' | 'bottom' | 'left';
8
+ /**
9
+ * Status of a wizard step.
10
+ */
11
+ type WizardStepStatus = 'completed' | 'active' | 'upcoming';
12
+ /**
13
+ * Definition of a single wizard step.
14
+ */
15
+ interface WizardStep {
16
+ /**
17
+ * Title displayed in the step list.
18
+ */
19
+ title: string;
20
+ /**
21
+ * Optional description displayed below the title in the step list.
22
+ */
23
+ description?: string;
24
+ /**
25
+ * The content rendered when this step is active.
26
+ */
27
+ content: React.ReactNode;
28
+ /**
29
+ * Called when the user clicks "Next". If it returns false or
30
+ * a Promise that resolves to false, the wizard will not advance.
31
+ */
32
+ onNext?: () => boolean | Promise<boolean>;
33
+ }
34
+ /**
35
+ * Props for the Wizard component.
36
+ */
37
+ interface WizardProps {
38
+ /**
39
+ * Array of steps to display in the wizard.
40
+ */
41
+ steps: WizardStep[];
42
+ /**
43
+ * Position of the step list. Defaults to 'top'.
44
+ */
45
+ layout?: WizardLayout;
46
+ /**
47
+ * Called when the wizard completes (user clicks "Finish" on the last step).
48
+ */
49
+ onComplete?: () => void;
50
+ /**
51
+ * Called when the user clicks "Cancel".
52
+ * If not provided, the Cancel button is not rendered.
53
+ */
54
+ onCancel?: () => void;
55
+ /**
56
+ * Called whenever the active step changes.
57
+ */
58
+ onStepChange?: (params: {
59
+ stepIndex: number;
60
+ }) => void;
61
+ /**
62
+ * The initially active step index. Defaults to 0.
63
+ */
64
+ initialStep?: number;
65
+ /**
66
+ * Allow clicking on completed steps to navigate back.
67
+ * Defaults to true.
68
+ */
69
+ allowStepClick?: boolean;
70
+ }
71
+ /**
72
+ * Context value exposed by WizardProvider.
73
+ */
74
+ interface WizardContextValue {
75
+ /**
76
+ * Current active step index.
77
+ */
78
+ currentStep: number;
79
+ /**
80
+ * Total number of steps.
81
+ */
82
+ totalSteps: number;
83
+ /**
84
+ * Navigate to the next step.
85
+ */
86
+ goToNext: () => Promise<void>;
87
+ /**
88
+ * Navigate to the previous step.
89
+ */
90
+ goToPrevious: () => void;
91
+ /**
92
+ * Navigate to a specific step (only if it's completed or active).
93
+ */
94
+ goToStep: (params: {
95
+ stepIndex: number;
96
+ }) => void;
97
+ /**
98
+ * Whether the wizard is on the first step.
99
+ */
100
+ isFirstStep: boolean;
101
+ /**
102
+ * Whether the wizard is on the last step.
103
+ */
104
+ isLastStep: boolean;
105
+ /**
106
+ * Get the status of a step by index.
107
+ */
108
+ getStepStatus: (params: {
109
+ stepIndex: number;
110
+ }) => WizardStepStatus;
111
+ /**
112
+ * Register a validation function for the current step.
113
+ * This allows step content components to provide their own validation logic.
114
+ */
115
+ setStepValidation: (validate: () => boolean | Promise<boolean>) => void;
116
+ }
117
+
118
+ declare const Wizard: {
119
+ ({ steps, layout, onComplete, onCancel, onStepChange, initialStep, allowStepClick, }: WizardProps): react_jsx_runtime.JSX.Element;
120
+ displayName: string;
121
+ };
122
+
123
+ /**
124
+ * Hook to access the wizard context from within step content.
125
+ */
126
+ declare const useWizard: () => WizardContextValue;
127
+
128
+ export { Wizard, type WizardContextValue, type WizardLayout, type WizardProps, type WizardStep, type WizardStepStatus, useWizard };
@@ -0,0 +1,128 @@
1
+ import * as React from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+
4
+ /**
5
+ * Position of the step list relative to the wizard content.
6
+ */
7
+ type WizardLayout = 'top' | 'right' | 'bottom' | 'left';
8
+ /**
9
+ * Status of a wizard step.
10
+ */
11
+ type WizardStepStatus = 'completed' | 'active' | 'upcoming';
12
+ /**
13
+ * Definition of a single wizard step.
14
+ */
15
+ interface WizardStep {
16
+ /**
17
+ * Title displayed in the step list.
18
+ */
19
+ title: string;
20
+ /**
21
+ * Optional description displayed below the title in the step list.
22
+ */
23
+ description?: string;
24
+ /**
25
+ * The content rendered when this step is active.
26
+ */
27
+ content: React.ReactNode;
28
+ /**
29
+ * Called when the user clicks "Next". If it returns false or
30
+ * a Promise that resolves to false, the wizard will not advance.
31
+ */
32
+ onNext?: () => boolean | Promise<boolean>;
33
+ }
34
+ /**
35
+ * Props for the Wizard component.
36
+ */
37
+ interface WizardProps {
38
+ /**
39
+ * Array of steps to display in the wizard.
40
+ */
41
+ steps: WizardStep[];
42
+ /**
43
+ * Position of the step list. Defaults to 'top'.
44
+ */
45
+ layout?: WizardLayout;
46
+ /**
47
+ * Called when the wizard completes (user clicks "Finish" on the last step).
48
+ */
49
+ onComplete?: () => void;
50
+ /**
51
+ * Called when the user clicks "Cancel".
52
+ * If not provided, the Cancel button is not rendered.
53
+ */
54
+ onCancel?: () => void;
55
+ /**
56
+ * Called whenever the active step changes.
57
+ */
58
+ onStepChange?: (params: {
59
+ stepIndex: number;
60
+ }) => void;
61
+ /**
62
+ * The initially active step index. Defaults to 0.
63
+ */
64
+ initialStep?: number;
65
+ /**
66
+ * Allow clicking on completed steps to navigate back.
67
+ * Defaults to true.
68
+ */
69
+ allowStepClick?: boolean;
70
+ }
71
+ /**
72
+ * Context value exposed by WizardProvider.
73
+ */
74
+ interface WizardContextValue {
75
+ /**
76
+ * Current active step index.
77
+ */
78
+ currentStep: number;
79
+ /**
80
+ * Total number of steps.
81
+ */
82
+ totalSteps: number;
83
+ /**
84
+ * Navigate to the next step.
85
+ */
86
+ goToNext: () => Promise<void>;
87
+ /**
88
+ * Navigate to the previous step.
89
+ */
90
+ goToPrevious: () => void;
91
+ /**
92
+ * Navigate to a specific step (only if it's completed or active).
93
+ */
94
+ goToStep: (params: {
95
+ stepIndex: number;
96
+ }) => void;
97
+ /**
98
+ * Whether the wizard is on the first step.
99
+ */
100
+ isFirstStep: boolean;
101
+ /**
102
+ * Whether the wizard is on the last step.
103
+ */
104
+ isLastStep: boolean;
105
+ /**
106
+ * Get the status of a step by index.
107
+ */
108
+ getStepStatus: (params: {
109
+ stepIndex: number;
110
+ }) => WizardStepStatus;
111
+ /**
112
+ * Register a validation function for the current step.
113
+ * This allows step content components to provide their own validation logic.
114
+ */
115
+ setStepValidation: (validate: () => boolean | Promise<boolean>) => void;
116
+ }
117
+
118
+ declare const Wizard: {
119
+ ({ steps, layout, onComplete, onCancel, onStepChange, initialStep, allowStepClick, }: WizardProps): react_jsx_runtime.JSX.Element;
120
+ displayName: string;
121
+ };
122
+
123
+ /**
124
+ * Hook to access the wizard context from within step content.
125
+ */
126
+ declare const useWizard: () => WizardContextValue;
127
+
128
+ export { Wizard, type WizardContextValue, type WizardLayout, type WizardProps, type WizardStep, type WizardStepStatus, useWizard };
package/dist/index.js ADDED
@@ -0,0 +1,329 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ import * as React from 'react';
3
+ "use strict";
4
+
5
+ var __create = Object.create;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __name = (target, value) => __defProp(target, "name", {
12
+ value,
13
+ configurable: true
14
+ });
15
+ var __export = (target, all) => {
16
+ for (var name in all) __defProp(target, name, {
17
+ get: all[name],
18
+ enumerable: true
19
+ });
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") {
23
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
24
+ get: () => from[key],
25
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
26
+ });
27
+ }
28
+ return to;
29
+ };
30
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
31
+ // If the importer is in node compatibility mode or this is not an ESM
32
+ // file that has been converted to a CommonJS file using a Babel-
33
+ // compatible transform (i.e. "__esModule" has not been set), then set
34
+ // "default" to the CommonJS "module.exports" for node compatibility.
35
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
36
+ value: mod,
37
+ enumerable: true
38
+ }) : target, mod));
39
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
40
+ value: true
41
+ }), mod);
42
+
43
+ // src/index.ts
44
+ var index_exports = {};
45
+ __export(index_exports, {
46
+ Wizard: () => Wizard,
47
+ useWizard: () => useWizard
48
+ });
49
+ module.exports = __toCommonJS(index_exports);
50
+
51
+ // src/Wizard.tsx
52
+ var import_react_i18n = require("@ttoss/react-i18n");
53
+ var import_ui2 = require("@ttoss/ui");
54
+ var React3 = __toESM(require("react"), 1);
55
+
56
+ // src/WizardContext.ts
57
+ var React2 = __toESM(require("react"), 1);
58
+ var WizardContext = React2.createContext(null);
59
+ var useWizard = /* @__PURE__ */__name(() => {
60
+ const context = React2.useContext(WizardContext);
61
+ if (!context) {
62
+ throw new Error("useWizard must be used within a Wizard component.");
63
+ }
64
+ return context;
65
+ }, "useWizard");
66
+
67
+ // src/WizardStepList.tsx
68
+ var import_react = require("@chakra-ui/react");
69
+ var import_ui = require("@ttoss/ui");
70
+ var WizardStepList = /* @__PURE__ */__name(({
71
+ steps,
72
+ currentStep,
73
+ layout,
74
+ allowStepClick,
75
+ getStepStatus,
76
+ onStepClick
77
+ }) => {
78
+ const isHorizontal = layout === "top" || layout === "bottom";
79
+ const orientation = isHorizontal ? "horizontal" : "vertical";
80
+ return /* @__PURE__ */React.createElement(import_ui.Flex, {
81
+ role: "navigation",
82
+ "aria-label": "Wizard steps",
83
+ sx: {
84
+ padding: "6",
85
+ backgroundColor: "navigation.background.muted.default",
86
+ ...(isHorizontal ? {
87
+ width: "100%",
88
+ borderBottom: layout === "top" ? "1px solid" : void 0,
89
+ borderTop: layout === "bottom" ? "1px solid" : void 0,
90
+ borderColor: "display.border.muted.default"
91
+ } : {
92
+ minWidth: "200px",
93
+ borderRight: layout === "left" ? "1px solid" : void 0,
94
+ borderLeft: layout === "right" ? "1px solid" : void 0,
95
+ borderColor: "display.border.muted.default"
96
+ })
97
+ }
98
+ }, /* @__PURE__ */React.createElement(import_react.Steps.Root, {
99
+ step: currentStep,
100
+ count: steps.length,
101
+ orientation
102
+ }, /* @__PURE__ */React.createElement(import_react.Steps.List, null, steps.map((step, index) => {
103
+ const status = getStepStatus({
104
+ stepIndex: index
105
+ });
106
+ const isClickable = allowStepClick && status === "completed" && index !== currentStep;
107
+ return /* @__PURE__ */React.createElement(import_react.Steps.Item, {
108
+ key: index,
109
+ index
110
+ }, /* @__PURE__ */React.createElement(import_ui.Flex, {
111
+ sx: {
112
+ flexDirection: isHorizontal ? "column" : "row",
113
+ alignItems: "center",
114
+ gap: "2"
115
+ }
116
+ }, /* @__PURE__ */React.createElement(import_ui.Box, {
117
+ role: "button",
118
+ tabIndex: isClickable ? 0 : -1,
119
+ onClick: /* @__PURE__ */__name(() => {
120
+ if (isClickable) {
121
+ onStepClick({
122
+ stepIndex: index
123
+ });
124
+ }
125
+ }, "onClick"),
126
+ onKeyDown: /* @__PURE__ */__name(e => {
127
+ if (isClickable && (e.key === "Enter" || e.key === " ")) {
128
+ e.preventDefault();
129
+ onStepClick({
130
+ stepIndex: index
131
+ });
132
+ }
133
+ }, "onKeyDown"),
134
+ "aria-current": status === "active" ? "step" : void 0,
135
+ sx: {
136
+ cursor: isClickable ? "pointer" : "default"
137
+ }
138
+ }, /* @__PURE__ */React.createElement(import_react.Steps.Indicator, null, /* @__PURE__ */React.createElement(import_react.Steps.Status, {
139
+ complete: "\u2713",
140
+ incomplete: /* @__PURE__ */React.createElement(import_react.Steps.Number, null)
141
+ }))), (step.title || step.description) && /* @__PURE__ */React.createElement(import_ui.Box, null, step.title && /* @__PURE__ */React.createElement(import_react.Steps.Title, null, step.title), step.description && /* @__PURE__ */React.createElement(import_react.Steps.Description, null, step.description))), index < steps.length - 1 && /* @__PURE__ */React.createElement(import_react.Steps.Separator, null));
142
+ }))));
143
+ }, "WizardStepList");
144
+
145
+ // src/Wizard.tsx
146
+ var messages = (0, import_react_i18n.defineMessages)({
147
+ previous: {
148
+ defaultMessage: "Previous",
149
+ description: "Label for the previous step button in the wizard."
150
+ },
151
+ next: {
152
+ defaultMessage: "Next",
153
+ description: "Label for the next step button in the wizard."
154
+ },
155
+ finish: {
156
+ defaultMessage: "Finish",
157
+ description: "Label for the finish button on the last wizard step."
158
+ },
159
+ cancel: {
160
+ defaultMessage: "Cancel",
161
+ description: "Label for the cancel button in the wizard."
162
+ }
163
+ });
164
+ var getFlexDirection = /* @__PURE__ */__name(layout => {
165
+ switch (layout) {
166
+ case "top":
167
+ return "column";
168
+ case "bottom":
169
+ return "column-reverse";
170
+ case "left":
171
+ return "row";
172
+ case "right":
173
+ return "row-reverse";
174
+ }
175
+ }, "getFlexDirection");
176
+ var Wizard = /* @__PURE__ */__name(({
177
+ steps,
178
+ layout = "top",
179
+ onComplete,
180
+ onCancel,
181
+ onStepChange,
182
+ initialStep = 0,
183
+ allowStepClick = true
184
+ }) => {
185
+ const {
186
+ intl
187
+ } = (0, import_react_i18n.useI18n)();
188
+ const [currentStep, setCurrentStep] = React3.useState(initialStep);
189
+ const stepValidationRef = React3.useRef(null);
190
+ const totalSteps = steps.length;
191
+ const isFirstStep = currentStep === 0;
192
+ const isLastStep = currentStep === totalSteps - 1;
193
+ const getStepStatus = React3.useCallback(({
194
+ stepIndex
195
+ }) => {
196
+ if (stepIndex < currentStep) {
197
+ return "completed";
198
+ }
199
+ if (stepIndex === currentStep) {
200
+ return "active";
201
+ }
202
+ return "upcoming";
203
+ }, [currentStep]);
204
+ const goToNext = React3.useCallback(async () => {
205
+ const step = steps[currentStep];
206
+ if (stepValidationRef.current) {
207
+ const canProceed = await stepValidationRef.current();
208
+ if (!canProceed) {
209
+ return;
210
+ }
211
+ }
212
+ if (step.onNext) {
213
+ const canProceed = await step.onNext();
214
+ if (!canProceed) {
215
+ return;
216
+ }
217
+ }
218
+ if (isLastStep) {
219
+ onComplete?.();
220
+ } else {
221
+ const nextStep = currentStep + 1;
222
+ stepValidationRef.current = null;
223
+ setCurrentStep(nextStep);
224
+ onStepChange?.({
225
+ stepIndex: nextStep
226
+ });
227
+ }
228
+ }, [currentStep, steps, isLastStep, onComplete, onStepChange]);
229
+ const goToPrevious = React3.useCallback(() => {
230
+ if (!isFirstStep) {
231
+ const prevStep = currentStep - 1;
232
+ stepValidationRef.current = null;
233
+ setCurrentStep(prevStep);
234
+ onStepChange?.({
235
+ stepIndex: prevStep
236
+ });
237
+ }
238
+ }, [currentStep, isFirstStep, onStepChange]);
239
+ const goToStep = React3.useCallback(({
240
+ stepIndex
241
+ }) => {
242
+ if (stepIndex >= 0 && stepIndex < totalSteps && stepIndex <= currentStep) {
243
+ stepValidationRef.current = null;
244
+ setCurrentStep(stepIndex);
245
+ onStepChange?.({
246
+ stepIndex
247
+ });
248
+ }
249
+ }, [currentStep, totalSteps, onStepChange]);
250
+ const setStepValidation = React3.useCallback(validate => {
251
+ stepValidationRef.current = validate;
252
+ }, []);
253
+ const contextValue = React3.useMemo(() => {
254
+ return {
255
+ currentStep,
256
+ totalSteps,
257
+ goToNext,
258
+ goToPrevious,
259
+ goToStep,
260
+ isFirstStep,
261
+ isLastStep,
262
+ getStepStatus,
263
+ setStepValidation
264
+ };
265
+ }, [currentStep, totalSteps, goToNext, goToPrevious, goToStep, isFirstStep, isLastStep, getStepStatus, setStepValidation]);
266
+ return /* @__PURE__ */React3.createElement(WizardContext.Provider, {
267
+ value: contextValue
268
+ }, /* @__PURE__ */React3.createElement(import_ui2.Flex, {
269
+ sx: {
270
+ flexDirection: getFlexDirection(layout),
271
+ width: "100%",
272
+ minHeight: "300px",
273
+ border: "1px solid",
274
+ borderColor: "display.border.muted.default",
275
+ borderRadius: "8px",
276
+ overflow: "hidden"
277
+ }
278
+ }, /* @__PURE__ */React3.createElement(WizardStepList, {
279
+ steps,
280
+ currentStep,
281
+ layout,
282
+ allowStepClick,
283
+ getStepStatus,
284
+ onStepClick: goToStep
285
+ }), /* @__PURE__ */React3.createElement(import_ui2.Flex, {
286
+ sx: {
287
+ flexDirection: "column",
288
+ flex: 1,
289
+ padding: "6"
290
+ }
291
+ }, /* @__PURE__ */React3.createElement(import_ui2.Box, {
292
+ sx: {
293
+ flex: 1,
294
+ marginBottom: "4"
295
+ }
296
+ }, steps[currentStep].content), /* @__PURE__ */React3.createElement(import_ui2.Flex, {
297
+ sx: {
298
+ justifyContent: "space-between",
299
+ alignItems: "center",
300
+ gap: "3"
301
+ }
302
+ }, /* @__PURE__ */React3.createElement(import_ui2.Flex, {
303
+ sx: {
304
+ gap: "3"
305
+ }
306
+ }, onCancel && /* @__PURE__ */React3.createElement(import_ui2.Button, {
307
+ variant: "secondary",
308
+ onClick: onCancel,
309
+ "aria-label": intl.formatMessage(messages.cancel)
310
+ }, intl.formatMessage(messages.cancel))), /* @__PURE__ */React3.createElement(import_ui2.Flex, {
311
+ sx: {
312
+ gap: "3"
313
+ }
314
+ }, /* @__PURE__ */React3.createElement(import_ui2.Button, {
315
+ variant: "secondary",
316
+ onClick: goToPrevious,
317
+ disabled: isFirstStep,
318
+ "aria-label": intl.formatMessage(messages.previous)
319
+ }, intl.formatMessage(messages.previous)), /* @__PURE__ */React3.createElement(import_ui2.Button, {
320
+ onClick: goToNext,
321
+ "aria-label": isLastStep ? intl.formatMessage(messages.finish) : intl.formatMessage(messages.next)
322
+ }, isLastStep ? intl.formatMessage(messages.finish) : intl.formatMessage(messages.next)))))));
323
+ }, "Wizard");
324
+ Wizard.displayName = "Wizard";
325
+ // Annotate the CommonJS export names for ESM import in node:
326
+ 0 && (module.exports = {
327
+ Wizard,
328
+ useWizard
329
+ });
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@ttoss/react-wizard",
3
+ "version": "0.2.0",
4
+ "description": "A React wizard component for guiding users through multi-step flows with configurable step list layouts.",
5
+ "license": "MIT",
6
+ "author": "ttoss",
7
+ "contributors": [
8
+ "Pedro Arantes <pedro@arantespp.com> (https://arantespp.com/contact)"
9
+ ],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/ttoss/ttoss.git",
13
+ "directory": "packages/react-wizard"
14
+ },
15
+ "type": "module",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/esm/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "sideEffects": false,
26
+ "peerDependencies": {
27
+ "@chakra-ui/react": "^3",
28
+ "react": ">=16.8.0",
29
+ "react-icons": "^5",
30
+ "@ttoss/react-i18n": "^2.1.0",
31
+ "@ttoss/ui": "^6.6.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/jest": "^30.0.0",
35
+ "@types/react": "^19.2.14",
36
+ "jest": "^30.2.0",
37
+ "react": "^19.2.4",
38
+ "tsup": "^8.5.1",
39
+ "@ttoss/i18n-cli": "^0.7.39",
40
+ "@ttoss/config": "^1.36.0",
41
+ "@ttoss/forms": "^0.41.0",
42
+ "@ttoss/test-utils": "^4.1.0",
43
+ "@ttoss/ui": "^6.6.0",
44
+ "@ttoss/react-i18n": "^2.1.0"
45
+ },
46
+ "keywords": [
47
+ "React",
48
+ "multi-step",
49
+ "stepper",
50
+ "ui",
51
+ "wizard"
52
+ ],
53
+ "publishConfig": {
54
+ "access": "public",
55
+ "provenance": true
56
+ },
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "i18n": "ttoss-i18n",
60
+ "test": "jest --projects tests/unit"
61
+ }
62
+ }