@momo-kits/foundation 0.167.1-beta.13 → 0.167.1-beta.14

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 (56) hide show
  1. package/Application/BottomSheet.tsx +246 -42
  2. package/Application/BottomTab/BottomTabBar.tsx +6 -3
  3. package/Application/BottomTab/CustomBottomTabItem.tsx +3 -5
  4. package/Application/BottomTab/DuoBarCompression.tsx +135 -0
  5. package/Application/BottomTab/DuoTabBar.tsx +537 -0
  6. package/Application/BottomTab/index.tsx +145 -134
  7. package/Application/Components/DuoGlassBackground.tsx +158 -0
  8. package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
  9. package/Application/Components/HeaderAnimated.tsx +9 -3
  10. package/Application/Components/HeaderExtendHeader.tsx +70 -28
  11. package/Application/Components/HeaderLeft.tsx +38 -0
  12. package/Application/Components/HeaderRight.tsx +144 -9
  13. package/Application/Components/HeaderTitle.tsx +43 -8
  14. package/Application/Components/SearchHeader.tsx +20 -15
  15. package/Application/Components/SideBarButton.tsx +134 -0
  16. package/Application/ModalScreen.tsx +20 -2
  17. package/Application/NavigationContainer.tsx +22 -38
  18. package/Application/Navigator.ts +1 -3
  19. package/Application/StackScreen.tsx +2 -5
  20. package/Application/device.ts +52 -0
  21. package/Application/types.ts +10 -1
  22. package/Application/utils.tsx +10 -7
  23. package/Badge/Badge.tsx +2 -3
  24. package/Badge/BadgeDotAnimation.tsx +3 -3
  25. package/Button/index.tsx +11 -11
  26. package/Consts/theme.ts +3 -4
  27. package/Input/Input.tsx +3 -4
  28. package/Input/InputMoney.tsx +123 -195
  29. package/Input/InputOTP.tsx +9 -12
  30. package/Input/InputPhoneNumber.tsx +3 -7
  31. package/Input/InputSearch.tsx +17 -14
  32. package/Input/InputTextArea.tsx +3 -4
  33. package/Input/SystemTextInput.tsx +2 -3
  34. package/Input/TextTyping.tsx +11 -6
  35. package/Input/styles.ts +9 -0
  36. package/Input/utils.ts +2 -3
  37. package/Layout/Card.tsx +8 -26
  38. package/Layout/FloatingButton.tsx +3 -4
  39. package/Layout/Item.tsx +1 -10
  40. package/Layout/ReservedRegions.tsx +78 -0
  41. package/Layout/Screen.tsx +242 -48
  42. package/Layout/Section.tsx +5 -18
  43. package/Layout/index.ts +4 -4
  44. package/Layout/styles.ts +5 -0
  45. package/Layout/utils.ts +478 -5
  46. package/Pagination/Dot.tsx +3 -6
  47. package/Popup/PopupNotify.tsx +49 -28
  48. package/Popup/PopupPromotion.tsx +21 -8
  49. package/Popup/utils.ts +26 -0
  50. package/Radio/index.tsx +2 -3
  51. package/Text/index.tsx +4 -0
  52. package/Text/utils.ts +2 -3
  53. package/Title/index.tsx +8 -11
  54. package/Title/styles.ts +0 -1
  55. package/package.json +10 -7
  56. package/Layout/GridSystem.tsx +0 -137
@@ -1,10 +1,16 @@
1
1
  import React, { useContext, useRef } from 'react';
2
- import { Dimensions, StyleSheet, TouchableOpacity, View } from 'react-native';
2
+ import { StyleSheet, TouchableOpacity, View } from 'react-native';
3
3
  import { PopupPromotionProps } from './types';
4
4
  import { ApplicationContext, MiniAppContext } from '../Context';
5
5
  import { Image } from '../Image';
6
6
  import { Colors, Radius, Spacing } from '../Consts';
7
7
  import { Icon } from '../Icon';
8
+ import { usePopupMaxHeight, usePopupWidth } from './utils';
9
+
10
+ const ASPECT_RATIO = 0.72;
11
+ const ICON_CLOSE_SIZE = 20;
12
+ // close button row under the image: marginTop + vertical padding + icon
13
+ const CLOSE_ROW_HEIGHT = Spacing.S * 3 + ICON_CLOSE_SIZE;
8
14
 
9
15
  const PopupPromotion: React.FC<PopupPromotionProps> = ({
10
16
  image,
@@ -14,7 +20,14 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
14
20
  }) => {
15
21
  const context = useContext<any>(MiniAppContext);
16
22
  const { theme, navigator } = useContext(ApplicationContext);
17
- const { width: widthDevice } = Dimensions.get('window');
23
+ const popupWidth = usePopupWidth();
24
+ const maxHeight = usePopupMaxHeight();
25
+ // fit the portrait image by height when iPhone Duo leaves too little room
26
+ let imageWidth = popupWidth;
27
+ if (maxHeight !== undefined) {
28
+ const heightFitWidth = (maxHeight - CLOSE_ROW_HEIGHT) * ASPECT_RATIO;
29
+ imageWidth = Math.min(popupWidth, heightFitWidth);
30
+ }
18
31
  const closeAction = useRef('touch_outside');
19
32
 
20
33
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
@@ -69,7 +82,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
69
82
  return (
70
83
  <View
71
84
  accessibilityLabel={'popup_promotion'}
72
- style={showBaseLineDebug && styles.debugBaseLine}
85
+ style={[{ width: imageWidth }, showBaseLineDebug && styles.debugBaseLine]}
73
86
  >
74
87
  <TouchableOpacity onPress={() => onAction(onActionClick)}>
75
88
  <Image
@@ -80,7 +93,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
80
93
  style={[
81
94
  styles.container,
82
95
  {
83
- width: widthDevice - Spacing.XL * 2,
96
+ width: imageWidth,
84
97
  },
85
98
  ]}
86
99
  />
@@ -92,7 +105,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
92
105
 
93
106
  const styles = StyleSheet.create({
94
107
  container: {
95
- aspectRatio: 0.72,
108
+ aspectRatio: ASPECT_RATIO,
96
109
  width: '100%',
97
110
  },
98
111
  debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
@@ -103,11 +116,11 @@ const styles = StyleSheet.create({
103
116
  marginTop: Spacing.S,
104
117
  },
105
118
  iconButton: {
106
- padding: 8,
119
+ padding: Spacing.S,
107
120
  },
108
121
  iconClose: {
109
- width: 20,
110
- height: 20,
122
+ width: ICON_CLOSE_SIZE,
123
+ height: ICON_CLOSE_SIZE,
111
124
  alignItems: 'center',
112
125
  justifyContent: 'center',
113
126
  borderRadius: Radius.M,
package/Popup/utils.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { Dimensions, useWindowDimensions } from 'react-native';
2
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
3
+ import { Radius, Spacing } from '../Consts';
4
+ import { getDuoModalBounds, isIPhoneDuo } from '../Application/device';
5
+
6
+ const usePopupWidth = () => {
7
+ const insets = useSafeAreaInsets();
8
+ const { width, height } = useWindowDimensions();
9
+ if (!isIPhoneDuo()) {
10
+ return Dimensions.get('window').width - Spacing.XL * 2;
11
+ }
12
+ return getDuoModalBounds(insets, width, height).maxWidth;
13
+ };
14
+
15
+ const usePopupMaxHeight = () => {
16
+ const insets = useSafeAreaInsets();
17
+ const { width, height } = useWindowDimensions();
18
+ if (!isIPhoneDuo()) {
19
+ return undefined;
20
+ }
21
+ return getDuoModalBounds(insets, width, height).maxHeight;
22
+ };
23
+
24
+ const getPopupRadius = () => (isIPhoneDuo() ? Radius.XL : Radius.L);
25
+
26
+ export { usePopupWidth, usePopupMaxHeight, getPopupRadius };
package/Radio/index.tsx CHANGED
@@ -47,10 +47,9 @@ const Radio: FC<RadioProps> = ({
47
47
  };
48
48
  }
49
49
  if (disabled) {
50
+ const { background, text } = theme.colors;
50
51
  disabledStyle = {
51
- borderColor: selected
52
- ? theme.colors.background.tonal
53
- : theme.colors.text.disable,
52
+ borderColor: selected ? background.tonal : text.disable,
54
53
  };
55
54
  }
56
55
 
package/Text/index.tsx CHANGED
@@ -153,6 +153,10 @@ const TypoStyles = (typo: Typography, newFontFamily?: string) => {
153
153
  fontSize: useScaleSize(fontSize),
154
154
  lineHeight: useScaleSize(lineHeight),
155
155
  fontStyle,
156
+ // fontFamily da mang san weight. Tren Android, ReactFontManager doi
157
+ // `fonts/<family>_bold.ttf` khi fontWeight >= 700; file do khong ton tai nen
158
+ // font se roi ve font he thong. Bo fontWeight de Android dung dung file.
159
+ fontWeight: undefined,
156
160
  };
157
161
  };
158
162
 
package/Text/utils.ts CHANGED
@@ -2,18 +2,17 @@ import { Dimensions, PixelRatio, useWindowDimensions } from 'react-native';
2
2
  import { useContext } from 'react';
3
3
  import { MiniAppContext } from '../Context';
4
4
 
5
- const deviceWidth = Dimensions.get('window').width;
6
5
  const DEFAULT_SCREEN_SIZE = 375;
7
6
  const MAX_FONT_SCALE = 1.5;
8
7
  const MAX_DEVICE_SCALE = 5;
9
8
 
10
9
  const useScaleSize = (size: number, scaleRate?: number) => {
10
+ const { width } = useWindowDimensions();
11
11
  const context = useContext<any>(MiniAppContext);
12
12
  if (context?.fontScale?.useOSScaleRate === false) {
13
13
  return size * (context.fontScale.userScaleRate ?? 1);
14
14
  }
15
15
  const fontScale = PixelRatio.getFontScale();
16
- const { width } = useWindowDimensions();
17
16
  const deviceScale = width / DEFAULT_SCREEN_SIZE;
18
17
 
19
18
  const maxScaleRate = scaleRate ?? MAX_FONT_SCALE;
@@ -40,7 +39,7 @@ const useScaleSize = (size: number, scaleRate?: number) => {
40
39
 
41
40
  const scaleSize = (size: number) => {
42
41
  const fontScale = PixelRatio.getFontScale();
43
- const deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE;
42
+ const deviceScale = Dimensions.get('window').width / DEFAULT_SCREEN_SIZE;
44
43
 
45
44
  let fontSizeDeviceScale = size;
46
45
  let fontSizeOSScale = size;
package/Title/index.tsx CHANGED
@@ -78,8 +78,10 @@ const Title: FC<TitleProps> = ({
78
78
  const titleFontFamily = exportFontFamily('bold');
79
79
  const isSection = type === 'section';
80
80
  const numberOfLines = showTrailingAction || !!badgeLabel ? 1 : 2;
81
- const buttonTypo: Typography =
82
- buttonSize === 'small' ? 'action_xs_bold' : 'action_s_bold';
81
+ let buttonTypo: Typography = 'action_s_bold';
82
+ if (buttonSize === 'small') {
83
+ buttonTypo = 'action_xs_bold';
84
+ }
83
85
  const flexStyle: ViewStyle = showTrailingAction ? { maxWidth: '95%' } : {};
84
86
  const componentName = 'Title';
85
87
 
@@ -114,6 +116,7 @@ const Title: FC<TitleProps> = ({
114
116
  };
115
117
 
116
118
  const renderContent = () => {
119
+ const maxWidth = contentWidth > 0 ? contentWidth - badgeWidth : undefined;
117
120
  return (
118
121
  <View style={styles.contentView}>
119
122
  <View
@@ -132,10 +135,7 @@ const Title: FC<TitleProps> = ({
132
135
  styleSheet[typography],
133
136
  { fontFamily: titleFontFamily },
134
137
  styles.title,
135
- {
136
- maxWidth:
137
- contentWidth > 0 ? contentWidth - badgeWidth : undefined,
138
- },
138
+ { maxWidth },
139
139
  ]}
140
140
  >
141
141
  {title}
@@ -175,6 +175,7 @@ const Title: FC<TitleProps> = ({
175
175
  };
176
176
 
177
177
  const renderActionLeft = () => {
178
+ const iconAlpha = isSection ? '99' : '4D';
178
179
  return (
179
180
  <TouchableOpacity
180
181
  accessibilityLabel={componentId + '|trailing-touch'}
@@ -186,11 +187,7 @@ const Title: FC<TitleProps> = ({
186
187
  <View
187
188
  style={[
188
189
  styles.iconLeft,
189
- {
190
- backgroundColor: isSection
191
- ? Colors.black_06 + '99'
192
- : Colors.black_06 + '4D',
193
- },
190
+ { backgroundColor: Colors.black_06 + iconAlpha },
194
191
  ]}
195
192
  >
196
193
  <Icon
package/Title/styles.ts CHANGED
@@ -42,7 +42,6 @@ export default StyleSheet.create({
42
42
  },
43
43
  contentView: { marginRight: Spacing.S, flex: 1 },
44
44
  title: {
45
- fontWeight: 'bold',
46
45
  color: Colors.black_17,
47
46
  },
48
47
  badge: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.167.1-beta.13",
3
+ "version": "0.167.1-beta.14",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -8,22 +8,25 @@
8
8
  "@momo-kits/foundation"
9
9
  ],
10
10
  "dependencies": {
11
+ "react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
11
12
  "@react-navigation/bottom-tabs": "7.4.2",
12
13
  "@react-navigation/core": "7.12.1",
13
14
  "@react-navigation/elements": "2.5.2",
14
15
  "@react-navigation/native": "7.1.14",
15
16
  "@react-navigation/routers": "7.4.1",
16
17
  "@react-navigation/stack": "7.4.2",
17
- "@shopify/flash-list": "2.1.0",
18
- "lottie-react-native": "7.2.4",
19
- "react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
20
18
  "react-native-gesture-handler": "2.27.1",
21
19
  "react-native-linear-gradient": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-linear-gradient#v3.0.0",
22
20
  "react-native-reanimated": "4.2.2",
23
- "react-native-safe-area-context": "5.5.2"
21
+ "react-native-worklets": "0.6.1",
22
+ "react-native-safe-area-context": "5.5.2",
23
+ "react-native-reserved-regions": "0.2.0",
24
+ "@shopify/flash-list": "2.1.0",
25
+ "lottie-react-native": "7.2.4"
24
26
  },
25
27
  "peerDependencies": {
26
- "react-native": "*"
28
+ "react-native": "*",
29
+ "react-native-worklets": "0.6.1"
27
30
  },
28
31
  "devDependencies": {
29
32
  "@types/color": "3.0.6"
@@ -32,4 +35,4 @@
32
35
  "registry": "https://registry.npmjs.org/"
33
36
  },
34
37
  "license": "MoMo"
35
- }
38
+ }
@@ -1,137 +0,0 @@
1
- import React, { useContext } from 'react';
2
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
3
- import { Dimensions, StyleSheet, View } from 'react-native';
4
- import { ApplicationContext } from '../Context';
5
- import { Colors, Spacing } from '../Consts';
6
- import { GridContextProps } from './types';
7
- import { useGridSystem } from './utils';
8
-
9
- const GridSystem: React.FC<any> = ({
10
- width = Dimensions.get('window').width,
11
- useMargin = true,
12
- gutterSize = Spacing.M,
13
- screenGrid = true,
14
- gridColor = Colors.blue_07,
15
- }) => {
16
- const { theme } = useContext(ApplicationContext);
17
- const { numberOfColumns } = useGridSystem();
18
-
19
- const margin = useMargin ? Spacing.M : 0;
20
- const widthSection = width - margin * 2;
21
- const totalGutterSize = gutterSize * (numberOfColumns - 1);
22
- const sizePerSpan = (widthSection - totalGutterSize) / numberOfColumns;
23
-
24
- const grid: GridContextProps = {
25
- numberOfColumns,
26
- gutterSize,
27
- sizePerSpan,
28
- getSizeSpan: span => {
29
- return span * sizePerSpan + (span - 1) * gutterSize;
30
- },
31
- };
32
- const insets = useSafeAreaInsets();
33
-
34
- const list: number[] = [];
35
- for (let i = 1; i <= grid.numberOfColumns; i++) {
36
- list.push(i);
37
- }
38
-
39
- return (
40
- <>
41
- <View
42
- pointerEvents="none"
43
- style={[
44
- styles.gridContainer,
45
- screenGrid && insets,
46
- {
47
- borderColor: theme.colors.error.primary,
48
- marginHorizontal: margin,
49
- top: Spacing.M,
50
- bottom: Spacing.M,
51
- },
52
- ]}
53
- >
54
- {list.map((_, index) => {
55
- return (
56
- <View style={{ flexDirection: 'row' }} key={index.toString()}>
57
- {index !== 0 && <View style={{ width: grid.gutterSize }} />}
58
- <View
59
- key={`Grid${index.toString()}`}
60
- pointerEvents="none"
61
- style={[
62
- styles.gridColumn,
63
- {
64
- width: grid.sizePerSpan,
65
- backgroundColor: gridColor,
66
- },
67
- ]}
68
- />
69
- </View>
70
- );
71
- })}
72
- </View>
73
- {screenGrid && (
74
- <>
75
- <View pointerEvents="none" style={styles.dangerLeftContainer} />
76
- <View pointerEvents="none" style={styles.dangerRightContainer} />
77
- <View
78
- pointerEvents="none"
79
- style={[styles.dangerTopContainer, { height: Spacing.M }]}
80
- />
81
- <View
82
- pointerEvents="none"
83
- style={[styles.dangerBottomContainer, { height: insets.bottom }]}
84
- />
85
- </>
86
- )}
87
- </>
88
- );
89
- };
90
-
91
- const styles = StyleSheet.create({
92
- gridContainer: {
93
- position: 'absolute',
94
- top: 0,
95
- bottom: 0,
96
- left: 0,
97
- right: 0,
98
- flexDirection: 'row',
99
- borderWidth: 1,
100
- },
101
- gridColumn: {
102
- height: '100%',
103
- opacity: 0.2,
104
- },
105
- dangerTopContainer: {
106
- opacity: 0.2,
107
- backgroundColor: Colors.red_03,
108
- width: '100%',
109
- top: 0,
110
- position: 'absolute',
111
- },
112
- dangerBottomContainer: {
113
- opacity: 0.2,
114
- backgroundColor: Colors.red_03,
115
- width: '100%',
116
- bottom: 0,
117
- position: 'absolute',
118
- },
119
- dangerLeftContainer: {
120
- opacity: 0.2,
121
- backgroundColor: Colors.red_03,
122
- width: Spacing.M,
123
- height: '100%',
124
- left: 0,
125
- position: 'absolute',
126
- },
127
- dangerRightContainer: {
128
- opacity: 0.2,
129
- backgroundColor: Colors.red_03,
130
- width: Spacing.M,
131
- height: '100%',
132
- right: 0,
133
- position: 'absolute',
134
- },
135
- });
136
-
137
- export default GridSystem;