smartstepper
Version:
SmartStepper is a modern, customizable React stepper component for building multi-step forms, wizards, and onboarding flows. Integrates with react-hook-form, supports Yup/Zod validation, and offers a flexible, config-driven API for dynamic forms.
206 lines (205 loc) • 6.09 kB
TypeScript
import type { HTMLAttributes, ReactElement } from 'react';
import type { Control, FieldValues, Resolver, UseControllerProps, UseFormGetValues, UseFormRegister, UseFormReset, UseFormSetValue, UseFormWatch } from 'react-hook-form';
import type { AnyObjectSchema } from 'yup';
import type { ZodSchema } from 'zod';
/**
* Configuration object for the SmartStepper component.
* @template S - Step name type (string literal union)
*/
export interface SmartStepperConfig<S extends string> {
/**
* Logic for determining navigation between steps.
* Each step can define its own next/previous navigation logic.
*/
orchestration: {
[s in S]: {
/**
* Function to determine the next step based on form data.
* @param data - The current form values.
* @returns The name of the next step.
*/
next?: (data: FieldValues) => S | S;
/**
* Function to determine the previous step based on form data.
* @param data - The current form values.
* @returns The name of the previous step.
*/
previous?: (data: FieldValues) => S | S;
};
};
/**
* The initial step name.
*/
start: S;
/**
* Validation schema and default values for each step.
*/
validations: {
[s in S]: {
/**
* Yup validation schema for the step.
*/
schema: AnyObjectSchema | ZodSchema;
/**
* Optional default values for the step fields.
*/
defaultValues?: FieldValues;
};
};
/**
* View configuration for each step, including the component and optional wrapper.
*/
views: {
[s in S]: {
/**
* The React component to render for this step.
*/
component: ReactElement;
/**
* Optional wrapper for the step.
* Can be either:
* - A React element (legacy, uses cloneElement - not recommended for React 19)
* - A render function that receives children and returns a wrapped element (recommended)
*
* @example
* // Recommended (React 19 compatible):
* wrapper: (children) => <Card>{children}</Card>
*
* // Legacy (uses cloneElement):
* wrapper: <Card />
*/
wrapper?: ReactElement | ((children: ReactElement) => ReactElement);
};
};
/**
* Optional callback invoked on final submit.
* @param data - The final form data.
*/
onSubmit?: (data: FieldValues) => void;
}
/**
* Props for the SmartStepper component.
* @template S - Step name type
*/
export interface SmartStepperProps<S extends string> {
/**
* The configuration object for the stepper.
*/
config: SmartStepperConfig<S>;
}
/**
* Context value provided by the SmartStepper context.
* @template T - Field values type
*/
export interface ISmartStepperContextValue<T extends FieldValues> {
/**
* Navigate to the next step, optionally specifying a target step and whether to unregister fields.
* @param targetStepName - Optional name of the step to navigate to.
* @param unregister - Whether to unregister fields from the previous step.
*/
navigateToNextStep(targetStepName?: string, unregister?: boolean): Promise<void>;
/**
* Navigate to the previous step.
*/
navigateToPreviousStep(): void;
/**
* Register fields for the stepper form.
*/
registerStepperFields: UseFormRegister<T>;
/**
* Get current values of the stepper fields.
*/
getStepperFieldValues: UseFormGetValues<T>;
/**
* Set values for the stepper fields.
*/
setStepperFieldValues: UseFormSetValue<T>;
/**
* Reset the stepper fields.
*/
stepperFieldResetter: UseFormReset<T>;
/**
* Check if navigation to the next step is allowed (e.g., validation passes).
*/
canNavigateToNextStep(): Promise<boolean>;
/**
* React Hook Form control object for the stepper.
*/
control: Control<T, T>;
/**
* Watch values for the stepper fields.
*/
watchStepperFieldValues: UseFormWatch<T>;
}
/**
* Props for a single step in the stepper.
*/
export interface IStepProps {
/**
* The name of the step.
*/
stepName: string;
/**
* The fields to validate for this step.
*/
fieldsForValidation: string[];
/**
* The content of the step.
*/
children: React.ReactNode;
}
/**
* Type for a step React element.
*/
export type TStepType = ReactElement<IStepProps>;
/**
* Props for a step form, used internally by the stepper.
* @template T - Field values type
*/
export interface IStepFormProps<T extends FieldValues = FieldValues> extends Omit<HTMLAttributes<HTMLFormElement>, 'onSubmit'> {
/**
* Callback for form submission.
* @param data - The form data for the step.
*/
onSubmit?: (data: T) => void;
/**
* Resolver for validation (e.g., from react-hook-form).
*/
resolver: Resolver<T>;
/**
* The step(s) to render as children.
*/
children: TStepType | TStepType[];
/**
* Scroll mode when changing steps.
*/
changeStepScrollMode?: 'page' | 'step';
/**
* Optional class name for the form.
*/
className?: string;
}
/**
* Internal schema for a single step in the stepper.
* @template K - Field name type
*/
interface ISmartStepperSchema<K> {
/**
* The name of the step.
*/
stepName: string;
/**
* The fields to validate for this step.
*/
fieldsForValidation: K[];
/**
* The React component for this step.
*/
component: ReactElement;
}
/**
* Array of step schemas for the stepper.
* @template K - Field name type
*/
export type TSmartStepperSchema<K> = ISmartStepperSchema<K>[];
export { FieldValues, UseControllerProps };