@momo-kits/foundation 0.77.8-beta.4 → 0.77.8-beta.5

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.
@@ -1,12 +1,6 @@
1
- import React, {
2
- useCallback,
3
- useContext,
4
- useEffect,
5
- useMemo,
6
- useRef,
7
- useState,
8
- } from 'react';
1
+ import React, {useContext, useEffect, useRef} from 'react';
9
2
  import {
3
+ Dimensions,
10
4
  KeyboardAvoidingView,
11
5
  Platform,
12
6
  Pressable,
@@ -91,10 +85,11 @@ const Modal: React.FC<ModalParams> = props => {
91
85
 
92
86
  const BottomSheet: React.FC<BottomSheetParams> = props => {
93
87
  const {theme, navigator} = useContext(ApplicationContext);
88
+ const {height} = Dimensions.get('window');
94
89
  const {
95
90
  screen,
96
91
  options,
97
- useSnap = true,
92
+ snapPoints = [height * 0.5, height * 0.9],
98
93
  }: BottomSheetParams = props.route.params;
99
94
  const Component = useRef(screen).current;
100
95
  const navigation = new Navigation(props.navigation, theme);
@@ -105,31 +100,9 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
105
100
 
106
101
  delete params.screen;
107
102
 
108
- const [contentHeight, setContentHeight] = useState(undefined);
109
- const snapPoints = useMemo(() => {
110
- if (useSnap) {
111
- return ['50%', '90%'];
112
- }
113
- return [contentHeight ?? '50%'];
114
- }, [contentHeight]);
115
-
116
103
  const bottomSheetRef = useRef<any>(null);
117
104
  const mountedRef = useRef(true);
118
105
 
119
- let handleOnLayout;
120
- if (useSnap) {
121
- handleOnLayout = useCallback(
122
- ({
123
- nativeEvent: {
124
- layout: {height},
125
- },
126
- }) => {
127
- setContentHeight(height);
128
- },
129
- [],
130
- );
131
- }
132
-
133
106
  let backgroundColor = theme.colors.background.default;
134
107
  if (options?.surface) {
135
108
  backgroundColor = theme.colors.background.surface;
@@ -154,7 +127,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
154
127
  <SafeAreaView style={Styles.flex}>
155
128
  <BottomSheetModal
156
129
  ref={bottomSheetRef}
157
- snapPoints={snapPoints}
130
+ snapPoints={snapPoints?.map(item => item + 68)}
158
131
  onDismiss={() => {
159
132
  if (mountedRef.current) {
160
133
  navigator?.pop();
@@ -162,7 +135,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
162
135
  }}
163
136
  handleComponent={null}
164
137
  backdropComponent={backdropComponent}>
165
- <View onLayout={handleOnLayout} accessibilityLabel={'BottomSheet'}>
138
+ <View accessibilityLabel={'BottomSheet'}>
166
139
  <View style={[styles.sheetContainer, {backgroundColor}]}>
167
140
  <View style={styles.indicatorContainer}>
168
141
  <View
@@ -108,7 +108,7 @@ export interface ModalParams extends ScreenParams {
108
108
  export interface BottomSheetParams extends ScreenParams {
109
109
  [key: string]: any;
110
110
  onDismiss?: () => void;
111
- useSnap?: boolean;
111
+ snapPoints?: ReadonlyArray<number>;
112
112
  }
113
113
 
114
114
  export type NavigationButtonProps = {
package/Button/index.tsx CHANGED
@@ -11,6 +11,7 @@ import {Typography} from '../Text/types';
11
11
  import {Colors} from '../Consts';
12
12
  import styles from './styles';
13
13
  import {Icon} from '../Icon';
14
+ import {Loader} from '../Loader';
14
15
 
15
16
  export interface ButtonProps extends TouchableOpacityProps {
16
17
  /**
@@ -55,6 +56,11 @@ export interface ButtonProps extends TouchableOpacityProps {
55
56
  */
56
57
  useTintColor?: boolean;
57
58
 
59
+ /**
60
+ * If true, the icon of button will use be show indicator loading.
61
+ */
62
+ loading?: boolean;
63
+
58
64
  /**
59
65
  * A callback function that is called when the button is pressed.
60
66
  */
@@ -68,6 +74,7 @@ const Button: FC<ButtonProps> = ({
68
74
  full = true,
69
75
  iconRight,
70
76
  iconLeft,
77
+ loading = false,
71
78
  title = 'Button',
72
79
  onPress,
73
80
  ...rest
@@ -223,6 +230,19 @@ const Button: FC<ButtonProps> = ({
223
230
  const renderTrailing = () => {
224
231
  const marginLeft = getIconSpace();
225
232
  const color = useTintColor ? getTextColor() : undefined;
233
+ if (loading) {
234
+ const iconSize = getIconSize();
235
+ const color = getTextColor();
236
+ return (
237
+ <View
238
+ style={[
239
+ styles.trailing,
240
+ {width: iconSize, height: iconSize, marginLeft},
241
+ ]}>
242
+ <Loader type="spinner" color={color} />
243
+ </View>
244
+ );
245
+ }
226
246
  if (iconRight) {
227
247
  const iconSize = getIconSize();
228
248
  return (
package/Input/Input.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext, useRef, useState} from 'react';
1
+ import React, {FC, forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
4
  TextInput,
@@ -12,125 +12,144 @@ import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
12
12
  import {InputProps} from './index';
13
13
  import {Icon} from '../Icon';
14
14
  import {checkTyping} from './utils';
15
+ import {Loader} from '../Loader';
15
16
 
16
- const Input: FC<InputProps> = ({
17
- value,
18
- onChangeText,
19
- floatingValue,
20
- floatingIcon,
21
- size,
22
- placeholder,
23
- onBlur,
24
- onFocus,
25
- errorMessage,
26
- icon,
27
- disabled,
28
- floatingIconColor,
29
- iconColor,
30
- required,
31
- errorSpacing,
32
- ...props
33
- }) => {
34
- const {theme} = useContext(ApplicationContext);
35
- const [focused, setFocused] = useState(false);
36
- const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
17
+ const Input: FC<InputProps> = forwardRef(
18
+ (
19
+ {
20
+ value,
21
+ onChangeText,
22
+ floatingValue,
23
+ floatingIcon,
24
+ size,
25
+ placeholder,
26
+ onBlur,
27
+ onFocus,
28
+ errorMessage,
29
+ icon,
30
+ disabled,
31
+ floatingIconColor,
32
+ iconColor,
33
+ required,
34
+ errorSpacing,
35
+ loading,
36
+ ...props
37
+ },
38
+ ref,
39
+ ) => {
40
+ const {theme} = useContext(ApplicationContext);
41
+ const [focused, setFocused] = useState(false);
42
+ const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
43
+ const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
37
44
 
38
- const inputRef = useRef<any>(null);
45
+ const onClearText = () => {
46
+ inputRef?.current?.clear();
47
+ _onChangeText('');
48
+ };
39
49
 
40
- const onClearText = () => {
41
- inputRef?.current?.clear();
42
- _onChangeText('');
43
- };
50
+ const _onChangeText = (text: string) => {
51
+ checkTyping(text, haveValue, setHaveValue);
52
+ onChangeText?.(text);
53
+ };
44
54
 
45
- const _onChangeText = (text: string) => {
46
- checkTyping(text, haveValue, setHaveValue);
47
- onChangeText?.(text);
48
- };
55
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
56
+ setFocused(true);
57
+ onFocus?.(e);
58
+ };
49
59
 
50
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
51
- setFocused(true);
52
- onFocus?.(e);
53
- };
60
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
61
+ setFocused(false);
62
+ onBlur?.(e);
63
+ };
54
64
 
55
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
56
- setFocused(false);
57
- onBlur?.(e);
58
- };
65
+ const renderIcon = (color: string | undefined) => {
66
+ if (loading) {
67
+ return <Loader type={'spinner'} color={color} />;
68
+ }
69
+ if (icon) {
70
+ return <Icon color={color} source={icon} size={24} />;
71
+ }
72
+ };
59
73
 
60
- const renderInputView = () => {
61
- const disabledColor = theme.colors.text.disable;
62
- let textColor = theme.colors.text.default;
63
- let placeholderColor = theme.colors.text.hint;
64
- let iconTintColor = iconColor;
74
+ const renderInputView = () => {
75
+ const disabledColor = theme.colors.text.disable;
76
+ let textColor = theme.colors.text.default;
77
+ let placeholderColor = theme.colors.text.hint;
78
+ let iconTintColor = iconColor;
65
79
 
66
- if (disabled) {
67
- textColor = disabledColor;
68
- placeholderColor = disabledColor;
69
- iconTintColor = disabledColor;
70
- }
80
+ if (disabled) {
81
+ textColor = disabledColor;
82
+ placeholderColor = disabledColor;
83
+ iconTintColor = disabledColor;
84
+ }
71
85
 
72
- return (
73
- <View
74
- style={[
75
- styles.inputWrapper,
76
- {backgroundColor: theme.colors.background.surface},
77
- getSizeStyle(size),
78
- getBorderColor(theme, focused, errorMessage, disabled),
79
- ]}>
80
- <FloatingView
81
- floatingValue={floatingValue}
82
- floatingIconColor={floatingIconColor}
83
- disabled={disabled}
84
- required={required}
85
- floatingIcon={floatingIcon}
86
- />
87
- <View style={styles.inputView}>
88
- <TextInput
89
- {...props}
90
- accessibilityLabel={`TextInput`}
91
- editable={!disabled}
92
- textAlignVertical="top"
93
- ref={inputRef}
94
- style={[
95
- styles.input,
96
- {
97
- color: textColor,
98
- fontFamily: `${theme.font}-Regular`,
99
- },
100
- ]}
101
- textBreakStrategy="highQuality"
102
- value={value}
103
- onChangeText={_onChangeText}
104
- onFocus={_onFocus}
105
- onBlur={_onBlur}
106
- placeholder={placeholder}
107
- selectionColor={theme.colors.primary}
108
- placeholderTextColor={placeholderColor}
86
+ return (
87
+ <View
88
+ style={[
89
+ styles.inputWrapper,
90
+ {backgroundColor: theme.colors.background.surface},
91
+ getSizeStyle(size),
92
+ getBorderColor(theme, focused, errorMessage, disabled),
93
+ ]}>
94
+ <FloatingView
95
+ floatingValue={floatingValue}
96
+ floatingIconColor={floatingIconColor}
97
+ disabled={disabled}
98
+ required={required}
99
+ floatingIcon={floatingIcon}
109
100
  />
101
+ <View style={styles.inputView}>
102
+ <TextInput
103
+ {...props}
104
+ accessibilityLabel={`TextInput`}
105
+ editable={!disabled}
106
+ textAlignVertical="top"
107
+ ref={inputRef}
108
+ style={[
109
+ styles.input,
110
+ {
111
+ color: textColor,
112
+ fontFamily: `${theme.font}-Regular`,
113
+ },
114
+ ]}
115
+ textBreakStrategy="highQuality"
116
+ value={value}
117
+ onChangeText={_onChangeText}
118
+ onFocus={_onFocus}
119
+ onBlur={_onBlur}
120
+ placeholder={placeholder}
121
+ selectionColor={theme.colors.primary}
122
+ placeholderTextColor={placeholderColor}
123
+ />
124
+ </View>
125
+ <View style={styles.iconView}>
126
+ {focused && haveValue && (
127
+ <TouchableOpacity
128
+ style={styles.iconWrapper}
129
+ onPress={onClearText}>
130
+ <Icon
131
+ source="24_navigation_close_circle_full"
132
+ size={16}
133
+ color={theme.colors.text.hint}
134
+ />
135
+ </TouchableOpacity>
136
+ )}
137
+ {renderIcon(iconTintColor)}
138
+ </View>
110
139
  </View>
111
- <View style={styles.iconView}>
112
- {focused && haveValue && (
113
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
114
- <Icon
115
- source="24_navigation_close_circle_full"
116
- size={16}
117
- color={theme.colors.text.hint}
118
- />
119
- </TouchableOpacity>
120
- )}
121
- {!!icon && <Icon color={iconTintColor} source={icon} size={24} />}
122
- </View>
140
+ );
141
+ };
142
+
143
+ return (
144
+ <View
145
+ style={styles.wrapper}
146
+ accessibilityLabel={`Input/${floatingValue}`}>
147
+ {renderInputView()}
148
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
123
149
  </View>
124
150
  );
125
- };
126
-
127
- return (
128
- <View style={styles.wrapper} accessibilityLabel={`Input/${floatingValue}`}>
129
- {renderInputView()}
130
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
131
- </View>
132
- );
133
- };
151
+ },
152
+ );
134
153
 
135
154
  Input.defaultProps = {
136
155
  size: 'small',
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext, useRef, useState} from 'react';
1
+ import React, {FC, forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
4
  TextInput,
@@ -13,124 +13,131 @@ import {InputMoneyProps} from './index';
13
13
  import {Icon} from '../Icon';
14
14
  import {formatMoneyToNumber, formatNumberToMoney} from './utils';
15
15
 
16
- const InputMoney: FC<InputMoneyProps> = ({
17
- onChangeText,
18
- floatingValue,
19
- floatingIcon,
20
- size = 'small',
21
- onBlur,
22
- onFocus,
23
- errorMessage,
24
- icon,
25
- disabled,
26
- floatingIconColor,
27
- iconColor,
28
- required,
29
- errorSpacing,
30
- ...props
31
- }) => {
32
- const {theme} = useContext(ApplicationContext);
33
- const [focused, setFocused] = useState(false);
34
- const inputRef = useRef<any>(null);
35
- const [value, setValue] = useState('');
36
- const onClearText = () => {
37
- inputRef?.current?.clear();
38
- setValue('');
39
- onChangeText?.('');
40
- };
41
- const _onChangeText = (text: string) => {
42
- if (text.length < value.length && value.indexOf(text) === 0) {
43
- text = value.slice(0, -2) + 'đ';
44
- }
45
- const valueFormat = formatMoneyToNumber(text, 'đ');
46
- setValue(formatNumberToMoney(valueFormat, 'đ'));
47
- onChangeText?.(formatMoneyToNumber(text, 'đ').toString());
48
- };
16
+ const InputMoney: FC<InputMoneyProps> = forwardRef(
17
+ (
18
+ {
19
+ onChangeText,
20
+ floatingValue,
21
+ floatingIcon,
22
+ size = 'small',
23
+ onBlur,
24
+ onFocus,
25
+ errorMessage,
26
+ icon,
27
+ disabled,
28
+ floatingIconColor,
29
+ iconColor,
30
+ required,
31
+ errorSpacing,
32
+ ...props
33
+ },
34
+ ref,
35
+ ) => {
36
+ const {theme} = useContext(ApplicationContext);
37
+ const [focused, setFocused] = useState(false);
38
+ const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
39
+ const [value, setValue] = useState('');
40
+ const onClearText = () => {
41
+ inputRef?.current?.clear();
42
+ setValue('');
43
+ onChangeText?.('');
44
+ };
45
+ const _onChangeText = (text: string) => {
46
+ if (text.length < value.length && value.indexOf(text) === 0) {
47
+ text = value.slice(0, -2) + 'đ';
48
+ }
49
+ const valueFormat = formatMoneyToNumber(text, 'đ');
50
+ setValue(formatNumberToMoney(valueFormat, 'đ'));
51
+ onChangeText?.(formatMoneyToNumber(text, 'đ').toString());
52
+ };
49
53
 
50
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
51
- setFocused(true);
52
- onFocus?.(e);
53
- };
54
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
55
+ setFocused(true);
56
+ onFocus?.(e);
57
+ };
54
58
 
55
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
56
- setFocused(false);
57
- onBlur?.(e);
58
- };
59
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
60
+ setFocused(false);
61
+ onBlur?.(e);
62
+ };
59
63
 
60
- const renderInputView = () => {
61
- const disabledColor = theme.colors.text.disable;
62
- let textColor = theme.colors.text.default;
63
- let placeholderColor = theme.colors.text.hint;
64
- let iconTintColor = iconColor;
64
+ const renderInputView = () => {
65
+ const disabledColor = theme.colors.text.disable;
66
+ let textColor = theme.colors.text.default;
67
+ let placeholderColor = theme.colors.text.hint;
68
+ let iconTintColor = iconColor;
65
69
 
66
- if (disabled) {
67
- textColor = disabledColor;
68
- placeholderColor = disabledColor;
69
- iconTintColor = disabledColor;
70
- }
70
+ if (disabled) {
71
+ textColor = disabledColor;
72
+ placeholderColor = disabledColor;
73
+ iconTintColor = disabledColor;
74
+ }
71
75
 
72
- return (
73
- <View
74
- style={[
75
- styles.inputWrapper,
76
- {backgroundColor: theme.colors.background.surface},
77
- getSizeStyle(size),
78
- getBorderColor(theme, focused, errorMessage, disabled),
79
- ]}>
80
- <FloatingView
81
- floatingValue={floatingValue}
82
- floatingIconColor={floatingIconColor}
83
- disabled={disabled}
84
- required={required}
85
- floatingIcon={floatingIcon}
86
- />
87
- <View style={styles.inputView}>
88
- <TextInput
89
- {...props}
90
- accessibilityLabel={`TextInput`}
91
- editable={!disabled}
92
- textAlignVertical="top"
93
- ref={inputRef}
94
- keyboardType={'number-pad'}
95
- style={[
96
- styles.moneyInput,
97
- {
98
- color: textColor,
99
- },
100
- ]}
101
- value={value}
102
- onChangeText={_onChangeText}
103
- onFocus={_onFocus}
104
- onBlur={_onBlur}
105
- selectionColor={theme.colors.primary}
106
- placeholderTextColor={placeholderColor}
107
- placeholder={'0đ'}
76
+ return (
77
+ <View
78
+ style={[
79
+ styles.inputWrapper,
80
+ {backgroundColor: theme.colors.background.surface},
81
+ getSizeStyle(size),
82
+ getBorderColor(theme, focused, errorMessage, disabled),
83
+ ]}>
84
+ <FloatingView
85
+ floatingValue={floatingValue}
86
+ floatingIconColor={floatingIconColor}
87
+ disabled={disabled}
88
+ required={required}
89
+ floatingIcon={floatingIcon}
108
90
  />
91
+ <View style={styles.inputView}>
92
+ <TextInput
93
+ {...props}
94
+ accessibilityLabel={`TextInput`}
95
+ editable={!disabled}
96
+ textAlignVertical="top"
97
+ ref={inputRef}
98
+ keyboardType={'number-pad'}
99
+ style={[
100
+ styles.moneyInput,
101
+ {
102
+ color: textColor,
103
+ },
104
+ ]}
105
+ value={value}
106
+ onChangeText={_onChangeText}
107
+ onFocus={_onFocus}
108
+ onBlur={_onBlur}
109
+ selectionColor={theme.colors.primary}
110
+ placeholderTextColor={placeholderColor}
111
+ placeholder={'0đ'}
112
+ />
113
+ </View>
114
+ <View style={styles.iconView}>
115
+ {focused && (
116
+ <TouchableOpacity
117
+ style={styles.iconWrapper}
118
+ onPress={onClearText}>
119
+ <Icon
120
+ source="24_navigation_close_circle_full"
121
+ size={16}
122
+ color={theme.colors.text.hint}
123
+ />
124
+ </TouchableOpacity>
125
+ )}
126
+ {!!icon && <Icon color={iconTintColor} source={icon} />}
127
+ </View>
109
128
  </View>
110
- <View style={styles.iconView}>
111
- {focused && (
112
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
113
- <Icon
114
- source="24_navigation_close_circle_full"
115
- size={16}
116
- color={theme.colors.text.hint}
117
- />
118
- </TouchableOpacity>
119
- )}
120
- {!!icon && <Icon color={iconTintColor} source={icon} />}
121
- </View>
129
+ );
130
+ };
131
+
132
+ return (
133
+ <View
134
+ style={styles.wrapper}
135
+ accessibilityLabel={`InputMoney/${floatingValue}`}>
136
+ {renderInputView()}
137
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
122
138
  </View>
123
139
  );
124
- };
125
-
126
- return (
127
- <View
128
- style={styles.wrapper}
129
- accessibilityLabel={`InputMoney/${floatingValue}`}>
130
- {renderInputView()}
131
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
132
- </View>
133
- );
134
- };
140
+ },
141
+ );
135
142
 
136
143
  export default InputMoney;
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext, useRef, useState} from 'react';
1
+ import React, {FC, forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
4
  TextInput,
@@ -13,141 +13,146 @@ import {Icon} from '../Icon';
13
13
  import {Text} from '../Text';
14
14
  import {checkTyping} from './utils';
15
15
 
16
- const InputSearch: FC<InputSearchProps> = ({
17
- placeholder,
18
- onFocus,
19
- onBlur,
20
- iconColor,
21
- value,
22
- onChangeText,
23
- icon,
24
- buttonText = 'Hủy',
25
- showButtonText = true,
26
- showBorder = true,
27
- style,
28
- defaultValue,
29
- onPressButtonText,
30
- ...props
31
- }) => {
32
- const {theme} = useContext(ApplicationContext);
33
- const [focused, setFocused] = useState(false);
34
- const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
35
- const inputRef = useRef<any>(null);
36
- let iconTintColor = iconColor;
16
+ const InputSearch: FC<InputSearchProps> = forwardRef(
17
+ (
18
+ {
19
+ placeholder,
20
+ onFocus,
21
+ onBlur,
22
+ iconColor,
23
+ value,
24
+ onChangeText,
25
+ icon,
26
+ buttonText = 'Hủy',
27
+ showButtonText = true,
28
+ showBorder = true,
29
+ style,
30
+ defaultValue,
31
+ onPressButtonText,
32
+ ...props
33
+ },
34
+ ref,
35
+ ) => {
36
+ const {theme} = useContext(ApplicationContext);
37
+ const [focused, setFocused] = useState(false);
38
+ const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
39
+ const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
40
+ let iconTintColor = iconColor;
37
41
 
38
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
39
- setFocused(true);
40
- onFocus?.(e);
41
- };
42
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
43
+ setFocused(true);
44
+ onFocus?.(e);
45
+ };
42
46
 
43
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
44
- setFocused(false);
45
- onBlur?.(e);
46
- };
47
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
48
+ setFocused(false);
49
+ onBlur?.(e);
50
+ };
47
51
 
48
- const onClearText = () => {
49
- inputRef?.current?.clear();
50
- _onChangeText('');
51
- };
52
+ const onClearText = () => {
53
+ inputRef?.current?.clear();
54
+ _onChangeText('');
55
+ };
52
56
 
53
- const _onChangeText = (text: string) => {
54
- checkTyping(text, haveValue, setHaveValue);
55
- onChangeText?.(text);
56
- };
57
+ const _onChangeText = (text: string) => {
58
+ checkTyping(text, haveValue, setHaveValue);
59
+ onChangeText?.(text);
60
+ };
57
61
 
58
- const renderInputView = () => {
59
- let textColor = theme.colors.text.default;
60
- let placeholderColor = theme.colors.text.hint;
62
+ const renderInputView = () => {
63
+ let textColor = theme.colors.text.default;
64
+ let placeholderColor = theme.colors.text.hint;
61
65
 
62
- return (
63
- <TextInput
64
- {...props}
65
- accessibilityLabel={`TextInput`}
66
- textAlignVertical="top"
67
- ref={inputRef}
68
- style={[
69
- styles.searchInput,
70
- {
71
- color: textColor,
72
- },
73
- ]}
74
- value={value}
75
- onChangeText={_onChangeText}
76
- onFocus={_onFocus}
77
- onBlur={_onBlur}
78
- placeholder={placeholder}
79
- selectionColor={theme.colors.primary}
80
- placeholderTextColor={placeholderColor}
81
- />
82
- );
83
- };
66
+ return (
67
+ <TextInput
68
+ {...props}
69
+ accessibilityLabel={`TextInput`}
70
+ textAlignVertical="top"
71
+ ref={inputRef}
72
+ style={[
73
+ styles.searchInput,
74
+ {
75
+ color: textColor,
76
+ },
77
+ ]}
78
+ value={value}
79
+ onChangeText={_onChangeText}
80
+ onFocus={_onFocus}
81
+ onBlur={_onBlur}
82
+ placeholder={placeholder}
83
+ selectionColor={theme.colors.primary}
84
+ placeholderTextColor={placeholderColor}
85
+ />
86
+ );
87
+ };
84
88
 
85
- const renderIconView = () => {
89
+ const renderIconView = () => {
90
+ return (
91
+ <View
92
+ style={{
93
+ flexDirection: 'row',
94
+ }}>
95
+ {focused && haveValue && (
96
+ <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
97
+ <Icon
98
+ source="24_navigation_close_circle_full"
99
+ size={16}
100
+ color={theme.colors.text.hint}
101
+ />
102
+ </TouchableOpacity>
103
+ )}
104
+ {!!icon && (
105
+ <View style={{flexDirection: 'row'}}>
106
+ <View
107
+ style={[
108
+ styles.divider,
109
+ {
110
+ backgroundColor: theme.colors.primary,
111
+ },
112
+ ]}
113
+ />
114
+ <Icon
115
+ color={iconTintColor}
116
+ source={icon}
117
+ style={styles.iconSearchInput}
118
+ />
119
+ </View>
120
+ )}
121
+ </View>
122
+ );
123
+ };
86
124
  return (
87
125
  <View
88
- style={{
89
- flexDirection: 'row',
90
- }}>
91
- {focused && haveValue && (
92
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
93
- <Icon
94
- source="24_navigation_close_circle_full"
95
- size={16}
96
- color={theme.colors.text.hint}
97
- />
126
+ style={[style, styles.searchInputContainer]}
127
+ accessibilityLabel={`InputSearch/${placeholder}`}>
128
+ <View
129
+ style={[
130
+ styles.searchInputWrapper,
131
+ {
132
+ backgroundColor: theme.colors.background.surface,
133
+ borderColor: theme.colors.background.surface,
134
+ },
135
+ showBorder && {borderColor: theme.colors.border.default},
136
+ focused && {borderColor: theme.colors.primary},
137
+ ]}>
138
+ <Icon
139
+ source={'navigation_search'}
140
+ size={24}
141
+ color={theme.colors.text.hint}
142
+ />
143
+ {renderInputView()}
144
+ {renderIconView()}
145
+ </View>
146
+ {showButtonText && (
147
+ <TouchableOpacity onPress={onPressButtonText}>
148
+ <Text typography={'action_default'} style={styles.textButton}>
149
+ {buttonText}
150
+ </Text>
98
151
  </TouchableOpacity>
99
152
  )}
100
- {!!icon && (
101
- <View style={{flexDirection: 'row'}}>
102
- <View
103
- style={[
104
- styles.divider,
105
- {
106
- backgroundColor: theme.colors.primary,
107
- },
108
- ]}
109
- />
110
- <Icon
111
- color={iconTintColor}
112
- source={icon}
113
- style={styles.iconSearchInput}
114
- />
115
- </View>
116
- )}
117
153
  </View>
118
154
  );
119
- };
120
- return (
121
- <View
122
- style={[style, styles.searchInputContainer]}
123
- accessibilityLabel={`InputSearch/${placeholder}`}>
124
- <View
125
- style={[
126
- styles.searchInputWrapper,
127
- {
128
- backgroundColor: theme.colors.background.surface,
129
- borderColor: theme.colors.background.surface,
130
- },
131
- showBorder && {borderColor: theme.colors.border.default},
132
- focused && {borderColor: theme.colors.primary},
133
- ]}>
134
- <Icon
135
- source={'navigation_search'}
136
- size={24}
137
- color={theme.colors.text.hint}
138
- />
139
- {renderInputView()}
140
- {renderIconView()}
141
- </View>
142
- {showButtonText && (
143
- <TouchableOpacity onPress={onPressButtonText}>
144
- <Text typography={'action_default'} style={styles.textButton}>
145
- {buttonText}
146
- </Text>
147
- </TouchableOpacity>
148
- )}
149
- </View>
150
- );
151
- };
155
+ },
156
+ );
152
157
 
153
158
  export default InputSearch;
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext, useRef, useState} from 'react';
1
+ import React, {FC, forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
4
  TextInput,
@@ -19,135 +19,142 @@ import {InputTextAreaProps} from './index';
19
19
  import {Icon} from '../Icon';
20
20
  import {ApplicationContext} from '../Application';
21
21
 
22
- const InputTextArea: FC<InputTextAreaProps> = ({
23
- errorMessage,
24
- onChangeText,
25
- floatingIconColor,
26
- floatingIcon,
27
- floatingValue,
28
- onFocus,
29
- onBlur,
30
- disabled,
31
- value,
32
- defaultValue,
33
- height,
34
- placeholder,
35
- maxLength,
36
- required,
37
- errorSpacing,
38
- ...props
39
- }) => {
40
- const {theme} = useContext(ApplicationContext);
41
- const [focused, setFocused] = useState(false);
42
- const [inputValue, setInputValue] = useState(defaultValue ?? '');
43
- const inputRef = useRef<any>(null);
22
+ const InputTextArea: FC<InputTextAreaProps> = forwardRef(
23
+ (
24
+ {
25
+ errorMessage,
26
+ onChangeText,
27
+ floatingIconColor,
28
+ floatingIcon,
29
+ floatingValue,
30
+ onFocus,
31
+ onBlur,
32
+ disabled,
33
+ value,
34
+ defaultValue,
35
+ height,
36
+ placeholder,
37
+ maxLength,
38
+ required,
39
+ errorSpacing,
40
+ ...props
41
+ },
42
+ ref,
43
+ ) => {
44
+ const {theme} = useContext(ApplicationContext);
45
+ const [focused, setFocused] = useState(false);
46
+ const [inputValue, setInputValue] = useState(defaultValue ?? '');
47
+ const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
44
48
 
45
- const onClearText = () => {
46
- inputRef?.current?.clear();
47
- _onChangeText('');
48
- };
49
+ const onClearText = () => {
50
+ inputRef?.current?.clear();
51
+ _onChangeText('');
52
+ };
49
53
 
50
- const _onChangeText = (text: string) => {
51
- onChangeText?.(text);
52
- setInputValue(text);
53
- };
54
+ const _onChangeText = (text: string) => {
55
+ onChangeText?.(text);
56
+ setInputValue(text);
57
+ };
54
58
 
55
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
56
- setFocused(true);
57
- onFocus?.(e);
58
- };
59
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
60
+ setFocused(true);
61
+ onFocus?.(e);
62
+ };
59
63
 
60
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
61
- setFocused(false);
62
- onBlur?.(e);
63
- };
64
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
65
+ setFocused(false);
66
+ onBlur?.(e);
67
+ };
64
68
 
65
- const renderCountingView = () => {
66
- return (
67
- <View style={styles.countingView}>
68
- <Text color={theme.colors.text.hint} typography={'description_xs'}>
69
- {`${inputValue.length}/${maxLength}`}
70
- </Text>
71
- </View>
72
- );
73
- };
74
- const renderInputView = () => {
75
- const disabledColor = theme.colors.text.disable;
76
- let textColor = theme.colors.text.default;
77
- let placeholderColor = theme.colors.text.hint;
69
+ const renderCountingView = () => {
70
+ return (
71
+ <View style={styles.countingView}>
72
+ <Text color={theme.colors.text.hint} typography={'description_xs'}>
73
+ {`${inputValue.length}/${maxLength}`}
74
+ </Text>
75
+ </View>
76
+ );
77
+ };
78
+ const renderInputView = () => {
79
+ const disabledColor = theme.colors.text.disable;
80
+ let textColor = theme.colors.text.default;
81
+ let placeholderColor = theme.colors.text.hint;
78
82
 
79
- if (disabled) {
80
- textColor = disabledColor;
81
- placeholderColor = disabledColor;
82
- }
83
+ if (disabled) {
84
+ textColor = disabledColor;
85
+ placeholderColor = disabledColor;
86
+ }
83
87
 
84
- return (
85
- <View
86
- style={[
87
- styles.textAreaWrapper,
88
- {
89
- height: height || DEFAULT_HEIGHT,
90
- backgroundColor: theme.colors.background.surface,
91
- },
92
- getBorderColor(theme, focused, errorMessage, disabled),
93
- ]}>
94
- <FloatingView
95
- floatingValue={floatingValue}
96
- floatingIconColor={floatingIconColor}
97
- disabled={disabled}
98
- floatingIcon={floatingIcon}
99
- required={required}
100
- />
101
- <View style={styles.rowArea}>
102
- <View style={styles.textAreaView}>
103
- <TextInput
104
- {...props}
105
- accessibilityLabel={`TextInput`}
106
- ref={inputRef}
107
- editable={!disabled}
108
- textAlignVertical="top"
109
- style={[
110
- styles.textArea,
111
- {
112
- color: textColor,
113
- },
114
- ]}
115
- maxLength={maxLength}
116
- textBreakStrategy="highQuality"
117
- multiline={true}
118
- value={value}
119
- onChangeText={_onChangeText}
120
- onFocus={_onFocus}
121
- onBlur={_onBlur}
122
- placeholder={placeholder}
123
- selectionColor={theme.colors.primary}
124
- placeholderTextColor={placeholderColor}
125
- />
126
- </View>
127
- {focused && inputValue.length > 0 && (
128
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
129
- <Icon
130
- source="24_navigation_close_circle_full"
131
- size={16}
132
- color={theme.colors.text.hint}
88
+ return (
89
+ <View
90
+ style={[
91
+ styles.textAreaWrapper,
92
+ {
93
+ height: height || DEFAULT_HEIGHT,
94
+ backgroundColor: theme.colors.background.surface,
95
+ },
96
+ getBorderColor(theme, focused, errorMessage, disabled),
97
+ ]}>
98
+ <FloatingView
99
+ floatingValue={floatingValue}
100
+ floatingIconColor={floatingIconColor}
101
+ disabled={disabled}
102
+ floatingIcon={floatingIcon}
103
+ required={required}
104
+ />
105
+ <View style={styles.rowArea}>
106
+ <View style={styles.textAreaView}>
107
+ <TextInput
108
+ {...props}
109
+ accessibilityLabel={`TextInput`}
110
+ ref={inputRef}
111
+ editable={!disabled}
112
+ textAlignVertical="top"
113
+ style={[
114
+ styles.textArea,
115
+ {
116
+ color: textColor,
117
+ },
118
+ ]}
119
+ maxLength={maxLength}
120
+ textBreakStrategy="highQuality"
121
+ multiline={true}
122
+ value={value}
123
+ onChangeText={_onChangeText}
124
+ onFocus={_onFocus}
125
+ onBlur={_onBlur}
126
+ placeholder={placeholder}
127
+ selectionColor={theme.colors.primary}
128
+ placeholderTextColor={placeholderColor}
133
129
  />
134
- </TouchableOpacity>
135
- )}
130
+ </View>
131
+ {focused && inputValue.length > 0 && (
132
+ <TouchableOpacity
133
+ style={styles.iconWrapper}
134
+ onPress={onClearText}>
135
+ <Icon
136
+ source="24_navigation_close_circle_full"
137
+ size={16}
138
+ color={theme.colors.text.hint}
139
+ />
140
+ </TouchableOpacity>
141
+ )}
142
+ </View>
143
+ {renderCountingView()}
136
144
  </View>
137
- {renderCountingView()}
145
+ );
146
+ };
147
+
148
+ return (
149
+ <View
150
+ style={styles.wrapper}
151
+ accessibilityLabel={`InputTextArea/${floatingValue}`}>
152
+ {renderInputView()}
153
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
138
154
  </View>
139
155
  );
140
- };
141
-
142
- return (
143
- <View
144
- style={styles.wrapper}
145
- accessibilityLabel={`InputTextArea/${floatingValue}`}>
146
- {renderInputView()}
147
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
148
- </View>
149
- );
150
- };
156
+ },
157
+ );
151
158
 
152
159
  InputTextArea.defaultProps = {
153
160
  maxLength: MAX_LENGTH,
package/Input/index.tsx CHANGED
@@ -59,6 +59,11 @@ export interface InputProps extends TextInputProps {
59
59
  * Defaults to `false` if not provided.
60
60
  */
61
61
  errorSpacing?: boolean;
62
+
63
+ /**
64
+ * If true, the icon of input will use be show indicator loading.
65
+ */
66
+ loading?: boolean;
62
67
  }
63
68
 
64
69
  type InputPropsWithoutSizeAndIcon = Omit<
@@ -1,17 +1,17 @@
1
1
  import React, {FC, useContext} from 'react';
2
- import {View, ViewProps} from 'react-native';
3
2
  import AnimatedLottieView from 'lottie-react-native';
4
3
  import animation from '../Assets/DotAnimation.json';
5
4
  import {ApplicationContext} from '../Application';
6
5
  import {hexToRGBA} from './utils';
6
+ import {LoaderProps} from './types';
7
7
 
8
- const DotLoader: FC<ViewProps> = ({style}) => {
8
+ const DotLoader: FC<LoaderProps> = ({color}) => {
9
9
  const {theme} = useContext(ApplicationContext);
10
10
 
11
11
  const arrayColor = [
12
- theme.colors.primary,
13
- theme.colors.secondary,
14
- theme.colors.primary,
12
+ color ?? theme.colors.primary,
13
+ theme.colors.background.surface,
14
+ color ?? theme.colors.primary,
15
15
  ];
16
16
 
17
17
  let source: any = animation;
@@ -26,13 +26,11 @@ const DotLoader: FC<ViewProps> = ({style}) => {
26
26
  });
27
27
 
28
28
  return (
29
- <View style={style}>
30
- <AnimatedLottieView
31
- source={source}
32
- style={{width: 52, height: 18}}
33
- autoPlay
34
- />
35
- </View>
29
+ <AnimatedLottieView
30
+ source={source}
31
+ style={{width: 52, height: 18}}
32
+ autoPlay
33
+ />
36
34
  );
37
35
  };
38
36
 
package/Loader/Loader.tsx CHANGED
@@ -3,12 +3,11 @@ import {LoaderProps} from './types';
3
3
  import DotLoader from './DotLoader';
4
4
  import Spinner from './Spinner';
5
5
 
6
- const Loader: FC<LoaderProps> = ({type = 'dot', style}) => {
6
+ const Loader: FC<LoaderProps> = ({type = 'dot', ...props}) => {
7
7
  if (type === 'spinner') {
8
- return <Spinner style={style} />;
8
+ return <Spinner {...props} key={props.color} />;
9
9
  }
10
-
11
- return <DotLoader style={style} />;
10
+ return <DotLoader {...props} key={props.color} />;
12
11
  };
13
12
 
14
13
  export default Loader;
@@ -1,30 +1,28 @@
1
1
  import React, {FC, useContext} from 'react';
2
- import {View, ViewProps} from 'react-native';
3
2
  import AnimatedLottieView from 'lottie-react-native';
4
3
  import animation from '../Assets/SpinnerAnimation.json';
5
4
  import {hexToRGBA} from './utils';
6
5
  import {ApplicationContext} from '../Application';
6
+ import {LoaderProps} from './types';
7
7
 
8
- const Spinner: FC<ViewProps> = ({style}) => {
8
+ const Spinner: FC<LoaderProps> = ({color}) => {
9
9
  const {theme} = useContext(ApplicationContext);
10
10
 
11
11
  let source: any = animation;
12
12
  source.assets[0].layers.forEach((layer: any) => {
13
13
  layer.shapes[0].it.forEach((item: any) => {
14
14
  if (item.ty === 'fl' && item.c) {
15
- item.c.k = hexToRGBA(theme.colors.primary);
15
+ item.c.k = hexToRGBA(color ?? theme.colors.primary);
16
16
  }
17
17
  });
18
18
  });
19
19
 
20
20
  return (
21
- <View style={style}>
22
- <AnimatedLottieView
23
- source={source}
24
- style={{width: 24, height: 24}}
25
- autoPlay
26
- />
27
- </View>
21
+ <AnimatedLottieView
22
+ source={source}
23
+ style={{width: 24, height: 24}}
24
+ autoPlay
25
+ />
28
26
  );
29
27
  };
30
28
 
package/Loader/types.ts CHANGED
@@ -2,10 +2,12 @@ import {ViewStyle} from 'react-native';
2
2
 
3
3
  export type LoaderProps = {
4
4
  type?: 'dot' | 'spinner';
5
+ color?: string;
5
6
  style?: ViewStyle | ViewStyle[];
6
7
  };
7
8
 
8
9
  export type ProgressBarProps = {
9
10
  percent: number;
11
+ color?: string;
10
12
  style?: ViewStyle | ViewStyle[];
11
13
  };
package/Text/utils.ts CHANGED
@@ -6,7 +6,7 @@ const scaleSize = (size: number) => {
6
6
  const scaleRate = deviceWidth / DEFAULT_SCREEN_SIZE;
7
7
 
8
8
  if (scaleRate > 1) {
9
- return Math.min(Math.round(size * scaleRate), size + 5);
9
+ return Math.min(Math.round(size * scaleRate), size + 3);
10
10
  }
11
11
 
12
12
  return size;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.77.8-beta.04",
3
+ "version": "0.77.8-beta.05",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {