@momo-kits/foundation 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Image/index.tsx CHANGED
@@ -3,7 +3,7 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
3
3
  import FastImage from 'react-native-fast-image';
4
4
  import styles from './styles';
5
5
  import {ApplicationContext} from '../Navigation';
6
- import {ContentLoader} from '../ContentLoader';
6
+ import {Skeleton} from '../Skeleton';
7
7
  import {Icon} from '../Icon';
8
8
  import {Styles} from '../Consts';
9
9
  import {FastImagePropsWithoutStyle} from './types';
@@ -24,7 +24,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
24
24
  const renderContent = () => {
25
25
  if (loading || fail) {
26
26
  let content = (
27
- <ContentLoader style={[StyleSheet.absoluteFill, styles.image]} />
27
+ <Skeleton style={[StyleSheet.absoluteFill, styles.image]} />
28
28
  );
29
29
  if (fail) {
30
30
  content = (
package/Input/Input.tsx CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  import {ApplicationContext} from '../Navigation';
10
10
  import styles from './styles';
11
11
  import {Image} from '../Image';
12
- import {ErrorView, FloatingView, getBorderColor} from './common';
12
+ import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
13
13
  import {InputProps} from './index';
14
14
  import {Icon} from '../Icon';
15
15
 
@@ -27,6 +27,7 @@ const Input: FC<InputProps> = ({
27
27
  disabled,
28
28
  floatingIconColor,
29
29
  iconColor,
30
+ required,
30
31
  ...props
31
32
  }) => {
32
33
  const {theme} = useContext(ApplicationContext);
@@ -35,17 +36,12 @@ const Input: FC<InputProps> = ({
35
36
 
36
37
  const onClearText = () => {
37
38
  inputRef?.current?.clear();
39
+ _onChangeText('');
38
40
  };
39
41
 
40
42
  const _onChangeText = (text: string) => {
41
43
  onChangeText?.(text);
42
44
  };
43
- const getSizeStyle = () => {
44
- if (size === 'small') {
45
- return styles.smallContainer;
46
- }
47
- return styles.container;
48
- };
49
45
 
50
46
  const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
51
47
  setFocused(true);
@@ -72,7 +68,7 @@ const Input: FC<InputProps> = ({
72
68
  return (
73
69
  <View
74
70
  style={[
75
- getSizeStyle(),
71
+ getSizeStyle(size),
76
72
  getBorderColor(focused, errorMessage, disabled),
77
73
  styles.inputWrapper,
78
74
  {backgroundColor: theme.colors.background.surface},
@@ -81,6 +77,7 @@ const Input: FC<InputProps> = ({
81
77
  floatingValue={floatingValue}
82
78
  floatingIconColor={floatingIconColor}
83
79
  disabled={disabled}
80
+ required={required}
84
81
  floatingIcon={floatingIcon}
85
82
  />
86
83
  <View style={styles.inputView}>
@@ -95,6 +92,7 @@ const Input: FC<InputProps> = ({
95
92
  color: textColor,
96
93
  },
97
94
  ]}
95
+ textBreakStrategy="highQuality"
98
96
  value={value}
99
97
  onChangeText={_onChangeText}
100
98
  onFocus={_onFocus}
@@ -0,0 +1,139 @@
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 {Image} from '../Image';
12
+ import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
13
+ import {InputMoneyProps} from './index';
14
+ import {Icon} from '../Icon';
15
+ import {formatMoneyToNumber, formatNumberToMoney} from './utils';
16
+
17
+ const InputMoney: FC<InputMoneyProps> = ({
18
+ onChangeText,
19
+ floatingValue,
20
+ floatingIcon,
21
+ size = 'small',
22
+ onBlur,
23
+ onFocus,
24
+ errorMessage,
25
+ icon,
26
+ disabled,
27
+ floatingIconColor,
28
+ iconColor,
29
+ required,
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
+ };
49
+
50
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
51
+ setFocused(true);
52
+ onFocus?.(e);
53
+ };
54
+
55
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
56
+ setFocused(false);
57
+ onBlur?.(e);
58
+ };
59
+
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;
65
+
66
+ if (disabled) {
67
+ textColor = disabledColor;
68
+ placeholderColor = disabledColor;
69
+ iconTintColor = disabledColor;
70
+ }
71
+
72
+ return (
73
+ <View
74
+ style={[
75
+ getSizeStyle(size),
76
+ getBorderColor(focused, errorMessage, disabled),
77
+ styles.inputWrapper,
78
+ {backgroundColor: theme.colors.background.surface},
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
+ editable={!disabled}
91
+ textAlignVertical="top"
92
+ ref={inputRef}
93
+ keyboardType={'number-pad'}
94
+ style={[
95
+ styles.moneyInput,
96
+ {
97
+ color: textColor,
98
+ },
99
+ ]}
100
+ value={value}
101
+ onChangeText={_onChangeText}
102
+ onFocus={_onFocus}
103
+ onBlur={_onBlur}
104
+ selectionColor={theme.colors.primary}
105
+ placeholderTextColor={placeholderColor}
106
+ placeholder={'0đ'}
107
+ />
108
+ </View>
109
+ <View style={styles.iconView}>
110
+ {focused && (
111
+ <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
112
+ <Icon
113
+ source="24_navigation_close_circle_full"
114
+ size={16}
115
+ color={theme.colors.text.hint}
116
+ />
117
+ </TouchableOpacity>
118
+ )}
119
+ {icon && (
120
+ <Image
121
+ tintColor={iconTintColor}
122
+ source={{uri: icon}}
123
+ style={styles.icon}
124
+ />
125
+ )}
126
+ </View>
127
+ </View>
128
+ );
129
+ };
130
+
131
+ return (
132
+ <View style={styles.wrapper}>
133
+ {renderInputView()}
134
+ <ErrorView errorMessage={errorMessage} />
135
+ </View>
136
+ );
137
+ };
138
+
139
+ export default InputMoney;
@@ -6,7 +6,7 @@ import {
6
6
  TouchableOpacity,
7
7
  View,
8
8
  } from 'react-native';
9
- import {SearchInputProps} from './index';
9
+ import {InputSearchProps} from './index';
10
10
  import {getBorderColor} from './common';
11
11
  import {ApplicationContext} from '../Navigation';
12
12
  import styles from './styles';
@@ -14,7 +14,7 @@ import {Icon} from '../Icon';
14
14
  import {Image} from '../Image';
15
15
  import {Text} from '../Text';
16
16
 
17
- const SearchInput: FC<SearchInputProps> = ({
17
+ const InputSearch: FC<InputSearchProps> = ({
18
18
  errorMessage,
19
19
  disabled,
20
20
  placeholder,
@@ -47,6 +47,7 @@ const SearchInput: FC<SearchInputProps> = ({
47
47
 
48
48
  const onClearText = () => {
49
49
  inputRef?.current?.clear();
50
+ _onChangeText('');
50
51
  };
51
52
 
52
53
  const _onChangeText = (text: string) => {
@@ -148,4 +149,4 @@ const SearchInput: FC<SearchInputProps> = ({
148
149
  );
149
150
  };
150
151
 
151
- export default SearchInput;
152
+ export default InputSearch;
@@ -16,10 +16,10 @@ import {
16
16
  getBorderColor,
17
17
  MAX_LENGTH,
18
18
  } from './common';
19
- import {TextAreaProps} from './index';
19
+ import {InputTextAreaProps} from './index';
20
20
  import {Icon} from '../Icon';
21
21
 
22
- const TextArea: FC<TextAreaProps> = props => {
22
+ const InputTextArea: FC<InputTextAreaProps> = props => {
23
23
  const {theme} = useContext(ApplicationContext);
24
24
  const {
25
25
  errorMessage,
@@ -35,6 +35,7 @@ const TextArea: FC<TextAreaProps> = props => {
35
35
  height,
36
36
  placeholder,
37
37
  maxLength,
38
+ required,
38
39
  } = props;
39
40
 
40
41
  const [focused, setFocused] = useState(false);
@@ -43,6 +44,7 @@ const TextArea: FC<TextAreaProps> = props => {
43
44
 
44
45
  const onClearText = () => {
45
46
  inputRef?.current?.clear();
47
+ _onChangeText('');
46
48
  };
47
49
 
48
50
  const _onChangeText = (text: string) => {
@@ -94,6 +96,7 @@ const TextArea: FC<TextAreaProps> = props => {
94
96
  floatingIconColor={floatingIconColor}
95
97
  disabled={disabled}
96
98
  floatingIcon={floatingIcon}
99
+ required={required}
97
100
  />
98
101
  <View style={styles.rowArea}>
99
102
  <View style={styles.textAreaView}>
@@ -108,6 +111,7 @@ const TextArea: FC<TextAreaProps> = props => {
108
111
  },
109
112
  ]}
110
113
  maxLength={maxLength}
114
+ textBreakStrategy="highQuality"
111
115
  multiline={true}
112
116
  value={value}
113
117
  onChangeText={_onChangeText}
@@ -141,8 +145,8 @@ const TextArea: FC<TextAreaProps> = props => {
141
145
  );
142
146
  };
143
147
 
144
- TextArea.defaultProps = {
148
+ InputTextArea.defaultProps = {
145
149
  maxLength: MAX_LENGTH,
146
150
  };
147
151
 
148
- export default TextArea;
152
+ export default InputTextArea;
package/Input/common.tsx CHANGED
@@ -11,6 +11,7 @@ type FloatingViewProps = {
11
11
  floatingIconColor?: string;
12
12
  disabled?: boolean;
13
13
  floatingIcon?: string;
14
+ required?: boolean;
14
15
  };
15
16
 
16
17
  export const DEFAULT_HEIGHT = 112;
@@ -40,6 +41,12 @@ export const getBorderColor = (
40
41
  return {borderColor};
41
42
  };
42
43
 
44
+ export const getSizeStyle = (size?: 'small' | 'large') => {
45
+ if (size === 'small') {
46
+ return styles.smallContainer;
47
+ }
48
+ return styles.container;
49
+ };
43
50
  export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
44
51
  const {theme} = useContext(ApplicationContext);
45
52
  const errorColor = theme.colors.error.primary;
@@ -63,6 +70,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
63
70
  floatingIconColor,
64
71
  disabled,
65
72
  floatingIcon,
73
+ required,
66
74
  }) => {
67
75
  const {theme} = useContext(ApplicationContext);
68
76
 
@@ -85,6 +93,11 @@ export const FloatingView: FC<FloatingViewProps> = ({
85
93
  ]}>
86
94
  <Text color={floatingTextColor} typography={'label_s'}>
87
95
  {floatingValue}
96
+ {required && (
97
+ <Text typography={'label_s'} color={theme.colors.error.primary}>
98
+ *
99
+ </Text>
100
+ )}
88
101
  </Text>
89
102
  {floatingIcon && (
90
103
  <Image
package/Input/index.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import Input from './Input';
2
- import TextArea from './TextArea';
3
- import SearchInput from './SearchInput';
2
+ import InputTextArea from './InputTextArea';
3
+ import InputSearch from './InputSearch';
4
+ import InputMoney from './InputMoney';
4
5
  import {TextInputProps} from 'react-native';
5
6
 
6
7
  export interface InputProps extends TextInputProps {
@@ -12,20 +13,26 @@ export interface InputProps extends TextInputProps {
12
13
  disabled?: boolean;
13
14
  floatingIconColor?: string;
14
15
  iconColor?: string;
16
+ required?: boolean;
15
17
  }
16
18
 
17
- type InputPropsWithoutSize = Omit<InputProps, 'size'>;
19
+ type InputPropsWithoutSizeAndIcon = Omit<
20
+ InputProps,
21
+ 'size' | 'icon' | 'iconColor'
22
+ >;
23
+ type InputPropsWithoutRequiredAndSize = Omit<InputProps, 'required' | 'size'>;
24
+ type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
18
25
 
19
- export interface TextAreaProps extends TextInputProps, InputPropsWithoutSize {
26
+ export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
20
27
  height?: number;
21
28
  }
22
29
 
23
- export interface SearchInputProps
24
- extends TextInputProps,
25
- InputPropsWithoutSize {
30
+ export interface InputSearchProps extends InputPropsWithoutRequiredAndSize {
26
31
  buttonText?: string;
27
32
  showButtonText?: boolean;
28
33
  showIcon?: boolean;
29
34
  }
30
35
 
31
- export {Input, TextArea, SearchInput};
36
+ export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
37
+
38
+ export {Input, InputTextArea, InputSearch, InputMoney};
package/Input/styles.ts CHANGED
@@ -10,14 +10,12 @@ export default StyleSheet.create({
10
10
  container: {
11
11
  borderWidth: 1,
12
12
  borderRadius: Radius.S,
13
- marginBottom: Spacing.XS,
14
13
  height: 56,
15
14
  paddingVertical: 8,
16
15
  },
17
16
  smallContainer: {
18
17
  borderRadius: Radius.S,
19
18
  borderWidth: 1,
20
- marginBottom: Spacing.XS,
21
19
  height: 48,
22
20
  },
23
21
  floatingView: {
@@ -32,6 +30,7 @@ export default StyleSheet.create({
32
30
  errorView: {
33
31
  flexDirection: 'row',
34
32
  alignItems: 'center',
33
+ marginTop: Spacing.XS,
35
34
  },
36
35
  inputView: {
37
36
  justifyContent: 'space-between',
@@ -115,4 +114,11 @@ export default StyleSheet.create({
115
114
  width: 1,
116
115
  marginLeft: Spacing.XS,
117
116
  },
117
+ moneyInput: {
118
+ width: '100%',
119
+ paddingLeft: Spacing.M,
120
+ height: '100%',
121
+ fontSize: 20,
122
+ fontWeight: 'bold',
123
+ },
118
124
  });
package/Input/utils.ts ADDED
@@ -0,0 +1,63 @@
1
+ const formatNumberToMoney = (number: number, currency = '') => {
2
+ if (!number || isNaN(number) || Number(number) === 0) {
3
+ return `0${currency}`;
4
+ }
5
+
6
+ const array = [];
7
+ let result = '';
8
+ let isNegative = false;
9
+
10
+ if (number < 0) {
11
+ isNegative = true;
12
+ }
13
+
14
+ const numberString = Math.abs(number).toString();
15
+ if (numberString.length < 3) {
16
+ return numberString + currency;
17
+ }
18
+
19
+ let count = 0;
20
+ for (let i = numberString.length - 1; i >= 0; i -= 1) {
21
+ count += 1;
22
+ if (numberString[i] === '.' || numberString[i] === ',') {
23
+ array.push(',');
24
+ count = 0;
25
+ } else {
26
+ array.push(numberString[i]);
27
+ }
28
+ if (count === 3 && i >= 1) {
29
+ array.push('.');
30
+ count = 0;
31
+ }
32
+ }
33
+
34
+ for (let i = array.length - 1; i >= 0; i -= 1) {
35
+ result += array[i];
36
+ }
37
+
38
+ if (isNegative) {
39
+ result = `-${result}`;
40
+ }
41
+
42
+ return result + currency;
43
+ };
44
+
45
+ const formatMoneyToNumber = (money: string, currencyUnit: string) => {
46
+ if (money && money.length > 0) {
47
+ const moneyString = money
48
+ .replace(currencyUnit, '')
49
+ .replace(/,/g, '')
50
+ .replace(/đ/g, '')
51
+ .replace(/\./g, '')
52
+ .replace(/ /g, '');
53
+ const number = Number(moneyString);
54
+ if (isNaN(number)) {
55
+ return 0;
56
+ }
57
+ return number;
58
+ }
59
+
60
+ return Number(money);
61
+ };
62
+
63
+ export {formatMoneyToNumber, formatNumberToMoney};
@@ -11,6 +11,7 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
11
11
  edges,
12
12
  enableKeyboardAvoidingView,
13
13
  scrollable,
14
+ scrollViewProps,
14
15
  }) => {
15
16
  let Component: any = View;
16
17
  const headerHeight = useHeaderHeight();
@@ -50,7 +51,9 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
50
51
  ios: 'padding',
51
52
  android: undefined,
52
53
  })}>
53
- <Component style={Styles.flex}>{renderContent()}</Component>
54
+ <Component {...scrollViewProps} style={Styles.flex}>
55
+ {renderContent()}
56
+ </Component>
54
57
  </KeyboardAvoidingView>
55
58
  </SafeAreaView>
56
59
  );
@@ -0,0 +1,41 @@
1
+ import React, {FC} from 'react';
2
+ import {View} from 'react-native';
3
+ import {BottomTabItemProps, BottomTabProps} from './types';
4
+ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
5
+ import {Icon} from '@momo-kits/foundation';
6
+
7
+ const Tab = createBottomTabNavigator();
8
+
9
+ const BottomTab: FC<BottomTabProps> = ({tabs}) => {
10
+ return (
11
+ <Tab.Navigator>
12
+ {tabs.map((item, index) => {
13
+ return (
14
+ // @ts-ignore
15
+ <Tab.Screen
16
+ key={`${item.label}-${index}`}
17
+ name={item.label}
18
+ component={item.component}
19
+ options={{
20
+ tabBarLabel: item.label,
21
+ tabBarBadge: item?.badgeLabel,
22
+ tabBarBadgeStyle: {
23
+ borderColor: 'white',
24
+ borderWidth: 2,
25
+ fontSize: 10,
26
+ lineHeight: 14,
27
+ fontWeight: 'bold',
28
+ alignSelf: 'center',
29
+ },
30
+ tabBarIcon: ({color, size}) => (
31
+ <Icon source={item.icon} color={color} size={size} />
32
+ ),
33
+ }}
34
+ />
35
+ );
36
+ })}
37
+ </Tab.Navigator>
38
+ );
39
+ };
40
+
41
+ export default BottomTab;
@@ -88,19 +88,9 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
88
88
  }
89
89
  };
90
90
 
91
- let backgroundColor;
92
- if (tintColor != Colors.black_01) {
93
- backgroundColor = theme.colors.background.surface;
94
- }
95
-
96
91
  return (
97
92
  <View style={styles.headerLeft}>
98
- <NavigationButton
99
- icon="ic_back"
100
- tintColor={tintColor}
101
- backgroundColor={backgroundColor}
102
- onPress={goBack}
103
- />
93
+ <NavigationButton icon="ic_back" tintColor={tintColor} onPress={goBack} />
104
94
  </View>
105
95
  );
106
96
  };
@@ -206,7 +196,6 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
206
196
  <NavigationButton
207
197
  icon="addFavorite"
208
198
  tintColor={tintColor}
209
- backgroundColor={backgroundColor}
210
199
  onPress={() => {}}
211
200
  />
212
201
  <View
@@ -121,7 +121,11 @@ const BottomSheet: React.FC<BottomSheetParams> = ({navigation, route}) => {
121
121
  <BottomSheetModal
122
122
  ref={bottomSheetRef}
123
123
  snapPoints={snapPoints}
124
- onDismiss={navigation.pop}
124
+ onDismiss={() => {
125
+ if (mountedRef.current) {
126
+ navigation.pop();
127
+ }
128
+ }}
125
129
  handleComponent={null}
126
130
  backdropComponent={backdropComponent}>
127
131
  <View style={{paddingBottom: bottom}}>
@@ -3,6 +3,7 @@ import React, {useContext} from 'react';
3
3
  import {NavigationButtonProps} from './types';
4
4
  import {ApplicationContext} from './index';
5
5
  import {Icon} from '../Icon';
6
+ import {Colors} from '../Consts';
6
7
 
7
8
  const NavigationButton: React.FC<NavigationButtonProps> = ({
8
9
  icon,
@@ -12,6 +13,10 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
12
13
  useBorder = true,
13
14
  }) => {
14
15
  const {theme} = useContext(ApplicationContext);
16
+ if (!backgroundColor && tintColor != Colors.black_01) {
17
+ backgroundColor = theme.colors.background.surface;
18
+ }
19
+
15
20
  return (
16
21
  <TouchableOpacity
17
22
  style={[
@@ -2,6 +2,7 @@ import {NavigationContainer, ApplicationContext} from './NavigationContainer';
2
2
  import ScreenContainer from '../Layout/ScreenContainer';
3
3
  import NavigationButton from './NavigationButton';
4
4
  import {HeaderRightAction} from './Components';
5
+ import BottomTab from './BottomTab';
5
6
 
6
7
  export {
7
8
  NavigationContainer,
@@ -9,4 +10,5 @@ export {
9
10
  ScreenContainer,
10
11
  NavigationButton,
11
12
  HeaderRightAction,
13
+ BottomTab,
12
14
  };
@@ -1,5 +1,5 @@
1
- import {ViewProps} from 'react-native';
2
- import React from 'react';
1
+ import {ScrollViewProps, ViewProps} from 'react-native';
2
+ import React, {ComponentType, ReactElement} from 'react';
3
3
  import Navigator from './Navigator';
4
4
 
5
5
  export type Theme = {
@@ -72,6 +72,7 @@ export interface ScreenContainerProps extends ViewProps {
72
72
  edges?: any[];
73
73
  enableKeyboardAvoidingView?: boolean;
74
74
  scrollable: boolean;
75
+ scrollViewProps?: ScrollViewProps;
75
76
  }
76
77
 
77
78
  export type ScreenParams = {
@@ -121,3 +122,15 @@ export type TitleCustomProps = {
121
122
  tintColor?: string;
122
123
  content?: React.ReactNode;
123
124
  };
125
+
126
+ export type BottomTabItemProps = {
127
+ label: string;
128
+ icon: string;
129
+ showDot?: boolean;
130
+ badgeLabel?: string;
131
+ component: ComponentType<any> | undefined;
132
+ };
133
+
134
+ export type BottomTabProps = {
135
+ tabs: BottomTabItemProps[];
136
+ };
@@ -1,21 +1,40 @@
1
1
  import React, {useContext} from 'react';
2
- import {StyleSheet, View} from 'react-native';
2
+ import {StyleSheet, TouchableOpacity, View} from 'react-native';
3
3
  import {PopupPromotionProps} from './types';
4
4
  import {ApplicationContext} from '../Navigation';
5
5
  import {Image} from '../Image';
6
- import {Button} from '../Button';
7
- import {Spacing} from '../Consts';
6
+ import {Radius} from '../Consts';
7
+ import {Icon} from '../Icon';
8
8
 
9
- const PopupPromotion: React.FC<PopupPromotionProps> = ({image, primary}) => {
9
+ const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
10
10
  const {theme, navigator} = useContext(ApplicationContext);
11
11
 
12
12
  /**
13
- * on action popup
14
- * @param callback
13
+ * build close action
15
14
  */
16
- const onAction = (callback?: () => void) => {
17
- navigator?.pop();
18
- callback?.();
15
+ const buildCloseIcon = () => {
16
+ return (
17
+ <View style={styles.iconCloseContainer}>
18
+ <TouchableOpacity
19
+ onPress={() => {
20
+ navigator?.pop();
21
+ onClose?.();
22
+ }}
23
+ style={[
24
+ styles.iconClose,
25
+ {
26
+ backgroundColor: theme.colors.text.default,
27
+ borderColor: theme.colors.background.surface,
28
+ },
29
+ ]}>
30
+ <Icon
31
+ source="navigation_close"
32
+ color={theme.colors.background.surface}
33
+ size={14}
34
+ />
35
+ </TouchableOpacity>
36
+ </View>
37
+ );
19
38
  };
20
39
 
21
40
  return (
@@ -26,37 +45,34 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({image, primary}) => {
26
45
  uri: image,
27
46
  }}
28
47
  />
29
- <View style={styles.actionContainer}>
30
- <Button
31
- title={primary?.title}
32
- onPress={() => {
33
- onAction(primary?.onPress);
34
- }}
35
- />
36
- </View>
48
+ {buildCloseIcon()}
37
49
  </>
38
50
  );
39
51
  };
40
52
 
41
53
  const styles = StyleSheet.create({
42
54
  container: {
43
- aspectRatio: 0.66,
55
+ aspectRatio: 0.72,
44
56
  },
45
- actionContainer: {
57
+ iconCloseContainer: {
46
58
  position: 'absolute',
47
- bottom: 0,
48
59
  width: '100%',
49
- paddingVertical: Spacing.XL,
50
- paddingHorizontal: Spacing.L,
60
+ flexDirection: 'row',
61
+ justifyContent: 'center',
62
+ bottom: -36,
63
+ },
64
+ iconClose: {
65
+ width: 20,
66
+ height: 20,
67
+ alignItems: 'center',
68
+ justifyContent: 'center',
69
+ borderRadius: Radius.M,
70
+ borderWidth: 2,
51
71
  },
52
72
  });
53
73
 
54
74
  PopupPromotion.defaultProps = {
55
75
  image: 'https://google.com',
56
- primary: {
57
- title: 'Primary',
58
- onPress: () => {},
59
- },
60
76
  };
61
77
 
62
78
  export default PopupPromotion;
package/Popup/types.ts CHANGED
@@ -11,7 +11,7 @@ export type PopupNotifyProps = {
11
11
 
12
12
  export type PopupPromotionProps = {
13
13
  image: string;
14
- primary: PopupAction;
14
+ onClose?: () => void;
15
15
  };
16
16
 
17
17
  type PopupAction = {
package/Radio/index.tsx CHANGED
@@ -17,12 +17,24 @@ const Radio: FC<RadioProps> = ({
17
17
  }) => {
18
18
  const {theme} = useContext(ApplicationContext);
19
19
  const selected = value === groupValue;
20
- const borderWidth = selected ? 6 : 2;
21
- let borderColor = selected ? theme.colors.primary : theme.colors.text.default;
20
+ let disabledStyle = {};
21
+ let checkBoxStyle = {
22
+ borderWidth: 2,
23
+ borderColor: theme.colors.text.default,
24
+ };
25
+
26
+ if (selected) {
27
+ checkBoxStyle = {
28
+ borderWidth: 6,
29
+ borderColor: theme.colors.primary,
30
+ };
31
+ }
22
32
  if (disabled) {
23
- borderColor = selected
24
- ? theme.colors.background.tonal
25
- : theme.colors.text.disable;
33
+ disabledStyle = {
34
+ borderColor: selected
35
+ ? theme.colors.background.tonal
36
+ : theme.colors.text.disable,
37
+ };
26
38
  }
27
39
 
28
40
  return (
@@ -39,7 +51,9 @@ const Radio: FC<RadioProps> = ({
39
51
  <View
40
52
  style={[
41
53
  styles.radio,
42
- {borderWidth, borderColor, marginRight: !!label ? Spacing.XS : 0},
54
+ checkBoxStyle,
55
+ disabledStyle,
56
+ {marginRight: !!label ? Spacing.XS : 0},
43
57
  ]}
44
58
  />
45
59
  {!!label && <Text typography={'description_default'}>{label}</Text>}
@@ -1,11 +1,11 @@
1
1
  import React, {useContext, useEffect, useMemo, useRef} from 'react';
2
2
  import {Animated, Platform, useWindowDimensions, View} from 'react-native';
3
3
  import LinearGradient from 'react-native-linear-gradient';
4
- import {ContentLoaderTypes} from './types';
4
+ import {SkeletonTypes} from './types';
5
5
  import {ApplicationContext} from '../Navigation';
6
6
  import {Styles} from '../Consts';
7
7
  import styles from './styles';
8
- const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
8
+ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
9
9
  const {width} = useWindowDimensions();
10
10
  const {theme} = useContext(ApplicationContext);
11
11
  const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
@@ -62,6 +62,4 @@ const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
62
62
  );
63
63
  };
64
64
 
65
- ContentLoader.defaultProps = {};
66
-
67
- export {ContentLoader};
65
+ export {Skeleton};
@@ -0,0 +1,3 @@
1
+ export type SkeletonTypes = {
2
+ style?: object;
3
+ };
package/index.ts CHANGED
@@ -22,8 +22,8 @@ export * from './Icon/types';
22
22
  export * from './IconButton';
23
23
  export * from './Image';
24
24
  export * from './Image/types';
25
- export * from './ContentLoader';
26
- export * from './ContentLoader/types';
25
+ export * from './Skeleton';
26
+ export * from './Skeleton/types';
27
27
  export * from './CheckBox';
28
28
  export * from './CheckBox/types';
29
29
  export * from './Radio';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {
@@ -1,3 +0,0 @@
1
- export type ContentLoaderTypes = {
2
- style?: object;
3
- };
File without changes