Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/react/src/components/Stepper/Step/Step.api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Meta } from '@storybook/blocks';
import LinkTo from '@storybook/addon-links/react';
import { TableInterface } from '~storybook/components/TableInterface';

<Meta title="Components API/Step" />

# Dropzone API

```js
import { Step } from '@elonkit/react';
```

## Component name

The name `ESStep` can be used when providing default props or style overrides in the theme.

## Props

<TableInterface name="StepProps" variant="props" />

<br />

## CSS

<TableInterface name="StepClasses" variant="css" />

<br />

## Demos

<ul>
<li>
<LinkTo kind="components-Stepper" story="demo">
<code>Stepper</code>
</LinkTo>
</li>
</ul>
40 changes: 40 additions & 0 deletions packages/react/src/components/Stepper/Step/Step.classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { generateUtilityClass, generateUtilityClasses } from '@mui/material';

export type StepClasses = {
/** Styles applied to the root element. */
root: string;
/** Styles applied to the root element if component disabled. */
disabled: string;
/** Styles applied to the size element. */
size: string;
/** Styles applied to the completed element. */
completed: string;
/** State class applied to the root element if `error={true}`. */
error: string;
/** Styles applied to the activeStep element. */
activeStep: string;
/** Styles applied to the root element if position='bottom'. */
positionBottom: string;
/** Styles applied to the root element if position='default'. */
positionDefault: string;
/** Styles applied to the orientation element. */
vertical: string;
};

export type StepClassKey = keyof StepClasses;

export function getStepUtilityClass(slot: string): string {
return generateUtilityClass('ESStep', slot);
}

export const stepClasses: StepClasses = generateUtilityClasses('ESStep', [
'root',
'disabled',
'size',
'completed',
'positionBottom',
'positionDefault',
'vertical',
'error',
'activeStep',
]);
222 changes: 222 additions & 0 deletions packages/react/src/components/Stepper/Step/Step.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import { StepProps } from './Step.types';

import clsx from 'clsx';
import { getStepUtilityClass } from './Step.classes';

import { unstable_composeClasses as composeClasses } from '@mui/base';

import { styled, useThemeProps } from '@mui/material/styles';
import { capitalize } from '@mui/material';

import { IconCheckW500, IconExclamation } from '../../../icons';
import { ButtonBase, buttonBaseClasses } from '../../ButtonBase';

type StepOwnerState = {
classes?: StepProps['classes'];
error?: boolean;
completed?: boolean;
size?: string;
activeStep?: number;
disabled?: boolean;
position?: 'default' | 'bottom';
orientation?: 'horizontal' | 'vertical';
};

const useUtilityClasses = (ownerState: StepOwnerState) => {
const { classes, completed, error, size, position, orientation } = ownerState;

const slots = {
root: [
'root',
completed && 'completed',
error && 'error',
`size${size}`,
position && `position${capitalize(position)}`,
orientation,
],
button: ['button'],
circle: ['circle'],
};

return composeClasses(slots, getStepUtilityClass, classes);
};

const StepRoot = styled(ButtonBase, {
name: 'ESStep',
slot: 'Root',
overridesResolver: (_props, styles) => {
const {
ownerState: { orientation, position },
} = _props;
return [styles.root, styles[orientation], position && styles[`position${capitalize(position)}`]];
},
})<{ ownerState: StepOwnerState }>(({ theme }) => ({
minHeight: '56px',
height: '100%',
position: 'relative',
'--text': theme.vars.palette.monoA.A900,
'--hovered': theme.vars.palette.monoA.A100,
'--pressed': theme.vars.palette.monoA.A200,
padding: '16px 24px 16px 16px',
borderRadius: '3px',

[`&.${buttonBaseClasses.disabled}`]: {
'--text': theme.vars.palette.monoA.A500,
'--icon': theme.vars.palette.monoA.A400,
cursor: 'not-allowed',
},

[`& .${buttonBaseClasses.wrapper}`]: {
display: 'flex',
justifyContent: 'flex-start',
},

variants: [
{
props: {
position: 'bottom',
orientation: 'horizontal',
},
style: {
marginTop: '21px',
padding: '16px',

[`& .${buttonBaseClasses.wrapper}`]: {
flexDirection: 'column',
height: 'auto',
gap: '8px',
},
},
},
{
props: {
error: true,
},
style: {
'--text': theme.vars.palette.error[300],
},
},
],
}));

const StepCircle = styled('div', {
name: 'ESStep',
slot: 'Circle',
overridesResolver: (props, styles) => {
const {
ownerState: { completed, error, disabled },
} = props;
return [styles.circle, completed && styles.completed, error && styles.error, disabled && styles.disabled];
},
})<{ ownerState: StepOwnerState }>(({ theme }) => ({
marginRight: '12px',
marginLeft: '8px',
borderRadius: '50%',
color: theme.vars.palette.monoB[500],
height: '32px',
width: '32px',
minWidth: '32px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: theme.vars.palette.monoA.A500,
fontWeight: 700,

variants: [
{
props: {
size: '24',
},
style: {
height: '24px',
width: '24px',
minWidth: '24px',
},
},
{
props: {
completed: true,
},
style: {
background: theme.vars.palette.primary[300],
},
},
{
props: {
activeStep: true,
},
style: {
background: theme.vars.palette.primary[300],
},
},
{
props: {
error: true,
},
style: {
background: theme.vars.palette.error[300],
},
},
{
props: {
disabled: true,
},
style: {
background: theme.vars.palette.monoA.A300,
},
},
{
props: {
position: 'bottom',
},
style: {
marginRight: '8px',
},
},
],
}));

export const Step = (inProps: StepProps) => {
const {
sx,
className,
disabled,
children,
error,
stepIndex,
completed,
activeStep,
position,
size = '32',
orientation,
required,
iconCompleted = <IconCheckW500 size={size} />,
iconError = <IconExclamation size={size} />,
...props
} = useThemeProps({
props: inProps,
name: 'ESStep',
});
const ownerState = {
...props,
size,
error,
completed,
activeStep,
disabled,
position,
orientation,
required,
};

const classes = useUtilityClasses(ownerState);

return (
<StepRoot className={clsx(className, classes.root)} disabled={disabled} ownerState={ownerState} sx={sx}>
<StepCircle className={classes.circle} ownerState={ownerState}>
{completed ? iconCompleted : error ? iconError : stepIndex}
</StepCircle>
{children}
</StepRoot>
);
};
55 changes: 55 additions & 0 deletions packages/react/src/components/Stepper/Step/Step.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ReactNode } from 'react';

import { StepClasses } from './Step.classes';

import { SxProps, Theme } from '@mui/material';

export interface StepProps {
children?: ReactNode;
/** Class applied to the root element. */
className?: string;
/** Override or extend the styles applied to the component. */
classes?: Partial<StepClasses>;
/** The system prop that allows defining system overrides as well as additional CSS styles. */
sx?: SxProps<Theme>;
/**
* Avatar size.
* @default 32
*/
size?: '24' | '32';
/** Styles applied to the track element. */
completed?: boolean;
/** Is the step complete */
activeStep?: number;
/**
* If `true`, the component is error.
*/
error?: boolean;

stepIndex?: number;
/** If true, the step is disabled. */
disabled?: boolean;

/**
* The component position.
* @default 'default'
*/
position?: 'default' | 'bottom';
/**
* The component position.
* @default 'horizontal'
*/
orientation?: 'horizontal' | 'vertical';

/** Icon to display with completed step. */
iconCompleted?: ReactNode;

/** Icon to display with error step. */
iconError?: ReactNode;

/**
* If `true`, the `input` element is required.
* @default false
*/
required?: boolean;
}
4 changes: 4 additions & 0 deletions packages/react/src/components/Stepper/Step/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { Step } from './Step';
export type { StepClasses, StepClassKey } from './Step.classes';
export { stepClasses } from './Step.classes';
export type { StepProps } from './Step.types';
Loading
Loading