Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Created new Stepper / StepperProvider components #855

Merged
merged 10 commits into from
Nov 5, 2024
11 changes: 11 additions & 0 deletions src/atoms/hooks/hooks.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ import { Typography } from 'src/molecules';
import styled from 'styled-components';

const hookList = [
{
name: 'useStepper',
body: 'Returns stepper methods and state',
code: `const {
steps: [Step, Step, ...Step[]];
currentStep: number;
currentSubStep: number;
setCurrentStep: (value: number) => void;
goToNextStep: () => void;
goToPreviousStep: () => void; } = useStepper()`,
},
{
name: 'useSignalRMessages',
body: 'Returns service bus messages with wss given a topic + host + token',
Expand Down
2 changes: 2 additions & 0 deletions src/atoms/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { useAuth } from 'src/providers/AuthProvider/AuthProvider';
import { useReleaseNotes } from 'src/providers/ReleaseNotesProvider';
import { useSideBar } from 'src/providers/SideBarProvider';
import { useSnackbar } from 'src/providers/SnackbarProvider/SnackbarProvider';
import { useStepper } from 'src/providers/StepperProvider';
import { useTableOfContents } from 'src/providers/TableOfContentsProvider';
import { useThemeProvider } from 'src/providers/ThemeProvider/ThemeProvider';
import { useTutorialSteps } from 'src/providers/TutorialStepsProvider';

export {
useAuth,
useStepper,
useSelect,
useDebounce,
useFakeProgress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ const IconWrapper = styled.span<IconWrapperProps>`
}
`;

interface StepProps {
interface OldStepProps {
currentIndex: number;
setCurrentIndex: (value: number) => void;
index: number;
onlyShowCurrentStepLabel?: boolean;
children?: string;
}

const Step: FC<StepProps> = ({
export const OldStep: FC<OldStepProps> = ({
currentIndex,
setCurrentIndex,
index,
Expand Down Expand Up @@ -135,5 +135,3 @@ const Step: FC<StepProps> = ({
</Container>
);
};

export default Step;
33 changes: 33 additions & 0 deletions src/deprecated/OldStepper/OldStepLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { FC, useMemo } from 'react';

import { tokens } from '@equinor/eds-tokens';

import styled from 'styled-components';

const { colors } = tokens;

interface LineProps {
$background: string;
}

const Line = styled.hr<LineProps>`
height: 1px;
width: 100%;
background: ${(props) => props.$background};
border: none;
margin: 0;
`;

interface StepLineProps {
done: boolean;
}

const OldStepLine: FC<StepLineProps> = ({ done }) => {
const background = useMemo((): string => {
if (done) return colors.interactive.primary__resting.rgba;
return colors.interactive.disabled__text.rgba;
}, [done]);
return <Line $background={background} />;
};

export default OldStepLine;
45 changes: 45 additions & 0 deletions src/deprecated/OldStepper/OldStepper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Meta, StoryFn } from '@storybook/react';

import { OldStepper, OldStepperProps } from './OldStepper';

import styled from 'styled-components';

const meta: Meta<typeof OldStepper> = {
title: 'Deprecated/Stepper',
component: OldStepper,
argTypes: {
current: { control: 'number' },
setCurrent: { action: 'Called setCurrent' },
steps: { control: 'object' },
onlyShowCurrentStepLabel: { control: 'boolean' },
maxWidth: { control: 'text' },
},
args: {
current: 0,
steps: ['Select conveyance', 'Select provider', 'Select service'],
onlyShowCurrentStepLabel: false,
},
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/fk8AI59x5HqPCBg4Nemlkl/%F0%9F%92%A0-Component-Library---Amplify?type=design&node-id=5694-19911&mode=design&t=jlQAMMWK1GLpzcAL-4',
},
},
};

export default meta;

const Container = styled.div`
height: 20rem;
display: flex;
justify-content: center;
padding: 0 10rem;
`;

export const Primary: StoryFn<OldStepperProps> = (args) => {
return (
<Container>
<OldStepper {...args} />
</Container>
);
};
75 changes: 75 additions & 0 deletions src/deprecated/OldStepper/OldStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { FC, ReactElement, useMemo } from 'react';

import { OldStep } from './OldStep';
import OldStepLine from './OldStepLine';
import { spacings } from 'src/atoms/style';

import styled from 'styled-components';

interface ContainerProps {
$stepAmount: number;
$maxWidth?: string;
}
const Container = styled.div<ContainerProps>`
display: grid;
grid-template-columns:
repeat(${({ $stepAmount }) => $stepAmount - 1}, auto 1fr)
auto;
grid-gap: ${spacings.small};
align-items: center;
width: 100%;
${({ $maxWidth }) => $maxWidth && `max-width: ${$maxWidth}`}
`;

export interface OldStepperProps {
current: number;
setCurrent: (value: number) => void;
steps: string[];
onlyShowCurrentStepLabel?: boolean;
maxWidth?: string;
}

/**
* @deprecated Use the new Stepper + StepperProvider component instead
*/
export const OldStepper: FC<OldStepperProps> = ({
current,
setCurrent,
steps,
onlyShowCurrentStepLabel = false,
maxWidth,
}) => {
const children = useMemo((): ReactElement[] => {
const all: ReactElement[] = [];
steps.forEach((step, index) => {
all.push(
<OldStep
key={`step-${index}`}
index={index}
currentIndex={current}
setCurrentIndex={setCurrent}
onlyShowCurrentStepLabel={onlyShowCurrentStepLabel}
>
{step}
</OldStep>
);

if (index !== steps.length - 1) {
all.push(
<OldStepLine key={`step-line-${index}`} done={current > index} />
);
}
});
return all;
}, [current, onlyShowCurrentStepLabel, setCurrent, steps]);

return (
<Container
$stepAmount={steps.length}
$maxWidth={maxWidth}
data-testid="stepper-container"
>
{children}
</Container>
);
};
1 change: 1 addition & 0 deletions src/deprecated/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ export { default as SingleSelectDrawer } from './SingleSelectDrawer';
export { default as IconToggleButton } from './IconToggleButton';
export { default as Tutorial } from './Tutorial/Tutorial';
export { HighlightBlocks } from './Tutorial/HighlightBlocks/HighlightBlocks';
export { OldStepper } from './OldStepper/OldStepper';
export { FullPageStatus } from './FullPageStatus/FullPageStatus';
88 changes: 88 additions & 0 deletions src/molecules/Stepper/Step/Step.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { FC, useMemo, useState } from 'react';

import { Typography } from '@equinor/eds-core-react';
import { TypographyVariants } from '@equinor/eds-core-react/dist/types/components/Typography/Typography.tokens';

import { colors, spacings } from 'src/atoms/style';
import { StepIcon } from 'src/molecules/Stepper/Step/StepIcon';
import { useStepper } from 'src/providers/StepperProvider';

import styled from 'styled-components';

interface ContainerProps {
$clickable: boolean;
}

const Container = styled.div<ContainerProps>`
display: flex;
gap: ${spacings.small};
align-items: center;
white-space: nowrap;
${(props) =>
props.$clickable &&
`
&:hover {
cursor: pointer;
}
`}
`;

interface StepProps {
index: number;
onlyShowCurrentStepLabel?: boolean;
children?: string;
}

export const Step: FC<StepProps> = ({
index,
onlyShowCurrentStepLabel = false,
children,
}) => {
const { currentStep, setCurrentStep } = useStepper();
const [containerRef, setContainerRef] = useState<HTMLDivElement | null>(null);

const textVariant = useMemo((): TypographyVariants => {
if (index < currentStep) return 'body_short';
return 'body_short_bold';
}, [currentStep, index]);

const textColor = useMemo((): string | undefined => {
if (index > currentStep) return colors.interactive.disabled__text.rgba;
return colors.text.static_icons__default.rgba;
}, [currentStep, index]);

const handleOnClick = () => {
if (index < currentStep) {
setCurrentStep(index);
}
};

return (
<Container
data-testid="step"
ref={(ref: HTMLDivElement | null) => {
if (containerRef === null && ref !== null) {
setContainerRef(ref);
}
}}
style={
containerRef !== null && !onlyShowCurrentStepLabel
? {
width: `calc(${containerRef.clientWidth}px)`,
}
: undefined
}
$clickable={index < currentStep}
onClick={handleOnClick}
>
<StepIcon index={index} />
{(!onlyShowCurrentStepLabel || currentStep === index) && (
<Typography variant={textVariant} color={textColor}>
{children}
</Typography>
)}
</Container>
);
};

export default Step;
63 changes: 63 additions & 0 deletions src/molecules/Stepper/Step/StepIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { FC } from 'react';

import { Icon, Typography } from '@equinor/eds-core-react';
import { check } from '@equinor/eds-icons';

import { colors, shape } from 'src/atoms/style';
import { useStepper } from 'src/providers/StepperProvider';

import styled from 'styled-components';

interface IconWrapperProps {
$filled?: boolean;
$outlined?: boolean;
}

const IconWrapper = styled.span<IconWrapperProps>`
display: flex;
justify-content: center;
align-items: center;
width: 22px;
height: 22px;
border-radius: ${shape.circle.borderRadius};
border: 2px solid
${({ $filled, $outlined }) =>
($filled ?? $outlined)
? colors.interactive.primary__resting.rgba
: colors.interactive.disabled__text.rgba};
background: ${({ $filled }) =>
$filled ? colors.interactive.primary__resting.rgba : 'none'};
> p {
// Ensure text icons are not squished
padding: 8px;
color: ${(props) =>
props.$filled
? colors.text.static_icons__primary_white.rgba
: colors.interactive.disabled__text.rgba};
}
> svg {
transform: scale(0.9);
}
`;

interface StepIconProps {
index: number;
}

export const StepIcon: FC<StepIconProps> = ({ index }) => {
const { currentStep } = useStepper();

if (index >= currentStep) {
return (
<IconWrapper $filled={index === currentStep}>
<Typography variant="caption">{index + 1}</Typography>
</IconWrapper>
);
}

return (
<IconWrapper $outlined data-testid="wrapper">
<Icon data={check} color={colors.interactive.primary__resting.rgba} />
</IconWrapper>
);
};
4 changes: 1 addition & 3 deletions src/molecules/Stepper/StepLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ interface StepLineProps {
done: boolean;
}

const StepLine: FC<StepLineProps> = ({ done }) => {
export const StepLine: FC<StepLineProps> = ({ done }) => {
const background = useMemo((): string => {
if (done) return colors.interactive.primary__resting.rgba;
return colors.interactive.disabled__text.rgba;
}, [done]);
return <Line $background={background} />;
};

export default StepLine;
Loading