@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
@@ -7,18 +7,15 @@ import {
7
7
  View,
8
8
  } from 'react-native';
9
9
  import styles from './styles';
10
- import {Image} from '../Image';
11
10
  import {Text} from '../Text';
12
- import {TextAreaProps} from './types';
13
11
  import {ApplicationContext} from '../Navigation';
14
- import {Colors} from '../Consts';
12
+ import {getBorderColor, renderFloatingView} from './common';
13
+ import {TextAreaProps} from './index';
14
+ import {Icon} from '../Icon';
15
15
 
16
- const errorMessageIcon =
17
- 'https://img.mservice.com.vn/app/img/kits/error_mess_icon.png';
18
- const ic_clear =
19
- 'https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/24_navigation_close_circle_full.png';
20
16
  const DEFAULT_HEIGHT = 112;
21
17
  const MAX_LENGTH = 300;
18
+
22
19
  const TextArea: FC<TextAreaProps> = props => {
23
20
  const {theme} = useContext(ApplicationContext);
24
21
  const {
@@ -59,56 +56,6 @@ const TextArea: FC<TextAreaProps> = props => {
59
56
  setFocused(false);
60
57
  onBlur?.(e);
61
58
  };
62
- const getBorderColor = () => {
63
- let borderColor = theme.colors.border.default;
64
-
65
- if (focused) {
66
- borderColor = theme.colors.primary;
67
- }
68
-
69
- if (!!errorMessage) {
70
- borderColor = theme.colors.error.primary;
71
- }
72
-
73
- if (disabled) {
74
- borderColor = theme.colors.border.disable;
75
- }
76
-
77
- return {borderColor};
78
- };
79
-
80
- const renderFloatingView = () => {
81
- if (floatingValue) {
82
- let floatingTextColor = theme.colors.text.hint;
83
- let floatingIconTintColor = floatingIconColor;
84
- if (disabled) {
85
- floatingTextColor = theme.colors.text.disable;
86
- floatingIconTintColor = theme.colors.text.disable;
87
- }
88
-
89
- return (
90
- <View
91
- style={[
92
- styles.floatingView,
93
- {
94
- backgroundColor: Colors.black_01,
95
- zIndex: 10,
96
- },
97
- ]}>
98
- <Text color={floatingTextColor} typography={'label_s'}>
99
- {floatingValue}
100
- </Text>
101
- {floatingIcon && (
102
- <Image
103
- tintColor={floatingIconTintColor}
104
- source={{uri: floatingIcon}}
105
- style={styles.floatingIcon}
106
- />
107
- )}
108
- </View>
109
- );
110
- }
111
- };
112
59
 
113
60
  const renderCountingView = () => {
114
61
  return (
@@ -132,11 +79,19 @@ const TextArea: FC<TextAreaProps> = props => {
132
79
  return (
133
80
  <View
134
81
  style={[
135
- getBorderColor(),
82
+ getBorderColor(focused, errorMessage, disabled),
136
83
  styles.textAreaWrapper,
137
- {height: height || DEFAULT_HEIGHT},
84
+ {
85
+ height: height || DEFAULT_HEIGHT,
86
+ backgroundColor: theme.colors.background.surface,
87
+ },
138
88
  ]}>
139
- {renderFloatingView()}
89
+ {renderFloatingView(
90
+ floatingValue,
91
+ floatingIconColor,
92
+ disabled,
93
+ floatingIcon,
94
+ )}
140
95
  <View style={styles.rowArea}>
141
96
  <View style={styles.textAreaView}>
142
97
  <TextInput
@@ -162,10 +117,10 @@ const TextArea: FC<TextAreaProps> = props => {
162
117
  </View>
163
118
  {focused && (
164
119
  <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
165
- <Image
166
- tintColor={theme.colors.text.hint}
167
- source={{uri: ic_clear}}
168
- style={styles.iconClose}
120
+ <Icon
121
+ source="24_navigation_close_circle_full"
122
+ size={16}
123
+ color={theme.colors.text.hint}
169
124
  />
170
125
  </TouchableOpacity>
171
126
  )}
@@ -179,7 +134,13 @@ const TextArea: FC<TextAreaProps> = props => {
179
134
  if (errorMessage) {
180
135
  return (
181
136
  <View style={styles.errorView}>
182
- <Image style={styles.errorIcon} source={{uri: errorMessageIcon}} />
137
+ <View style={styles.errorIcon}>
138
+ <Icon
139
+ source="ic_error"
140
+ size={16}
141
+ color={theme.colors.error.primary}
142
+ />
143
+ </View>
183
144
  <Text color={theme.colors.error.primary} typography={'description_s'}>
184
145
  {errorMessage}
185
146
  </Text>
@@ -0,0 +1,70 @@
1
+ import {View} from 'react-native';
2
+ import styles from './styles';
3
+ import {Text} from '../Text';
4
+ import {Image} from '../Image';
5
+ import React, {useContext} from 'react';
6
+ import {ApplicationContext} from '../Navigation';
7
+
8
+ export const getBorderColor = (
9
+ focused: boolean,
10
+ errorMessage?: string,
11
+ disabled?: boolean,
12
+ ) => {
13
+ const {theme} = useContext(ApplicationContext);
14
+
15
+ let borderColor = theme.colors.border.default;
16
+
17
+ if (focused) {
18
+ borderColor = theme.colors.primary;
19
+ }
20
+
21
+ if (!!errorMessage) {
22
+ borderColor = theme.colors.error.primary;
23
+ }
24
+
25
+ if (disabled) {
26
+ borderColor = theme.colors.border.disable;
27
+ }
28
+
29
+ return {borderColor};
30
+ };
31
+
32
+ export const renderFloatingView = (
33
+ floatingValue?: string,
34
+ floatingIconColor?: string,
35
+ disabled?: boolean,
36
+ floatingIcon?: string,
37
+ ) => {
38
+ const {theme} = useContext(ApplicationContext);
39
+
40
+ if (floatingValue) {
41
+ let floatingTextColor = theme.colors.text.hint;
42
+ let floatingIconTintColor = floatingIconColor;
43
+ if (disabled) {
44
+ floatingTextColor = theme.colors.text.disable;
45
+ floatingIconTintColor = theme.colors.text.disable;
46
+ }
47
+
48
+ return (
49
+ <View
50
+ style={[
51
+ styles.floatingView,
52
+ {
53
+ backgroundColor: theme.colors.background.surface,
54
+ zIndex: 10,
55
+ },
56
+ ]}>
57
+ <Text color={floatingTextColor} typography={'label_s'}>
58
+ {floatingValue}
59
+ </Text>
60
+ {floatingIcon && (
61
+ <Image
62
+ tintColor={floatingIconTintColor}
63
+ source={{uri: floatingIcon}}
64
+ style={styles.floatingIcon}
65
+ />
66
+ )}
67
+ </View>
68
+ );
69
+ }
70
+ };
package/Input/index.tsx CHANGED
@@ -1,200 +1,26 @@
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 {InputProps} from './types';
1
+ import Input from './Input';
12
2
  import TextArea from './TextArea';
13
- import {Text} from '../Text';
14
- import {Image} from '../Image';
15
- import {Colors} from '../Consts';
3
+ import {TextInputProps} from 'react-native';
4
+
5
+ export interface InputProps extends TextInputProps {
6
+ size?: 'small' | 'large';
7
+ floatingValue?: string;
8
+ floatingIcon?: string;
9
+ errorMessage?: string;
10
+ icon?: string;
11
+ disabled?: boolean;
12
+ floatingIconColor?: string;
13
+ iconColor?: string;
14
+ }
15
+
16
+ export interface TextAreaProps extends TextInputProps {
17
+ errorMessage: string;
18
+ floatingValue: string;
19
+ floatingIcon: string;
20
+ disabled: boolean;
21
+ floatingIconColor: string;
22
+ placeholder: string;
23
+ height: number;
24
+ }
16
25
 
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
- const Input: FC<InputProps> = props => {
23
- const {theme} = useContext(ApplicationContext);
24
- const {
25
- value,
26
- onChangeText,
27
- floatingValue,
28
- floatingIcon,
29
- size,
30
- placeholder,
31
- onBlur,
32
- onFocus,
33
- errorMessage,
34
- icon,
35
- disabled,
36
- floatingIconColor,
37
- iconColor,
38
- } = props;
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 getBorderColor = () => {
58
- let borderColor = theme.colors.border.default;
59
-
60
- if (focused) {
61
- borderColor = theme.colors.primary;
62
- }
63
-
64
- if (!!errorMessage) {
65
- borderColor = theme.colors.error.primary;
66
- }
67
-
68
- if (disabled) {
69
- borderColor = theme.colors.border.disable;
70
- }
71
-
72
- return {borderColor};
73
- };
74
-
75
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
76
- setFocused(true);
77
- onFocus?.(e);
78
- };
79
-
80
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
81
- setFocused(false);
82
- onBlur?.(e);
83
- };
84
-
85
- const renderFloatingView = () => {
86
- if (floatingValue) {
87
- let floatingTextColor = theme.colors.text.hint;
88
- let floatingIconTintColor = floatingIconColor;
89
- if (disabled) {
90
- floatingTextColor = theme.colors.text.disable;
91
- floatingIconTintColor = theme.colors.text.disable;
92
- }
93
-
94
- return (
95
- <View
96
- style={[
97
- styles.floatingView,
98
- {
99
- backgroundColor: Colors.black_01,
100
- zIndex: 10,
101
- },
102
- ]}>
103
- <Text color={floatingTextColor} typography={'label_s'}>
104
- {floatingValue}
105
- </Text>
106
- {floatingIcon && (
107
- <Image
108
- tintColor={floatingIconTintColor}
109
- source={{uri: floatingIcon}}
110
- style={styles.floatingIcon}
111
- />
112
- )}
113
- </View>
114
- );
115
- }
116
- };
117
-
118
- const renderInputView = () => {
119
- const disabledColor = theme.colors.text.disable;
120
- let textColor = theme.colors.text.default;
121
- let placeholderColor = theme.colors.text.hint;
122
- let iconTintColor = iconColor;
123
-
124
- if (disabled) {
125
- textColor = disabledColor;
126
- placeholderColor = disabledColor;
127
- iconTintColor = disabledColor;
128
- }
129
-
130
- return (
131
- <View style={[getSizeStyle(), getBorderColor(), styles.inputWrapper]}>
132
- {renderFloatingView()}
133
- <View style={styles.inputView}>
134
- <TextInput
135
- editable={!disabled}
136
- textAlignVertical="top"
137
- ref={inputRef}
138
- style={[
139
- styles.input,
140
- {
141
- color: textColor,
142
- },
143
- ]}
144
- value={value}
145
- onChangeText={_onChangeText}
146
- onFocus={_onFocus}
147
- onBlur={_onBlur}
148
- placeholder={placeholder}
149
- selectionColor={theme.colors.primary}
150
- placeholderTextColor={placeholderColor}
151
- />
152
- </View>
153
- <View style={styles.iconView}>
154
- {focused && (
155
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
156
- <Image
157
- tintColor={theme.colors.text.hint}
158
- source={{uri: ic_clear}}
159
- style={styles.iconClose}
160
- />
161
- </TouchableOpacity>
162
- )}
163
- {icon && (
164
- <Image
165
- tintColor={iconTintColor}
166
- source={{uri: icon}}
167
- style={styles.icon}
168
- />
169
- )}
170
- </View>
171
- </View>
172
- );
173
- };
174
-
175
- const renderErrorView = () => {
176
- if (errorMessage) {
177
- return (
178
- <View style={styles.errorView}>
179
- <Image style={styles.errorIcon} source={{uri: errorMessageIcon}} />
180
- <Text color={theme.colors.error.primary} typography={'description_s'}>
181
- {errorMessage}
182
- </Text>
183
- </View>
184
- );
185
- }
186
- };
187
-
188
- return (
189
- <View style={styles.wrapper}>
190
- {renderInputView()}
191
- {renderErrorView()}
192
- </View>
193
- );
194
- };
195
-
196
- Input.defaultProps = {
197
- size: 'large',
198
- maxLength: MAX_LENGTH,
199
- };
200
26
  export {Input, TextArea};
package/Input/styles.ts CHANGED
@@ -29,7 +29,7 @@ export default StyleSheet.create({
29
29
  flexDirection: 'row',
30
30
  },
31
31
  floatingIcon: {width: 16, height: 16, marginLeft: Spacing.XS},
32
- errorIcon: {width: 16, height: 16, marginRight: Spacing.XS},
32
+ errorIcon: {marginRight: Spacing.XS},
33
33
  errorView: {
34
34
  flexDirection: 'row',
35
35
  alignItems: 'center',
@@ -38,10 +38,6 @@ export default StyleSheet.create({
38
38
  justifyContent: 'space-between',
39
39
  flex: 1,
40
40
  },
41
- iconClose: {
42
- width: 16,
43
- height: 16,
44
- },
45
41
  iconView: {
46
42
  flexDirection: 'row',
47
43
  alignItems: 'center',
@@ -5,7 +5,7 @@ import {ApplicationContext} from '../Navigation';
5
5
  import {useGridSystem} from './index';
6
6
  import {Colors, Spacing} from '../Consts';
7
7
 
8
- const GridSystem: React.FC<any> = () => {
8
+ const GridSystem: React.FC = () => {
9
9
  const {theme} = useContext(ApplicationContext);
10
10
  const grid = useGridSystem();
11
11
  const insets = useSafeAreaInsets();
@@ -1,33 +1,26 @@
1
1
  import {KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native';
2
2
  import {useHeaderHeight} from '@react-navigation/stack';
3
3
  import {SafeAreaView} from 'react-native-safe-area-context';
4
- import React, {useContext, useLayoutEffect} from 'react';
4
+ import React from 'react';
5
5
  import {ScreenContainerProps} from '../Navigation/types';
6
- import {ApplicationContext} from '../Navigation';
7
6
  import {Spacing, Styles} from '../Consts';
8
7
  import {ScreenSection, validateChildren} from './index';
9
8
 
10
9
  const ScreenContainer: React.FC<ScreenContainerProps> = ({
11
10
  children,
12
- navigation,
13
- options,
14
11
  edges,
15
12
  enableKeyboardAvoidingView,
16
13
  scrollable,
17
14
  }) => {
18
15
  let Component: any = View;
19
- const {theme} = useContext(ApplicationContext);
20
16
  const headerHeight = useHeaderHeight();
21
17
  if (scrollable) {
22
18
  Component = ScrollView;
23
19
  }
24
20
 
25
- useLayoutEffect(() => {
26
- if (options) {
27
- navigation.setOptions(options);
28
- }
29
- }, [navigation, options]);
30
-
21
+ /**
22
+ * build content for screen
23
+ */
31
24
  const renderContent = () => {
32
25
  const results = validateChildren(children, ScreenSection);
33
26
  if (Array.isArray(results)) {
@@ -48,14 +41,7 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
48
41
  };
49
42
 
50
43
  return (
51
- <SafeAreaView
52
- style={[
53
- Styles.flex,
54
- {
55
- backgroundColor: theme.colors.background.default,
56
- },
57
- ]}
58
- edges={edges}>
44
+ <SafeAreaView style={Styles.flex} edges={edges}>
59
45
  <KeyboardAvoidingView
60
46
  style={Styles.flex}
61
47
  keyboardVerticalOffset={headerHeight}
@@ -7,6 +7,9 @@ import {ScreenSectionProps} from './types';
7
7
  const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
8
8
  const grid = useGridSystem();
9
9
 
10
+ /**
11
+ * render overlay only dev mode
12
+ */
10
13
  const renderOverlay = () => {
11
14
  return (
12
15
  <View
@@ -24,6 +27,12 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
24
27
  );
25
28
  };
26
29
 
30
+ /**
31
+ * build a row view in side session
32
+ * @param rows
33
+ * @param cursor
34
+ * @param endRow
35
+ */
27
36
  const addRowView = (
28
37
  rows: any[],
29
38
  cursor: number = 0,
@@ -50,6 +59,10 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
50
59
  );
51
60
  };
52
61
 
62
+ /**
63
+ * render children content for session
64
+ * @param children
65
+ */
53
66
  const renderView = (
54
67
  children: any,
55
68
  ): React.ReactElement | React.ReactElement[] => {
@@ -13,6 +13,9 @@ const SectionItem: React.FC<SectionItemProps> = ({
13
13
  const {theme} = useContext(ApplicationContext);
14
14
  const grid = useGridSystem();
15
15
 
16
+ /**
17
+ * render overlay view only dev mode
18
+ */
16
19
  const renderOverlay = () => {
17
20
  return (
18
21
  <View
package/Layout/utils.ts CHANGED
@@ -2,6 +2,10 @@ import {Alert, Dimensions} from 'react-native';
2
2
  import React, {ReactElement} from 'react';
3
3
  import {GutterSize, NumberOfColumns, ScreenPadding} from '../Consts';
4
4
 
5
+ /**
6
+ * hook component for use grid system
7
+ * @param useMargin
8
+ */
5
9
  const useGridSystem = (useMargin: boolean = true) => {
6
10
  const isDevMode = false;
7
11
  const gutterSize = GutterSize;
@@ -12,6 +16,10 @@ const useGridSystem = (useMargin: boolean = true) => {
12
16
  const totalGutterSize = gutterSize * (numberOfColumns - 1);
13
17
  const sizePerSpan = (parentWidth - totalGutterSize) / numberOfColumns;
14
18
 
19
+ /**
20
+ * get size of element with number span
21
+ * @param span
22
+ */
15
23
  const getSizeSpan = (span: number = numberOfColumns): number => {
16
24
  return span * sizePerSpan + (span - 1) * gutterSize;
17
25
  };
@@ -25,6 +33,12 @@ const useGridSystem = (useMargin: boolean = true) => {
25
33
  getSizeSpan,
26
34
  };
27
35
  };
36
+
37
+ /**
38
+ * validate children type
39
+ * @param children
40
+ * @param childrenType
41
+ */
28
42
  const validateChildren = (
29
43
  children:
30
44
  | React.ReactElement<any, string | React.JSXElementConstructor<any>>
@@ -1,8 +1,11 @@
1
1
  import React, {useContext} from 'react';
2
2
  import {StatusBar, StyleSheet, View} from 'react-native';
3
3
  import {ApplicationContext, NavigationButton} from './index';
4
- import {Styles} from '../Consts';
4
+ import {Colors, Styles} from '../Consts';
5
5
  import {Image} from '../Image';
6
+ import {HeaderBackgroundProps, TitleCustomProps} from './types';
7
+ import {useGridSystem} from '../Layout';
8
+ import {Text} from '../Text';
6
9
 
7
10
  const styles = StyleSheet.create({
8
11
  headerBackground: {
@@ -11,9 +14,24 @@ const styles = StyleSheet.create({
11
14
  position: 'absolute',
12
15
  aspectRatio: 375 / 154,
13
16
  },
17
+ headerTitleContainer: {
18
+ alignItems: 'center',
19
+ justifyContent: 'center',
20
+ },
21
+ avatar: {width: 36, height: 36, borderRadius: 18},
22
+ dotAvatar: {
23
+ position: 'absolute',
24
+ width: 12,
25
+ height: 12,
26
+ borderRadius: 6,
27
+ bottom: 0,
28
+ right: 0,
29
+ borderWidth: 1,
30
+ borderColor: Colors.black_01,
31
+ },
14
32
  });
15
33
 
16
- const HeaderBackground = () => {
34
+ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({image}) => {
17
35
  const {theme} = useContext(ApplicationContext);
18
36
  return (
19
37
  <View
@@ -21,15 +39,45 @@ const HeaderBackground = () => {
21
39
  Styles.flex,
22
40
  {backgroundColor: theme.colors.background.surface, overflow: 'hidden'},
23
41
  ]}>
24
- {theme.assets?.headerBackground && (
25
- <>
26
- <StatusBar barStyle="light-content" />
27
- <Image
28
- style={styles.headerBackground}
29
- source={{uri: theme.assets?.headerBackground}}
30
- />
31
- </>
32
- )}
42
+ <StatusBar
43
+ barStyle={image || theme.dark ? 'light-content' : 'dark-content'}
44
+ />
45
+ {image && <Image style={styles.headerBackground} source={{uri: image}} />}
46
+ </View>
47
+ );
48
+ };
49
+
50
+ const HeaderCustom: React.FC<TitleCustomProps> = ({
51
+ title,
52
+ subTitle,
53
+ image,
54
+ content,
55
+ tintColor,
56
+ dotColor,
57
+ }) => {
58
+ const {getSizeSpan} = useGridSystem();
59
+
60
+ const header = (
61
+ <View style={Styles.row}>
62
+ <View>
63
+ <Image source={{uri: image}} style={styles.avatar} />
64
+ {dotColor && (
65
+ <View style={[styles.dotAvatar, {backgroundColor: dotColor}]} />
66
+ )}
67
+ </View>
68
+ <View style={[Styles.flex, Styles.paddingHorizontal8]}>
69
+ <Text typography="title_xs" color={tintColor}>
70
+ {title}
71
+ </Text>
72
+ <Text typography="description_s" color={tintColor}>
73
+ {subTitle}
74
+ </Text>
75
+ </View>
76
+ </View>
77
+ );
78
+ return (
79
+ <View style={[styles.headerTitleContainer, {width: getSizeSpan(10)}]}>
80
+ {content ?? header}
33
81
  </View>
34
82
  );
35
83
  };
@@ -60,4 +108,4 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
60
108
  return <View style={Styles.headerRightButton}>{renderAction()}</View>;
61
109
  };
62
110
 
63
- export {HeaderBackground, HeaderRightAction};
111
+ export {HeaderBackground, HeaderRightAction, HeaderCustom};