Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 1x 1x 6x 6x 6x 17x 6x 11x 2x 9x 17x 6x 17x 17x | import React, { type JSX } from 'react';
import { Stepper as MuiStepper, Step, StepLabel, SxProps, Theme, Typography, useTheme } from '@mui/material';
import { useStrings } from '../../strings';
export type StepperStep = {
label: string;
/**
* Marks the step as optional. Whether an optional step shows as completed comes from `completed` here rather than
* from `completedSteps` or the active step, since the user may have skipped it.
*/
optional?: { completed: boolean };
};
export type StepperProps = {
activeStep: number;
className?: string;
/**
* Indexes of the steps that are completed. When provided, only these steps show as completed, so a step stays
* completed when the user goes back to an earlier one. The active step always uses the active styling, even if it is
* in this list. When omitted, every step before the active one shows as completed.
*/
completedSteps?: number[];
/**
* Styles applied to each step label, after the defaults. MUI styles active and completed labels with a more specific
* selector, so label text overrides should target `.MuiStepLabel-label.Mui-active` and
* `.MuiStepLabel-label.Mui-completed` as well as `.MuiStepLabel-label`.
*/
stepLabelSx?: SxProps<Theme>;
steps: (string | StepperStep)[];
sx?: SxProps<Theme>;
};
const LABEL_SELECTOR = '.MuiStepLabel-label, .MuiStepLabel-label.Mui-active, .MuiStepLabel-label.Mui-completed';
const Stepper = ({ activeStep, className, completedSteps, stepLabelSx, steps, sx }: StepperProps): JSX.Element => {
const theme = useTheme();
const strings = useStrings();
const isCompleted = (step: StepperStep, index: number): boolean | undefined => {
if (index === activeStep) {
return false;
}
if (step.optional) {
return step.optional.completed;
}
return completedSteps ? completedSteps.includes(index) : undefined;
};
const getStepLabelStyles = (index: number): SxProps<Theme> => [
{
'.MuiStepIcon-root': { fill: theme.palette.TwClrBgTertiary as string },
'.MuiStepIcon-root.Mui-active': { fill: theme.palette.TwClrIcnSecondary as string },
'.MuiStepIcon-root.Mui-completed': { fill: theme.palette.TwClrTxtBrand as string },
[LABEL_SELECTOR]: {
fontSize: '14px',
fontWeight: 400,
color: (index === activeStep ? theme.palette.TwClrTxt : theme.palette.TwClrTxtSecondary) as string,
},
},
...(Array.isArray(stepLabelSx) ? stepLabelSx : [stepLabelSx]),
];
return (
<MuiStepper
activeStep={activeStep}
className={className}
sx={[{ margin: theme.spacing(1, 0, 3) }, ...(Array.isArray(sx) ? sx : [sx])]}
>
{steps.map((stepOrLabel, index) => {
const step = typeof stepOrLabel === 'string' ? { label: stepOrLabel } : stepOrLabel;
return (
<Step key={index} completed={isCompleted(step, index)}>
<StepLabel
optional={
step.optional && (
<Typography variant='caption' color={theme.palette.TwClrTxtSecondary as string}>
{strings.OPTIONAL}
</Typography>
)
}
sx={getStepLabelStyles(index)}
>
{step.label}
</StepLabel>
</Step>
);
})}
</MuiStepper>
);
};
export default Stepper;
|