Created
September 24, 2022 18:21
-
-
Save hereisfahad/0b5c6b2e4a0adcffb8b2b15ea6c4dc24 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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