@momo-kits/foundation 1.0.11 → 1.0.13

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/Assets/icon.json CHANGED
@@ -3934,5 +3934,14 @@
3934
3934
  },
3935
3935
  "ic_error": {
3936
3936
  "uri": "https://img.mservice.com.vn/app/img/kits/error_mess_icon.png"
3937
+ },
3938
+ "media_fail": {
3939
+ "uri": "https://static.momocdn.net/app/img/kits/media_fail.png"
3940
+ },
3941
+ "ic_checked": {
3942
+ "uri": "https://img.mservice.com.vn/app/img/kits/checked_ic.png"
3943
+ },
3944
+ "ic_minus": {
3945
+ "uri": "https://img.mservice.com.vn/app/img/kits/minus.png"
3937
3946
  }
3938
3947
  }
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 {Image} from '../Image';
14
+ import {Icon} from '../Icon';
14
15
 
15
16
  export interface ButtonProps extends TouchableOpacityProps {
16
17
  type?:
@@ -179,11 +180,7 @@ const Button: FC<ButtonProps> = ({
179
180
  styles.leading,
180
181
  {width: iconSize, height: iconSize, marginRight},
181
182
  ]}>
182
- <Image
183
- tintColor={color}
184
- source={{uri: iconLeft}}
185
- style={{width: iconSize, height: iconSize}}
186
- />
183
+ <Icon color={color} source={iconLeft} size={iconSize} />
187
184
  </View>
188
185
  );
189
186
  }
@@ -203,11 +200,7 @@ const Button: FC<ButtonProps> = ({
203
200
  styles.trailing,
204
201
  {width: iconSize, height: iconSize, marginLeft},
205
202
  ]}>
206
- <Image
207
- tintColor={color}
208
- source={{uri: iconRight}}
209
- style={{width: iconSize, height: iconSize}}
210
- />
203
+ <Icon color={color} source={iconRight} size={iconSize} />
211
204
  </View>
212
205
  );
213
206
  }
@@ -2,13 +2,10 @@ import React, {FC, useContext} from 'react';
2
2
  import {TouchableOpacity, View} from 'react-native';
3
3
  import {CheckBoxProps} from './types';
4
4
  import styles from './styles';
5
- import Image from 'react-native-fast-image';
6
5
  import {ApplicationContext} from '../Navigation';
7
6
  import {Text} from '../Text';
7
+ import {Icon} from '../Icon';
8
8
 
9
- const IC_INDETERMINATED = 'https://img.mservice.com.vn/app/img/kits/minus.png';
10
- const IC_CHECKED_DEFAULT =
11
- 'https://img.mservice.com.vn/app/img/kits/checked_ic.png';
12
9
  const CheckBox: FC<CheckBoxProps> = props => {
13
10
  const {theme} = useContext(ApplicationContext);
14
11
  const {value, disabled, onChange, style, label, indeterminated} = props;
@@ -21,11 +18,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
21
18
  ? theme.colors.primary
22
19
  : theme.colors.background.surface;
23
20
 
24
- let iconSource = value ? IC_CHECKED_DEFAULT : undefined;
25
-
26
- if (indeterminated) {
27
- iconSource = IC_INDETERMINATED;
28
- }
21
+ let iconSource = indeterminated ? 'ic_minus' : 'ic_checked';
29
22
 
30
23
  if (disabled) {
31
24
  borderColor = haveValue
@@ -47,7 +40,13 @@ const CheckBox: FC<CheckBoxProps> = props => {
47
40
  disabled={disabled}
48
41
  style={[style, styles.container]}>
49
42
  <View style={[checkboxStyle, styles.checkbox]}>
50
- <Image style={styles.icon} source={{uri: iconSource}} />
43
+ {haveValue && (
44
+ <Icon
45
+ color={theme.colors.background.surface}
46
+ size={20}
47
+ source={iconSource}
48
+ />
49
+ )}
51
50
  </View>
52
51
  <Text typography={'description_default'}>{label}</Text>
53
52
  </TouchableOpacity>
@@ -12,5 +12,4 @@ export default StyleSheet.create({
12
12
  alignItems: 'center',
13
13
  },
14
14
  container: {flexDirection: 'row'},
15
- icon: {width: 20, height: 20},
16
15
  });
package/Icon/index.tsx CHANGED
@@ -20,6 +20,7 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
20
20
 
21
21
  return (
22
22
  <Image
23
+ loading={false}
23
24
  source={getIconSource()}
24
25
  style={[style, {width: size, height: size}]}
25
26
  tintColor={color ?? theme.colors.text.default}
package/Image/index.tsx CHANGED
@@ -10,11 +10,12 @@ import {FastImagePropsWithoutStyle} from './types';
10
10
 
11
11
  export interface ImageProps extends FastImagePropsWithoutStyle {
12
12
  style?: StyleProp<ViewStyle>;
13
+ loading?: boolean;
13
14
  }
14
15
 
15
16
  const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
16
17
  const {theme} = useContext(ApplicationContext);
17
- const [loading, setLoading] = useState(typeof source === 'object');
18
+ const [loading, setLoading] = useState(rest.loading);
18
19
  const [fail, setFail] = useState(false);
19
20
 
20
21
  /**
@@ -29,7 +30,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
29
30
  if (fail) {
30
31
  content = (
31
32
  <View style={Styles.flexCenter}>
32
- <Icon source="error-outline" />
33
+ <Icon source="media_fail" color={theme.colors.text.disable} />
33
34
  </View>
34
35
  );
35
36
  }
@@ -54,7 +55,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
54
55
  style={styles.image}
55
56
  onLoad={() => {
56
57
  setFail(false);
57
- setLoading(true);
58
+ setLoading(rest.loading);
58
59
  }}
59
60
  onLoadEnd={() => setLoading(false)}
60
61
  onError={() => setFail(true)}
@@ -64,4 +65,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
64
65
  );
65
66
  };
66
67
 
68
+ Image.defaultProps = {
69
+ loading: true,
70
+ };
67
71
  export {Image};
package/Input/Input.tsx CHANGED
@@ -113,11 +113,7 @@ const Input: FC<InputProps> = ({
113
113
  </TouchableOpacity>
114
114
  )}
115
115
  {icon && (
116
- <Image
117
- tintColor={iconTintColor}
118
- source={{uri: icon}}
119
- style={styles.icon}
120
- />
116
+ <Icon icon={iconTintColor} source={icon} style={styles.icon} />
121
117
  )}
122
118
  </View>
123
119
  </View>
@@ -116,13 +116,7 @@ const InputMoney: FC<InputMoneyProps> = ({
116
116
  />
117
117
  </TouchableOpacity>
118
118
  )}
119
- {icon && (
120
- <Image
121
- tintColor={iconTintColor}
122
- source={{uri: icon}}
123
- style={styles.icon}
124
- />
125
- )}
119
+ {icon && <Icon color={iconTintColor} source={icon} />}
126
120
  </View>
127
121
  </View>
128
122
  );
@@ -7,16 +7,12 @@ import {
7
7
  View,
8
8
  } from 'react-native';
9
9
  import {InputSearchProps} from './index';
10
- import {getBorderColor} from './common';
11
10
  import {ApplicationContext} from '../Navigation';
12
11
  import styles from './styles';
13
12
  import {Icon} from '../Icon';
14
- import {Image} from '../Image';
15
13
  import {Text} from '../Text';
16
14
 
17
15
  const InputSearch: FC<InputSearchProps> = ({
18
- errorMessage,
19
- disabled,
20
16
  placeholder,
21
17
  onFocus,
22
18
  onBlur,
@@ -27,6 +23,7 @@ const InputSearch: FC<InputSearchProps> = ({
27
23
  buttonText = 'Hủy',
28
24
  showButtonText = true,
29
25
  showIcon = true,
26
+ showBorder = true,
30
27
  style,
31
28
  ...props
32
29
  }) => {
@@ -54,20 +51,25 @@ const InputSearch: FC<InputSearchProps> = ({
54
51
  onChangeText?.(text);
55
52
  };
56
53
 
54
+ const getBorderColor = () => {
55
+ let borderColor = showBorder
56
+ ? theme.colors.border.default
57
+ : theme.colors.background.surface;
58
+
59
+ if (focused) {
60
+ borderColor = theme.colors.primary;
61
+ }
62
+
63
+ return {borderColor};
64
+ };
65
+
57
66
  const renderInputView = () => {
58
- const disabledColor = theme.colors.text.disable;
59
67
  let textColor = theme.colors.text.default;
60
68
  let placeholderColor = theme.colors.text.hint;
61
69
 
62
- if (disabled) {
63
- textColor = disabledColor;
64
- placeholderColor = disabledColor;
65
- iconTintColor = disabledColor;
66
- }
67
70
  return (
68
71
  <TextInput
69
72
  {...props}
70
- editable={!disabled}
71
73
  textAlignVertical="top"
72
74
  ref={inputRef}
73
75
  style={[
@@ -112,9 +114,9 @@ const InputSearch: FC<InputSearchProps> = ({
112
114
  },
113
115
  ]}
114
116
  />
115
- <Image
116
- tintColor={iconTintColor}
117
- source={{uri: icon}}
117
+ <Icon
118
+ color={iconTintColor}
119
+ source={icon}
118
120
  style={styles.iconSearchInput}
119
121
  />
120
122
  </View>
@@ -126,9 +128,11 @@ const InputSearch: FC<InputSearchProps> = ({
126
128
  <View style={[style, styles.searchInputContainer]}>
127
129
  <View
128
130
  style={[
129
- getBorderColor(focused, errorMessage, disabled),
131
+ getBorderColor(),
130
132
  styles.searchInputWrapper,
131
- {backgroundColor: theme.colors.background.surface},
133
+ {
134
+ backgroundColor: theme.colors.background.surface,
135
+ },
132
136
  ]}>
133
137
  <Icon
134
138
  source={'navigation_search'}
package/Input/common.tsx CHANGED
@@ -100,9 +100,10 @@ export const FloatingView: FC<FloatingViewProps> = ({
100
100
  )}
101
101
  </Text>
102
102
  {floatingIcon && (
103
- <Image
104
- tintColor={floatingIconTintColor}
105
- source={{uri: floatingIcon}}
103
+ <Icon
104
+ color={floatingIconTintColor}
105
+ source={floatingIcon}
106
+ size={16}
106
107
  style={styles.floatingIcon}
107
108
  />
108
109
  )}
package/Input/index.tsx CHANGED
@@ -20,17 +20,21 @@ type InputPropsWithoutSizeAndIcon = Omit<
20
20
  InputProps,
21
21
  'size' | 'icon' | 'iconColor'
22
22
  >;
23
- type InputPropsWithoutRequiredAndSize = Omit<InputProps, 'required' | 'size'>;
23
+ type InputPropsOmitForSearch = Omit<
24
+ InputProps,
25
+ 'required' | 'size' | 'errorMessage' | 'disabled'
26
+ >;
24
27
  type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
25
28
 
26
29
  export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
27
30
  height?: number;
28
31
  }
29
32
 
30
- export interface InputSearchProps extends InputPropsWithoutRequiredAndSize {
33
+ export interface InputSearchProps extends InputPropsOmitForSearch {
31
34
  buttonText?: string;
32
35
  showButtonText?: boolean;
33
36
  showIcon?: boolean;
37
+ showBorder?: boolean;
34
38
  }
35
39
 
36
40
  export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
package/Input/styles.ts CHANGED
@@ -25,7 +25,7 @@ export default StyleSheet.create({
25
25
  paddingHorizontal: Spacing.S,
26
26
  flexDirection: 'row',
27
27
  },
28
- floatingIcon: {width: 16, height: 16, marginLeft: Spacing.XS},
28
+ floatingIcon: {marginLeft: Spacing.XS},
29
29
  errorIcon: {marginRight: Spacing.XS},
30
30
  errorView: {
31
31
  flexDirection: 'row',
@@ -104,8 +104,6 @@ export default StyleSheet.create({
104
104
  alignItems: 'center',
105
105
  },
106
106
  iconSearchInput: {
107
- width: 24,
108
- height: 24,
109
107
  marginLeft: Spacing.S,
110
108
  },
111
109
  searchInputContainer: {flexDirection: 'row', alignItems: 'center'},
@@ -1,10 +1,11 @@
1
- import {KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native';
1
+ import {Animated, KeyboardAvoidingView, Platform, View} from 'react-native';
2
2
  import {useHeaderHeight} from '@react-navigation/stack';
3
3
  import {SafeAreaView} from 'react-native-safe-area-context';
4
4
  import React from 'react';
5
5
  import {ScreenContainerProps} from '../Navigation/types';
6
6
  import {Spacing, Styles} from '../Consts';
7
7
  import {ScreenSection, validateChildren} from './index';
8
+ import {Image} from '../Image';
8
9
 
9
10
  const ScreenContainer: React.FC<ScreenContainerProps> = ({
10
11
  children,
@@ -12,11 +13,12 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
12
13
  enableKeyboardAvoidingView,
13
14
  scrollable,
14
15
  scrollViewProps,
16
+ headerImage,
15
17
  }) => {
16
18
  let Component: any = View;
17
19
  const headerHeight = useHeaderHeight();
18
20
  if (scrollable) {
19
- Component = ScrollView;
21
+ Component = Animated.ScrollView;
20
22
  }
21
23
 
22
24
  /**
@@ -52,6 +54,14 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
52
54
  android: undefined,
53
55
  })}>
54
56
  <Component {...scrollViewProps} style={Styles.flex}>
57
+ {headerImage && (
58
+ <Image
59
+ source={{
60
+ uri: headerImage,
61
+ }}
62
+ style={{width: '100%', height: 300}}
63
+ />
64
+ )}
55
65
  {renderContent()}
56
66
  </Component>
57
67
  </KeyboardAvoidingView>
@@ -1,8 +1,7 @@
1
1
  import React, {FC} from 'react';
2
- import {View} from 'react-native';
3
- import {BottomTabItemProps, BottomTabProps} from './types';
2
+ import {BottomTabProps} from './types';
4
3
  import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
5
- import {Icon} from '@momo-kits/foundation';
4
+ import {Icon} from '../Icon';
6
5
 
7
6
  const Tab = createBottomTabNavigator();
8
7
 
@@ -11,11 +10,10 @@ const BottomTab: FC<BottomTabProps> = ({tabs}) => {
11
10
  <Tab.Navigator>
12
11
  {tabs.map((item, index) => {
13
12
  return (
14
- // @ts-ignore
15
13
  <Tab.Screen
16
14
  key={`${item.label}-${index}`}
17
15
  name={item.label}
18
- component={item.component}
16
+ component={item.screen}
19
17
  options={{
20
18
  tabBarLabel: item.label,
21
19
  tabBarBadge: item?.badgeLabel,
@@ -1,5 +1,6 @@
1
1
  import React, {useContext} from 'react';
2
2
  import {
3
+ Animated,
3
4
  DeviceEventEmitter,
4
5
  StatusBar,
5
6
  StyleSheet,
@@ -47,7 +48,6 @@ const styles = StyleSheet.create({
47
48
  marginLeft: Spacing.S,
48
49
  padding: Spacing.XS,
49
50
  height: 28,
50
- borderWidth: 0.5,
51
51
  borderRadius: 14,
52
52
  borderColor: '#00000066',
53
53
  justifyContent: 'center',
@@ -62,15 +62,19 @@ const styles = StyleSheet.create({
62
62
  headerLeft: {
63
63
  marginLeft: 12,
64
64
  },
65
+ title: {fontSize: 15, lineHeight: 22, fontWeight: '600'},
65
66
  });
66
67
 
67
- const HeaderTitle = (props: any) => {
68
+ const HeaderTitle: React.FC<any> = props => {
69
+ const opacity = props.animatedValue?.interpolate({
70
+ inputRange: [0, 200],
71
+ outputRange: [0, 1],
72
+ extrapolate: 'clamp',
73
+ });
68
74
  return (
69
- <Text
75
+ <Animated.Text
70
76
  {...props}
71
- typography="header_default"
72
- weight="bold"
73
- color={props.tintColor}
77
+ style={[styles.title, {opacity, color: props.tintColor}]}
74
78
  />
75
79
  );
76
80
  };
@@ -98,19 +102,28 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
98
102
  const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
99
103
  image,
100
104
  backgroundColor,
105
+ animatedValue,
101
106
  }) => {
102
107
  const {theme} = useContext(ApplicationContext);
103
108
  let headerImage = theme.assets?.headerBackground;
104
109
  if (image === null) {
105
110
  headerImage = undefined;
106
111
  }
112
+ const opacity = animatedValue?.interpolate({
113
+ inputRange: [0, 200],
114
+ outputRange: [0, 1],
115
+ extrapolate: 'clamp',
116
+ });
107
117
  return (
108
- <View
118
+ <Animated.View
109
119
  style={[
110
120
  Styles.flex,
111
121
  {
112
122
  backgroundColor: backgroundColor ?? theme.colors.background.default,
113
123
  overflow: 'hidden',
124
+ borderBottomWidth: headerImage ? 0 : 1,
125
+ borderColor: theme.colors.border.default,
126
+ opacity,
114
127
  },
115
128
  ]}>
116
129
  <StatusBar
@@ -119,7 +132,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
119
132
  {headerImage && (
120
133
  <Image style={styles.headerBackground} source={{uri: headerImage}} />
121
134
  )}
122
- </View>
135
+ </Animated.View>
123
136
  );
124
137
  };
125
138
 
@@ -193,15 +206,13 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
193
206
 
194
207
  return (
195
208
  <View style={styles.headerRightButton}>
196
- <NavigationButton
197
- icon="addFavorite"
198
- tintColor={tintColor}
199
- onPress={() => {}}
200
- />
201
209
  <View
202
210
  style={[
203
211
  styles.toolkitContainer,
204
- {backgroundColor: backgroundColor ?? '#00000066'},
212
+ {
213
+ backgroundColor: backgroundColor ?? '#00000066',
214
+ borderWidth: backgroundColor ? 0.5 : 0,
215
+ },
205
216
  ]}>
206
217
  <TouchableOpacity>
207
218
  <Icon color={tintColor} source="navigation_more_horiz" size={20} />
@@ -23,7 +23,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
23
23
  styles.container,
24
24
  {
25
25
  backgroundColor: backgroundColor ?? '#00000066',
26
- borderWidth: useBorder ? 0.5 : 0,
26
+ borderWidth: useBorder && backgroundColor ? 0.5 : 0,
27
27
  },
28
28
  ]}
29
29
  onPress={onPress}>
@@ -22,8 +22,9 @@ const StackScreen: React.FC<any> = props => {
22
22
  if (options) {
23
23
  params.navigation.setOptions(options);
24
24
  }
25
- }, [navigation, options]);
25
+ }, [options]);
26
26
 
27
+ console.log(params);
27
28
  return <Component {...params} />;
28
29
  };
29
30
 
@@ -1,5 +1,5 @@
1
- import {ScrollViewProps, ViewProps} from 'react-native';
2
- import React, {ComponentType, ReactElement} from 'react';
1
+ import {Animated, ScrollViewProps, ViewProps} from 'react-native';
2
+ import React from 'react';
3
3
  import Navigator from './Navigator';
4
4
 
5
5
  export type Theme = {
@@ -73,6 +73,7 @@ export interface ScreenContainerProps extends ViewProps {
73
73
  enableKeyboardAvoidingView?: boolean;
74
74
  scrollable: boolean;
75
75
  scrollViewProps?: ScrollViewProps;
76
+ headerImage?: string;
76
77
  }
77
78
 
78
79
  export type ScreenParams = {
@@ -107,11 +108,13 @@ export type NavigationOptions = {
107
108
  headerTitleAlign?: 'left' | 'center';
108
109
  customTitle?: TitleCustomProps;
109
110
  headerRight?: (props?: any) => React.ReactElement;
111
+ animatedValue?: Animated.Value;
110
112
  };
111
113
 
112
114
  export type HeaderBackgroundProps = {
113
115
  image?: string | null;
114
116
  backgroundColor?: string | null;
117
+ animatedValue?: Animated.Value;
115
118
  };
116
119
 
117
120
  export type TitleCustomProps = {
@@ -128,7 +131,7 @@ export type BottomTabItemProps = {
128
131
  icon: string;
129
132
  showDot?: boolean;
130
133
  badgeLabel?: string;
131
- component: ComponentType<any> | undefined;
134
+ screen: React.ComponentType<any>;
132
135
  };
133
136
 
134
137
  export type BottomTabProps = {
@@ -73,43 +73,58 @@ const getModalOptions = (): StackNavigationOptions => {
73
73
  };
74
74
 
75
75
  const getOptions = (params: NavigationOptions, theme: Theme) => {
76
- let surfaceTheme: {};
77
- let titleTheme: {};
76
+ let backgroundProps = {};
77
+ let titleProps = {};
78
+ let options = {};
78
79
 
79
80
  if (params.surface == true) {
80
- surfaceTheme = {
81
- headerBackground: () => (
82
- <HeaderBackground
83
- image={null}
84
- backgroundColor={theme.colors.background.surface}
85
- />
86
- ),
81
+ options = {
82
+ ...options,
87
83
  ...getTintColor({
88
84
  ...theme,
89
85
  assets: {...theme.assets, headerBackground: undefined},
90
86
  }),
91
87
  };
92
- } else {
93
- surfaceTheme = {
94
- headerBackground: HeaderBackground,
95
- ...getTintColor(theme),
88
+ backgroundProps = {
89
+ ...backgroundProps,
90
+ image: null,
91
+ backgroundColor: theme.colors.background.surface,
96
92
  };
93
+ } else {
94
+ backgroundProps = {};
95
+ options = {...options, ...getTintColor(theme)};
96
+ }
97
+
98
+ if (params.animatedValue) {
99
+ backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
100
+ titleProps = {...titleProps, animatedValue: params.animatedValue};
101
+ options = {...options, headerTransparent: true};
102
+ } else {
103
+ options = {...options, headerTransparent: false};
97
104
  }
98
105
 
99
106
  if (params.customTitle) {
100
- titleTheme = {
107
+ options = {
108
+ ...options,
101
109
  headerTitleAlign: 'left',
102
110
  headerTitle: (props: any) => {
103
111
  return <HeaderCustom {...params.customTitle} {...props} />;
104
112
  },
105
113
  };
106
114
  } else {
107
- titleTheme = {
108
- headerTitle: HeaderTitle,
115
+ options = {
116
+ ...options,
117
+ headerTitle: (props: any) => {
118
+ return <HeaderTitle {...titleProps} {...props} />;
119
+ },
109
120
  };
110
121
  }
111
122
 
112
- return {...params, ...surfaceTheme, ...titleTheme};
123
+ return {
124
+ ...params,
125
+ ...options,
126
+ headerBackground: () => <HeaderBackground {...backgroundProps} />,
127
+ };
113
128
  };
114
129
 
115
130
  export {getStackOptions, getDialogOptions, getModalOptions, getOptions};
@@ -3,7 +3,7 @@ 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 {Radius} from '../Consts';
6
+ import {Radius, Spacing} from '../Consts';
7
7
  import {Icon} from '../Icon';
8
8
 
9
9
  const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
@@ -55,11 +55,10 @@ const styles = StyleSheet.create({
55
55
  aspectRatio: 0.72,
56
56
  },
57
57
  iconCloseContainer: {
58
- position: 'absolute',
59
58
  width: '100%',
60
59
  flexDirection: 'row',
61
60
  justifyContent: 'center',
62
- bottom: -36,
61
+ marginTop: Spacing.L,
63
62
  },
64
63
  iconClose: {
65
64
  width: 20,
@@ -1,31 +1,29 @@
1
- import React, {useContext, useEffect, useMemo, useRef} from 'react';
2
- import {Animated, Platform, useWindowDimensions, View} from 'react-native';
1
+ import React, {useEffect, useMemo, useRef, useState} from 'react';
2
+ import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
3
3
  import LinearGradient from 'react-native-linear-gradient';
4
4
  import {SkeletonTypes} from './types';
5
- import {ApplicationContext} from '../Navigation';
6
5
  import {Styles} from '../Consts';
7
6
  import styles from './styles';
7
+ import {Colors} from '@momo-kits/foundation';
8
+
8
9
  const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
9
- const {width} = useWindowDimensions();
10
- const {theme} = useContext(ApplicationContext);
11
- const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
10
+ const [width, setWidth] = useState(0);
11
+ const PRIMARY_COLOR = Colors.black_05;
12
+ const HIGHLIGHT_COLOR1 = Colors.black_05;
13
+ const HIGHLIGHT_COLOR2 = Colors.black_03;
14
+ const beginShimmerPosition = useRef(new Animated.Value(0)).current;
12
15
 
13
- const shimmerColors = [
14
- theme.colors.text.disable + '40',
15
- theme.colors.text.disable + '80',
16
- theme.colors.text.disable,
17
- ];
18
- const location = [0.3, 0.5, 0.7];
16
+ const shimmerColors = [HIGHLIGHT_COLOR1, HIGHLIGHT_COLOR2, HIGHLIGHT_COLOR1];
19
17
  const linearTranslate = beginShimmerPosition.interpolate({
20
- inputRange: [-1, 1],
21
- outputRange: [0, width],
18
+ inputRange: [0, 1],
19
+ outputRange: [-width, width],
22
20
  });
23
21
  const animatedValue = useMemo(() => {
24
22
  return Animated.loop(
25
23
  Animated.timing(beginShimmerPosition, {
26
24
  toValue: 1,
27
- delay: 0,
28
25
  duration: 1000,
26
+ easing: Easing.linear,
29
27
  useNativeDriver: Platform.OS !== 'web',
30
28
  }),
31
29
  );
@@ -38,23 +36,33 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
38
36
  };
39
37
  }, [animatedValue]);
40
38
 
39
+ const onLayout = (newWidth: number) => {
40
+ if (newWidth !== width) {
41
+ setWidth(newWidth);
42
+ }
43
+ };
41
44
  return (
42
45
  <View style={[styles.container, style]}>
43
- <View style={[Styles.flex, {backgroundColor: shimmerColors[0]}]}>
46
+ <View
47
+ onLayout={e => onLayout(e.nativeEvent.layout.width)}
48
+ style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
44
49
  <Animated.View
45
- style={[Styles.flex, {transform: [{translateX: linearTranslate}]}]}>
50
+ style={{
51
+ transform: [{translateX: linearTranslate}],
52
+ width: '60%',
53
+ height: '100%',
54
+ }}>
46
55
  <LinearGradient
56
+ style={[StyleSheet.absoluteFill]}
47
57
  colors={shimmerColors}
48
- style={[Styles.flex, {width: width}]}
49
58
  start={{
50
- x: -1,
51
- y: 0.5,
59
+ x: 0,
60
+ y: 0,
52
61
  }}
53
62
  end={{
54
- x: 2,
55
- y: 0.5,
63
+ x: 1,
64
+ y: 0,
56
65
  }}
57
- locations={location}
58
66
  />
59
67
  </Animated.View>
60
68
  </View>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {