@momo-kits/foundation 1.0.1 → 1.0.4

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.
Files changed (50) hide show
  1. package/Button/index.tsx +39 -23
  2. package/CheckBox/index.tsx +11 -7
  3. package/CheckBox/types.ts +6 -3
  4. package/Consts/theme.ts +57 -1
  5. package/ContentLoader/index.tsx +2 -3
  6. package/Icon/icon.json +3 -0
  7. package/Icon/index.tsx +9 -4
  8. package/Icon/types.ts +4 -1
  9. package/IconButton/index.tsx +24 -4
  10. package/Image/index.tsx +11 -12
  11. package/Image/types.ts +1 -3
  12. package/Input/Input.tsx +160 -0
  13. package/Input/TextArea.tsx +26 -65
  14. package/Input/common.tsx +70 -0
  15. package/Input/index.tsx +23 -197
  16. package/Input/styles.ts +1 -5
  17. package/Layout/GridSystem.tsx +1 -1
  18. package/Layout/ScreenContainer.tsx +5 -19
  19. package/Layout/ScreenSection.tsx +13 -0
  20. package/Layout/SectionItem.tsx +3 -0
  21. package/Layout/utils.ts +14 -0
  22. package/Navigation/Components.tsx +60 -12
  23. package/Navigation/ModalScreen.tsx +56 -43
  24. package/Navigation/Navigation.ts +8 -4
  25. package/Navigation/NavigationButton.tsx +5 -2
  26. package/Navigation/NavigationContainer.tsx +25 -58
  27. package/Navigation/StackScreen.tsx +12 -7
  28. package/Navigation/types.ts +20 -7
  29. package/Navigation/utils.tsx +77 -21
  30. package/Playground/index.tsx +249 -0
  31. package/Playground/styles.ts +16 -0
  32. package/Playground/types.ts +16 -0
  33. package/Popup/PopupNotify.tsx +210 -0
  34. package/Popup/PopupPromotion.tsx +62 -0
  35. package/Popup/index.tsx +4 -0
  36. package/Popup/types.ts +22 -0
  37. package/Radio/index.tsx +25 -9
  38. package/Radio/types.ts +5 -2
  39. package/Switch/index.tsx +8 -6
  40. package/Switch/types.ts +6 -3
  41. package/Text/index.tsx +9 -7
  42. package/Text/styles.ts +3 -3
  43. package/Text/types.ts +5 -14
  44. package/index.ts +6 -6
  45. package/package.json +4 -5
  46. package/publish.sh +6 -8
  47. package/ActivityIndicator.tsx +0 -244
  48. package/Button/types.ts +0 -27
  49. package/IconButton/types.ts +0 -16
  50. package/Input/types.ts +0 -23
package/Button/index.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  import React, {FC, useContext} from 'react';
2
2
  import {
3
- GestureResponderEvent,
4
3
  StyleSheet,
5
4
  TouchableOpacity,
5
+ TouchableOpacityProps,
6
6
  View,
7
7
  } from 'react-native';
8
8
  import {ApplicationContext} from '../Navigation';
@@ -10,25 +10,42 @@ import {Text} from '../Text';
10
10
  import {Typography} from '../Text/types';
11
11
  import {Colors} from '../Consts';
12
12
  import styles from './styles';
13
- import {ButtonProps} from './types';
14
13
  import {Image} from '../Image';
15
14
 
16
- const Button: FC<ButtonProps> = props => {
15
+ export interface ButtonProps extends TouchableOpacityProps {
16
+ type?:
17
+ | 'primary'
18
+ | 'secondary'
19
+ | 'tonal'
20
+ | 'outline'
21
+ | 'danger'
22
+ | 'text'
23
+ | 'disabled';
24
+ size?: 'large' | 'medium' | 'small';
25
+ full?: boolean;
26
+ iconRight?: string;
27
+ iconLeft?: string;
28
+ title: string;
29
+ useTintColor?: boolean;
30
+ }
31
+
32
+ const Button: FC<ButtonProps> = ({
33
+ type,
34
+ size,
35
+ useTintColor,
36
+ full,
37
+ iconRight,
38
+ iconLeft,
39
+ title,
40
+ onPress,
41
+ ...rest
42
+ }) => {
17
43
  const {theme} = useContext(ApplicationContext);
18
- const {type, size, useTintColor, full, iconRight, iconLeft, title, onPress} =
19
- props;
20
-
21
- /**
22
- * export size style
23
- */
24
44
  const getSizeStyle = () => {
25
45
  const styleSheet: {[key: string]: any} = styles;
26
46
  return styleSheet[size ?? 'small'];
27
47
  };
28
48
 
29
- /**
30
- * export type style
31
- */
32
49
  const getTypeStyle = () => {
33
50
  switch (type) {
34
51
  case 'disabled':
@@ -39,13 +56,13 @@ const Button: FC<ButtonProps> = props => {
39
56
  return {backgroundColor: theme.colors.primary};
40
57
  case 'secondary':
41
58
  return {
42
- backgroundColor: theme.colors.background.disable,
59
+ backgroundColor: theme.colors.background.surface,
43
60
  borderWidth: 1,
44
61
  borderColor: theme.colors.border.default,
45
62
  };
46
63
  case 'outline':
47
64
  return {
48
- backgroundColor: Colors.black_01,
65
+ backgroundColor: theme.colors.background.surface,
49
66
  borderWidth: 1,
50
67
  borderColor: theme.colors.primary,
51
68
  };
@@ -58,9 +75,7 @@ const Button: FC<ButtonProps> = props => {
58
75
  backgroundColor: theme.colors.error.primary,
59
76
  };
60
77
  case 'text':
61
- return {
62
- backgroundColor: Colors.black_01,
63
- };
78
+ return {};
64
79
  default:
65
80
  return {backgroundColor: theme.colors.primary};
66
81
  }
@@ -137,9 +152,9 @@ const Button: FC<ButtonProps> = props => {
137
152
  };
138
153
 
139
154
  /**
140
- * render Text
155
+ * render title
141
156
  */
142
- const renderText = () => {
157
+ const renderTitle = () => {
143
158
  const typography = getTypography();
144
159
  const color = getTextColor();
145
160
  return (
@@ -204,7 +219,7 @@ const Button: FC<ButtonProps> = props => {
204
219
  full && {width: '100%'},
205
220
  ]);
206
221
 
207
- const onPressButton = (e: GestureResponderEvent) => {
222
+ const onPressButton = (e: any) => {
208
223
  if (type === 'disabled') {
209
224
  return () => {};
210
225
  }
@@ -212,14 +227,15 @@ const Button: FC<ButtonProps> = props => {
212
227
  };
213
228
 
214
229
  const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
230
+
215
231
  return (
216
232
  <TouchableOpacity
217
- {...props}
233
+ {...rest}
218
234
  activeOpacity={activeOpacity}
219
235
  onPress={onPressButton}
220
236
  style={buttonStyle}>
221
237
  {renderLeading()}
222
- {renderText()}
238
+ {renderTitle()}
223
239
  {renderTrailing()}
224
240
  </TouchableOpacity>
225
241
  );
@@ -234,4 +250,4 @@ Button.defaultProps = {
234
250
  useTintColor: true,
235
251
  };
236
252
 
237
- export default Button;
253
+ export {Button};
@@ -1,25 +1,25 @@
1
1
  import React, {FC, useContext} from 'react';
2
2
  import {TouchableOpacity, View} from 'react-native';
3
-
4
3
  import {CheckBoxProps} from './types';
5
- import {Text} from '@momo-kits/foundation';
6
4
  import styles from './styles';
7
5
  import Image from 'react-native-fast-image';
8
6
  import {ApplicationContext} from '../Navigation';
9
- import {Colors} from '../Consts';
7
+ import {Text} from '../Text';
10
8
 
11
9
  const IC_INDETERMINATED = 'https://img.mservice.com.vn/app/img/kits/minus.png';
12
10
  const IC_CHECKED_DEFAULT =
13
11
  'https://img.mservice.com.vn/app/img/kits/checked_ic.png';
14
12
  const CheckBox: FC<CheckBoxProps> = props => {
15
13
  const {theme} = useContext(ApplicationContext);
16
- const {value, disabled, onChange, label, indeterminated} = props;
14
+ const {value, disabled, onChange, style, label, indeterminated} = props;
17
15
 
18
16
  const haveValue = value || indeterminated;
19
17
  let borderColor = haveValue
20
18
  ? theme.colors.primary
21
19
  : theme.colors.text.default;
22
- let backgroundColor = haveValue ? theme.colors.primary : Colors.black_01;
20
+ let backgroundColor = haveValue
21
+ ? theme.colors.primary
22
+ : theme.colors.background.surface;
23
23
 
24
24
  let iconSource = value ? IC_CHECKED_DEFAULT : undefined;
25
25
 
@@ -33,7 +33,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
33
33
  : theme.colors.border.disable;
34
34
  backgroundColor = haveValue
35
35
  ? theme.colors.background.disable
36
- : Colors.black_01;
36
+ : theme.colors.background.surface;
37
37
  }
38
38
  const checkboxStyle = {borderColor, backgroundColor, borderWidth: 1};
39
39
 
@@ -45,7 +45,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
45
45
  activeOpacity={0.8}
46
46
  onPress={onChangeValue}
47
47
  disabled={disabled}
48
- style={styles.container}>
48
+ style={[style, styles.container]}>
49
49
  <View style={[checkboxStyle, styles.checkbox]}>
50
50
  <Image style={styles.icon} source={{uri: iconSource}} />
51
51
  </View>
@@ -54,4 +54,8 @@ const CheckBox: FC<CheckBoxProps> = props => {
54
54
  );
55
55
  };
56
56
 
57
+ CheckBox.defaultProps = {
58
+ disabled: false,
59
+ };
60
+
57
61
  export {CheckBox};
package/CheckBox/types.ts CHANGED
@@ -1,7 +1,10 @@
1
- export interface CheckBoxProps {
1
+ import {ViewStyle} from 'react-native';
2
+
3
+ export type CheckBoxProps = {
2
4
  value: boolean;
3
5
  disabled?: boolean;
4
6
  label?: string;
5
7
  onChange: (value: boolean) => void;
6
- indeterminated: boolean;
7
- }
8
+ indeterminated?: boolean;
9
+ style?: ViewStyle;
10
+ };
package/Consts/theme.ts CHANGED
@@ -57,9 +57,65 @@ const defaultTheme: Theme = {
57
57
  },
58
58
  };
59
59
 
60
+ const defaultDarkTheme: Theme = {
61
+ dark: true,
62
+ colors: {
63
+ primary: '#ff79b0',
64
+ secondary: '#ffacdc',
65
+ background: {
66
+ default: '#121212', // Dark background
67
+ surface: '#1e1e1e', // Slightly lighter surface background
68
+ tonal: '#171717', // Tonal background
69
+ pressed: '#1a1a1a', // Pressed state background
70
+ selected: '#1a1a1a', // Selected state background
71
+ disable: '#303030', // Disabled state background
72
+ },
73
+ text: {
74
+ default: '#ffffff', // White text for better contrast
75
+ secondary: '#b0b0b0', // Light gray secondary text
76
+ hint: '#727272', // Hint text color
77
+ disable: '#505050', // Disabled text color
78
+ },
79
+ border: {
80
+ default: '#2a2a2a', // Darker borders
81
+ disable: '#242424', // Disabled state border color
82
+ },
83
+ success: {
84
+ primary: Colors.green_03,
85
+ secondary: Colors.green_07,
86
+ container: Colors.green_08,
87
+ },
88
+ warning: {
89
+ primary: Colors.orange_03,
90
+ secondary: Colors.orange_07,
91
+ container: Colors.orange_08,
92
+ },
93
+ error: {
94
+ primary: Colors.red_03,
95
+ secondary: Colors.red_07,
96
+ container: Colors.red_08,
97
+ },
98
+ highlight: {
99
+ primary: Colors.mint_03,
100
+ secondary: Colors.mint_07,
101
+ container: Colors.mint_08,
102
+ },
103
+ interactive: {
104
+ primary: Colors.blue_03,
105
+ secondary: Colors.blue_07,
106
+ container: Colors.blue_08,
107
+ },
108
+ },
109
+ font: 'SFProText',
110
+ assets: {
111
+ headerBackground:
112
+ 'https://static.momocdn.net/app/img/app/img/header-background.png',
113
+ },
114
+ };
115
+
60
116
  const defaultContext: Context = {
61
117
  theme: defaultTheme,
62
118
  navigator: undefined,
63
119
  };
64
120
 
65
- export {defaultContext, defaultTheme};
121
+ export {defaultContext, defaultTheme, defaultDarkTheme};
@@ -1,15 +1,14 @@
1
1
  import React, {useContext, useEffect, useMemo, useRef} from 'react';
2
2
  import {Animated, Platform, useWindowDimensions, View} from 'react-native';
3
+ import LinearGradient from 'react-native-linear-gradient';
3
4
  import {ContentLoaderTypes} from './types';
4
5
  import {ApplicationContext} from '../Navigation';
5
- import LinearGradient from 'react-native-linear-gradient';
6
6
  import {Styles} from '../Consts';
7
7
  import styles from './styles';
8
- const ContentLoader: React.FC<ContentLoaderTypes> = props => {
8
+ const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
9
9
  const {width} = useWindowDimensions();
10
10
  const {theme} = useContext(ApplicationContext);
11
11
  const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
12
- const {style} = props;
13
12
 
14
13
  const shimmerColors = [
15
14
  theme.colors.text.disable + '40',
package/Icon/icon.json CHANGED
@@ -3931,5 +3931,8 @@
3931
3931
  },
3932
3932
  "header_background": {
3933
3933
  "uri": "https://img.mservice.com.vn/app/img/kits/navigation-bar.png"
3934
+ },
3935
+ "ic_error": {
3936
+ "uri": "https://img.mservice.com.vn/app/img/kits/error_mess_icon.png"
3934
3937
  }
3935
3938
  }
package/Icon/index.tsx CHANGED
@@ -1,13 +1,18 @@
1
1
  import React, {useContext} from 'react';
2
- import {IconProps, Image, ApplicationContext} from '../index';
3
2
  import IconSources from './icon.json';
3
+ import {IconProps} from './types';
4
+ import {ApplicationContext} from '../Navigation';
5
+ import {Image} from '../Image';
4
6
 
5
- const Icon: React.FC<IconProps> = ({source, size, color}) => {
7
+ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
6
8
  const {theme} = useContext(ApplicationContext);
7
9
 
10
+ /**
11
+ * get icon source maps or remote http
12
+ */
8
13
  const getIconSource = (): any => {
9
14
  if (source && !source.includes('http')) {
10
- let icon: {[key: string]: object} = IconSources;
15
+ let icon: {[key: string]: {uri: string}} = IconSources;
11
16
  return icon[source] ?? icon.ic_warning;
12
17
  }
13
18
  return {uri: source};
@@ -16,7 +21,7 @@ const Icon: React.FC<IconProps> = ({source, size, color}) => {
16
21
  return (
17
22
  <Image
18
23
  source={getIconSource()}
19
- style={{width: size, height: size}}
24
+ style={[style, {width: size, height: size}]}
20
25
  tintColor={color ?? theme.colors.text.default}
21
26
  />
22
27
  );
package/Icon/types.ts CHANGED
@@ -1,5 +1,8 @@
1
+ import {ViewStyle} from 'react-native';
2
+
1
3
  export type IconProps = {
2
- source?: string;
4
+ source: string;
3
5
  size?: number;
4
6
  color?: string;
7
+ style?: ViewStyle;
5
8
  };
@@ -3,13 +3,19 @@ import {
3
3
  GestureResponderEvent,
4
4
  StyleSheet,
5
5
  TouchableOpacity,
6
+ TouchableOpacityProps,
6
7
  } from 'react-native';
7
- import {IconButtonProps} from './types';
8
8
  import {ApplicationContext} from '../Navigation';
9
9
  import {Colors} from '../Consts';
10
10
  import {Icon} from '../Icon';
11
11
  import styles from './styles';
12
12
 
13
+ export interface IconButtonProps extends TouchableOpacityProps {
14
+ icon: string;
15
+ type?: 'primary' | 'tonal' | 'secondary' | 'danger' | 'outline' | 'disabled';
16
+ size?: 'large' | 'small';
17
+ }
18
+
13
19
  const IconButton: React.FC<IconButtonProps> = ({
14
20
  type,
15
21
  icon,
@@ -19,12 +25,19 @@ const IconButton: React.FC<IconButtonProps> = ({
19
25
  }) => {
20
26
  const {theme} = useContext(ApplicationContext);
21
27
 
28
+ /**
29
+ * get size icon button
30
+ */
22
31
  const getSizeStyle = () => {
23
32
  if (size === 'small') {
24
33
  return styles.small;
25
34
  }
26
35
  return styles.large;
27
36
  };
37
+
38
+ /**
39
+ * get style for icon button by type
40
+ */
28
41
  const getTypeStyle = () => {
29
42
  switch (type) {
30
43
  case 'disabled':
@@ -35,13 +48,13 @@ const IconButton: React.FC<IconButtonProps> = ({
35
48
  return {backgroundColor: theme.colors.primary};
36
49
  case 'secondary':
37
50
  return {
38
- backgroundColor: Colors.black_01,
51
+ backgroundColor: theme.colors.background.surface,
39
52
  borderWidth: 1,
40
53
  borderColor: theme.colors.border.default,
41
54
  };
42
55
  case 'outline':
43
56
  return {
44
- backgroundColor: Colors.black_01,
57
+ backgroundColor: theme.colors.background.surface,
45
58
  borderWidth: 1,
46
59
  borderColor: theme.colors.primary,
47
60
  };
@@ -58,6 +71,9 @@ const IconButton: React.FC<IconButtonProps> = ({
58
71
  }
59
72
  };
60
73
 
74
+ /**
75
+ * get color for icon
76
+ */
61
77
  const getIconColor = () => {
62
78
  switch (type) {
63
79
  case 'disabled':
@@ -77,6 +93,10 @@ const IconButton: React.FC<IconButtonProps> = ({
77
93
  }
78
94
  };
79
95
 
96
+ /**
97
+ * handle press
98
+ * @param e
99
+ */
80
100
  const onPressButton = (e: GestureResponderEvent) => {
81
101
  if (type === 'disabled') {
82
102
  return () => {};
@@ -85,9 +105,9 @@ const IconButton: React.FC<IconButtonProps> = ({
85
105
  };
86
106
 
87
107
  const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
88
-
89
108
  const buttonStyle = StyleSheet.flatten([getTypeStyle(), getSizeStyle()]);
90
109
  const iconSize = size === 'small' ? 16 : 24;
110
+
91
111
  return (
92
112
  <TouchableOpacity
93
113
  {...rest}
package/Image/index.tsx CHANGED
@@ -1,27 +1,29 @@
1
1
  import React, {useContext, useState} from 'react';
2
- import {StyleSheet, View} from 'react-native';
2
+ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
3
3
  import FastImage from 'react-native-fast-image';
4
-
5
4
  import styles from './styles';
6
- import {ImageProps} from './types';
7
5
  import {ApplicationContext} from '../Navigation';
8
6
  import {ContentLoader} from '../ContentLoader';
9
7
  import {Icon} from '../Icon';
10
8
  import {Styles} from '../Consts';
9
+ import {FastImagePropsWithoutStyle} from './types';
10
+
11
+ export interface ImageProps extends FastImagePropsWithoutStyle {
12
+ style?: StyleProp<ViewStyle>;
13
+ }
11
14
 
12
- const Image: React.FC<ImageProps> = props => {
15
+ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
13
16
  const {theme} = useContext(ApplicationContext);
14
- const {style, placeholder, source} = props;
15
17
  const [loading, setLoading] = useState(typeof source === 'object');
16
18
  const [fail, setFail] = useState(false);
17
19
 
18
20
  /**
19
- * render content
21
+ * render content loading | fail | rendered
20
22
  * @returns {JSX.Element}
21
23
  */
22
24
  const renderContent = () => {
23
25
  if (loading || fail) {
24
- let content = placeholder ?? (
26
+ let content = (
25
27
  <ContentLoader style={[StyleSheet.absoluteFill, styles.image]} />
26
28
  );
27
29
  if (fail) {
@@ -47,7 +49,8 @@ const Image: React.FC<ImageProps> = props => {
47
49
  return (
48
50
  <View style={[styles.container, style]}>
49
51
  <FastImage
50
- {...props}
52
+ {...rest}
53
+ source={source}
51
54
  style={styles.image}
52
55
  onLoad={() => {
53
56
  setFail(false);
@@ -61,8 +64,4 @@ const Image: React.FC<ImageProps> = props => {
61
64
  );
62
65
  };
63
66
 
64
- Image.defaultProps = {
65
- style: {},
66
- };
67
-
68
67
  export {Image};
package/Image/types.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  import {FastImageProps} from 'react-native-fast-image';
2
2
 
3
- export interface ImageProps extends FastImageProps {
4
- placeholder?: boolean;
5
- }
3
+ export type FastImagePropsWithoutStyle = Omit<FastImageProps, 'style'>;
@@ -0,0 +1,160 @@
1
+ import React, {FC, useContext, useRef, useState} from 'react';
2
+ import {
3
+ NativeSyntheticEvent,
4
+ TextInput,
5
+ TextInputFocusEventData,
6
+ TouchableOpacity,
7
+ View,
8
+ } from 'react-native';
9
+ import {ApplicationContext} from '../Navigation';
10
+ import styles from './styles';
11
+ import {Text} from '../Text';
12
+ import {Image} from '../Image';
13
+ import {getBorderColor, renderFloatingView} from './common';
14
+ import {InputProps} from './index';
15
+ import {Icon} from '../Icon';
16
+
17
+ const Input: FC<InputProps> = ({
18
+ value,
19
+ onChangeText,
20
+ floatingValue,
21
+ floatingIcon,
22
+ size,
23
+ placeholder,
24
+ onBlur,
25
+ onFocus,
26
+ errorMessage,
27
+ icon,
28
+ disabled,
29
+ floatingIconColor,
30
+ iconColor,
31
+ ...props
32
+ }) => {
33
+ const {theme} = useContext(ApplicationContext);
34
+ const [focused, setFocused] = useState(false);
35
+ const inputRef = useRef<any>(null);
36
+
37
+ const onClearText = () => {
38
+ inputRef?.current?.clear();
39
+ };
40
+
41
+ const _onChangeText = (text: string) => {
42
+ onChangeText?.(text);
43
+ };
44
+ const getSizeStyle = () => {
45
+ if (size === 'small') {
46
+ return styles.smallContainer;
47
+ }
48
+ return styles.container;
49
+ };
50
+
51
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
52
+ setFocused(true);
53
+ onFocus?.(e);
54
+ };
55
+
56
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
57
+ setFocused(false);
58
+ onBlur?.(e);
59
+ };
60
+
61
+ const renderInputView = () => {
62
+ const disabledColor = theme.colors.text.disable;
63
+ let textColor = theme.colors.text.default;
64
+ let placeholderColor = theme.colors.text.hint;
65
+ let iconTintColor = iconColor;
66
+
67
+ if (disabled) {
68
+ textColor = disabledColor;
69
+ placeholderColor = disabledColor;
70
+ iconTintColor = disabledColor;
71
+ }
72
+
73
+ return (
74
+ <View
75
+ style={[
76
+ getSizeStyle(),
77
+ getBorderColor(focused, errorMessage, disabled),
78
+ styles.inputWrapper,
79
+ ]}>
80
+ {renderFloatingView(
81
+ floatingValue,
82
+ floatingIconColor,
83
+ disabled,
84
+ floatingIcon,
85
+ )}
86
+ <View style={styles.inputView}>
87
+ <TextInput
88
+ {...props}
89
+ editable={!disabled}
90
+ textAlignVertical="top"
91
+ ref={inputRef}
92
+ style={[
93
+ styles.input,
94
+ {
95
+ color: textColor,
96
+ },
97
+ ]}
98
+ value={value}
99
+ onChangeText={_onChangeText}
100
+ onFocus={_onFocus}
101
+ onBlur={_onBlur}
102
+ placeholder={placeholder}
103
+ selectionColor={theme.colors.primary}
104
+ placeholderTextColor={placeholderColor}
105
+ />
106
+ </View>
107
+ <View style={styles.iconView}>
108
+ {focused && (
109
+ <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
110
+ <Icon
111
+ source="24_navigation_close_circle_full"
112
+ size={16}
113
+ color={theme.colors.text.hint}
114
+ />
115
+ </TouchableOpacity>
116
+ )}
117
+ {icon && (
118
+ <Image
119
+ tintColor={iconTintColor}
120
+ source={{uri: icon}}
121
+ style={styles.icon}
122
+ />
123
+ )}
124
+ </View>
125
+ </View>
126
+ );
127
+ };
128
+
129
+ const renderErrorView = () => {
130
+ if (errorMessage) {
131
+ return (
132
+ <View style={styles.errorView}>
133
+ <View style={styles.errorIcon}>
134
+ <Icon
135
+ source="ic_error"
136
+ size={16}
137
+ color={theme.colors.error.primary}
138
+ />
139
+ </View>
140
+ <Text color={theme.colors.error.primary} typography={'description_s'}>
141
+ {errorMessage}
142
+ </Text>
143
+ </View>
144
+ );
145
+ }
146
+ };
147
+
148
+ return (
149
+ <View style={styles.wrapper}>
150
+ {renderInputView()}
151
+ {renderErrorView()}
152
+ </View>
153
+ );
154
+ };
155
+
156
+ Input.defaultProps = {
157
+ size: 'large',
158
+ };
159
+
160
+ export default Input;