dhre-ui-kit 0.0.76 → 0.0.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dhre-ui-kit",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
4
4
  "main": "src/index.ts",
5
5
  "files": [
6
6
  "src",
@@ -0,0 +1,166 @@
1
+ import React, {useEffect, useState, useRef} from 'react';
2
+ import {
3
+ View,
4
+ TextInput,
5
+ Pressable,
6
+ NativeSyntheticEvent,
7
+ TextInputKeyPressEventData,
8
+ } from 'react-native';
9
+ import {FontStyle} from '../../utils/appEnum';
10
+ import {styles} from './styles';
11
+ import {IProps, OTPInputHandle} from './otp.interface';
12
+ import CustomTypography from '../customTypography';
13
+ import {useTheme} from '../../theme/ThemeContext';
14
+ import {withThemeProvider} from '../../theme/withThemeProvider';
15
+
16
+ const OTPInput = React.forwardRef<OTPInputHandle, IProps>(
17
+ (
18
+ {
19
+ length = 4,
20
+ onComplete,
21
+ resendOTP,
22
+ errorMessage,
23
+ testId = '',
24
+ otpContainerStyle,
25
+ },
26
+ ref,
27
+ ) => {
28
+ const [otp, setOTP] = useState('');
29
+ const [isResendOtpEnable, setIsResendOtpEnable] = useState(false);
30
+ const [activeInput, setActiveInput] = useState<number | null>(null);
31
+ const {theme} = useTheme();
32
+ const refs = useRef<(TextInput | null)[]>([]);
33
+ refs.current = Array(length)
34
+ .fill(0)
35
+ .map((_, index) => refs.current[index] || null);
36
+
37
+ useEffect(() => {
38
+ enableResendOtp();
39
+ }, []);
40
+
41
+ const onClickResendOTP = () => {
42
+ setIsResendOtpEnable(false);
43
+ enableResendOtp();
44
+ resendOTP?.();
45
+ };
46
+
47
+ const enableResendOtp = () => {
48
+ setTimeout(() => {
49
+ setIsResendOtpEnable(true);
50
+ }, 5000);
51
+ };
52
+
53
+ React.useImperativeHandle(ref, () => ({
54
+ reset() {
55
+ setOTP('');
56
+ },
57
+ }));
58
+
59
+ const handleChange = (index: number, value: string) => {
60
+ const regex = /^\d+$/;
61
+ if (
62
+ value.length === 1 &&
63
+ regex.test(value) &&
64
+ index >= 0 &&
65
+ index < length
66
+ ) {
67
+ const newOTP = `${otp}${value}`;
68
+ setOTP(newOTP);
69
+ refs.current[index + 1]?.focus();
70
+ } else if (value.length === 0 && index > 0) {
71
+ const newOTP = otp.slice(0, -1);
72
+ setOTP(newOTP);
73
+ refs.current[index - 1]?.focus();
74
+ } else {
75
+ const newOTP = otp.slice(0, -1);
76
+ setOTP(newOTP);
77
+ refs.current[index]?.focus();
78
+ }
79
+ };
80
+
81
+ const handleKeyPress = (
82
+ e: NativeSyntheticEvent<TextInputKeyPressEventData>,
83
+ index: number,
84
+ ) => {
85
+ if (e.nativeEvent.key === 'Backspace' && index > 0) {
86
+ refs.current[index - 1]?.focus();
87
+ }
88
+ };
89
+
90
+ useEffect(() => {
91
+ if (otp.length === length) {
92
+ onComplete?.(otp);
93
+ }
94
+ }, [otp]);
95
+
96
+ return (
97
+ <View style={{...otpContainerStyle}} data-testid={testId}>
98
+ <CustomTypography
99
+ text={'OTP'}
100
+ variant={FontStyle.B4_REGULAR}
101
+ style={{
102
+ color: otp?.length ? theme.CONTENT_PRIMARY : theme.CONTENT_SECONDRY,
103
+ textAlign: 'left',
104
+ }}
105
+ />
106
+ <View style={{...styles.textInputContainer}}>
107
+ {Array.from({length}).map((_, index) => (
108
+ <TextInput
109
+ key={index?.toString()}
110
+ style={{
111
+ ...styles.textInputStyle,
112
+ color: theme.CONTENT_PRIMARY,
113
+ borderColor: errorMessage
114
+ ? theme.ERROR
115
+ : otp.length === length
116
+ ? theme.SUCCESS
117
+ : activeInput === index
118
+ ? theme.BORDER_INVERTED
119
+ : theme.BORDER_PRIMARY,
120
+ }}
121
+ onFocus={() => setActiveInput(index)}
122
+ onBlur={() => setActiveInput(null)}
123
+ onKeyPress={e => handleKeyPress(e, index)}
124
+ onChangeText={text => handleChange(index, text)}
125
+ value={otp[index] ? '●' : ''}
126
+ placeholder=""
127
+ keyboardType="numeric"
128
+ ref={el => (refs.current[index] = el)}
129
+ returnKeyType={otp.length === length ? 'done' : 'next'}
130
+ selectionColor={theme.CONTENT_PRIMARY}
131
+ />
132
+ ))}
133
+ </View>
134
+
135
+ <View style={styles.resendOtpContainer}>
136
+ {errorMessage ? (
137
+ <CustomTypography
138
+ text={errorMessage}
139
+ variant={FontStyle.L2_REGULAR}
140
+ style={{
141
+ color: theme.ERROR,
142
+ }}
143
+ />
144
+ ) : (
145
+ <View />
146
+ )}
147
+ <Pressable onPress={onClickResendOTP} disabled={!isResendOtpEnable}>
148
+ <CustomTypography
149
+ text={'Resend OTP'}
150
+ variant={FontStyle.L2_REGULAR}
151
+ style={{
152
+ textDecorationLine: 'underline',
153
+ color: isResendOtpEnable
154
+ ? theme.CONTENT_PRIMARY
155
+ : theme.CONTENT_DISABLE,
156
+ }}
157
+ />
158
+ </Pressable>
159
+ </View>
160
+ </View>
161
+ );
162
+ },
163
+ );
164
+
165
+ export default withThemeProvider(OTPInput);
166
+ OTPInput.displayName = 'OTPInput';
@@ -0,0 +1,14 @@
1
+ import {ViewStyle} from 'react-native';
2
+
3
+ export interface IProps {
4
+ length?: number;
5
+ onComplete?: (otp?: string) => void;
6
+ errorMessage?: string;
7
+ testId?: string;
8
+ otpContainerStyle?: ViewStyle;
9
+ resendOTP?: () => void;
10
+ }
11
+
12
+ export type OTPInputHandle = {
13
+ reset: () => void;
14
+ };
@@ -0,0 +1,29 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {verticalScale, moderateScale} from '../../utils/stylehelper';
3
+
4
+ const styles = StyleSheet.create({
5
+ textInputContainer: {
6
+ flexDirection: 'row',
7
+ justifyContent: 'space-between',
8
+ marginTop: verticalScale(8),
9
+ },
10
+ textInputStyle: {
11
+ height: verticalScale(48),
12
+ width: moderateScale(72),
13
+ borderRadius: moderateScale(8),
14
+ borderWidth: 1,
15
+ textAlign: 'center',
16
+ fontSize: moderateScale(12),
17
+ },
18
+ resendOtpContainer: {
19
+ flexDirection: 'row',
20
+ alignItems: 'center',
21
+ justifyContent: 'space-between',
22
+ marginTop: verticalScale(12),
23
+ },
24
+ resendOtpTextEnable: {
25
+ textDecorationLine: 'underline',
26
+ },
27
+ });
28
+
29
+ export {styles};
@@ -1,8 +1,8 @@
1
- import commonStyles from '../../utils/commonStyles';
2
1
  import React, {useEffect} from 'react';
3
- import {View} from 'react-native';
2
+ import {StyleSheet, View} from 'react-native';
4
3
  import * as Progress from 'react-native-progress';
5
4
  import {ShapeType} from '../../utils/appEnum';
5
+ import CustomText from '../customText';
6
6
 
7
7
  interface CustomProgressBarProps {
8
8
  value: number; // Current progress value (0 to 100)
@@ -19,6 +19,7 @@ interface CustomProgressBarProps {
19
19
  setProgress: React.Dispatch<React.SetStateAction<number>>;
20
20
  increment?: number; // Optional increment value for progress update
21
21
  interval?: number; // Optional interval time (ms) for progress update
22
+ percentageText?: string;
22
23
  }
23
24
 
24
25
  const CustomProgressBar: React.FC<CustomProgressBarProps> = ({
@@ -36,6 +37,7 @@ const CustomProgressBar: React.FC<CustomProgressBarProps> = ({
36
37
  setProgress,
37
38
  increment = 1, // Default increment to 1
38
39
  interval = 100, // Default interval to 100ms
40
+ percentageText
39
41
  }) => {
40
42
  useEffect(() => {
41
43
  const progressInterval = setInterval(() => {
@@ -49,6 +51,23 @@ const CustomProgressBar: React.FC<CustomProgressBarProps> = ({
49
51
  return () => clearInterval(progressInterval);
50
52
  }, [progress, value, increment, interval]);
51
53
 
54
+ const showPercentage = () => {
55
+ return (
56
+ <View style={styles.flexDirection}>
57
+ <CustomText
58
+ text={`${value}%`}
59
+ variant="B1_REGULAR"
60
+ textColor="CONTENT_PRIMARY"
61
+ />
62
+ {percentageText ?
63
+ <CustomText
64
+ text={percentageText}
65
+ variant="L3_REGULAR"
66
+ textColor="CONTENT_PRIMARY"
67
+ />: null}
68
+ </View>
69
+ );
70
+ };
52
71
  const renderProgressBar = () => {
53
72
  switch (type) {
54
73
  case ShapeType.LINE:
@@ -74,7 +93,7 @@ const CustomProgressBar: React.FC<CustomProgressBarProps> = ({
74
93
  unfilledColor={unfilledColor}
75
94
  borderWidth={borderWidth}
76
95
  showsText={true}
77
- formatText={() => `${value}%`}
96
+ formatText={showPercentage}
78
97
  testID="custom-progress-bar-circle"
79
98
  />
80
99
  );
@@ -83,11 +102,15 @@ const CustomProgressBar: React.FC<CustomProgressBarProps> = ({
83
102
  }
84
103
  };
85
104
 
86
- return (
87
- <View style={commonStyles.centeredContainer} testID="custom-progress-bar">
88
- {renderProgressBar()}
89
- </View>
90
- );
105
+ return <View testID="custom-progress-bar">{renderProgressBar()}</View>;
91
106
  };
92
107
 
108
+ const styles = StyleSheet.create({
109
+ flexDirection: {
110
+ flexDirection: 'column',
111
+ justifyContent:'center',
112
+ alignItems:'center'
113
+ },
114
+ });
115
+
93
116
  export default CustomProgressBar;
@@ -0,0 +1,96 @@
1
+ import {View} from 'react-native';
2
+ import React from 'react';
3
+ import {CircleTick} from '../../assets';
4
+ import {styles} from './styles';
5
+ import {IData, IProps, Status} from './stepper.interface';
6
+ import {DHRE_COLORS_TEXT} from 'src/theme/colors';
7
+ import {FontStyle} from 'src/utils/appEnum';
8
+ import CustomTypography from '../customTypography';
9
+
10
+ const Stepper = ({
11
+ containerStyle,
12
+ showStepCount = false,
13
+ showStatus = false,
14
+ data,
15
+ }: IProps) => {
16
+ const renderCircleStyle = (status?: string) => {
17
+ if (status === Status.Active) {
18
+ return styles.activeStepCircle;
19
+ } else if (status === Status.Inactive) {
20
+ return styles.inactiveStepCircle;
21
+ } else if (status === Status.Completed) {
22
+ return styles.completeStepCircle;
23
+ } else {
24
+ return styles.stepCountCircle;
25
+ }
26
+ };
27
+ const renderLableStyle = (status?: string) => {
28
+ if (status === Status.Active) {
29
+ return styles.activeStepLabel;
30
+ } else if (status === Status.Inactive) {
31
+ return styles.inactiveStepLabel;
32
+ } else if (status === Status.Completed) {
33
+ return styles.completeStepLabel;
34
+ } else {
35
+ return styles.countStepLabel;
36
+ }
37
+ };
38
+
39
+ const renderDividerStyle = (status?: string) => {
40
+ if (status === Status.Active) {
41
+ return styles.activeStepDivider;
42
+ } else if (status === Status.Inactive) {
43
+ return styles.inactiveStepDivider;
44
+ } else if (status === Status.Completed) {
45
+ return styles.completeStepDivider;
46
+ } else {
47
+ return styles.countStepDivider;
48
+ }
49
+ };
50
+
51
+ return (
52
+ <View style={{...styles.stepperContainer, ...containerStyle}}>
53
+ {data?.map((item: IData, index) => {
54
+ const stepCircleStyle = renderCircleStyle(item?.status);
55
+ const dividerStyle = renderDividerStyle(item?.status);
56
+ const labelStyle = renderLableStyle(item?.status);
57
+ const lastViewStyle =
58
+ index === data?.length - 1 ? styles.lastStepWrapper : null;
59
+ return (
60
+ <View
61
+ key={index?.toString()}
62
+ style={{...styles.stepperWrapper, ...lastViewStyle}}>
63
+ <View style={styles.stepperSeparatorContainer}>
64
+ <View style={{...stepCircleStyle}}>
65
+ {showStepCount && (
66
+ <CustomTypography
67
+ text={item?.step}
68
+ variant={FontStyle.L2_REGULAR}
69
+ style={{
70
+ color: DHRE_COLORS_TEXT.DH_WHITE,
71
+ }}
72
+ />
73
+ )}
74
+ {showStatus && item?.status === Status.Completed && (
75
+ <CircleTick />
76
+ )}
77
+ </View>
78
+ {index != data?.length - 1 && (
79
+ <View style={{...styles.separator, ...dividerStyle}} />
80
+ )}
81
+ </View>
82
+ <View style={styles.lableContainer}>
83
+ <CustomTypography
84
+ text={item?.label}
85
+ variant={FontStyle.L3_REGULAR}
86
+ style={labelStyle}
87
+ />
88
+ </View>
89
+ </View>
90
+ );
91
+ })}
92
+ </View>
93
+ );
94
+ };
95
+
96
+ export default Stepper;
@@ -0,0 +1,24 @@
1
+ import {ViewStyle} from 'react-native';
2
+
3
+ type StatusType = 'Active' | 'Inactive' | 'Completed' | 'Rejected' | 'Count';
4
+
5
+ export enum Status {
6
+ Active = 'Active',
7
+ Inactive = 'Inactive',
8
+ Completed = 'Completed',
9
+ Rejected = 'Rejected',
10
+ Count = 'Count',
11
+ }
12
+
13
+ export interface IData {
14
+ step: string;
15
+ label?: string;
16
+ status?: StatusType;
17
+ }
18
+
19
+ export interface IProps {
20
+ containerStyle?: ViewStyle;
21
+ showStepCount?: boolean;
22
+ showStatus?: boolean;
23
+ data: IData[];
24
+ }
@@ -0,0 +1,93 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {DHRE_COLORS_TEXT} from '../../theme/colors';
3
+
4
+ const styles = StyleSheet.create({
5
+ stepperContainer: {
6
+ flexDirection: 'row',
7
+ marginBottom: 24,
8
+ justifyContent: 'space-between',
9
+ },
10
+ stepperWrapper: {
11
+ flex: 1,
12
+ marginRight: 10,
13
+ overflow: 'hidden',
14
+ },
15
+ lastStepWrapper: {flex: 0.5},
16
+ stepperSeparatorContainer: {
17
+ flexDirection: 'row',
18
+ alignItems: 'center',
19
+ },
20
+ activeStepCircle: {
21
+ height: 24,
22
+ width: 24,
23
+ borderRadius: 12,
24
+ alignItems: 'center',
25
+ borderWidth: 2,
26
+ borderColor: '#000000',
27
+ justifyContent: 'center',
28
+ },
29
+ activeStepLabel: {
30
+ color: DHRE_COLORS_TEXT.DH_BLACK,
31
+ marginTop: 11,
32
+ },
33
+ activeStepDivider: {
34
+ borderColor: '#686868',
35
+ },
36
+ inactiveStepCircle: {
37
+ height: 24,
38
+ width: 24,
39
+ borderRadius: 12,
40
+ alignItems: 'center',
41
+ borderWidth: 2,
42
+ borderColor: '#A7A7A7',
43
+ justifyContent: 'center',
44
+ },
45
+ inactiveStepLabel: {
46
+ color: '#686868',
47
+ marginTop: 11,
48
+ },
49
+ inactiveStepDivider: {
50
+ borderColor: '#686868',
51
+ },
52
+ completeStepCircle: {
53
+ height: 24,
54
+ width: 24,
55
+ backgroundColor: '#00B578',
56
+ borderRadius: 12,
57
+ alignItems: 'center',
58
+ justifyContent: 'center',
59
+ },
60
+ completeStepLabel: {
61
+ color: DHRE_COLORS_TEXT.DH_BLACK,
62
+ marginTop: 11,
63
+ },
64
+ completeStepDivider: {
65
+ borderColor: DHRE_COLORS_TEXT.DH_BLACK,
66
+ borderStyle: 'solid',
67
+ },
68
+ stepCountCircle: {
69
+ height: 24,
70
+ width: 24,
71
+ borderRadius: 12,
72
+ alignItems: 'center',
73
+ borderWidth: 1,
74
+ borderColor: '#A7A7A7',
75
+ justifyContent: 'center',
76
+ },
77
+ countStepLabel: {
78
+ color: DHRE_COLORS_TEXT.DH_WHITE,
79
+ marginTop: 11,
80
+ },
81
+ countStepDivider: {
82
+ borderColor: '#686868',
83
+ },
84
+ separator: {
85
+ borderWidth: 1,
86
+ borderStyle: 'dashed',
87
+ width: '100%',
88
+ marginLeft: 10,
89
+ },
90
+ lableContainer: {width: 60},
91
+ });
92
+
93
+ export {styles};
package/src/index.ts CHANGED
@@ -40,6 +40,8 @@ export {default as CustomSwitchBtn} from './components/customSwitchBtn';
40
40
  export {default as toastService} from './components/toast/ToastService';
41
41
  export {default as SingleSelectionTags} from './components/singleSelectionTag';
42
42
  export {default as CustomDocumentPicker} from './components/customDocumentPicker';
43
+ export {default as OTP} from './components/otp';
44
+ export {default as Stepper} from './components/stepper';
43
45
  export {FONT_STYLES} from './theme/fonts';
44
46
  export {FontStyle, Theme} from './utils/appEnum';
45
47