dhre-ui-kit 0.0.76 → 0.0.77

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.77",
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};
@@ -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};
@@ -22,20 +22,19 @@ interface CommonTextInputProps {
22
22
  editable?: boolean;
23
23
  }
24
24
 
25
- const CommonTextInput: React.FC<CommonTextInputProps> = ({
26
- label,
27
- value,
28
- onChangeText,
29
- isSecureTextEntry = false,
30
- keyboardType = 'default',
31
- placeholderText,
32
- activeBorderColor = theme.CONTENT_PRIMARY['light'],
33
- inactiveBorderColor = theme.BORDER_PRIMARY['light'],
34
- inputStyle,
35
- maxLength,
36
- errorMessage,
37
- editable = true,
38
- }) => {
25
+ const CommonTextInput: React.FC<CommonTextInputProps> = props => {
26
+ const {
27
+ value,
28
+ isSecureTextEntry = false,
29
+ keyboardType = 'default',
30
+ placeholderText,
31
+ activeBorderColor = theme.CONTENT_PRIMARY['light'],
32
+ inactiveBorderColor = theme.BORDER_PRIMARY['light'],
33
+ inputStyle,
34
+ maxLength,
35
+ errorMessage,
36
+ editable = true,
37
+ } = props;
39
38
  return (
40
39
  <>
41
40
  <TextInput
@@ -44,9 +43,7 @@ const CommonTextInput: React.FC<CommonTextInputProps> = ({
44
43
  ...styles.outlineStyle,
45
44
  borderColor: value?.length ? activeBorderColor : inactiveBorderColor,
46
45
  }}
47
- label={label}
48
46
  value={value}
49
- onChangeText={onChangeText}
50
47
  secureTextEntry={isSecureTextEntry}
51
48
  keyboardType={keyboardType}
52
49
  theme={{colors: {primary: DHRE_COLORS_TEXT.DH_BLACK}}}
@@ -54,6 +51,7 @@ const CommonTextInput: React.FC<CommonTextInputProps> = ({
54
51
  maxLength={maxLength}
55
52
  placeholder={placeholderText}
56
53
  editable={editable}
54
+ {...props}
57
55
  />
58
56
  {errorMessage ? (
59
57
  <CustomTypography
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