Skip to content

Commit

Permalink
use render prop pattern for stepper buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
jay-deshmukh committed Jan 3, 2025
1 parent c66490c commit 81ffb53
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 98 deletions.
2 changes: 1 addition & 1 deletion lib/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tyk-technologies/tyk-ui",
"version": "4.4.13",
"version": "4.4.14",
"description": "Tyk UI - ui reusable components",
"main": "src/index.js",
"scripts": {
Expand Down
79 changes: 78 additions & 1 deletion src/components/Stepper/Readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,79 @@
## Custom buttons using Render Props method
```jsx
import React from "react";
import Button from "../Button";
import Confirm from "../Confirm";
import Stepper from "./index";

const MyStepperComponent = () => {
const handleFinish = () => {
console.log("Finished!");
};

const validateStep = (stepId) => {
return true;
};

return (
<Stepper onFinish={handleFinish} stepValidator={validateStep}>
<Stepper.Step
title="Step 1"
description="First step"
id="step1"
></Stepper.Step>

<Stepper.Step
title="Step 2"
description="Second step"
id="step2"
></Stepper.Step>

<Stepper.Buttons>
{({ goToNextStep, goToPreviousStep, isLastStep, activeStep, stepId }) => (
<div
style={{
display: "flex",
width: "100%",
justifyContent: "flex-end",
gap: "8px",
marginLeft: 0,
}}
>
{ stepId !== 'step2' && <Confirm
title="Console log"
description="Are u sure u want to console log?"
>
{(confirm) => (
<Button
onClick={confirm((event) => {
console.log("Button clicked", {event, activeStep, stepId});
})}
theme="secondary"
>
Skip (Confirm)
</Button>
)}
</Confirm>}

{activeStep > 0 && (
<Button onClick={goToPreviousStep} theme="secondary">
Back
</Button>
)}
<Button onClick={goToNextStep} theme="primary">
{isLastStep ? "Complete" : "Next"}
</Button>
</div>
)}
</Stepper.Buttons>
</Stepper>
);
};

<MyStepperComponent />;
```

## Vertical Stepper

```jsx
import React from 'react';
Expand Down Expand Up @@ -42,6 +118,7 @@ const ExampleStepper = () => {
<ExampleStepper />
```

## Horizontal Stepper
```jsx
import React from "react";
import Stepper from "./index.js";
Expand Down Expand Up @@ -124,4 +201,4 @@ const ExampleStepper = () => {
};

<ExampleStepper />
```
```
55 changes: 29 additions & 26 deletions src/components/Stepper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import React, { useState, useMemo } from "react";
import PropTypes from "prop-types";
import { StepperProvider } from "./StepperContext";
import StepList from "./js/StepList";
import StepperButtons from "./js/StepperButtons";
import { DefaultButtons } from "./js/StepperButtons";
import Buttons from "./js/Buttons";
import Step from "./js/Step";
import "./stepper.css";

const Stepper = ({
Expand All @@ -24,11 +26,24 @@ const Stepper = ({
const [validationAttempted, setValidationAttempted] = useState(false);
const isHorizontal = orientation === "horizontal";

const steps = useMemo(() => {
return React.Children.toArray(children).filter(
(child) => child.type.name === "Step"
);
}, [children]);
const { steps, buttons } = useMemo(() => {
const children_array = React.Children.toArray(children);
return {
steps: children_array.filter(
(child) => child.type.displayName === "StepperStep"
),
buttons: children_array.find(
(child) => child.type.displayName === "StepperButtons"
) || (
<DefaultButtons
nextBtnTxt={nextBtnTxt}
finishBtnTxt={finishBtnTxt}
backBtnTxt={backBtnTxt}
skipBtnTxt={skipBtnTxt}
/>
),
};
}, [children, nextBtnTxt, finishBtnTxt, backBtnTxt, skipBtnTxt]);

const contextValue = {
activeStep,
Expand All @@ -43,7 +58,7 @@ const Stepper = ({
validationAttempted,
setValidationAttempted,
orientation,
onSkip
onSkip,
};

return (
Expand All @@ -57,33 +72,25 @@ const Stepper = ({
style={
isHorizontal && contentHeight
? {
height: contentHeight,
maxHeight: contentHeight,
overflow: "scroll",
}
height: contentHeight,
maxHeight: contentHeight,
overflow: "scroll",
}
: {}
}
>
{isHorizontal && steps[activeStep]}
</div>
)}
<StepperButtons
nextBtnTxt={nextBtnTxt}
finishBtnTxt={finishBtnTxt}
backBtnTxt={backBtnTxt}
skipBtnTxt={skipBtnTxt}
/>
{buttons}
</div>
</div>
</StepperProvider>
);
};

export const Step = ({ children }) => {
return <>{children}</>;
};

Stepper.Step = Step;
Stepper.Buttons = Buttons;

Stepper.propTypes = {
/**
Expand Down Expand Up @@ -131,8 +138,4 @@ Stepper.defaultProps = {
orientation: "vertical",
};

Step.propTypes = {
children: PropTypes.node.isRequired,
};

export default Stepper;
export default Stepper;
73 changes: 73 additions & 0 deletions src/components/Stepper/js/Buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from "react";
import PropTypes from "prop-types";
import { useStepper } from "../StepperContext";

const Buttons = ({ children }) => {
const {
activeStep,
steps,
setActiveStep,
setErrors,
onFinish,
onChange,
onSkip,
stepValidator,
stepErrMessage,
setValidationAttempted,
} = useStepper();

const isLastStep = activeStep === steps.length - 1;

const goToNextStep = async () => {
setValidationAttempted(true);
const isNextStepAllowed = await stepValidator(steps[activeStep]?.props?.id);

if (isNextStepAllowed) {
if (activeStep < steps.length - 1) {
setActiveStep((prev) => prev + 1);
setErrors((prev) => ({ ...prev, [activeStep]: null }));
onChange(steps[activeStep]?.props?.id);
} else if (activeStep === steps.length - 1) {
onFinish();
}
setValidationAttempted(false);
} else {
setErrors((prev) => ({
...prev,
[activeStep]: stepErrMessage,
}));
}
};

const goToPreviousStep = () => {
if (activeStep > 0) {
setActiveStep((prev) => prev - 1);
setValidationAttempted(false);
onChange(steps[activeStep]?.props?.id);
}
};

const onSkipStep = () => {
onSkip(steps[activeStep]?.props?.id);
};

return (
<div className="stepper-buttons">
{children({
goToNextStep,
goToPreviousStep,
onSkipStep,
isLastStep,
activeStep,
stepId: steps[activeStep]?.props?.id || "",
})}
</div>
);
};

Buttons.displayName = "StepperButtons";
Buttons.propTypes = {
children: PropTypes.func.isRequired,
};

export default Buttons;
17 changes: 17 additions & 0 deletions src/components/Stepper/js/Step.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import PropTypes from "prop-types";

const Step = ({ children }) => {
return <>{children}</>;
};

Step.displayName = "StepperStep";

Step.propTypes = {
children: PropTypes.node.isRequired,
title: PropTypes.string,
description: PropTypes.string,
id: PropTypes.string,
};

export default Step;
Loading

0 comments on commit 81ffb53

Please sign in to comment.