Skip to content

Instantly share code, notes, and snippets.

@hereisfahad
Created September 24, 2022 18:21
Show Gist options
  • Save hereisfahad/0b5c6b2e4a0adcffb8b2b15ea6c4dc24 to your computer and use it in GitHub Desktop.
Save hereisfahad/0b5c6b2e4a0adcffb8b2b15ea6c4dc24 to your computer and use it in GitHub Desktop.
import * as React from 'react';
import Box from '@mui/material/Box';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import { styled } from '@mui/material/styles';
import StepConnector, {
stepConnectorClasses,
} from '@mui/material/StepConnector';
import { Step as StepProps } from '../types';
interface OwnProps {
steps: StepProps[];
}
export default function HorizontalLinearStepper({ steps }: OwnProps) {
const [activeStep, setActiveStep] = React.useState(0);
const [skipped, setSkipped] = React.useState(new Set<number>());
const isStepOptional = (step: number) => {
// TODO: should any of the steps be optional? Returning false for now.
return false;
};
const isStepSkipped = (step: number) => {
return skipped.has(step);
};
const handleNext = () => {
let newSkipped = skipped;
if (isStepSkipped(activeStep)) {
newSkipped = new Set(newSkipped.values());
newSkipped.delete(activeStep);
}
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped(newSkipped);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this,
// it should never occur unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const handleReset = () => {
setActiveStep(0);
};
const ColorlibConnector = styled(StepConnector)(({ theme }) => ({
[`&.${stepConnectorClasses.alternativeLabel}`]: {
top: 7,
right: '45%',
left: '-45%',
},
[`&.${stepConnectorClasses.active}`]: {
[`& .${stepConnectorClasses.line}`]: {
backgroundColor: '#0555C0',
},
},
[`&.${stepConnectorClasses.completed}`]: {
[`& .${stepConnectorClasses.line}`]: {
backgroundColor: '#0555C0',
},
},
[`& .${stepConnectorClasses.line}`]: {
height: 5,
border: 0,
backgroundColor: '#ECECEC',
borderRadius: 6,
},
}));
const ColorlibStepIconRoot = styled('div')<{
ownerState: { completed?: boolean; active?: boolean };
}>(({ ownerState }) => ({
backgroundColor: '#ECECEC',
zIndex: 1,
color: '#fff',
width: 20,
height: 20,
display: 'flex',
borderRadius: '50%',
justifyContent: 'center',
alignItems: 'center',
...(ownerState.active && {
backgroundColor: '#0555C0',
}),
...(ownerState.completed && {
backgroundColor: '#0555C0',
}),
}));
function ColorlibStepIcon(props) {
const { active, completed, className } = props;
return (
<ColorlibStepIconRoot
ownerState={{ completed, active }}
className={className}
/>
);
}
return (
<Box
sx={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
height: '100vh',
}}
>
<Stepper
sx={{ maxWidth: '415px', marginTop: '53px' }}
activeStep={activeStep}
alternativeLabel
connector={<ColorlibConnector />}
>
{steps.map((step, index) => {
const { title: label } = step;
const stepProps: { completed?: boolean } = {};
const labelProps: {
optional?: React.ReactNode;
} = {};
if (isStepOptional(index)) {
labelProps.optional = (
<Typography variant="caption">Optional</Typography>
);
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label}>
<StepLabel StepIconComponent={ColorlibStepIcon}>
<span style={{ fontSize: '10px' }}>{label}</span>
</StepLabel>
</Step>
);
})}
</Stepper>
<React.Fragment>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: 'calc(100vh - 166px)',
}}
>
{activeStep || activeStep === 0 ? steps[activeStep].component : null}
</Box>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
<Button
color="inherit"
disabled={activeStep === 0}
onClick={handleBack}
sx={{ mr: 1 }}
>
Back
</Button>
<Box sx={{ flex: '1 1 auto' }} />
{isStepOptional(activeStep) && (
<Button color="inherit" onClick={handleSkip} sx={{ mr: 1 }}>
Skip
</Button>
)}
<Button onClick={handleNext}>
{activeStep === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</Box>
</React.Fragment>
</Box>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment