react-native-progress-steps
Version:
A simple and fully customizable React Native component that implements a progress stepper UI.
136 lines (135 loc) • 5.32 kB
JavaScript
import React, { useEffect, useRef } from 'react';
import { View, Text, StyleSheet, Dimensions, Animated } from 'react-native';
import { Check } from 'lucide-react-native';
const CIRCLE_SIZE = 40;
const MOBILE_BREAKPOINT = 768;
const MOBILE_LINE_POSITION = 78;
const DESKTOP_LINE_POSITION = 58;
const StepIcon = ({ borderWidth = 2, activeStepIconBorderColor = '#2D2D2D', progressBarColor = '#EBEBE4', completedProgressBarColor = '#2D2D2D', activeStepIconColor = 'transparent', completedStepIconColor = '#2D2D2D', disabledStepIconColor = '#EBEBE4', labelColor = '#D3D3D3', labelFontSize = 14, activeLabelColor = '#2D2D2D', completedLabelColor = '#2D2D2D', activeStepNumColor = '#2D2D2D', completedStepNumColor = '#2D2D2D', disabledStepNumColor = '#FFFFFF', completedCheckColor = '#FFFFFF', ...props }) => {
const { isActiveStep, isCompletedStep, isFirstStep, isLastStep, stepNum, label, labelFontFamily, activeLabelFontSize, } = props;
const lineAnimationValue = useRef(new Animated.Value(0)).current;
useEffect(() => {
if (isCompletedStep || isActiveStep) {
Animated.spring(lineAnimationValue, {
toValue: 1,
useNativeDriver: false,
tension: 25,
friction: 25,
}).start();
}
else {
lineAnimationValue.setValue(0);
}
}, [isCompletedStep, isActiveStep]);
const getLinePosition = () => {
const screenWidth = Dimensions.get('window').width;
const isMobileWidth = screenWidth <= MOBILE_BREAKPOINT;
return isMobileWidth ? MOBILE_LINE_POSITION : DESKTOP_LINE_POSITION;
};
const getLineColor = (isLeftLine) => {
if (isLeftLine && (isCompletedStep || isActiveStep)) {
return completedProgressBarColor;
}
if (!isLeftLine && isCompletedStep) {
return completedProgressBarColor;
}
return progressBarColor;
};
const getStepColor = () => {
if (isActiveStep)
return activeStepIconColor;
if (isCompletedStep)
return completedStepIconColor;
return disabledStepIconColor;
};
const getLabelColor = () => {
if (isActiveStep)
return activeLabelColor;
if (isCompletedStep)
return completedLabelColor;
return labelColor;
};
const getNumberColor = () => {
if (isActiveStep)
return activeStepNumColor;
if (isCompletedStep)
return completedStepNumColor;
return disabledStepNumColor;
};
const linePosition = getLinePosition();
const renderLine = (isLeft) => (React.createElement(View, { style: [
styles.line,
{
position: 'absolute',
...(isLeft ? { left: 0, right: `${linePosition}%` } : { left: `${linePosition}%`, right: 0 }),
height: borderWidth,
backgroundColor: progressBarColor,
},
] },
React.createElement(Animated.View, { style: {
position: 'absolute',
left: 0,
right: 0,
height: '100%',
backgroundColor: getLineColor(isLeft),
width: lineAnimationValue.interpolate({
inputRange: [0, 1],
outputRange: ['0%', '100%'],
}),
} })));
return (React.createElement(View, { style: styles.container },
React.createElement(View, { style: styles.lineContainer },
!isFirstStep && renderLine(true),
React.createElement(View, { style: [
styles.circle,
{
width: CIRCLE_SIZE,
height: CIRCLE_SIZE,
borderRadius: CIRCLE_SIZE / 2,
backgroundColor: getStepColor(),
...(isActiveStep && {
borderColor: activeStepIconBorderColor,
borderWidth: 3,
}),
},
] }, isCompletedStep ? (React.createElement(Check, { size: 18, color: completedCheckColor })) : (React.createElement(Text, { style: [styles.stepText, { color: getNumberColor() }] }, stepNum))),
!isLastStep && renderLine(false)),
React.createElement(Text, { style: [
styles.label,
{
color: getLabelColor(),
fontSize: isActiveStep ? activeLabelFontSize || labelFontSize : labelFontSize,
fontFamily: labelFontFamily,
},
], numberOfLines: 2 }, label)));
};
const styles = StyleSheet.create({
container: {
alignItems: 'center',
},
lineContainer: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
},
circle: {
justifyContent: 'center',
alignItems: 'center',
zIndex: 2,
},
line: {
zIndex: 1,
},
stepText: {
fontSize: 16,
fontWeight: '500',
},
label: {
textAlign: 'center',
marginTop: 8,
maxWidth: '80%',
},
});
export default StepIcon;