@momo-kits/foundation 0.92.9-beta.0 → 0.92.9-beta.2

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.
@@ -1,4 +1,4 @@
1
- import React, {useContext, useEffect, useRef, useState} from 'react';
1
+ import React, {useCallback, useContext, useEffect, useRef} from 'react';
2
2
  import {
3
3
  Animated,
4
4
  Dimensions,
@@ -26,18 +26,21 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
26
26
  options,
27
27
  surface,
28
28
  barrierDismissible = false,
29
- snapPoint = 'content',
30
29
  draggable = true,
31
- dragOnContent = false,
30
+ useBottomInset = true,
31
+ keyboardVerticalOffset,
32
32
  }: BottomSheetParams = props.route.params;
33
- const [modalVisible, setModalVisible] = useState(false);
34
- const animatedHeight = useRef(new Animated.Value(0)).current;
35
- const pan = useRef(new Animated.ValueXY()).current;
33
+ const pan = useRef(
34
+ new Animated.ValueXY({
35
+ y: heightDevice,
36
+ x: 0,
37
+ }),
38
+ ).current;
36
39
  const panResponder = useRef(
37
40
  PanResponder.create({
38
41
  onStartShouldSetPanResponder: () => draggable,
39
42
  onMoveShouldSetPanResponder: (_, gestureState) => {
40
- return draggable && dragOnContent && gestureState.dy > 0;
43
+ return draggable && gestureState.dy > 0;
41
44
  },
42
45
  onPanResponderMove: (e, gestureState) => {
43
46
  gestureState.dy > 0 &&
@@ -58,7 +61,6 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
58
61
  },
59
62
  }),
60
63
  ).current;
61
- const estimate = useRef(0.9);
62
64
 
63
65
  let backgroundColor = theme.colors.background.default;
64
66
  if (surface) {
@@ -66,25 +68,14 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
66
68
  }
67
69
 
68
70
  /**
69
- * handle open & emit dismiss event
71
+ * emit dismiss event
70
72
  */
71
73
  useEffect(() => {
72
- setTimeout(() => {
73
- const mapSnapPoint: any = {
74
- '30%': 0.3,
75
- '50%': 0.5,
76
- '70%': 0.7,
77
- '90%': 0.9,
78
- };
79
- const point = mapSnapPoint[snapPoint] ?? estimate.current;
80
- setModalVisible(true);
81
- Animated.timing(animatedHeight, {
82
- useNativeDriver: false,
83
- toValue: heightDevice * point,
84
- duration: 300,
85
- }).start();
86
- }, 100);
87
-
74
+ Animated.timing(pan, {
75
+ toValue: {x: 0, y: 0},
76
+ useNativeDriver: false,
77
+ duration: 150,
78
+ }).start();
88
79
  return () => {
89
80
  props.route.params?.onDismiss?.();
90
81
  };
@@ -93,94 +84,96 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
93
84
  /**
94
85
  * handler dismiss
95
86
  */
96
- const onDismiss = (force = false) => {
87
+ const onDismiss = (force = false, callback?: () => void) => {
97
88
  if (barrierDismissible && !force) {
98
89
  return;
99
90
  }
100
- Animated.timing(animatedHeight, {
91
+ Animated.timing(pan, {
92
+ toValue: {x: 0, y: heightDevice},
101
93
  useNativeDriver: false,
102
- toValue: 0,
103
- duration: 200,
94
+ duration: 100,
104
95
  }).start(() => {
105
- pan.setValue({x: 0, y: 0});
106
96
  navigator?.pop();
97
+ callback?.();
107
98
  });
108
99
  };
109
100
 
110
- return (
111
- <>
112
- <Modal
113
- transparent
114
- visible={modalVisible}
115
- onRequestClose={() => onDismiss()}>
116
- <KeyboardAvoidingView
117
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
118
- keyboardVerticalOffset={-20}
119
- style={Styles.flex}>
120
- <TouchableOpacity
121
- style={Styles.flex}
122
- activeOpacity={1}
123
- onPress={() => onDismiss()}
124
- />
125
- <Animated.View
126
- {...(dragOnContent && panResponder.panHandlers)}
127
- style={[
128
- styles.container,
129
- {transform: pan.getTranslateTransform()},
130
- {
131
- height: animatedHeight,
132
- backgroundColor,
133
- },
134
- ]}>
135
- {draggable && (
136
- <View
137
- {...(!dragOnContent && panResponder.panHandlers)}
138
- style={styles.draggableContainer}>
139
- <View style={{height: 16}}>
140
- <View style={styles.indicator} />
141
- </View>
142
- <View
143
- style={[
144
- styles.header,
145
- surface && {
146
- borderBottomColor: theme.colors.border.default,
147
- borderBottomWidth: 1,
148
- },
149
- ]}>
150
- <View style={styles.iconButton} />
151
- <Text
152
- style={[Styles.flex, {textAlign: 'center'}]}
153
- numberOfLines={1}
154
- typography="header_default_bold">
155
- {options.title ?? ''}
156
- </Text>
157
- <TouchableOpacity
158
- style={styles.iconButton}
159
- onPress={() => onDismiss(true)}>
160
- <Icon source="navigation_close" />
161
- </TouchableOpacity>
162
- </View>
163
- </View>
164
- )}
165
- <Screen {...props} {...props.route.params} />
166
- <View style={{height: Math.min(insets.bottom, 21)}} />
167
- </Animated.View>
168
- </KeyboardAvoidingView>
169
- </Modal>
170
- {snapPoint == 'content' && (
101
+ /**
102
+ * manual close
103
+ */
104
+ const requestClose = useCallback((callback?: () => void) => {
105
+ onDismiss(true, callback);
106
+ }, []);
107
+
108
+ /**
109
+ * render header
110
+ */
111
+ const renderHeader = useCallback(() => {
112
+ return (
113
+ <View
114
+ style={{
115
+ backgroundColor,
116
+ borderTopLeftRadius: Radius.M,
117
+ borderTopRightRadius: Radius.M,
118
+ }}
119
+ {...panResponder.panHandlers}>
120
+ <View style={{height: 16}}>
121
+ <View style={styles.indicator} />
122
+ </View>
171
123
  <View
172
- style={styles.estimate}
173
- onLayout={e => {
174
- estimate.current =
175
- (e.nativeEvent.layout.height + 68) / heightDevice;
176
- }}>
177
- <Screen {...props} {...props.route.params} />
178
- <View style={{height: Math.min(insets.bottom, 21)}} />
124
+ style={[
125
+ styles.header,
126
+ surface && {
127
+ borderBottomColor: theme.colors.border.default,
128
+ borderBottomWidth: 1,
129
+ },
130
+ ]}>
131
+ <View style={styles.iconButton} />
132
+ <Text
133
+ style={[Styles.flex, {textAlign: 'center'}]}
134
+ numberOfLines={1}
135
+ typography="header_default_bold">
136
+ {options.title ?? ''}
137
+ </Text>
138
+ <TouchableOpacity
139
+ style={styles.iconButton}
140
+ onPress={() => onDismiss(true)}>
141
+ <Icon source="navigation_close" />
142
+ </TouchableOpacity>
179
143
  </View>
180
- )}
181
- </>
144
+ </View>
145
+ );
146
+ }, []);
147
+
148
+ return (
149
+ <Modal transparent visible={true} onRequestClose={() => onDismiss()}>
150
+ <KeyboardAvoidingView
151
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
152
+ keyboardVerticalOffset={keyboardVerticalOffset ?? -20}
153
+ style={[Styles.flex, {justifyContent: 'flex-end'}]}>
154
+ <TouchableOpacity
155
+ style={Styles.flex}
156
+ activeOpacity={1}
157
+ onPress={() => onDismiss()}
158
+ />
159
+ <Animated.View style={{transform: pan.getTranslateTransform()}}>
160
+ {renderHeader()}
161
+ <View style={{backgroundColor: backgroundColor}}>
162
+ <Screen
163
+ {...props}
164
+ {...props.route.params}
165
+ requestClose={requestClose}
166
+ />
167
+ {useBottomInset && (
168
+ <View style={{height: Math.min(insets.bottom, 21)}} />
169
+ )}
170
+ </View>
171
+ </Animated.View>
172
+ </KeyboardAvoidingView>
173
+ </Modal>
182
174
  );
183
175
  };
176
+
184
177
  export default BottomSheet;
185
178
 
186
179
  const styles = StyleSheet.create({
@@ -26,7 +26,6 @@ type Props = BottomTabBarProps & {
26
26
  activeTintColor?: string;
27
27
  inactiveTintColor?: string;
28
28
  floatingButton?: FloatingButtonProps;
29
- accessibilityLabel?: string;
30
29
  };
31
30
 
32
31
  const getPaddingBottom = (insets: EdgeInsets) => {
@@ -65,7 +64,7 @@ export default function BottomTabBar({
65
64
  */
66
65
  const renderTabItem = useCallback(
67
66
  (data: any[]) => {
68
- return data?.map((route, index) => {
67
+ return data?.map((route, _) => {
69
68
  const focused = route.params.name === focusedTab;
70
69
  const {options} = descriptors[route?.key] as any;
71
70
  const onPress = () => {
@@ -90,19 +89,7 @@ export default function BottomTabBar({
90
89
  });
91
90
  };
92
91
 
93
- const label =
94
- options.tabBarLabel !== undefined
95
- ? options.tabBarLabel
96
- : options.title !== undefined
97
- ? options.title
98
- : route.name;
99
-
100
- const accessibilityLabel =
101
- options.tabBarAccessibilityLabel !== undefined
102
- ? options.tabBarAccessibilityLabel
103
- : typeof label === 'string'
104
- ? `${label}, tab, ${index + 1} of ${routes.length}`
105
- : undefined;
92
+ const label = options.tabBarLabel || options.title || route.name;
106
93
 
107
94
  return (
108
95
  <NavigationContext.Provider
@@ -115,7 +102,7 @@ export default function BottomTabBar({
115
102
  horizontal={false}
116
103
  onPress={onPress}
117
104
  onLongPress={onLongPress}
118
- accessibilityLabel={accessibilityLabel}
105
+ accessibilityLabel={`tab_item_${route.name}`}
119
106
  to={buildLink(route.name, route.params)}
120
107
  testID={options.tabBarTestID}
121
108
  allowFontScaling={allowFontScaling}
@@ -146,7 +133,7 @@ export default function BottomTabBar({
146
133
  */
147
134
  const renderFloatingButton = useCallback(() => {
148
135
  const renderFloatingButton = () => {
149
- if (typeof floatingButton?.icon == 'string') {
136
+ if (typeof floatingButton?.icon === 'string') {
150
137
  return <Icon source={floatingButton?.icon} size={32} color={'white'} />;
151
138
  }
152
139
  return floatingButton?.icon;
@@ -232,7 +219,7 @@ export default function BottomTabBar({
232
219
  style,
233
220
  ]}
234
221
  pointerEvents={'auto'}>
235
- <View style={styles.content}>
222
+ <View style={styles.content} accessibilityLabel={'bottom_tab_bar'}>
236
223
  {useFloating && floatingButton?.container}
237
224
  <Animated.View
238
225
  style={{
@@ -22,13 +22,18 @@ const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
22
22
  if (route.params?.options) {
23
23
  options = getOptions(route.params?.options, theme);
24
24
  }
25
+
25
26
  if (route.params?.nested) {
26
27
  return (
27
28
  <Stack.Navigator>
28
29
  <Stack.Screen
29
30
  name="Stack"
30
31
  component={StackScreen}
31
- initialParams={{screen: route.params?.screen, options}}
32
+ initialParams={{
33
+ screen: route.params?.screen,
34
+ options,
35
+ initialParams: route.params?.initialParams,
36
+ }}
32
37
  options={{...getStackOptions()}}
33
38
  />
34
39
  </Stack.Navigator>
@@ -40,7 +45,11 @@ const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
40
45
  <Stack.Screen
41
46
  name="Stack"
42
47
  component={StackScreen}
43
- initialParams={{screen: route.params?.screen, options}}
48
+ initialParams={{
49
+ screen: route.params?.screen,
50
+ options,
51
+ initialParams: route.params?.initialParams,
52
+ }}
44
53
  options={{...getStackOptions(), ...route.params?.options}}
45
54
  />
46
55
  </Stack.Navigator>
@@ -72,11 +81,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
72
81
  initialRouteName={initialRouteName}
73
82
  backBehavior={'firstRoute'}
74
83
  tabBar={props => (
75
- <BottomTabBar
76
- {...props}
77
- accessibilityLabel={'BottomTabBar'}
78
- floatingButton={floatingButton}
79
- />
84
+ <BottomTabBar {...props} floatingButton={floatingButton} />
80
85
  )}
81
86
  tabBarOptions={{
82
87
  style: {
@@ -89,7 +94,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
89
94
  }}>
90
95
  {tabs.map(item => {
91
96
  const isNum = !isNaN(parseInt(`${item?.badgeLabel}`));
92
- const isDot = typeof item?.badgeLabel == 'string' && !item?.badgeLabel;
97
+ const isDot = typeof item?.badgeLabel === 'string' && !item?.badgeLabel;
93
98
  return (
94
99
  <Tab.Screen
95
100
  key={item.name}
@@ -41,7 +41,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
41
41
  }) => {
42
42
  const {theme} = useContext(ApplicationContext);
43
43
  let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
44
- if (tintColor != Colors.black_01) {
44
+ if (tintColor !== Colors.black_01) {
45
45
  buttonStyle = {
46
46
  backgroundColor: 'transparent',
47
47
  borderColor: '#00000066',
@@ -238,7 +238,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
238
238
  tintColor,
239
239
  dotColor,
240
240
  }) => {
241
- const avatarStyle = imageShape == 'circle' ? styles.circle : styles.square;
241
+ const avatarStyle = imageShape === 'circle' ? styles.circle : styles.square;
242
242
  const header = (
243
243
  <View style={Styles.row}>
244
244
  <View>
@@ -265,7 +265,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
265
265
 
266
266
  const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
267
267
  const validateType = (child: React.ReactElement) => {
268
- const valid = child?.type === NavigationButton || child?.type == Fragment;
268
+ const valid = child?.type === NavigationButton || child?.type === Fragment;
269
269
  if (__DEV__ && !valid) {
270
270
  console.warn(
271
271
  'HeaderRightAction contains element type of NavigationButton, Please check again.',
@@ -306,7 +306,7 @@ const HeaderToolkitAction: React.FC<any> = ({
306
306
  const {onAction} = toolConfig ?? {};
307
307
 
308
308
  let backgroundColor;
309
- if (tintColor != Colors.black_01) {
309
+ if (tintColor !== Colors.black_01) {
310
310
  backgroundColor = 'transparent';
311
311
  }
312
312
 
@@ -55,7 +55,6 @@ const StackScreen: React.FC<ScreenParams> = props => {
55
55
  }
56
56
 
57
57
  navigator?.maxApi?.of?.({screenName});
58
-
59
58
  tracked.current.timeoutLoad = setTimeout(() => {
60
59
  onScreenLoad();
61
60
  }, 5000);
@@ -102,24 +102,24 @@ export type ScreenParams = {
102
102
 
103
103
  export type ModalParams = {
104
104
  [key: string]: any;
105
- screen: Screen;
105
+ screen: React.ComponentType;
106
106
  onDismiss?: () => void;
107
107
  barrierDismissible?: boolean;
108
108
  };
109
109
 
110
110
  export type BottomSheetParams = {
111
111
  [key: string]: any;
112
- screen: Screen;
112
+ screen: React.ComponentType;
113
113
  options: {
114
114
  title: string;
115
115
  surface?: boolean;
116
116
  };
117
- snapPoint?: '30%' | '50%' | '70%' | '90%' | 'content';
118
117
  surface?: boolean;
119
118
  onDismiss?: (type?: string) => void;
120
119
  barrierDismissible?: boolean;
121
120
  draggable?: boolean;
122
- dragOnContent?: boolean;
121
+ useBottomInset?: boolean;
122
+ keyboardVerticalOffset?: number;
123
123
  };
124
124
 
125
125
  export type NavigationButtonProps = {
@@ -197,6 +197,7 @@ export type BottomTabItemProps = {
197
197
  badgeLabel?: string | number;
198
198
  screen: Screen;
199
199
  options: NavigationOptions;
200
+ initialParams?: any;
200
201
  };
201
202
 
202
203
  export type BottomTabProps = {
@@ -94,7 +94,7 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
94
94
  };
95
95
  }
96
96
 
97
- if (typeof params.surface == 'boolean') {
97
+ if (typeof params.surface === 'boolean') {
98
98
  if (params.surface) {
99
99
  options = {
100
100
  ...options,
@@ -503,4 +503,4 @@
503
503
  "zalopay_icon": {
504
504
  "uri": "https://static.momocdn.net/app/img/kits/icon_bank/zalopay_icon.png"
505
505
  }
506
- }
506
+ }
package/Button/index.tsx CHANGED
@@ -94,7 +94,7 @@ const Button: FC<ButtonProps> = ({
94
94
  if (loading) {
95
95
  state = 'loading';
96
96
  }
97
- if (gradient?.length > 0 && type == 'primary') {
97
+ if (gradient?.length > 0 && type === 'primary') {
98
98
  gradientPros = {
99
99
  colors: gradient,
100
100
  start: {x: 1, y: 0.5},
@@ -217,9 +217,9 @@ const Button: FC<ButtonProps> = ({
217
217
  */
218
218
  const renderTitle = () => {
219
219
  const typography = getTypography();
220
- const color = getTextColor();
220
+ const textColor = getTextColor();
221
221
  return (
222
- <Text typography={typography} color={color} numberOfLines={1}>
222
+ <Text typography={typography} color={textColor} numberOfLines={1}>
223
223
  {title}
224
224
  </Text>
225
225
  );
@@ -231,7 +231,7 @@ const Button: FC<ButtonProps> = ({
231
231
  const renderLeading = () => {
232
232
  const iconSize = getIconSize();
233
233
  const marginRight = getIconSpace();
234
- const color = tintColor ?? getTextColor();
234
+ const textColor = tintColor ?? getTextColor();
235
235
 
236
236
  if (loading) {
237
237
  return (
@@ -256,7 +256,7 @@ const Button: FC<ButtonProps> = ({
256
256
  styles.leading,
257
257
  {width: iconSize, height: iconSize, marginRight},
258
258
  ]}>
259
- <Icon color={color} source={iconLeft} size={iconSize} />
259
+ <Icon color={textColor} source={iconLeft} size={iconSize} />
260
260
  </View>
261
261
  );
262
262
  }
@@ -266,7 +266,7 @@ const Button: FC<ButtonProps> = ({
266
266
  * render trailing
267
267
  */
268
268
  const renderTrailing = () => {
269
- const color = tintColor ?? getTextColor();
269
+ const textColor = tintColor ?? getTextColor();
270
270
  const marginLeft = getIconSpace();
271
271
 
272
272
  if (iconRight) {
@@ -277,7 +277,7 @@ const Button: FC<ButtonProps> = ({
277
277
  styles.trailing,
278
278
  {width: iconSize, height: iconSize, marginLeft},
279
279
  ]}>
280
- <Icon color={color} source={iconRight} size={iconSize} />
280
+ <Icon color={textColor} source={iconRight} size={iconSize} />
281
281
  </View>
282
282
  );
283
283
  }
package/Icon/index.tsx CHANGED
@@ -33,7 +33,7 @@ const Icon: React.FC<IconProps> = ({
33
33
  loading={false}
34
34
  source={getIconSource()}
35
35
  style={[style, {width: size, height: size}]}
36
- resizeMode='contain'
36
+ resizeMode="contain"
37
37
  {...tintColorProps}
38
38
  />
39
39
  );
package/Icon/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import {ImageStyle} from 'react-native-fast-image';
2
- import {StyleProp} from "react-native";
2
+ import {StyleProp} from 'react-native';
3
3
 
4
4
  export type IconProps = {
5
5
  /**
package/Image/index.tsx CHANGED
@@ -19,7 +19,6 @@ const Image: React.FC<ImageProps> = ({
19
19
  source,
20
20
  loading = true,
21
21
  children,
22
- params,
23
22
  accessibilityLabel,
24
23
  ...rest
25
24
  }) => {
@@ -1,6 +1,7 @@
1
1
  import React, {
2
2
  forwardRef,
3
3
  useContext,
4
+ useEffect,
4
5
  useImperativeHandle,
5
6
  useRef,
6
7
  useState,
@@ -40,6 +41,7 @@ const InputMoney = forwardRef(
40
41
  defaultValue = '',
41
42
  accessibilityLabel,
42
43
  hintText,
44
+ value: _value,
43
45
  ...props
44
46
  }: InputMoneyProps,
45
47
  ref,
@@ -48,6 +50,13 @@ const InputMoney = forwardRef(
48
50
  const [focused, setFocused] = useState(false);
49
51
  const inputRef = useRef<TextInput>(null);
50
52
 
53
+ useEffect(() => {
54
+ if (_value) {
55
+ setValue(validateText(_value));
56
+ onChangeText?.(formatMoneyToNumber(_value, 'đ').toString());
57
+ }
58
+ }, [_value]);
59
+
51
60
  const validateText = (text: string) => {
52
61
  const valueFormat = formatMoneyToNumber(text, 'đ');
53
62
  return formatNumberToMoney(valueFormat, 'đ');
@@ -71,11 +71,8 @@ const InputOTP = forwardRef(
71
71
  errorMessage,
72
72
  errorSpacing,
73
73
  floatingValue = 'Label',
74
- floatingIconColor,
75
- floatingIcon,
76
74
  placeholder,
77
75
  onChangeText,
78
- onFocus,
79
76
  onBlur,
80
77
  dataType = 'number',
81
78
  params,
@@ -125,16 +122,16 @@ const InputOTP = forwardRef(
125
122
  onChangeText?.(text);
126
123
  };
127
124
 
128
- const renderInputs = (length: number) => {
125
+ const renderInputs = (inputLength: number) => {
129
126
  const TextInputs: React.ReactNode[] = [];
130
- for (let i = 0; i < length; i++) {
127
+ for (let i = 0; i < inputLength; i++) {
131
128
  TextInputs.push(
132
129
  <View>
133
130
  {focused && value.length === i ? (
134
- <OTPCaret index={i} length={length} />
131
+ <OTPCaret index={i} length={inputLength} />
135
132
  ) : (
136
133
  <Text
137
- style={i !== length - 1 && {marginRight: Spacing.L}}
134
+ style={i !== inputLength - 1 && {marginRight: Spacing.L}}
138
135
  color={
139
136
  !!value[i]
140
137
  ? theme.colors.text.default
@@ -44,7 +44,6 @@ const InputTextArea = forwardRef(
44
44
  required,
45
45
  errorSpacing,
46
46
  style,
47
- accessibilityLabel,
48
47
  hintText,
49
48
  ...props
50
49
  }: InputTextAreaProps,