@momo-kits/foundation 1.0.0 → 1.0.3

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 (68) hide show
  1. package/Button/index.tsx +118 -171
  2. package/CheckBox/index.tsx +63 -0
  3. package/CheckBox/styles.ts +14 -0
  4. package/CheckBox/types.ts +10 -0
  5. package/Consts/colors+spacing+radius.ts +6 -4
  6. package/Consts/index.ts +4 -73
  7. package/Consts/styles.ts +1 -1
  8. package/Consts/theme.ts +121 -0
  9. package/ContentLoader/index.tsx +9 -13
  10. package/Icon/index.tsx +14 -11
  11. package/Icon/types.ts +1 -4
  12. package/IconButton/index.tsx +67 -67
  13. package/IconButton/styles.ts +19 -0
  14. package/Image/index.tsx +22 -21
  15. package/Image/types.ts +0 -1
  16. package/Input/Input.tsx +161 -0
  17. package/Input/TextArea.tsx +162 -0
  18. package/Input/common.tsx +70 -0
  19. package/Input/index.tsx +26 -0
  20. package/Input/styles.ts +92 -0
  21. package/Layout/GridSystem.tsx +109 -0
  22. package/Layout/ScreenContainer.tsx +84 -0
  23. package/Layout/ScreenSection.tsx +117 -0
  24. package/Layout/SectionItem.tsx +63 -0
  25. package/Layout/index.ts +11 -5
  26. package/Layout/types.ts +6 -33
  27. package/Layout/utils.ts +69 -23
  28. package/Navigation/Components.tsx +42 -9
  29. package/Navigation/ModalScreen.tsx +65 -40
  30. package/Navigation/Navigation.ts +5 -2
  31. package/Navigation/NavigationButton.tsx +10 -5
  32. package/Navigation/NavigationContainer.tsx +17 -13
  33. package/Navigation/StackScreen.tsx +8 -2
  34. package/Navigation/index.ts +5 -3
  35. package/Navigation/types.ts +72 -38
  36. package/Navigation/utils.tsx +37 -14
  37. package/Playground/index.tsx +132 -0
  38. package/Playground/styles.ts +16 -0
  39. package/Playground/types.ts +15 -0
  40. package/Popup/PopupNotify.tsx +210 -0
  41. package/Popup/PopupPromotion.tsx +66 -0
  42. package/Popup/index.tsx +4 -0
  43. package/Popup/types.ts +23 -0
  44. package/Radio/index.tsx +42 -0
  45. package/Radio/styles.ts +12 -0
  46. package/Radio/types.ts +7 -0
  47. package/Switch/index.tsx +35 -0
  48. package/Switch/styles.ts +23 -0
  49. package/Switch/types.ts +5 -0
  50. package/Text/index.tsx +36 -118
  51. package/Text/styles.ts +24 -23
  52. package/Text/types.ts +5 -12
  53. package/index.ts +21 -4
  54. package/package.json +3 -4
  55. package/Button/types.ts +0 -18
  56. package/CheckBox/index.js +0 -74
  57. package/CheckBox/styles.js +0 -3
  58. package/IconButton/types.ts +0 -17
  59. package/Layout/Row.tsx +0 -42
  60. package/Layout/Screen.tsx +0 -68
  61. package/Layout/Section.tsx +0 -30
  62. package/Layout/View.tsx +0 -84
  63. package/Layout/styles.ts +0 -24
  64. package/Navigation/ScreenContainer.tsx +0 -38
  65. package/SizedBox/index.js +0 -23
  66. package/SizedBox/styles.js +0 -7
  67. package/TextInput/index.js +0 -225
  68. package/TextInput/styles.js +0 -55
@@ -0,0 +1,121 @@
1
+ import {Context, Theme} from '../Navigation/types';
2
+ import {Colors} from './colors+spacing+radius';
3
+
4
+ const defaultTheme: Theme = {
5
+ dark: false,
6
+ colors: {
7
+ primary: Colors.pink_03,
8
+ secondary: Colors.pink_07,
9
+ background: {
10
+ default: '#f2f2f6',
11
+ surface: Colors.black_01,
12
+ tonal: Colors.pink_09,
13
+ pressed: '#fef4fa',
14
+ selected: Colors.pink_10,
15
+ disable: '#ebebf2',
16
+ },
17
+ text: {
18
+ default: Colors.black_17,
19
+ secondary: Colors.black_15,
20
+ hint: Colors.black_12,
21
+ disable: Colors.black_08,
22
+ },
23
+ border: {
24
+ default: Colors.black_04,
25
+ disable: Colors.black_02,
26
+ },
27
+ success: {
28
+ primary: Colors.green_03,
29
+ secondary: Colors.green_07,
30
+ container: Colors.green_08,
31
+ },
32
+ warning: {
33
+ primary: Colors.orange_03,
34
+ secondary: Colors.orange_07,
35
+ container: Colors.orange_08,
36
+ },
37
+ error: {
38
+ primary: Colors.red_03,
39
+ secondary: Colors.red_07,
40
+ container: Colors.red_08,
41
+ },
42
+ highlight: {
43
+ primary: Colors.mint_03,
44
+ secondary: Colors.mint_07,
45
+ container: Colors.mint_08,
46
+ },
47
+ interactive: {
48
+ primary: Colors.blue_03,
49
+ secondary: Colors.blue_07,
50
+ container: Colors.blue_08,
51
+ },
52
+ },
53
+ font: 'SFProText',
54
+ assets: {
55
+ headerBackground:
56
+ 'https://static.momocdn.net/app/img/app/img/header-background.png',
57
+ },
58
+ };
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
+
116
+ const defaultContext: Context = {
117
+ theme: defaultTheme,
118
+ navigator: undefined,
119
+ };
120
+
121
+ export {defaultContext, defaultTheme, defaultDarkTheme};
@@ -1,23 +1,19 @@
1
1
  import React, {useContext, useEffect, useMemo, useRef} from 'react';
2
2
  import {Animated, Platform, useWindowDimensions, View} from 'react-native';
3
- import {
4
- ContentLoaderTypes,
5
- LinearGradient,
6
- NavigationContext,
7
- Styles,
8
- } from '../index';
3
+ import {ContentLoaderTypes} from './types';
4
+ import {ApplicationContext} from '../Navigation';
5
+ import LinearGradient from 'react-native-linear-gradient';
6
+ import {Styles} from '../Consts';
9
7
  import styles from './styles';
10
-
11
- const ContentLoader: React.FC<ContentLoaderTypes> = props => {
8
+ const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
12
9
  const {width} = useWindowDimensions();
13
- const {theme} = useContext(NavigationContext);
10
+ const {theme} = useContext(ApplicationContext);
14
11
  const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
15
- const {style} = props;
16
12
 
17
13
  const shimmerColors = [
18
- theme.colors.border + '40',
19
- theme.colors.border + '80',
20
- theme.colors.border,
14
+ theme.colors.text.disable + '40',
15
+ theme.colors.text.disable + '80',
16
+ theme.colors.text.disable,
21
17
  ];
22
18
  const location = [0.3, 0.5, 0.7];
23
19
  const linearTranslate = beginShimmerPosition.interpolate({
package/Icon/index.tsx CHANGED
@@ -1,30 +1,33 @@
1
1
  import React, {useContext} from 'react';
2
- import {IconProps, Image, NavigationContext} from '../index';
3
- import SourceSets from './icon.json';
2
+ import {IconProps, Image, ApplicationContext} from '../index';
3
+ import IconSources from './icon.json';
4
4
 
5
- const Icon: React.FC<IconProps> = ({name, source, size, color}) => {
6
- const {theme} = useContext(NavigationContext);
5
+ const Icon: React.FC<IconProps> = ({source, size, color}) => {
6
+ const {theme} = useContext(ApplicationContext);
7
7
 
8
+ /**
9
+ * get icon source maps or remote http
10
+ */
8
11
  const getIconSource = (): any => {
9
- if (name) {
10
- let icon: {[key: string]: object} = SourceSets;
11
- return icon[name] ?? icon.ic_warning;
12
+ if (source && !source.includes('http')) {
13
+ let icon: {[key: string]: object} = IconSources;
14
+ return icon[source] ?? icon.ic_warning;
12
15
  }
13
- return source;
16
+ return {uri: source};
14
17
  };
15
18
 
16
19
  return (
17
20
  <Image
18
21
  source={getIconSource()}
19
22
  style={{width: size, height: size}}
20
- tintColor={color ?? theme.colors.text}
23
+ tintColor={color ?? theme.colors.text.default}
21
24
  />
22
25
  );
23
26
  };
24
27
 
25
28
  Icon.defaultProps = {
26
- name: 'ic_back',
29
+ source: 'ic_back',
27
30
  size: 24,
28
31
  };
29
32
 
30
- export {Icon};
33
+ export {Icon, IconSources};
package/Icon/types.ts CHANGED
@@ -1,8 +1,5 @@
1
- import {Source} from 'react-native-fast-image';
2
-
3
1
  export type IconProps = {
4
- name?: string;
5
- source?: Source | number | undefined;
2
+ source?: string;
6
3
  size?: number;
7
4
  color?: string;
8
5
  };
@@ -1,127 +1,127 @@
1
1
  import React, {useContext} from 'react';
2
- import {StyleSheet, TouchableOpacity, View} from 'react-native';
3
- import {NavigationContext, Colors, Icon, IconButtonProps} from '../index';
2
+ import {
3
+ GestureResponderEvent,
4
+ StyleSheet,
5
+ TouchableOpacity,
6
+ TouchableOpacityProps,
7
+ } from 'react-native';
8
+ import {ApplicationContext} from '../Navigation';
9
+ import {Colors} from '../Consts';
10
+ import {Icon} from '../Icon';
11
+ import styles from './styles';
12
+
13
+ export interface IconButtonProps extends TouchableOpacityProps {
14
+ icon: string;
15
+ type?: 'primary' | 'tonal' | 'secondary' | 'danger' | 'outline' | 'disabled';
16
+ size?: 'large' | 'small';
17
+ }
4
18
 
5
19
  const IconButton: React.FC<IconButtonProps> = ({
6
- style,
7
20
  type,
8
21
  icon,
9
22
  size,
10
- shape,
23
+ onPress,
11
24
  ...rest
12
25
  }) => {
13
- const {theme} = useContext(NavigationContext);
26
+ const {theme} = useContext(ApplicationContext);
14
27
 
15
28
  /**
16
- * export size style
29
+ * get size icon button
17
30
  */
18
31
  const getSizeStyle = () => {
19
- switch (size) {
20
- case 'large':
21
- return styles.large;
22
- case 'small':
23
- return styles.small;
24
-
25
- default:
26
- return styles.small;
32
+ if (size === 'small') {
33
+ return styles.small;
27
34
  }
35
+ return styles.large;
28
36
  };
29
37
 
30
38
  /**
31
- * export size style
32
- */
33
- const getIconSize = () => {
34
- switch (size) {
35
- case 'large':
36
- return 24;
37
- case 'small':
38
- return 16;
39
-
40
- default:
41
- return 16;
42
- }
43
- };
44
-
45
- /**
46
- * export type style
39
+ * get style for icon button by type
47
40
  */
48
41
  const getTypeStyle = () => {
49
42
  switch (type) {
43
+ case 'disabled':
44
+ return {
45
+ backgroundColor: theme.colors.background.disable,
46
+ };
50
47
  case 'primary':
51
48
  return {backgroundColor: theme.colors.primary};
52
- case 'tonal':
53
- return {backgroundColor: theme.colors.primary + '33'};
54
49
  case 'secondary':
55
- return {borderColor: theme.colors.border, borderWidth: 1};
50
+ return {
51
+ backgroundColor: theme.colors.background.surface,
52
+ borderWidth: 1,
53
+ borderColor: theme.colors.border.default,
54
+ };
56
55
  case 'outline':
57
56
  return {
57
+ backgroundColor: theme.colors.background.surface,
58
58
  borderWidth: 1,
59
59
  borderColor: theme.colors.primary,
60
60
  };
61
- case 'disabled':
62
- return {backgroundColor: theme.colors.border};
61
+ case 'tonal':
62
+ return {
63
+ backgroundColor: theme.colors.background.tonal,
64
+ };
65
+ case 'danger':
66
+ return {
67
+ backgroundColor: theme.colors.error.primary,
68
+ };
63
69
  default:
64
70
  return {backgroundColor: theme.colors.primary};
65
71
  }
66
72
  };
67
73
 
74
+ /**
75
+ * get color for icon
76
+ */
68
77
  const getIconColor = () => {
69
78
  switch (type) {
79
+ case 'disabled':
80
+ return theme.colors.text.disable;
70
81
  case 'primary':
71
82
  return Colors.black_01;
83
+ case 'danger':
84
+ return Colors.black_01;
72
85
  case 'tonal':
73
86
  return theme.colors.primary;
74
87
  case 'secondary':
75
- return theme.colors.text;
88
+ return theme.colors.text.default;
76
89
  case 'outline':
77
90
  return theme.colors.primary;
78
- case 'disabled':
79
- return theme.colors.text + '4D';
80
91
  default:
81
92
  return Colors.black_01;
82
93
  }
83
94
  };
84
95
 
85
- const buttonStyle = StyleSheet.flatten([
86
- getSizeStyle(),
87
- getTypeStyle(),
88
- shape === 'rectangle' && {borderRadius: 8},
89
- style,
90
- ]);
96
+ /**
97
+ * handle press
98
+ * @param e
99
+ */
100
+ const onPressButton = (e: GestureResponderEvent) => {
101
+ if (type === 'disabled') {
102
+ return () => {};
103
+ }
104
+ onPress?.(e);
105
+ };
106
+
107
+ const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
108
+ const buttonStyle = StyleSheet.flatten([getTypeStyle(), getSizeStyle()]);
109
+ const iconSize = size === 'small' ? 16 : 24;
91
110
 
92
111
  return (
93
112
  <TouchableOpacity
94
113
  {...rest}
95
- disabled={type === 'disabled'}
114
+ activeOpacity={activeOpacity}
115
+ onPress={onPressButton}
96
116
  style={buttonStyle}>
97
- <Icon name={icon} size={getIconSize()} color={getIconColor()} />
117
+ <Icon size={iconSize} source={icon} color={getIconColor()} />
98
118
  </TouchableOpacity>
99
119
  );
100
120
  };
101
121
 
102
122
  IconButton.defaultProps = {
103
- icon: 'close',
104
123
  type: 'primary',
105
- size: 'small',
106
- shape: 'circle',
107
- children: <View />,
124
+ disabled: false,
108
125
  };
109
126
 
110
- const styles = StyleSheet.create({
111
- large: {
112
- height: 48,
113
- width: 48,
114
- borderRadius: 24,
115
- justifyContent: 'center',
116
- alignItems: 'center',
117
- },
118
- small: {
119
- height: 36,
120
- width: 36,
121
- borderRadius: 18,
122
- justifyContent: 'center',
123
- alignItems: 'center',
124
- },
125
- });
126
-
127
127
  export {IconButton};
@@ -0,0 +1,19 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {Radius} from '../Consts';
3
+
4
+ export default StyleSheet.create({
5
+ large: {
6
+ width: 48,
7
+ height: 48,
8
+ borderRadius: Radius.XL,
9
+ justifyContent: 'center',
10
+ alignItems: 'center',
11
+ },
12
+ small: {
13
+ width: 40,
14
+ height: 40,
15
+ borderRadius: Radius.XL,
16
+ justifyContent: 'center',
17
+ alignItems: 'center',
18
+ },
19
+ });
package/Image/index.tsx CHANGED
@@ -1,24 +1,21 @@
1
1
  import React, {useContext, useState} from 'react';
2
2
  import {StyleSheet, View} from 'react-native';
3
3
  import FastImage from 'react-native-fast-image';
4
- import {
5
- ContentLoader,
6
- Icon,
7
- ImageProps,
8
- NavigationContext,
9
- Styles,
10
- Text,
11
- } from '../index';
4
+
12
5
  import styles from './styles';
6
+ import {ImageProps} from './types';
7
+ import {ApplicationContext} from '../Navigation';
8
+ import {ContentLoader} from '../ContentLoader';
9
+ import {Icon} from '../Icon';
10
+ import {Styles} from '../Consts';
13
11
 
14
- const Image: React.FC<ImageProps> = props => {
15
- const {theme} = useContext(NavigationContext);
16
- const {style, placeholder, error, source} = props;
12
+ const Image: React.FC<ImageProps> = ({style, placeholder, source, ...rest}) => {
13
+ const {theme} = useContext(ApplicationContext);
17
14
  const [loading, setLoading] = useState(typeof source === 'object');
18
15
  const [fail, setFail] = useState(false);
19
16
 
20
17
  /**
21
- * render content
18
+ * render content loading | fail | rendered
22
19
  * @returns {JSX.Element}
23
20
  */
24
21
  const renderContent = () => {
@@ -27,18 +24,21 @@ const Image: React.FC<ImageProps> = props => {
27
24
  <ContentLoader style={[StyleSheet.absoluteFill, styles.image]} />
28
25
  );
29
26
  if (fail) {
30
- content = error ?? (
31
- <View
32
- style={[Styles.flexCenter, {backgroundColor: theme.colors.border}]}>
33
- <Icon name="error-outline" />
34
- <Text typography="subtitle" style={Styles.textCenter}>
35
- Can't load image
36
- </Text>
27
+ content = (
28
+ <View style={Styles.flexCenter}>
29
+ <Icon source="error-outline" />
37
30
  </View>
38
31
  );
39
32
  }
40
33
  return (
41
- <View style={[StyleSheet.absoluteFill, styles.image]}>{content}</View>
34
+ <View
35
+ style={[
36
+ StyleSheet.absoluteFill,
37
+ styles.image,
38
+ {backgroundColor: theme.colors.background.disable},
39
+ ]}>
40
+ {content}
41
+ </View>
42
42
  );
43
43
  }
44
44
  };
@@ -46,7 +46,8 @@ const Image: React.FC<ImageProps> = props => {
46
46
  return (
47
47
  <View style={[styles.container, style]}>
48
48
  <FastImage
49
- {...props}
49
+ {...rest}
50
+ source={source}
50
51
  style={styles.image}
51
52
  onLoad={() => {
52
53
  setFail(false);
package/Image/types.ts CHANGED
@@ -2,5 +2,4 @@ import {FastImageProps} from 'react-native-fast-image';
2
2
 
3
3
  export interface ImageProps extends FastImageProps {
4
4
  placeholder?: boolean;
5
- error?: boolean;
6
5
  }
@@ -0,0 +1,161 @@
1
+ import React, {FC, useContext, useRef, useState} from 'react';
2
+ import {
3
+ NativeSyntheticEvent,
4
+ TextInput,
5
+ TextInputFocusEventData,
6
+ TextInputProps,
7
+ TouchableOpacity,
8
+ View,
9
+ } from 'react-native';
10
+ import {ApplicationContext} from '../Navigation';
11
+ import styles from './styles';
12
+ import {Text} from '../Text';
13
+ import {Image} from '../Image';
14
+ import {getBorderColor, renderFloatingView} from './common';
15
+ import {InputProps} from './index';
16
+
17
+ const errorMessageIcon =
18
+ 'https://img.mservice.com.vn/app/img/kits/error_mess_icon.png';
19
+ const ic_clear =
20
+ 'https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/24_navigation_close_circle_full.png';
21
+ const MAX_LENGTH = 100;
22
+
23
+ const Input: FC<InputProps> = ({
24
+ value,
25
+ onChangeText,
26
+ floatingValue,
27
+ floatingIcon,
28
+ size,
29
+ placeholder,
30
+ onBlur,
31
+ onFocus,
32
+ errorMessage,
33
+ icon,
34
+ disabled,
35
+ floatingIconColor,
36
+ iconColor,
37
+ }) => {
38
+ const {theme} = useContext(ApplicationContext);
39
+
40
+ const [focused, setFocused] = useState(false);
41
+ const inputRef = useRef(null);
42
+
43
+ const onClearText = () => {
44
+ inputRef?.current?.clear();
45
+ };
46
+
47
+ const _onChangeText = (text: string) => {
48
+ onChangeText?.(text);
49
+ };
50
+ const getSizeStyle = () => {
51
+ if (size === 'small') {
52
+ return styles.smallContainer;
53
+ }
54
+ return styles.container;
55
+ };
56
+
57
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
58
+ setFocused(true);
59
+ onFocus?.(e);
60
+ };
61
+
62
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
63
+ setFocused(false);
64
+ onBlur?.(e);
65
+ };
66
+
67
+ const renderInputView = () => {
68
+ const disabledColor = theme.colors.text.disable;
69
+ let textColor = theme.colors.text.default;
70
+ let placeholderColor = theme.colors.text.hint;
71
+ let iconTintColor = iconColor;
72
+
73
+ if (disabled) {
74
+ textColor = disabledColor;
75
+ placeholderColor = disabledColor;
76
+ iconTintColor = disabledColor;
77
+ }
78
+
79
+ return (
80
+ <View
81
+ style={[
82
+ getSizeStyle(),
83
+ getBorderColor(focused, errorMessage, disabled),
84
+ styles.inputWrapper,
85
+ ]}>
86
+ {renderFloatingView(
87
+ floatingValue,
88
+ floatingIconColor,
89
+ disabled,
90
+ floatingIcon,
91
+ )}
92
+ <View style={styles.inputView}>
93
+ <TextInput
94
+ editable={!disabled}
95
+ textAlignVertical="top"
96
+ ref={inputRef}
97
+ style={[
98
+ styles.input,
99
+ {
100
+ color: textColor,
101
+ },
102
+ ]}
103
+ value={value}
104
+ onChangeText={_onChangeText}
105
+ onFocus={_onFocus}
106
+ onBlur={_onBlur}
107
+ placeholder={placeholder}
108
+ selectionColor={theme.colors.primary}
109
+ placeholderTextColor={placeholderColor}
110
+ />
111
+ </View>
112
+ <View style={styles.iconView}>
113
+ {focused && (
114
+ <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
115
+ <Image
116
+ tintColor={theme.colors.text.hint}
117
+ source={{uri: ic_clear}}
118
+ style={styles.iconClose}
119
+ />
120
+ </TouchableOpacity>
121
+ )}
122
+ {icon && (
123
+ <Image
124
+ tintColor={iconTintColor}
125
+ source={{uri: icon}}
126
+ style={styles.icon}
127
+ />
128
+ )}
129
+ </View>
130
+ </View>
131
+ );
132
+ };
133
+
134
+ const renderErrorView = () => {
135
+ if (errorMessage) {
136
+ return (
137
+ <View style={styles.errorView}>
138
+ <Image style={styles.errorIcon} source={{uri: errorMessageIcon}} />
139
+ <Text color={theme.colors.error.primary} typography={'description_s'}>
140
+ {errorMessage}
141
+ </Text>
142
+ </View>
143
+ );
144
+ }
145
+ };
146
+
147
+ return (
148
+ <View style={styles.wrapper}>
149
+ {renderInputView()}
150
+ {renderErrorView()}
151
+ </View>
152
+ );
153
+ };
154
+
155
+ Input.defaultProps = {
156
+ size: 'large',
157
+ maxLength: MAX_LENGTH,
158
+ disabled: false,
159
+ };
160
+
161
+ export default Input;