Skip to content

Commit a981261

Browse files
Added Cutomisations and integrated step click handler
2 parents 3bda0ad + 5d63c1e commit a981261

14 files changed

Lines changed: 305 additions & 129 deletions

File tree

.eslintrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323
"@typescript-eslint/explicit-function-return-type": "error",
2424
"react/prop-types": "warn",
2525
"indent": ["error", 2],
26-
"arrow-body-style": ["error", "as-needed"]
26+
"arrow-body-style": ["error", "as-needed"],
27+
"no-trailing-spaces":"error",
28+
"comma-dangle":"error",
29+
"default-case":"error",
30+
"block-spacing": "error",
31+
"max-len":["warn", 150],
32+
"space-before-blocks":"error"
2733
},
2834
"settings": {
2935
"react": {

src/bubble/bubble.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React, { FC } from "react";
2+
import { IBubbleProps } from "./types";
3+
import whiteTick from '../assets/white-tick.svg';
4+
import { STEP_STATUSES } from '../constants';
5+
import styles from './styles';
6+
const Bubble: FC<IBubbleProps> = (props) => {
7+
const {
8+
step,
9+
enableStepClick,
10+
renderAdornment,
11+
index,
12+
currentActiveStepIndexVal,
13+
handleStepClick,
14+
getBubbleStyles,
15+
getActiveBubbleStyles,
16+
getInActiveBubbleStyles
17+
} = props;
18+
return (
19+
<div
20+
style={{...styles.eachBubble,
21+
...((getBubbleStyles && getBubbleStyles(step, index)) || {}),
22+
...((enableStepClick && styles.cursorPointer) || {}),
23+
...((index === currentActiveStepIndexVal) && styles.activeStepBubble || {}),
24+
...((index === currentActiveStepIndexVal && getActiveBubbleStyles && getActiveBubbleStyles(step, index)) || {}),
25+
...((step.status === STEP_STATUSES.UNVISITED && currentActiveStepIndexVal !== index) && styles.inactiveStepBubble || {}),
26+
...((step.status === STEP_STATUSES.UNVISITED && currentActiveStepIndexVal !== index
27+
&& getInActiveBubbleStyles && getInActiveBubbleStyles(step, index)) || {})
28+
}}
29+
onClick={(): void => handleStepClick(index)}
30+
role="presentation"
31+
>
32+
{(renderAdornment && renderAdornment(step, index))
33+
|| (
34+
<>
35+
{step?.status === STEP_STATUSES.COMPLETED && (
36+
<img
37+
src={whiteTick}
38+
style={styles.whiteTickImg}
39+
alt=""
40+
/>)
41+
|| index + 1}
42+
</>
43+
)}
44+
</div>
45+
);
46+
};
47+
48+
export default Bubble;

src/bubble/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Bubble from "./bubble";
2+
3+
export default Bubble;

src/bubble/styles.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const styles = {
2+
eachBubble: {
3+
borderRadius: '50%',
4+
height: '24px',
5+
width: '24px',
6+
background: '#312ec0',
7+
color: 'white',
8+
display: 'flex',
9+
alignItems: 'center',
10+
justifyContent: 'center',
11+
overflow: 'visible',
12+
fontWeight: '400',
13+
fontSize: '12px',
14+
lineHeight: '16px',
15+
border: '7px solid'
16+
},
17+
activeStepBubble: {
18+
border: '7px solid #CBCBEF'
19+
},
20+
inactiveStepBubble: {
21+
opacity: 0.4
22+
},
23+
cursorPointer: {
24+
cursor: 'pointer'
25+
},
26+
whiteTickImg: {
27+
objectFit: 'cover',
28+
width: '10px',
29+
height: '8px'
30+
}
31+
} as const;
32+
33+
export default styles;

src/bubble/types.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ReactElement } from "react";
2+
import { IStep } from "../stepper-component/types";
3+
4+
export interface IBubbleProps {
5+
step: IStep,
6+
enableStepClick: boolean,
7+
renderAdornment?(step: IStep, index: number): ReactElement,
8+
index: number,
9+
currentActiveStepIndexVal?: number,
10+
handleStepClick(index: number): void,
11+
getBubbleStyles?(step: IStep, index: number): object,
12+
getActiveBubbleStyles?(step: IStep, index: number): object,
13+
getInActiveBubbleStyles?(step: IStep, index: number): object,
14+
}

src/constants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export enum STEP_STATUSES {
2+
VISITED = 'visited',
3+
UNVISITED = 'unvisited',
4+
COMPLETED = 'completed'
5+
}
6+
7+
export enum LABEL_POSITION {
8+
LEFT = 'left',
9+
RIGHT = 'right'
10+
}

src/stepper-component/index.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/stepper-component/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Stepper from './stepperComponent';
2+
3+
export default Stepper;

src/stepper-component/stepperComponent.tsx

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,102 @@
1-
/* eslint-disable @typescript-eslint/no-var-requires */
2-
import React, { useState, useEffect } from 'react';
3-
import './styles.css';
4-
import { Istep, IstepperProps } from './types';
5-
import whiteTick from '../assets/white-tick.svg';
1+
import React, { useState, useEffect, ReactElement, FC } from 'react';
2+
import styles from './styles';
3+
import { IStep, IStepperProps } from './types';
4+
import Bubble from '../bubble';
5+
import { LABEL_POSITION } from '../constants';
66

7-
const Stepper = (props: IstepperProps): any => {
8-
const { steps, currentActiveStepIndex } = props;
7+
const Stepper: FC<IStepperProps> = (props) => {
8+
const {
9+
steps,
10+
currentActiveStepIndex,
11+
enableStepClick = false,
12+
onStepClick,
13+
renderAdornment,
14+
stylesOverride = {},
15+
labelPosition = LABEL_POSITION.RIGHT
16+
} = props;
917

10-
// const whiteTick = require('../assets/white-tick.svg') as string;
11-
const [stepsVal, setSteps] = useState<Istep[]>([]);
12-
const [currentActiveStepIndexVal, setCurrentActiveStepIndexVal] = useState<number>()
18+
const {
19+
getLabelDescriptionStyles,
20+
getLabelTitleStyles,
21+
getActiveLabelTitleStyles,
22+
getActiveLabelDescriptionStyles,
23+
getLineSeparatorStyles,
24+
getInactiveLineSeparatorStyles,
25+
getBubbleStyles,
26+
getActiveBubbleStyles,
27+
getInActiveBubbleStyles
28+
} = stylesOverride;
1329

14-
useEffect(() => {
15-
setSteps(steps);
16-
}, [steps]);
30+
const [currentActiveStepIndexVal, setCurrentActiveStepIndexVal] = useState<number>(0);
1731

1832
useEffect(() => {
19-
setCurrentActiveStepIndexVal(currentActiveStepIndex ?? 0);
33+
setCurrentActiveStepIndexVal((currentActiveStepIndex ?? 0) as number);
2034
}, [currentActiveStepIndex]);
2135

36+
const handleStepClick = (stepIndex: number): void => {
37+
if (enableStepClick) {
38+
if (onStepClick) onStepClick(stepIndex);
39+
else setCurrentActiveStepIndexVal(stepIndex);
40+
}
41+
}
42+
2243
return (
23-
<div className="stepperContainer">
24-
{stepsVal?.map((step: Istep, index: number) => (
25-
<div key={index} className="eachStep">
26-
<div className='bubbleLineWrapper'>
44+
<div style={styles.stepperContainer}>
45+
{steps?.map((step: IStep, index: number): ReactElement => (
46+
<div key={index} style={styles.eachStep}>
47+
<div style={styles.bubbleLineWrapper}>
48+
<Bubble
49+
step={step}
50+
index={index}
51+
enableStepClick={enableStepClick}
52+
currentActiveStepIndexVal= {currentActiveStepIndexVal}
53+
handleStepClick={handleStepClick}
54+
renderAdornment={renderAdornment}
55+
getBubbleStyles={getBubbleStyles}
56+
getActiveBubbleStyles={getActiveBubbleStyles}
57+
getInActiveBubbleStyles={getInActiveBubbleStyles}
58+
/>
2759
<div
28-
className={`eachBubble
29-
${index === currentActiveStepIndexVal && 'activeStepBubble'}
30-
${index > currentActiveStepIndexVal && 'inactiveStepBubble'}`}
60+
style={{
61+
...styles.labelContainer,
62+
...styles[`labelContainer__${labelPosition}`] ?? {}
63+
}}
3164
>
32-
{currentActiveStepIndexVal > index && (
33-
<img
34-
src={whiteTick}
35-
className="whiteTickImg"
36-
alt=""
37-
/>
38-
)
39-
|| index + 1}
40-
</div>
41-
<div className='eachLabel'>
42-
{step.label && (
43-
<span className='labelTitle'>
44-
{step?.label}
65+
{step?.label && (
66+
<span
67+
style={{...styles.labelTitle,
68+
...((enableStepClick && styles.cursorPointer) || {}),
69+
...((getLabelTitleStyles && getLabelTitleStyles(step, index)) || {}),
70+
...((index === currentActiveStepIndexVal && styles.activeLabelTitle) || {}),
71+
...((index === currentActiveStepIndexVal && getActiveLabelTitleStyles && getActiveLabelTitleStyles(step, index)) || {})
72+
}}
73+
onClick={(): void => handleStepClick(index)}
74+
role="presentation"
75+
>
76+
{step.label}
4577
</span>
4678
)}
4779
{step?.description && (
48-
<span className='labelDescription'>
49-
{step?.description}
80+
<span style={{...styles.labelDescription,
81+
...((enableStepClick && styles.cursorPointer) || {}),
82+
...((getLabelDescriptionStyles && getLabelDescriptionStyles(step, index)) || {}),
83+
...((index === currentActiveStepIndexVal) && styles.activeLabelDescription|| {}),
84+
...((index === currentActiveStepIndexVal && getActiveLabelDescriptionStyles && getActiveLabelDescriptionStyles(step, index)) || {})
85+
}}
86+
onClick={(): void => handleStepClick(index)}
87+
role="presentation"
88+
>
89+
{step.description}
5090
</span>
5191
)}
5292
</div>
53-
{index < stepsVal?.length - 1 && (
54-
<div className={`lineSeparator ${(index > currentActiveStepIndexVal - 1) && 'activeStepLineSeparator'}`} />
93+
{index < steps?.length - 1 && (
94+
<div style={{...styles.lineSeparator,
95+
...((getLineSeparatorStyles && getLineSeparatorStyles(step, index)) || {}),
96+
...((index > currentActiveStepIndexVal - 1) && styles.inactiveStepLineSeparator || {}),
97+
...((index > currentActiveStepIndexVal - 1
98+
&& getInactiveLineSeparatorStyles && getInactiveLineSeparatorStyles(step, index)) || {})
99+
}} />
55100
)}
56101
</div>
57102
</div>

src/stepper-component/styles.css

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)