Skip to content

Instantly share code, notes, and snippets.

@shivashp
Created January 22, 2021 14:54
Show Gist options
  • Save shivashp/d534a238daf1bd9d1860d422ecf77db6 to your computer and use it in GitHub Desktop.
Save shivashp/d534a238daf1bd9d1860d422ecf77db6 to your computer and use it in GitHub Desktop.
Multistep
import React, { useState } from 'react';
import { Box } from '@material-ui/core';
import { PrimaryButton, SecondaryButton } from '../Button/Button';
import { Body } from '../Text/Text';
const MultiStepContext = React.createContext();
const useMultiStep = () => {
const context = React.useContext(MultiStepContext);
if (!context) {
throw new Error('Multistep components should be inside Multistep');
}
return context;
};
/**
* Each step should be wrapped with Step Component
*/
const Step = ({ children, stepIndex }) => {
const { activeStep } = useMultiStep();
return activeStep === stepIndex ? children : null;
};
/**
* Parent component, everything related should be wrapped by MultiStep
*/
const MultiStep = React.memo(
({ children, defaultActiveState = 0, ...props }) => {
const [activeStep, setActiveStep] = useState(defaultActiveState);
let totalSteps = -1;
const handleNext = () => {
if (activeStep < totalSteps) {
setActiveStep((prevState) => prevState + 1);
}
};
const handleBack = () => {
if (activeStep > 0) {
setActiveStep((prevState) => prevState - 1);
}
};
const content = React.Children.map(children, (child) => {
if (child.type.prototype === Step.prototype) {
totalSteps += 1;
return React.cloneElement(child, { stepIndex: totalSteps });
}
return child;
});
return (
<MultiStepContext.Provider
value={{ activeStep, handleNext, handleBack, totalSteps }}
>
<Box {...props}>{content}</Box>
</MultiStepContext.Provider>
);
}
);
/*
* Gives you information about current step and total steps can be customized or placed anywhere inside MultiStep Component
*/
const MultiStepPanel = (props) => {
const { activeStep, totalSteps } = useMultiStep();
return (
<Body bold {...props}>
Step {activeStep + 1} of {totalSteps + 1}
</Body>
);
};
/**
* Provides next and back button support can be passed custom button components
*/
const MultiStepNavigation = ({ backComponent, nextComponent, ...props }) => {
const { handleNext, handleBack, activeStep } = useMultiStep();
const next = nextComponent ? (
nextComponent({ handleNext })
) : (
<PrimaryButton px={5} py={2} large onClick={handleNext}>
Next
</PrimaryButton>
);
const back = backComponent ? (
backComponent({ handleBack })
) : (
<SecondaryButton px={5} py={2} mr={2} large onClick={handleBack}>
Back
</SecondaryButton>
);
return (
<Box {...props}>
{activeStep !== 0 && back}
{next}
</Box>
);
};
export { MultiStep, MultiStepPanel, Step, MultiStepNavigation };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment