@momo-kits/foundation 0.89.6 → 0.92.1-beta.16

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/Input/Input.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import React, {forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
+ Platform,
4
5
  TextInput,
5
6
  TextInputFocusEventData,
6
7
  TouchableOpacity,
@@ -13,6 +14,16 @@ import {InputProps} from './index';
13
14
  import {Icon} from '../Icon';
14
15
  import {checkTyping} from './utils';
15
16
  import {Loader} from '../Loader';
17
+ import {
18
+ formatComponentName,
19
+ getAccessibilityID,
20
+ cleanNameForTracking,
21
+ } from '../Application/utils';
22
+
23
+ const {
24
+ ScreenContext,
25
+ MiniAppContext,
26
+ } = require('react-native/Libraries/Components/ScreenContext');
16
27
 
17
28
  const Input = forwardRef(
18
29
  (
@@ -38,16 +49,21 @@ const Input = forwardRef(
38
49
  fontWeight = 'Regular',
39
50
  onPressIcon,
40
51
  secureTextEntry,
52
+ keyboardType,
41
53
  style,
54
+ params,
55
+ componentId,
42
56
  ...props
43
57
  }: InputProps,
44
58
  ref,
45
59
  ) => {
46
60
  const {theme} = useContext(ApplicationContext);
61
+ const {appId, code} = useContext<any>(MiniAppContext);
47
62
  const [focused, setFocused] = useState(false);
48
63
  const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
49
64
  const [secureTextInput, setSecureTextInput] = useState(secureTextEntry);
50
65
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
66
+ const screenInfo = useContext<any>(ScreenContext);
51
67
 
52
68
  const onClearText = () => {
53
69
  inputRef?.current?.clear();
@@ -106,6 +122,21 @@ const Input = forwardRef(
106
122
  let textColor = theme.colors.text.default;
107
123
  let placeholderColor = theme.colors.text.hint;
108
124
  let iconTintColor = iconColor;
125
+ const accessibilityID = disabled
126
+ ? getAccessibilityID(
127
+ `${appId}/${code}/${
128
+ screenInfo.screenName
129
+ }/input_${cleanNameForTracking(
130
+ floatingValue ?? placeholder,
131
+ )}_disabled`,
132
+ )
133
+ : getAccessibilityID(
134
+ `${appId}/${code}/${
135
+ screenInfo.screenName
136
+ }/input_${cleanNameForTracking(
137
+ floatingValue ?? placeholder ?? value,
138
+ )}`,
139
+ );
109
140
 
110
141
  if (disabled) {
111
142
  textColor = disabledColor;
@@ -113,6 +144,13 @@ const Input = forwardRef(
113
144
  iconTintColor = disabledColor;
114
145
  }
115
146
 
147
+ if (secureTextEntry) {
148
+ keyboardType = Platform.select({
149
+ ios: 'ascii-capable',
150
+ android: 'visible-password',
151
+ });
152
+ }
153
+
116
154
  return (
117
155
  <View
118
156
  style={[
@@ -140,7 +178,8 @@ const Input = forwardRef(
140
178
  )}
141
179
  <TextInput
142
180
  {...props}
143
- editable={!disabled}
181
+ {...accessibilityID}
182
+ editable={props.editable && !disabled}
144
183
  secureTextEntry={secure}
145
184
  textAlignVertical="center"
146
185
  ref={inputRef}
@@ -160,6 +199,7 @@ const Input = forwardRef(
160
199
  placeholder={placeholder}
161
200
  selectionColor={theme.colors.primary}
162
201
  placeholderTextColor={placeholderColor}
202
+ keyboardType={keyboardType}
163
203
  />
164
204
  </View>
165
205
  <View style={styles.iconView}>
@@ -180,11 +220,34 @@ const Input = forwardRef(
180
220
  );
181
221
  };
182
222
 
223
+ let inputState = 'active';
224
+
225
+ if (value && value?.length > 0) {
226
+ inputState = 'filled';
227
+ }
228
+ if (errorMessage && errorMessage?.length > 0) {
229
+ inputState = 'error';
230
+ }
231
+
232
+ if (disabled) {
233
+ inputState = 'disabled';
234
+ }
235
+
183
236
  return (
184
- <View style={[style, styles.wrapper]}>
185
- {renderInputView()}
186
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
187
- </View>
237
+ <ScreenContext.Provider
238
+ value={{
239
+ ...screenInfo,
240
+ componentName: 'Input',
241
+ params,
242
+ componentLabel: formatComponentName(floatingValue || ''),
243
+ state: inputState,
244
+ componentId,
245
+ }}>
246
+ <View style={[style, styles.wrapper]}>
247
+ {renderInputView()}
248
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
249
+ </View>
250
+ </ScreenContext.Provider>
188
251
  );
189
252
  },
190
253
  );
@@ -7,6 +7,16 @@ import {InputDropDownProps} from './index';
7
7
  import {Icon} from '../Icon';
8
8
  import {Loader} from '../Loader';
9
9
  import {Styles} from '../Consts';
10
+ import {
11
+ cleanNameForTracking,
12
+ formatComponentName,
13
+ getAccessibilityID,
14
+ } from '../Application/utils';
15
+
16
+ const {
17
+ ScreenContext,
18
+ MiniAppContext,
19
+ } = require('react-native/Libraries/Components/ScreenContext');
10
20
 
11
21
  const InputDropDown = ({
12
22
  value,
@@ -26,10 +36,14 @@ const InputDropDown = ({
26
36
  leadingIcon,
27
37
  leadingIconColor,
28
38
  style,
39
+ params,
40
+ componentId,
29
41
  ...props
30
42
  }: InputDropDownProps) => {
43
+ const {appId, code} = useContext<any>(MiniAppContext);
31
44
  const {theme} = useContext(ApplicationContext);
32
45
  const full = !!value || !!placeholder;
46
+ const screenInfo = useContext<any>(ScreenContext);
33
47
 
34
48
  const renderIcon = (color: string | undefined) => {
35
49
  if (loading) {
@@ -45,6 +59,19 @@ const InputDropDown = ({
45
59
  let textColor = theme.colors.text.default;
46
60
  let placeholderColor = theme.colors.text.hint;
47
61
  let iconTintColor = iconColor;
62
+ const accessibilityID = disabled
63
+ ? getAccessibilityID(
64
+ `${appId}/${code}/${
65
+ screenInfo.screenName
66
+ }/input_${cleanNameForTracking(
67
+ floatingValue ?? placeholder,
68
+ )}_disabled`,
69
+ )
70
+ : getAccessibilityID(
71
+ `${appId}/${code}/${
72
+ screenInfo.screenName
73
+ }/input_${cleanNameForTracking(floatingValue ?? placeholder)}`,
74
+ );
48
75
 
49
76
  if (disabled) {
50
77
  textColor = disabledColor;
@@ -80,9 +107,9 @@ const InputDropDown = ({
80
107
  {full && (
81
108
  <TextInput
82
109
  {...props}
110
+ {...accessibilityID}
83
111
  onPressIn={onPress}
84
112
  editable={false}
85
- textAlignVertical="top"
86
113
  style={[
87
114
  styles.input,
88
115
  {
@@ -104,10 +131,22 @@ const InputDropDown = ({
104
131
  };
105
132
 
106
133
  return (
107
- <TouchableOpacity onPress={onPress} style={[style, full && styles.wrapper]}>
108
- {renderInputView()}
109
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
110
- </TouchableOpacity>
134
+ <ScreenContext.Provider
135
+ value={{
136
+ ...screenInfo,
137
+ componentName: 'InputOTP',
138
+ params,
139
+ state: 'enabled',
140
+ componentLabel: formatComponentName(floatingValue || ''),
141
+ componentId,
142
+ }}>
143
+ <TouchableOpacity
144
+ onPress={onPress}
145
+ style={[style, full && styles.wrapper]}>
146
+ {renderInputView()}
147
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
148
+ </TouchableOpacity>
149
+ </ScreenContext.Provider>
111
150
  );
112
151
  };
113
152
 
@@ -18,6 +18,16 @@ import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
18
18
  import {InputMoneyProps} from './index';
19
19
  import {Icon} from '../Icon';
20
20
  import {formatMoneyToNumber, formatNumberToMoney} from './utils';
21
+ import {
22
+ cleanNameForTracking,
23
+ formatComponentName,
24
+ getAccessibilityID,
25
+ } from '../Application/utils';
26
+
27
+ const {
28
+ ScreenContext,
29
+ MiniAppContext,
30
+ } = require('react-native/Libraries/Components/ScreenContext');
21
31
 
22
32
  const InputMoney = forwardRef(
23
33
  (
@@ -36,14 +46,18 @@ const InputMoney = forwardRef(
36
46
  required = false,
37
47
  errorSpacing,
38
48
  style,
49
+ params,
39
50
  defaultValue = '',
51
+ componentId,
40
52
  ...props
41
53
  }: InputMoneyProps,
42
54
  ref,
43
55
  ) => {
44
56
  const {theme} = useContext(ApplicationContext);
57
+ const {appId, code} = useContext<any>(MiniAppContext);
45
58
  const [focused, setFocused] = useState(false);
46
59
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
60
+ const screenInfo = useContext<any>(ScreenContext);
47
61
 
48
62
  const validateText = (text: string) => {
49
63
  const valueFormat = formatMoneyToNumber(text, 'đ');
@@ -89,6 +103,17 @@ const InputMoney = forwardRef(
89
103
  let textColor = theme.colors.text.default;
90
104
  let placeholderColor = theme.colors.text.hint;
91
105
  let iconTintColor = iconColor;
106
+ const accessibilityID = disabled
107
+ ? getAccessibilityID(
108
+ `${appId}/${code}/${
109
+ screenInfo.screenName
110
+ }/input_${cleanNameForTracking(floatingValue)}_disabled`,
111
+ )
112
+ : getAccessibilityID(
113
+ `${appId}/${code}/${
114
+ screenInfo.screenName
115
+ }/input_${cleanNameForTracking(floatingValue)}`,
116
+ );
92
117
 
93
118
  if (disabled) {
94
119
  textColor = disabledColor;
@@ -114,8 +139,8 @@ const InputMoney = forwardRef(
114
139
  <View style={styles.inputView}>
115
140
  <TextInput
116
141
  {...props}
142
+ {...accessibilityID}
117
143
  editable={!disabled}
118
- textAlignVertical="top"
119
144
  ref={inputRef}
120
145
  keyboardType={'number-pad'}
121
146
  style={[
@@ -151,11 +176,34 @@ const InputMoney = forwardRef(
151
176
  );
152
177
  };
153
178
 
179
+ let inputState = 'active';
180
+
181
+ if (value && value?.length > 0) {
182
+ inputState = 'filled';
183
+ }
184
+ if (errorMessage && errorMessage?.length > 0) {
185
+ inputState = 'error';
186
+ }
187
+
188
+ if (disabled) {
189
+ inputState = 'disabled';
190
+ }
191
+
154
192
  return (
155
- <View style={[style, styles.wrapper]}>
156
- {renderInputView()}
157
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
158
- </View>
193
+ <ScreenContext.Provider
194
+ value={{
195
+ ...screenInfo,
196
+ componentName: 'InputMoney',
197
+ params,
198
+ componentLabel: formatComponentName(floatingValue || ''),
199
+ state: inputState,
200
+ componentId,
201
+ }}>
202
+ <View style={[style, styles.wrapper]}>
203
+ {renderInputView()}
204
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
205
+ </View>
206
+ </ScreenContext.Provider>
159
207
  );
160
208
  },
161
209
  );
@@ -21,6 +21,16 @@ import styles from './styles';
21
21
  import {ErrorView, getBorderColor} from './common';
22
22
  import {ApplicationContext} from '../Application';
23
23
  import {Spacing} from '../Consts';
24
+ import {
25
+ cleanNameForTracking,
26
+ formatComponentName,
27
+ getAccessibilityID,
28
+ } from '../Application/utils';
29
+
30
+ const {
31
+ ScreenContext,
32
+ MiniAppContext,
33
+ } = require('react-native/Libraries/Components/ScreenContext');
24
34
 
25
35
  const OTPCaret: FC<CaretProps> = ({index, length}) => {
26
36
  const DURATION = 300;
@@ -78,16 +88,21 @@ const InputOTP = forwardRef(
78
88
  onFocus,
79
89
  onBlur,
80
90
  dataType = 'number',
91
+ params,
81
92
  style,
93
+ componentId,
82
94
  ...props
83
95
  }: InputOTPProps,
84
96
  ref,
85
97
  ) => {
86
98
  const MAX_LENGTH = 10;
99
+ const {appId, code} = useContext<any>(MiniAppContext);
100
+
87
101
  const [value, setValue] = useState('');
88
102
  const [focused, setFocused] = useState(false);
89
103
  const inputRef = useRef<TextInput>(null);
90
104
  const {theme} = useContext(ApplicationContext);
105
+ const screenInfo = useContext<any>(ScreenContext);
91
106
 
92
107
  useImperativeHandle(ref, () => ({
93
108
  onChangeText: (text: string) => {
@@ -180,6 +195,12 @@ const InputOTP = forwardRef(
180
195
  );
181
196
  };
182
197
 
198
+ const accessibilityID = getAccessibilityID(
199
+ `${appId}/${code}/${screenInfo.screenName}/input_${cleanNameForTracking(
200
+ floatingValue,
201
+ )}`,
202
+ );
203
+
183
204
  const renderInputView = () => {
184
205
  return (
185
206
  <View
@@ -205,6 +226,7 @@ const InputOTP = forwardRef(
205
226
  <View style={styles.inputView}>
206
227
  <TextInput
207
228
  {...props}
229
+ {...accessibilityID}
208
230
  ref={inputRef}
209
231
  value={value}
210
232
  onChangeText={_onChangeText}
@@ -221,13 +243,23 @@ const InputOTP = forwardRef(
221
243
  };
222
244
 
223
245
  return (
224
- <TouchableOpacity
225
- activeOpacity={1}
226
- onPress={onFocusInput}
227
- style={[style, styles.otpWrapper]}>
228
- {renderInputView()}
229
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
230
- </TouchableOpacity>
246
+ <ScreenContext.Provider
247
+ value={{
248
+ ...screenInfo,
249
+ componentName: 'InputOTP',
250
+ params,
251
+ componentLabel: formatComponentName(floatingValue || ''),
252
+ state: 'enabled',
253
+ componentId,
254
+ }}>
255
+ <TouchableOpacity
256
+ activeOpacity={1}
257
+ onPress={onFocusInput}
258
+ style={[style, styles.otpWrapper]}>
259
+ {renderInputView()}
260
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
261
+ </TouchableOpacity>
262
+ </ScreenContext.Provider>
231
263
  );
232
264
  },
233
265
  );
@@ -12,6 +12,12 @@ import styles from './styles';
12
12
  import {Icon} from '../Icon';
13
13
  import {Text} from '../Text';
14
14
  import {checkTyping} from './utils';
15
+ import {getAccessibilityID} from '../Application/utils';
16
+
17
+ const {
18
+ ScreenContext,
19
+ MiniAppContext,
20
+ } = require('react-native/Libraries/Components/ScreenContext');
15
21
 
16
22
  const InputSearch = forwardRef(
17
23
  (
@@ -28,15 +34,19 @@ const InputSearch = forwardRef(
28
34
  style,
29
35
  defaultValue,
30
36
  onPressButtonText,
31
- hasColorBG = true,
37
+ params,
38
+ componentId,
39
+ hasColorBG = false,
32
40
  ...props
33
41
  }: InputSearchProps,
34
42
  ref,
35
43
  ) => {
36
44
  const {theme} = useContext(ApplicationContext);
45
+ const {appId, code} = useContext<any>(MiniAppContext);
37
46
  const [focused, setFocused] = useState(false);
38
47
  const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
39
48
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
49
+ const screenInfo = useContext<any>(ScreenContext);
40
50
 
41
51
  const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
42
52
  setFocused(true);
@@ -62,6 +72,9 @@ const InputSearch = forwardRef(
62
72
  return (
63
73
  <TextInput
64
74
  {...props}
75
+ {...getAccessibilityID(
76
+ `${appId}/${code}/${screenInfo.screenName}/input_search`,
77
+ )}
65
78
  textAlignVertical="center"
66
79
  ref={inputRef}
67
80
  style={[
@@ -117,33 +130,56 @@ const InputSearch = forwardRef(
117
130
  );
118
131
  };
119
132
 
120
- const backgroundColor = hasColorBG ? theme.colors.background.default : theme.colors.background.surface
133
+ let inputState = 'empty';
134
+
135
+ if (focused) {
136
+ inputState = 'focus';
137
+ }
138
+
139
+ if (value && value?.length > 0) {
140
+ inputState = 'filled';
141
+ }
142
+
143
+ const backgroundColor = hasColorBG
144
+ ? theme.colors.background.default
145
+ : theme.colors.background.surface;
121
146
 
122
147
  return (
123
- <View style={[style, styles.searchInputContainer]}>
124
- <View
125
- style={[
126
- styles.searchInputWrapper,
127
- {
128
- backgroundColor,
129
- }
130
- ]}>
131
- <Icon
132
- source={'navigation_search'}
133
- size={24}
134
- color={theme.colors.text.hint}
135
- />
136
- {renderInputView()}
137
- {renderIconView()}
148
+ <ScreenContext.Provider
149
+ value={{
150
+ ...screenInfo,
151
+ componentName: 'InputSearch',
152
+ params,
153
+ state: inputState,
154
+ componentId,
155
+ }}>
156
+ <View style={[style, styles.searchInputContainer]}>
157
+ <View
158
+ style={[
159
+ styles.searchInputWrapper,
160
+ {
161
+ backgroundColor,
162
+ },
163
+ ]}>
164
+ <Icon
165
+ source={'navigation_search'}
166
+ size={24}
167
+ color={theme.colors.text.hint}
168
+ />
169
+ {renderInputView()}
170
+ {renderIconView()}
171
+ </View>
172
+ {showButtonText && (
173
+ <TouchableOpacity onPress={onPressButtonText}>
174
+ <Text
175
+ typography={'action_default_bold'}
176
+ style={styles.textButton}>
177
+ {buttonText}
178
+ </Text>
179
+ </TouchableOpacity>
180
+ )}
138
181
  </View>
139
- {showButtonText && (
140
- <TouchableOpacity onPress={onPressButtonText}>
141
- <Text typography={'action_default_bold'} style={styles.textButton}>
142
- {buttonText}
143
- </Text>
144
- </TouchableOpacity>
145
- )}
146
- </View>
182
+ </ScreenContext.Provider>
147
183
  );
148
184
  },
149
185
  );
@@ -18,6 +18,12 @@ import {
18
18
  import {InputTextAreaProps} from './index';
19
19
  import {Icon} from '../Icon';
20
20
  import {ApplicationContext} from '../Application';
21
+ import {cleanNameForTracking, getAccessibilityID} from '../Application/utils';
22
+
23
+ const {
24
+ ScreenContext,
25
+ MiniAppContext,
26
+ } = require('react-native/Libraries/Components/ScreenContext');
21
27
 
22
28
  const InputTextArea = forwardRef(
23
29
  (
@@ -43,6 +49,8 @@ const InputTextArea = forwardRef(
43
49
  ref,
44
50
  ) => {
45
51
  const {theme} = useContext(ApplicationContext);
52
+ const screenInfo = useContext<any>(ScreenContext);
53
+ const {appId, code} = useContext<any>(MiniAppContext);
46
54
  const [focused, setFocused] = useState(false);
47
55
  const [inputValue, setInputValue] = useState(defaultValue ?? '');
48
56
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
@@ -88,6 +96,20 @@ const InputTextArea = forwardRef(
88
96
  placeholderColor = disabledColor;
89
97
  }
90
98
 
99
+ const accessibilityID = disabled
100
+ ? getAccessibilityID(
101
+ `${appId}/${code}/${
102
+ screenInfo.screenName
103
+ }/input_${cleanNameForTracking(
104
+ floatingValue ?? placeholder,
105
+ )}_disabled`,
106
+ )
107
+ : getAccessibilityID(
108
+ `${appId}/${code}/${
109
+ screenInfo.screenName
110
+ }/input_${cleanNameForTracking(floatingValue ?? placeholder)}`,
111
+ );
112
+
91
113
  return (
92
114
  <View
93
115
  style={[
@@ -109,6 +131,7 @@ const InputTextArea = forwardRef(
109
131
  <View style={styles.textAreaView}>
110
132
  <TextInput
111
133
  {...props}
134
+ {...accessibilityID}
112
135
  ref={inputRef}
113
136
  editable={!disabled}
114
137
  textAlignVertical="top"
package/Input/index.tsx CHANGED
@@ -80,6 +80,9 @@ export interface InputProps extends TextInputProps {
80
80
  fontWeight?: 'Regular' | 'Bold';
81
81
 
82
82
  onPressIcon?: () => void;
83
+
84
+ params?: any;
85
+ componentId?: string;
83
86
  }
84
87
 
85
88
  type InputPropsWithoutSizeAndIcon = Omit<
@@ -121,7 +124,14 @@ export interface InputSearchProps extends TextInputProps {
121
124
  */
122
125
  icon?: string;
123
126
 
124
- hasColorBG?: boolean
127
+ /**
128
+ *
129
+ */
130
+ hasColorBG?: boolean;
131
+
132
+ params?: any;
133
+
134
+ componentId?: string;
125
135
  }
126
136
 
127
137
  export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
@@ -141,6 +151,8 @@ export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
141
151
  * 'number' - The OTP input will be treated as a number.
142
152
  */
143
153
  dataType?: 'string' | 'number';
154
+
155
+ floatingValue: string;
144
156
  }
145
157
 
146
158
  export type CaretProps = {
@@ -245,7 +257,22 @@ export interface InputDropDownProps {
245
257
  */
246
258
  leadingIconColor?: string;
247
259
 
248
- style: ViewStyle | ViewStyle[];
260
+ /**
261
+ * Optional. params for element tracking.
262
+ */
263
+ params?: {
264
+ [key: string]: any;
265
+ };
266
+
267
+ /**
268
+ * component id for element tracking.
269
+ */
270
+ componentId?: string;
271
+
272
+ /**
273
+ * Optional. Represents the style of the InputDropDown component.
274
+ */
275
+ style?: ViewStyle | ViewStyle[];
249
276
  }
250
277
 
251
278
  export {Input, InputTextArea, InputSearch, InputMoney, InputOTP, InputDropDown};