@momo-kits/foundation 0.152.1-beta.2 → 0.152.1-beta.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.
@@ -138,7 +138,7 @@ export type Tool = {
138
138
  };
139
139
 
140
140
  export type FeaturesFlag = {
141
- enableForceFoundationList?: boolean;
141
+ enableFoundationList?: boolean;
142
142
  enableBottomTabAnimation?: boolean;
143
143
  enableHapticBottomTab?: boolean;
144
144
  enableHapticDialog?: boolean;
package/Button/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext} from 'react';
1
+ import React, { FC, useContext, useRef } from 'react';
2
2
  import {
3
3
  Animated,
4
4
  StyleSheet,
@@ -17,11 +17,12 @@ import { Text } from '../Text';
17
17
  import { Typography } from '../Text/types';
18
18
  import { Colors, Spacing } from '../Consts';
19
19
  import styles from './styles';
20
- import {Icon} from '../Icon';
21
- import {Skeleton} from '../Skeleton';
20
+ import { Icon } from '../Icon';
21
+ import { Skeleton } from '../Skeleton';
22
22
  import LottieView from 'lottie-react-native';
23
23
 
24
24
  const AnimationLinear = Animated.createAnimatedComponent(LinearGradient);
25
+ const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
25
26
 
26
27
  export interface ButtonProps extends TouchableOpacityProps {
27
28
  /**
@@ -40,48 +41,26 @@ export interface ButtonProps extends TouchableOpacityProps {
40
41
  * Defines the size of the button.
41
42
  */
42
43
  size?: 'large' | 'medium' | 'small';
43
-
44
- /**
45
- * If true, the button will take the full width of its container.
46
- */
47
44
  full?: boolean;
48
-
49
- /**
50
- * Specifies the name of the icon that should be placed on the right side of the button.
51
- */
52
45
  iconRight?: string;
53
-
54
- /**
55
- * Specifies the name of the icon that should be placed on the left side of the button.
56
- */
57
46
  iconLeft?: string;
58
-
59
- /**
60
- * Represents the text that will be displayed on the button.
61
- */
62
47
  title: string;
63
-
64
- /**
65
- * If true, the icon of button will use the tint color provided by its container.
66
- */
67
48
  tintColor?: string;
68
-
69
- /**
70
- * If true, the icon of button will use be show indicator loading.
71
- */
72
49
  loading?: boolean;
73
-
74
- /**
75
- * A callback function that is called when the button is pressed.
76
- */
77
50
  onPress: () => void;
78
-
79
- /**
80
- * Optional. Params auto tracking component.
81
- */
82
51
  params?: any;
83
52
  }
84
53
 
54
+ const shouldLoadingOnLeft = (iconLeft?: string, iconRight?: string): boolean => {
55
+ const hasLeft = !!iconLeft;
56
+ const hasRight = !!iconRight;
57
+
58
+ if (!hasLeft && !hasRight) return true;
59
+ if (hasLeft && !hasRight) return true;
60
+ if (!hasLeft && hasRight) return false;
61
+ return false;
62
+ };
63
+
85
64
  const Button: FC<ButtonProps> = ({
86
65
  type = 'primary',
87
66
  size = 'large',
@@ -104,10 +83,30 @@ const Button: FC<ButtonProps> = ({
104
83
  `${componentName}/${title}`,
105
84
  rest.accessibilityLabel,
106
85
  );
86
+
107
87
  const { gradient, color } = config?.navigationBar?.buttonColors ?? {};
108
- let gradientPros;
109
88
  const isDisabled = type === 'disabled' || loading;
110
89
 
90
+ const pressAnim = useRef(new Animated.Value(0)).current;
91
+
92
+ const animateIn = () => {
93
+ if (isDisabled) return;
94
+ Animated.timing(pressAnim, {
95
+ toValue: 1,
96
+ duration: 100,
97
+ useNativeDriver: false,
98
+ }).start();
99
+ };
100
+
101
+ const animateOut = () => {
102
+ Animated.timing(pressAnim, {
103
+ toValue: 0,
104
+ duration: 100,
105
+ useNativeDriver: false,
106
+ }).start();
107
+ };
108
+
109
+ let gradientPros;
111
110
  if (gradient?.length > 0 && type === 'primary') {
112
111
  gradientPros = {
113
112
  colors: gradient,
@@ -116,6 +115,8 @@ const Button: FC<ButtonProps> = ({
116
115
  };
117
116
  }
118
117
 
118
+ const loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight);
119
+
119
120
  const getSizeStyle = () => {
120
121
  const styleSheet: { [key: string]: any } = styles;
121
122
  return styleSheet[size ?? 'small'];
@@ -166,14 +167,13 @@ const Button: FC<ButtonProps> = ({
166
167
  case 'medium':
167
168
  case 'small':
168
169
  return 16;
169
-
170
170
  default:
171
171
  return 24;
172
172
  }
173
173
  };
174
174
 
175
175
  /**
176
- * export icon size
176
+ * export icon space
177
177
  */
178
178
  const getIconSpace = () => {
179
179
  switch (size) {
@@ -182,7 +182,6 @@ const Button: FC<ButtonProps> = ({
182
182
  return 8;
183
183
  case 'small':
184
184
  return 4;
185
-
186
185
  default:
187
186
  return 8;
188
187
  }
@@ -199,7 +198,6 @@ const Button: FC<ButtonProps> = ({
199
198
  return 'action_s_bold';
200
199
  case 'small':
201
200
  return 'action_xs_bold';
202
-
203
201
  default:
204
202
  return 'action_default_bold';
205
203
  }
@@ -239,15 +237,28 @@ const Button: FC<ButtonProps> = ({
239
237
  );
240
238
  };
241
239
 
242
- /**
243
- * render leading
244
- */
245
- const renderLeading = () => {
240
+ const renderIcon = (position: 'left' | 'right') => {
246
241
  const iconSize = getIconSize();
247
- const marginRight = getIconSpace();
242
+ const space = getIconSpace();
248
243
  const textColor = tintColor ?? getTextColor();
249
244
 
250
- if (loading) {
245
+ const isLeft = position === 'left';
246
+ const icon = isLeft ? iconLeft : iconRight;
247
+
248
+ const showLoading =
249
+ loading && ((isLeft && loadingOnLeft) || (!isLeft && !loadingOnLeft));
250
+
251
+ const style = [
252
+ isLeft ? styles.leading : styles.trailing,
253
+ {
254
+ width: iconSize,
255
+ height: iconSize,
256
+ marginRight: isLeft ? space : 0,
257
+ marginLeft: isLeft ? 0 : space,
258
+ },
259
+ ];
260
+
261
+ if (showLoading) {
251
262
  return (
252
263
  <LottieView
253
264
  ref={animationRef}
@@ -259,63 +270,44 @@ const Button: FC<ButtonProps> = ({
259
270
  { keypath: 'loading 3.Ellipse 1.Stroke 1', color: textColor },
260
271
  { keypath: 'base pink 2.Ellipse 1.Stroke 1', color: textColor },
261
272
  ]}
262
- style={[
263
- styles.trailing,
264
- {
265
- width: iconSize,
266
- height: iconSize,
267
- marginRight,
268
- borderRadius: Spacing.M,
269
- },
270
- ]}
273
+ style={[style, { borderRadius: Spacing.M }]}
271
274
  />
272
275
  );
273
276
  }
274
- if (iconLeft) {
277
+
278
+ if (icon) {
275
279
  return (
276
- <View
277
- style={[
278
- styles.leading,
279
- { width: iconSize, height: iconSize, marginRight },
280
- ]}
281
- >
282
- <Icon color={textColor} source={iconLeft} size={iconSize} />
280
+ <View style={style}>
281
+ <Icon color={textColor} source={icon} size={iconSize} />
283
282
  </View>
284
283
  );
285
284
  }
285
+
286
+ return null;
286
287
  };
287
288
 
288
- /**
289
- * render trailing
290
- */
291
- const renderTrailing = () => {
292
- const textColor = tintColor ?? getTextColor();
293
- const marginLeft = getIconSpace();
289
+ const sizeStyle = getSizeStyle();
290
+ const typeStyle = getTypeStyle();
294
291
 
295
- if (iconRight) {
296
- const iconSize = getIconSize();
297
- return (
298
- <View
299
- style={[
300
- styles.trailing,
301
- { width: iconSize, height: iconSize, marginLeft },
302
- ]}
303
- >
304
- <Icon color={textColor} source={iconRight} size={iconSize} />
305
- </View>
306
- );
307
- }
308
- };
292
+ const containerStyle = StyleSheet.flatten([
293
+ full && { width: '100%' },
294
+ loading && { opacity: 0.75 },
295
+ ]);
309
296
 
310
297
  const buttonStyle = StyleSheet.flatten([
311
- getSizeStyle(),
312
- getTypeStyle(),
313
- full && {width: '100%'},
314
- loading && {opacity: 0.75}
298
+ sizeStyle,
299
+ typeStyle,
315
300
  ]);
316
301
 
302
+ const innerAnimatedStyle = {
303
+ marginHorizontal: pressAnim.interpolate({
304
+ inputRange: [0, 1],
305
+ outputRange: [0, 2],
306
+ }),
307
+ };
308
+
317
309
  if (skeleton?.loading) {
318
- return <Skeleton style={[buttonStyle, { paddingHorizontal: 0 }]} />;
310
+ return <Skeleton style={[containerStyle, buttonStyle, {paddingHorizontal: 0}]} />;
319
311
  }
320
312
 
321
313
  return (
@@ -325,9 +317,8 @@ const Button: FC<ButtonProps> = ({
325
317
  componentId,
326
318
  params,
327
319
  action: 'click',
328
- }}
329
- >
330
- <TouchableOpacity
320
+ }}>
321
+ <AnimatedTouchable
331
322
  {...rest}
332
323
  accessibilityLabel={componentId}
333
324
  accessibilityRole="button"
@@ -338,16 +329,26 @@ const Button: FC<ButtonProps> = ({
338
329
  }}
339
330
  disabled={isDisabled}
340
331
  activeOpacity={0.5}
341
- style={buttonStyle}
332
+ style={containerStyle}
333
+ onPressIn={animateIn}
334
+ onPressOut={animateOut}
335
+ onPress={rest.onPress}
342
336
  >
343
- {renderLeading()}
344
- {renderTitle()}
345
- {renderTrailing()}
346
- {gradientPros && (
347
- <AnimationLinear {...gradientPros} style={styles.gradientView} />
348
- )}
349
- {gradientPros && <View style={styles.strokeView} />}
350
- </TouchableOpacity>
337
+ <Animated.View
338
+ style={[
339
+ buttonStyle,
340
+ innerAnimatedStyle,
341
+ ]}
342
+ >
343
+ {renderIcon('left')}
344
+ {renderTitle()}
345
+ {renderIcon('right')}
346
+ {gradientPros && (
347
+ <AnimationLinear {...gradientPros} style={styles.gradientView} />
348
+ )}
349
+ {gradientPros && <View style={styles.strokeView} />}
350
+ </Animated.View>
351
+ </AnimatedTouchable>
351
352
  </ComponentContext.Provider>
352
353
  );
353
354
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.152.1-beta.2",
3
+ "version": "0.152.1-beta.4",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},