24
loading...
This website collects cookies to deliver better user experience
function SomeModal() {
[isFirstStep, setIsFirstStep] = React.useState(true);
return (
<div>{isFirstStep ? <FirstStepComponent /> : <SecondStepComponent />}</div>
);
}
use-stepper.tsx
import * as React from 'react';
type StepId = string;
export type Step = {
id: StepId;
order: number;
};
type UseStepperProps = {
steps: Step[];
initialStep: StepId;
};
function byStepId(stepId: StepId) {
return (step: Step) => {
return step.id === stepId;
};
}
function sortByOrder(stepOne: Step, stepTwo: Step) {
return stepOne.order - stepTwo.order;
}
function getId(step: Step) {
return step.id;
}
export function useStepper(props: UseStepperProps) {
const indexes = React.useMemo(
() => props.steps.sort(sortByOrder).map(getId),
[props.steps],
);
const [currentStep, setCurrentStep] = React.useState(() =>
props.steps.find(byStepId(props.initialStep)),
);
function nextStep() {
const nextIndex = indexes.indexOf(currentStep.id) + 1;
if (nextIndex >= indexes.length) {
return;
}
const nextStep = props.steps[nextIndex];
setCurrentStep(nextStep);
}
function goToStep(stepId: StepId) {
const step = props.steps.find(byStepId(stepId));
if (process.env.NODE_ENV !== 'production') {
if (!step) {
throw new Error(`Step Id "${stepId}" is not
registered`);
}
}
if (step) {
setCurrentStep(step);
}
}
function prevStep() {
const prevIndex = indexes.indexOf(currentStep.id) - 1;
if (prevIndex < 0) {
return;
}
const prevStep = props.steps[prevIndex];
setCurrentStep(prevStep);
}
function isCurrentStep(stepId: StepId) {
return stepId === currentStep.id;
}
return {
currentStep,
nextStep,
prevStep,
goToStep,
isCurrentStep,
};
}
stepper-context.tsx
import * as React from 'react';
import { useStepper } from '..';
export const StepperContext = React.createContext<ReturnType<typeof useStepper>>(
undefined,
);
export function useStepperContext() {
const value = React.useContext(StepperContext);
if (value === undefined) {
throw new Error('Stepper Context is undefined');
}
return value;
}
stepper.tsx
import * as React from 'react';
import { StepperContext, useStepperContext } from '..';
import { useStepper } from '..';
type StepId = string
type StepType = {
id: StepId;
order: number;
};
type StepperProps = React.PropsWithChildren<{
steps: StepType[];
initialStep: StepId;
}>;
export function Stepper(props: StepperProps) {
const value = useStepper(props);
return (
<StepperContext.Provider value={value}>
{props.children}
</StepperContext.Provider>
);
}
type StepperStepProps = {
step: StepId;
component: React.ComponentType<any>;
};
export function Step(props: StepProps) {
const stepperContext = useStepperContext();
return stepperContext.isCurrentStep(props.step) ? <props.component /> : null;
}
import * as React from "react";
import { Stepper, Step } from "..";
import { useStepperContext } from "..";
const STEPS = [
{ id: "first-step", order: 1 },
{ id: "second-components-step", order: 2 },
{ id: "id-for-the-third-step", order: 3 }
];
const FirstStep = () => {
const stepperContext = useStepperContext();
return (
<div>
<p>First step </p>
<button onClick={stepperContext.nextStep}>Next</button>
</div>
);
};
const SecondStep = () => {
const stepperContext = useStepperContext();
return (
<div>
<p>Some second step</p>
<button onClick={stepperContext.prevStep}>Prev</button>
<button onClick={stepperContext.nextStep}>Next</button>
</div>
);
};
const ThirdStep = () => {
const stepperContext = useStepperContext();
return (
<div>
<p>Third step</p>
<button onClick={stepperContext.prevStep}>Prev</button>
</div>
);
};
export function ContainerWithSteps() {
return (
<Stepper steps={STEPS} initialStep="first-step">
<Step step="first-step" component={FirstStep} />
<Step step="second-components-step" component={SecondStep} />
<Step step="id-for-the-third-step" component={ThirdStep} />
</Stepper>
);
}