-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
f9582e8
commit db8d0de
Showing
15 changed files
with
380 additions
and
10 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
```js | ||
|
||
const DefaultStepContent = ({ title }) => ( | ||
<div> | ||
<h4>{title}</h4> | ||
<p>Hello {title}</p> | ||
</div> | ||
); | ||
|
||
const steps = [ | ||
{ | ||
title: 'Step 1', | ||
description: 'This is the first step', | ||
component: <DefaultStepContent title="Step 1" />, | ||
}, | ||
{ | ||
title: 'Step 2', | ||
description: 'This is the second step', | ||
component: <DefaultStepContent title="Step 2" />, | ||
}, | ||
{ | ||
title: 'Step 3', | ||
description: 'This is the third step', | ||
component: <DefaultStepContent title="Step 3" />, | ||
}, | ||
]; | ||
|
||
<Stepper | ||
steps={steps} | ||
onFinish={() => console.log("LAST STEP")} | ||
onStepChange={(s) => console.log("STEP CHANGED", s)} | ||
/> | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import React from "react"; | ||
import Stepper from "./index"; | ||
|
||
describe("Stepper", () => { | ||
const steps = [ | ||
{ | ||
title: "Step 1", | ||
description: "Description 1", | ||
component: <div>Step 1 Content</div>, | ||
}, | ||
{ | ||
title: "Step 2", | ||
description: "Description 2", | ||
component: <div>Step 2 Content</div>, | ||
}, | ||
{ | ||
title: "Step 3", | ||
description: "Description 3", | ||
component: <div>Step 3 Content</div>, | ||
}, | ||
]; | ||
|
||
const selectors = { | ||
stepperContainer: ".Stepper-container", | ||
stepsContainer: ".steps-container", | ||
step: ".step", | ||
activeStep: ".step.active", | ||
completedStep: ".step.completed", | ||
stepIndicator: ".step-indicator", | ||
stepNumber: ".step-number", | ||
stepLine: ".step-line", | ||
stepContent: ".step-content", | ||
stepComponent: ".step-component", | ||
navigationButtons: ".navigation-buttons", | ||
backButton: 'button:contains("Back")', | ||
continueButton: 'button:contains("Continue")', | ||
finishButton: 'button:contains("Finish")', | ||
}; | ||
|
||
it("renders the component with the correct number of steps", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.stepperContainer) | ||
.should("exist") | ||
.get(selectors.stepsContainer) | ||
.should("exist") | ||
.get(selectors.step) | ||
.should("have.length", steps.length); | ||
}); | ||
|
||
it("displays the first step as active by default", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.activeStep) | ||
.should("have.length", 1) | ||
.get(selectors.activeStep) | ||
.find("h3") | ||
.should("contain", steps[0].title); | ||
}); | ||
|
||
it("starts with an initial step if specified", () => { | ||
const stepsWithInitial = [ | ||
...steps.slice(0, 2), | ||
{ ...steps[2], isInitial: true }, | ||
]; | ||
cy.mount(<Stepper steps={stepsWithInitial} />) | ||
.get(selectors.activeStep) | ||
.find("h3") | ||
.should("contain", steps[2].title); | ||
}); | ||
|
||
it("does not show the Back button on the first step", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.backButton) | ||
.should("not.exist"); | ||
}); | ||
|
||
it("moves to the next step when Continue is clicked", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.activeStep) | ||
.find("h3") | ||
.should("contain", steps[1].title) | ||
.get(selectors.completedStep) | ||
.should("have.length", 1); | ||
}); | ||
|
||
it("moves to the previous step when Back is clicked", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.backButton) | ||
.click() | ||
.get(selectors.activeStep) | ||
.find("h3") | ||
.should("contain", steps[0].title) | ||
.get(selectors.completedStep) | ||
.should("have.length", 0); | ||
}); | ||
|
||
it("shows Finish button on the last step", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.finishButton) | ||
.should("exist"); | ||
}); | ||
|
||
it("calls onFinish when Finish button is clicked", () => { | ||
const onFinish = cy.stub().as("onFinish"); | ||
cy.mount(<Stepper steps={steps} onFinish={onFinish} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.finishButton) | ||
.click() | ||
.get("@onFinish") | ||
.should("have.been.called"); | ||
}); | ||
|
||
it("calls onStepChange when moving between steps", () => { | ||
const onStepChange = cy.stub().as("onStepChange"); | ||
cy.mount(<Stepper steps={steps} onStepChange={onStepChange} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get("@onStepChange") | ||
.should("have.been.calledWith", steps[1]) | ||
.get(selectors.backButton) | ||
.click() | ||
.get("@onStepChange") | ||
.should("have.been.calledWith", steps[0]); | ||
}); | ||
|
||
it("disables Finish button when isDisableFinish is true", () => { | ||
cy.mount(<Stepper steps={steps} isDisableFinish={true} />) | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.finishButton) | ||
.should("be.disabled"); | ||
}); | ||
|
||
it("renders the correct step component for the active step", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.stepComponent) | ||
.contains("Step 1 Content") | ||
.get(selectors.continueButton) | ||
.click() | ||
.get(selectors.stepComponent) | ||
.contains("Step 2 Content"); | ||
}); | ||
|
||
it("renders step lines between steps", () => { | ||
cy.mount(<Stepper steps={steps} />) | ||
.get(selectors.stepLine) | ||
.should("have.length", steps.length - 1); | ||
}); | ||
|
||
it("displays step titles and descriptions", () => { | ||
cy.mount(<Stepper steps={steps} />); | ||
steps.forEach((step, index) => { | ||
cy.get(selectors.stepContent) | ||
.eq(index) | ||
.find("h3") | ||
.should("contain", step.title); | ||
cy.get(selectors.stepContent) | ||
.eq(index) | ||
.find("p") | ||
.should("contain", step.description); | ||
}); | ||
}); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
.wizard-container { | ||
max-width: 600px; | ||
margin: 0 auto; | ||
padding: 20px; | ||
} | ||
|
||
.steps-container { | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
|
||
.step { | ||
display: flex; | ||
margin-bottom: 20px; | ||
|
||
} | ||
|
||
.step-indicator { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
margin-right: 20px; | ||
} | ||
|
||
.step-number { | ||
/* background-color: var(--color-secondary-dark); */ | ||
width: 30px; | ||
height: 30px; | ||
border-radius: 50%; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
margin-bottom: 10px; | ||
border: 1px solid var(--color-secondary-dark); | ||
} | ||
|
||
.step-line { | ||
width: 1px; | ||
flex-grow: 1; | ||
background-color: var(--color-secondary-dark); | ||
} | ||
|
||
.step.active .step-number { | ||
/* background-color: var(--color-primary-base); */ | ||
/* color:var(--color-secondary-extra-dark); */ | ||
} | ||
|
||
.step.completed .step-number { | ||
/* background-color: var(--color-success-base); */ | ||
color: var(--color-success-base); | ||
border-color: var(--color-success-base); | ||
} | ||
|
||
.step-content { | ||
flex-grow: 1; | ||
} | ||
|
||
.step-content h3 { | ||
margin: 0 0 5px 0; | ||
} | ||
|
||
.step-content p { | ||
margin: 0 0 10px 0; | ||
} | ||
|
||
.step-component { | ||
margin-top: 10px; | ||
padding: 15px; | ||
} | ||
|
||
.navigation-buttons { | ||
display: flex; | ||
justify-content: right; | ||
margin-top: 20px; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import Button from "../Button"; | ||
import Icon from "../Icon"; | ||
|
||
const Stepper = ({ | ||
steps, | ||
isDisableFinish = false, | ||
onFinish = () => {}, | ||
onStepChange = () => {}, | ||
finishBtnText = "Finish", | ||
}) => { | ||
const [currentStep, setCurrentStep] = useState(0); | ||
|
||
useEffect(() => { | ||
const initialStep = steps.findIndex((step) => step.isInitial); | ||
setCurrentStep(initialStep !== -1 ? initialStep : 0); | ||
}, [steps]); | ||
|
||
const handleNext = () => { | ||
if (currentStep < steps.length - 1) { | ||
const nextStep = currentStep + 1; | ||
setCurrentStep(nextStep); | ||
onStepChange(steps[nextStep]); | ||
} | ||
}; | ||
|
||
const handleBack = () => { | ||
if (currentStep > 0) { | ||
const prevStep = currentStep - 1; | ||
setCurrentStep(prevStep); | ||
onStepChange(steps[prevStep]); | ||
} | ||
}; | ||
|
||
const isLastStep = currentStep === steps.length - 1; | ||
|
||
return ( | ||
<div className="Stepper-container"> | ||
<div className="steps-container"> | ||
{steps.map((step, index) => { | ||
const isStepComplete = index < currentStep; | ||
return ( | ||
<div | ||
key={index} | ||
className={`step ${index === currentStep ? "active" : ""} ${ | ||
isStepComplete ? "completed" : "" | ||
}`} | ||
> | ||
<div className="step-indicator"> | ||
<div className={`step-number`}> | ||
{isStepComplete ? <Icon type="check" /> : index + 1} | ||
</div> | ||
{index < steps.length - 1 && <div className="step-line"></div>} | ||
</div> | ||
<div className="step-content"> | ||
<h3>{step.title}</h3> | ||
<p>{step.description}</p> | ||
{index === currentStep && ( | ||
<div className="step-component">{step.component}</div> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
})} | ||
</div> | ||
<div className="navigation-buttons"> | ||
{currentStep >= 1 && ( | ||
<Button theme="secondary" onClick={handleBack}> | ||
Back | ||
</Button> | ||
)} | ||
| ||
<Button | ||
theme="primary" | ||
onClick={isLastStep ? onFinish : handleNext} | ||
disabled={isDisableFinish && isLastStep} | ||
> | ||
{isLastStep ? finishBtnText : "Continue"} | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Stepper; |
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