Skip to content

Commit

Permalink
add stepper component
Browse files Browse the repository at this point in the history
  • Loading branch information
mazmassa committed May 11, 2023
1 parent 14490af commit efb7566
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/components/Stepper/Stepper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Stepper } from "./Stepper";

export default { title: "Components/Stepper", component: Stepper };

export const _Stepper = {
render: () => (
<>
Step 1/3
<Stepper step={0} steps={["one", "two", "three"]} />
<br />
Step 2/3
<Stepper step={1} steps={["one", "two", "three"]} />
<br />
Step 3/3
<Stepper step={2} steps={["one", "two", "three"]} />
<br />
Step 3/3 (with check completed)
<Stepper step={3} steps={["one", "two", "three"]} />
</>
),
};
38 changes: 38 additions & 0 deletions src/components/Stepper/Stepper.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import "@testing-library/jest-dom";
import { render, screen, within } from "@testing-library/react";
import { Stepper } from ".";

describe("Components | Stepper", () => {
test("it should render", () => {
render(<Stepper step={0} steps={["one", "two", "three"]} />);

let stepper = screen.getByTestId("stepper");

expect(stepper).toBeInTheDocument();
});

test("it has the first step in stepIn mode", () => {
render(<Stepper step={0} steps={["one", "two", "three"]} />);

let step0 = screen.getByTestId("stepper-item-0");
let stepIn = within(step0).getByTestId("stepper-step-in");

expect(stepIn).toBeInTheDocument();
});

test("it has the 1st step as StepPast mode, the 2nd in stepIn and 3rd as StepNext", () => {
render(<Stepper step={1} steps={["one", "two", "three"]} />);

let step0 = screen.getByTestId("stepper-item-0");
let step1 = screen.getByTestId("stepper-item-1");
let step2 = screen.getByTestId("stepper-item-2");

let stepPast = within(step0).getByTestId("stepper-step-past");
let stepIn = within(step1).getByTestId("stepper-step-in");
let stepNext = within(step2).getByTestId("stepper-step-next");

expect(stepIn).toBeInTheDocument();
expect(stepPast).toBeInTheDocument();
expect(stepNext).toBeInTheDocument();
});
});
86 changes: 86 additions & 0 deletions src/components/Stepper/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { ComponentPropsWithoutRef } from "react";
import { FiCircle } from "react-icons/fi";

export interface StepperProps extends ComponentPropsWithoutRef<"ol"> {
steps: string[];
step: number;
}

let baseStepClass =
"flex items-center justify-center w-4 h-4 rounded-full shrink-0";

function StepIn() {
return (
<span
data-testid="stepper-step-in"
className={`${baseStepClass} bg-s-success`}
>
<FiCircle className="w-1 h-1 text-f-primary fill-i-primary" />
</span>
);
}

function StepNext() {
return (
<span
data-testid="stepper-step-next"
className={`${baseStepClass} border border-1 border-c-default bg-transparent`}
>
<FiCircle className="w-1 h-1 text-f-primary fill-i-primary" />
</span>
);
}

function StepPast() {
return (
<span
data-testid="stepper-step-past"
className={`${baseStepClass} bg-s-success`}
></span>
);
}

export function Stepper(props: StepperProps) {
const { step, steps } = props;

const edgeClass = "after:w-full after:border-b after:inline-block";
const edgePastClass = edgeClass + " after:border-c-default";
const edgeNextClass = edgeClass + " after:border-s-success";

return (
<ol className="flex items-center w-full" data-testid="stepper">
{steps.map((s, idx) => {
let isLastStep = idx === steps.length - 1;
let stepClass = isLastStep ? "" : edgeClass;
let flowClass = isLastStep ? "" : edgePastClass;
let textClass = "text-f-primary";

let currentStep = <StepNext />;

if (idx === step) {
currentStep = <StepIn />;
} else if (idx < step) {
currentStep = <StepPast />;
textClass = "text-f-tertiary";
flowClass = isLastStep ? "" : edgeNextClass;
}

return (
<li
data-testid={`stepper-item-${idx}`}
key={idx}
className={`flex w-full items-center ${stepClass} ${flowClass}`}
>
{currentStep}
<div
className={`ml-1 min-w-fit mr-1 text-xs ${textClass}`}
data-testid="stepper-label"
>
{s}
</div>
</li>
);
})}
</ol>
);
}
1 change: 1 addition & 0 deletions src/components/Stepper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Stepper";

0 comments on commit efb7566

Please sign in to comment.