@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.
- package/Application/types.ts +1 -1
- package/Button/index.tsx +101 -100
- package/package.json +1 -1
package/Application/types.ts
CHANGED
|
@@ -138,7 +138,7 @@ export type Tool = {
|
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
export type FeaturesFlag = {
|
|
141
|
-
|
|
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
|
|
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
|
|
242
|
+
const space = getIconSpace();
|
|
248
243
|
const textColor = tintColor ?? getTextColor();
|
|
249
244
|
|
|
250
|
-
|
|
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
|
-
|
|
277
|
+
|
|
278
|
+
if (icon) {
|
|
275
279
|
return (
|
|
276
|
-
<View
|
|
277
|
-
|
|
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
|
-
|
|
290
|
-
*/
|
|
291
|
-
const renderTrailing = () => {
|
|
292
|
-
const textColor = tintColor ?? getTextColor();
|
|
293
|
-
const marginLeft = getIconSpace();
|
|
289
|
+
const sizeStyle = getSizeStyle();
|
|
290
|
+
const typeStyle = getTypeStyle();
|
|
294
291
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
312
|
-
|
|
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, {
|
|
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={
|
|
332
|
+
style={containerStyle}
|
|
333
|
+
onPressIn={animateIn}
|
|
334
|
+
onPressOut={animateOut}
|
|
335
|
+
onPress={rest.onPress}
|
|
342
336
|
>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
};
|