@momo-kits/foundation 0.161.2-beta.7 → 0.161.2-beta.8
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/BottomSheet.tsx +2 -2
- package/Application/BottomTab/BottomTabBar.tsx +15 -15
- package/Application/BottomTab/index.tsx +55 -31
- package/Application/Components/BackgroundImageView.tsx +6 -22
- package/Application/Components/HeaderAnimated.tsx +29 -32
- package/Application/Components/HeaderBackground.tsx +26 -20
- package/Application/Components/HeaderExtendHeader.tsx +94 -114
- package/Application/Components/HeaderTitle.tsx +10 -39
- package/Application/Components/SearchHeader.tsx +21 -16
- package/Application/types.ts +4 -4
- package/Application/utils.tsx +3 -4
- package/Badge/BadgeDotAnimation.tsx +71 -53
- package/Button/index.tsx +4 -1
- package/Input/InputOTP.tsx +23 -38
- package/Layout/FloatingButton.tsx +59 -59
- package/Layout/Screen.tsx +57 -61
- package/Loader/ProgressBar.tsx +18 -20
- package/Pagination/Dot.tsx +2 -2
- package/Pagination/PaginationScroll.tsx +27 -31
- package/Skeleton/index.tsx +24 -32
- package/package.json +1 -1
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import React, { Ref, useContext } from 'react';
|
|
1
|
+
import React, { Ref, useContext, useEffect, useRef } from 'react';
|
|
2
2
|
import LinearGradient from 'react-native-linear-gradient';
|
|
3
|
-
import { Dimensions, Platform, StyleSheet, View } from 'react-native';
|
|
4
|
-
import Animated, {
|
|
5
|
-
Extrapolation,
|
|
6
|
-
interpolate,
|
|
7
|
-
useAnimatedStyle,
|
|
8
|
-
useSharedValue,
|
|
9
|
-
type SharedValue,
|
|
10
|
-
} from 'react-native-reanimated';
|
|
11
3
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
4
|
+
import { Animated, Dimensions, Platform, StyleSheet, View } from 'react-native';
|
|
12
5
|
import { HeaderType } from '../../Layout/types';
|
|
13
6
|
import { InputRef, InputSearch } from '../../Input';
|
|
14
7
|
import Navigation from '../Navigation';
|
|
@@ -21,10 +14,15 @@ const SCREEN_PADDING = 12;
|
|
|
21
14
|
const BACK_WIDTH = 28;
|
|
22
15
|
|
|
23
16
|
const { width: screenWidth } = Dimensions.get('window');
|
|
17
|
+
const LinearGradientAnimated = Animated.createAnimatedComponent(LinearGradient);
|
|
24
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Header extended with background image
|
|
21
|
+
* @constructor
|
|
22
|
+
*/
|
|
25
23
|
const HeaderExtendHeader: React.FC<{
|
|
26
24
|
headerType?: HeaderType;
|
|
27
|
-
animatedValue:
|
|
25
|
+
animatedValue: Animated.Value;
|
|
28
26
|
heightHeader: number;
|
|
29
27
|
headerRightWidth: number;
|
|
30
28
|
inputSearchProps?: SearchHeaderProps;
|
|
@@ -40,132 +38,118 @@ const HeaderExtendHeader: React.FC<{
|
|
|
40
38
|
headerRightWidth = 73,
|
|
41
39
|
inputSearchProps,
|
|
42
40
|
inputSearchRef,
|
|
43
|
-
useShadowHeader
|
|
41
|
+
useShadowHeader = true,
|
|
44
42
|
gradientColor: customGradientColor,
|
|
45
43
|
headerBackground: customBackground,
|
|
46
44
|
}) => {
|
|
47
45
|
const { theme } = useContext(ApplicationContext);
|
|
48
46
|
const context = useContext<any>(MiniAppContext);
|
|
49
|
-
const
|
|
50
|
-
const sv = animatedValue ?? fallback;
|
|
47
|
+
const animated = useRef(new Animated.Value(0));
|
|
51
48
|
const gradientColor = customGradientColor ?? theme.colors.gradient;
|
|
52
49
|
const headerBackground = customBackground ?? theme.assets?.headerBackground;
|
|
53
50
|
const leftPosition = inputSearchProps?.leftPosition || BACK_WIDTH + 20;
|
|
54
51
|
|
|
55
|
-
let useShadowHeader = useShadowHeaderProp;
|
|
56
|
-
if (inputSearchProps && Platform.OS === 'android') {
|
|
57
|
-
useShadowHeader = false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
52
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
61
53
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
const opacityBackground = animatedValue?.interpolate({
|
|
55
|
+
inputRange: [0, 52],
|
|
56
|
+
outputRange: [0, 1],
|
|
57
|
+
extrapolate: 'clamp',
|
|
58
|
+
});
|
|
59
|
+
const opacityGradient = animatedValue?.interpolate({
|
|
60
|
+
inputRange: [0, 52],
|
|
61
|
+
outputRange: [1, 0],
|
|
62
|
+
extrapolate: 'clamp',
|
|
63
|
+
});
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const listener = animatedValue.addListener(({ value }) => {
|
|
67
|
+
animated.current.setValue(value);
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
animatedValue?.removeListener(listener);
|
|
71
|
+
};
|
|
72
|
+
}, [animatedValue]);
|
|
74
73
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
[0, 100],
|
|
81
|
-
[SCREEN_PADDING, leftPosition],
|
|
82
|
-
Extrapolation.CLAMP,
|
|
83
|
-
),
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
width: interpolate(
|
|
87
|
-
sv.value,
|
|
88
|
-
[0, 100],
|
|
89
|
-
[
|
|
90
|
-
screenWidth - SCREEN_PADDING * 2,
|
|
91
|
-
screenWidth - leftPosition - 12 - headerRightWidth,
|
|
92
|
-
],
|
|
93
|
-
Extrapolation.CLAMP,
|
|
94
|
-
),
|
|
95
|
-
}));
|
|
74
|
+
const height = animated.current.interpolate({
|
|
75
|
+
inputRange: [0, 100],
|
|
76
|
+
outputRange: [heightHeader + 52, heightHeader],
|
|
77
|
+
extrapolate: 'clamp',
|
|
78
|
+
});
|
|
96
79
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: theme.colors.background.default };
|
|
80
|
+
const translateX = animated.current.interpolate({
|
|
81
|
+
inputRange: [0, 100],
|
|
82
|
+
outputRange: [SCREEN_PADDING, leftPosition],
|
|
83
|
+
extrapolate: 'clamp',
|
|
102
84
|
});
|
|
103
85
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
})
|
|
86
|
+
const backgroundColor = animated.current.interpolate({
|
|
87
|
+
inputRange: [0, 100],
|
|
88
|
+
outputRange: [
|
|
89
|
+
theme.colors.background.surface,
|
|
90
|
+
theme.colors.background.default,
|
|
91
|
+
],
|
|
92
|
+
extrapolate: 'clamp',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (inputSearchProps && Platform.OS === 'android') {
|
|
96
|
+
useShadowHeader = false;
|
|
97
|
+
}
|
|
112
98
|
|
|
113
99
|
if (inputSearchProps) {
|
|
114
100
|
return (
|
|
115
101
|
<View style={[{ zIndex: 0 }, showBaseLineDebug && styles.debugBaseLine]}>
|
|
116
|
-
<Animated.View style={
|
|
102
|
+
<Animated.View style={{ height: height }} />
|
|
117
103
|
<BackgroundImageView
|
|
118
104
|
useShadowHeader={useShadowHeader}
|
|
119
105
|
heightHeader={heightHeader}
|
|
120
|
-
|
|
106
|
+
opacityBackground={opacityBackground}
|
|
121
107
|
headerBackground={headerBackground}
|
|
122
108
|
/>
|
|
123
109
|
<Animated.View
|
|
124
110
|
style={[
|
|
125
111
|
styles.headerBox,
|
|
126
|
-
headerType === 'extended'
|
|
127
|
-
? heightStyle
|
|
128
|
-
: { height: heightHeader },
|
|
112
|
+
{ height: headerType === 'extended' ? height : heightHeader },
|
|
129
113
|
]}
|
|
130
114
|
>
|
|
131
115
|
{!!gradientColor && (
|
|
132
|
-
<
|
|
133
|
-
|
|
116
|
+
<LinearGradientAnimated
|
|
117
|
+
colors={[gradientColor, gradientColor + '00']}
|
|
118
|
+
style={[styles.extendedHeader, { opacity: opacityGradient }]}
|
|
134
119
|
>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
loading={false}
|
|
144
|
-
/>
|
|
145
|
-
)}
|
|
146
|
-
</LinearGradient>
|
|
147
|
-
</Animated.View>
|
|
120
|
+
{!!theme.assets?.headerBackground && (
|
|
121
|
+
<Image
|
|
122
|
+
style={styles.headerBackground}
|
|
123
|
+
source={{ uri: theme.assets?.headerBackground }}
|
|
124
|
+
loading={false}
|
|
125
|
+
/>
|
|
126
|
+
)}
|
|
127
|
+
</LinearGradientAnimated>
|
|
148
128
|
)}
|
|
149
129
|
</Animated.View>
|
|
150
130
|
<Animated.View
|
|
151
|
-
style={
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
heightStyle,
|
|
158
|
-
]}
|
|
131
|
+
style={{
|
|
132
|
+
justifyContent: 'flex-end',
|
|
133
|
+
height,
|
|
134
|
+
position: 'absolute',
|
|
135
|
+
zIndex: 2,
|
|
136
|
+
}}
|
|
159
137
|
>
|
|
160
138
|
<Animated.View
|
|
161
|
-
style={
|
|
139
|
+
style={{
|
|
140
|
+
transform: [{ translateX }],
|
|
141
|
+
marginVertical: Spacing.S,
|
|
142
|
+
width: animated.current.interpolate({
|
|
143
|
+
inputRange: [0, 100],
|
|
144
|
+
outputRange: [
|
|
145
|
+
screenWidth - SCREEN_PADDING * 2,
|
|
146
|
+
screenWidth - leftPosition - 12 - headerRightWidth,
|
|
147
|
+
],
|
|
148
|
+
extrapolate: 'clamp',
|
|
149
|
+
}),
|
|
150
|
+
}}
|
|
162
151
|
>
|
|
163
|
-
<Animated.View
|
|
164
|
-
style={[
|
|
165
|
-
{ borderRadius: Radius.XL },
|
|
166
|
-
searchBackgroundStyle,
|
|
167
|
-
]}
|
|
168
|
-
>
|
|
152
|
+
<Animated.View style={{ backgroundColor, borderRadius: Radius.XL }}>
|
|
169
153
|
<InputSearch
|
|
170
154
|
{...inputSearchProps}
|
|
171
155
|
ref={inputSearchRef}
|
|
@@ -185,26 +169,22 @@ const HeaderExtendHeader: React.FC<{
|
|
|
185
169
|
<BackgroundImageView
|
|
186
170
|
useShadowHeader={useShadowHeader}
|
|
187
171
|
heightHeader={heightHeader}
|
|
188
|
-
|
|
172
|
+
opacityBackground={opacityBackground}
|
|
189
173
|
headerBackground={headerBackground}
|
|
190
174
|
/>
|
|
191
175
|
{!!gradientColor && (
|
|
192
|
-
<
|
|
193
|
-
|
|
176
|
+
<LinearGradientAnimated
|
|
177
|
+
colors={[gradientColor, gradientColor + '00']}
|
|
178
|
+
style={[styles.extendedHeader, { opacity: opacityGradient }]}
|
|
194
179
|
>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
loading={false}
|
|
204
|
-
/>
|
|
205
|
-
)}
|
|
206
|
-
</LinearGradient>
|
|
207
|
-
</Animated.View>
|
|
180
|
+
{!!headerBackground && (
|
|
181
|
+
<Image
|
|
182
|
+
style={styles.headerBackground}
|
|
183
|
+
source={{ uri: headerBackground }}
|
|
184
|
+
loading={false}
|
|
185
|
+
/>
|
|
186
|
+
)}
|
|
187
|
+
</LinearGradientAnimated>
|
|
208
188
|
)}
|
|
209
189
|
<View style={{ height: heightHeader }} />
|
|
210
190
|
</View>
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import React, { useContext } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
Dimensions,
|
|
4
5
|
StyleSheet,
|
|
5
6
|
TouchableOpacity,
|
|
6
7
|
View,
|
|
7
8
|
} from 'react-native';
|
|
8
|
-
import Animated, {
|
|
9
|
-
Extrapolation,
|
|
10
|
-
interpolate,
|
|
11
|
-
useAnimatedStyle,
|
|
12
|
-
type SharedValue,
|
|
13
|
-
} from 'react-native-reanimated';
|
|
14
9
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
15
10
|
import { exportFontFamily, Text, useScaleSize } from '../../Text';
|
|
16
11
|
import { Colors, Radius, Spacing, Styles } from '../../Consts';
|
|
@@ -23,45 +18,21 @@ import { Image } from '../../Image';
|
|
|
23
18
|
import { Icon } from '../../Icon';
|
|
24
19
|
import { Skeleton } from '../../Skeleton';
|
|
25
20
|
|
|
26
|
-
type HeaderTitleInterpolate = {
|
|
27
|
-
inputRange: number[];
|
|
28
|
-
outputRange: number[];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type HeaderTitleExtraProps = {
|
|
32
|
-
animatedValue?: SharedValue<number>;
|
|
33
|
-
interpolate?: HeaderTitleInterpolate;
|
|
34
|
-
tintColor?: string;
|
|
35
|
-
children?: React.ReactNode;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
21
|
/**
|
|
39
22
|
* default header title used for nav
|
|
40
23
|
*/
|
|
41
|
-
const HeaderTitle: React.FC<
|
|
24
|
+
const HeaderTitle: React.FC<any> = props => {
|
|
42
25
|
const context = useContext<any>(MiniAppContext);
|
|
43
26
|
|
|
44
27
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
45
28
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!animatedValue) {
|
|
54
|
-
return { opacity: 1 };
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
opacity: interpolate(
|
|
58
|
-
animatedValue.value,
|
|
59
|
-
interpolateConfig.inputRange,
|
|
60
|
-
interpolateConfig.outputRange,
|
|
61
|
-
Extrapolation.CLAMP,
|
|
62
|
-
),
|
|
63
|
-
};
|
|
64
|
-
});
|
|
29
|
+
const opacity = props.animatedValue?.interpolate(
|
|
30
|
+
props.interpolate ?? {
|
|
31
|
+
inputRange: [0, 200],
|
|
32
|
+
outputRange: [0, 1],
|
|
33
|
+
extrapolate: 'clamp',
|
|
34
|
+
},
|
|
35
|
+
);
|
|
65
36
|
|
|
66
37
|
return (
|
|
67
38
|
<View
|
|
@@ -86,9 +57,9 @@ const HeaderTitle: React.FC<HeaderTitleExtraProps & { [key: string]: any }> = pr
|
|
|
86
57
|
},
|
|
87
58
|
{
|
|
88
59
|
fontFamily: exportFontFamily('bold', 'action_xs_bold'),
|
|
60
|
+
opacity,
|
|
89
61
|
color: props.tintColor,
|
|
90
62
|
},
|
|
91
|
-
animatedStyle,
|
|
92
63
|
]}
|
|
93
64
|
numberOfLines={1}
|
|
94
65
|
/>
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { Colors, Radius, Spacing, Styles } from '../../Consts';
|
|
2
2
|
import { InputRef, InputSearch } from '../../Input';
|
|
3
3
|
import {
|
|
4
|
+
Animated,
|
|
4
5
|
Dimensions,
|
|
5
6
|
StyleSheet,
|
|
6
7
|
TouchableOpacity,
|
|
7
8
|
View,
|
|
8
9
|
} from 'react-native';
|
|
9
|
-
import
|
|
10
|
-
useAnimatedStyle,
|
|
11
|
-
useSharedValue,
|
|
12
|
-
} from 'react-native-reanimated';
|
|
13
|
-
import React, { useContext } from 'react';
|
|
10
|
+
import React, { useContext, useEffect, useRef } from 'react';
|
|
14
11
|
import { SearchHeaderProps } from '../types';
|
|
15
12
|
import { ApplicationContext, MiniAppContext } from '../../Context';
|
|
16
13
|
import { Text } from '../../Text';
|
|
@@ -31,18 +28,28 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
|
|
|
31
28
|
const BACK_WIDTH = 28;
|
|
32
29
|
const { width: screenWidth } = Dimensions.get('window');
|
|
33
30
|
|
|
34
|
-
const
|
|
35
|
-
const sv = animatedValue ?? fallback;
|
|
31
|
+
const animated = useRef(new Animated.Value(0));
|
|
36
32
|
const leftPosition = props?.leftPosition ?? BACK_WIDTH + 20;
|
|
37
33
|
const headerRightWidth = props?.headerRightWidth ?? 73;
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const listener = animatedValue?.addListener(({ value }) => {
|
|
37
|
+
animated.current.setValue(value);
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
if (listener) {
|
|
41
|
+
animatedValue?.removeListener(listener);
|
|
42
|
+
}
|
|
45
43
|
};
|
|
44
|
+
}, [animatedValue]);
|
|
45
|
+
|
|
46
|
+
const backgroundColor = animated.current?.interpolate({
|
|
47
|
+
inputRange: [0, 100],
|
|
48
|
+
outputRange: [
|
|
49
|
+
theme.colors.background.surface,
|
|
50
|
+
theme.colors.background.default,
|
|
51
|
+
],
|
|
52
|
+
extrapolate: 'clamp',
|
|
46
53
|
});
|
|
47
54
|
|
|
48
55
|
const goBack = () => {
|
|
@@ -84,9 +91,7 @@ const SearchHeader = React.forwardRef<InputRef, SearchHeaderProps>(
|
|
|
84
91
|
},
|
|
85
92
|
]}
|
|
86
93
|
>
|
|
87
|
-
<Animated.View
|
|
88
|
-
style={[{ borderRadius: Radius.XL }, backgroundStyle]}
|
|
89
|
-
>
|
|
94
|
+
<Animated.View style={{ backgroundColor, borderRadius: Radius.XL }}>
|
|
90
95
|
<InputSearch
|
|
91
96
|
ref={ref}
|
|
92
97
|
{...props}
|
package/Application/types.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { EventArg } from '@react-navigation/core';
|
|
|
2
2
|
import { StackNavigationOptions } from '@react-navigation/stack';
|
|
3
3
|
import React, { ReactNode } from 'react';
|
|
4
4
|
import {
|
|
5
|
+
Animated,
|
|
5
6
|
TouchableOpacityProps,
|
|
6
7
|
ViewProps,
|
|
7
8
|
ViewStyle,
|
|
8
9
|
} from 'react-native';
|
|
9
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
10
10
|
import { PopupNotifyProps } from '../Popup/types';
|
|
11
11
|
import { InputRef, InputSearchProps } from '../Input';
|
|
12
12
|
import Navigation from './Navigation';
|
|
@@ -258,7 +258,7 @@ export interface HeaderBackProps extends NavigationButtonProps {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
export type HeaderBackgroundProps = {
|
|
261
|
-
animatedValue?:
|
|
261
|
+
animatedValue?: Animated.Value;
|
|
262
262
|
useGradient?: boolean;
|
|
263
263
|
useShadowHeader?: boolean;
|
|
264
264
|
backgroundColor?: string;
|
|
@@ -298,7 +298,7 @@ export type TitleJourneyProps = {
|
|
|
298
298
|
};
|
|
299
299
|
|
|
300
300
|
export interface HeaderAnimatedProps extends ViewProps {
|
|
301
|
-
animatedValue:
|
|
301
|
+
animatedValue: Animated.Value;
|
|
302
302
|
image: string;
|
|
303
303
|
useScale?: boolean;
|
|
304
304
|
}
|
|
@@ -342,7 +342,7 @@ export type AnimatedHeader = {
|
|
|
342
342
|
|
|
343
343
|
export interface SearchHeaderProps extends InputSearchProps {
|
|
344
344
|
ref?: React.RefObject<InputRef>;
|
|
345
|
-
animatedValue?:
|
|
345
|
+
animatedValue?: Animated.Value;
|
|
346
346
|
headerRightWidth?: 0 | 74 | 110 | number;
|
|
347
347
|
leftPosition?: 12 | 48 | number;
|
|
348
348
|
renderButtons?: () => ReactNode;
|
package/Application/utils.tsx
CHANGED
|
@@ -5,8 +5,7 @@ import {
|
|
|
5
5
|
} from '@react-navigation/stack';
|
|
6
6
|
import type { HeaderTitleProps, NavigationOptions } from './types';
|
|
7
7
|
import { Colors, Spacing } from '../Consts';
|
|
8
|
-
import { AppState, Platform } from 'react-native';
|
|
9
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
8
|
+
import { Animated, AppState, Platform } from 'react-native';
|
|
10
9
|
import {
|
|
11
10
|
MiniAppContext,
|
|
12
11
|
ScreenContext,
|
|
@@ -61,7 +60,7 @@ const getModalOptions = (): StackNavigationOptions => {
|
|
|
61
60
|
*/
|
|
62
61
|
const getOptions = (
|
|
63
62
|
params: NavigationOptions,
|
|
64
|
-
animatedValue?:
|
|
63
|
+
animatedValue?: Animated.Value,
|
|
65
64
|
) => {
|
|
66
65
|
let options: StackNavigationOptions = {};
|
|
67
66
|
|
|
@@ -132,7 +131,7 @@ const getOptions = (
|
|
|
132
131
|
|
|
133
132
|
const exportHeaderTitle = (
|
|
134
133
|
params: NavigationOptions,
|
|
135
|
-
animatedValue?:
|
|
134
|
+
animatedValue?: Animated.Value,
|
|
136
135
|
): StackNavigationOptions => {
|
|
137
136
|
if (typeof params.headerTitle === 'object') {
|
|
138
137
|
return {
|
|
@@ -1,75 +1,93 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import { View } from 'react-native';
|
|
3
|
-
import Animated, {
|
|
4
|
-
cancelAnimation,
|
|
5
|
-
useAnimatedStyle,
|
|
6
|
-
useSharedValue,
|
|
7
|
-
withRepeat,
|
|
8
|
-
withSequence,
|
|
9
|
-
withSpring,
|
|
10
|
-
withTiming,
|
|
11
|
-
} from 'react-native-reanimated';
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { Animated, View } from 'react-native';
|
|
12
3
|
import { BadgeDotProps } from './types';
|
|
13
4
|
import styles from './styles';
|
|
14
5
|
|
|
15
6
|
const DURATION = 500;
|
|
16
7
|
|
|
17
8
|
const BadgeDotAnimation = ({ size, style }: BadgeDotProps) => {
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
9
|
+
// Refs for animated values
|
|
10
|
+
const scaleAnim = useRef(new Animated.Value(1)).current;
|
|
11
|
+
const waveScaleAnim = useRef(new Animated.Value(1)).current;
|
|
12
|
+
const waveOpacityAnim = useRef(new Animated.Value(0)).current;
|
|
21
13
|
|
|
22
14
|
const dotStyle =
|
|
23
15
|
size === 'small' ? styles.dotAnimationSmall : styles.dotAnimation;
|
|
24
16
|
const waveStyle = size === 'small' ? styles.waveSmall : styles.wave;
|
|
25
17
|
|
|
26
18
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
19
|
+
// Infinite loop animation for the scale and wave effect
|
|
20
|
+
const animation = Animated.loop(
|
|
21
|
+
Animated.parallel([
|
|
22
|
+
// Dot pulse animation
|
|
23
|
+
Animated.sequence([
|
|
24
|
+
Animated.spring(scaleAnim, {
|
|
25
|
+
toValue: 1, // Scale up slightly
|
|
26
|
+
friction: 5, // Controls the "bounciness" of the spring
|
|
27
|
+
tension: 30, // Controls the "stiffness" of the spring
|
|
28
|
+
useNativeDriver: true,
|
|
29
|
+
}),
|
|
30
|
+
Animated.spring(scaleAnim, {
|
|
31
|
+
toValue: 1.1,
|
|
32
|
+
friction: 5,
|
|
33
|
+
tension: 30,
|
|
34
|
+
useNativeDriver: true,
|
|
35
|
+
}),
|
|
36
|
+
]), // Wave animation
|
|
37
|
+
Animated.sequence([
|
|
38
|
+
Animated.timing(waveScaleAnim, {
|
|
39
|
+
toValue: 2.5,
|
|
40
|
+
duration: DURATION * 3,
|
|
41
|
+
useNativeDriver: true,
|
|
42
|
+
}),
|
|
43
|
+
Animated.timing(waveScaleAnim, {
|
|
44
|
+
toValue: 1, // Reset wave size
|
|
45
|
+
duration: 0,
|
|
46
|
+
useNativeDriver: true,
|
|
47
|
+
}),
|
|
48
|
+
]), // Wave opacity animation
|
|
49
|
+
Animated.sequence([
|
|
50
|
+
Animated.timing(waveOpacityAnim, {
|
|
51
|
+
toValue: 0.3, // Wave becomes visible
|
|
52
|
+
duration: DURATION * 2,
|
|
53
|
+
useNativeDriver: true,
|
|
54
|
+
}),
|
|
55
|
+
Animated.timing(waveOpacityAnim, {
|
|
56
|
+
toValue: 0, // Wave fades out
|
|
57
|
+
duration: DURATION,
|
|
58
|
+
useNativeDriver: true,
|
|
59
|
+
}),
|
|
60
|
+
]),
|
|
61
|
+
]),
|
|
52
62
|
);
|
|
63
|
+
animation.start();
|
|
64
|
+
|
|
53
65
|
return () => {
|
|
54
|
-
|
|
55
|
-
cancelAnimation(waveScaleAnim);
|
|
56
|
-
cancelAnimation(waveOpacityAnim);
|
|
66
|
+
animation.stop();
|
|
57
67
|
};
|
|
58
68
|
}, [scaleAnim, waveOpacityAnim, waveScaleAnim]);
|
|
59
69
|
|
|
60
|
-
const waveAnimatedStyle = useAnimatedStyle(() => ({
|
|
61
|
-
transform: [{ scale: waveScaleAnim.value }],
|
|
62
|
-
opacity: waveOpacityAnim.value,
|
|
63
|
-
}));
|
|
64
|
-
|
|
65
|
-
const dotAnimatedStyle = useAnimatedStyle(() => ({
|
|
66
|
-
transform: [{ scale: scaleAnim.value }],
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
70
|
return (
|
|
70
71
|
<View style={[styles.dotAnimationContainer, style]}>
|
|
71
|
-
|
|
72
|
-
<Animated.View
|
|
72
|
+
{/* Wave Animation */}
|
|
73
|
+
<Animated.View
|
|
74
|
+
style={[
|
|
75
|
+
waveStyle,
|
|
76
|
+
{
|
|
77
|
+
transform: [{ scale: waveScaleAnim }],
|
|
78
|
+
opacity: waveOpacityAnim,
|
|
79
|
+
},
|
|
80
|
+
]}
|
|
81
|
+
/>
|
|
82
|
+
{/* Dot Animation */}
|
|
83
|
+
<Animated.View
|
|
84
|
+
style={[
|
|
85
|
+
dotStyle,
|
|
86
|
+
{
|
|
87
|
+
transform: [{ scale: scaleAnim }],
|
|
88
|
+
},
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
73
91
|
</View>
|
|
74
92
|
);
|
|
75
93
|
};
|
package/Button/index.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { FC, useContext, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
StyleSheet,
|
|
4
5
|
TouchableOpacity,
|
|
5
6
|
TouchableOpacityProps,
|
|
@@ -28,6 +29,8 @@ import Reanimated, {
|
|
|
28
29
|
withTiming,
|
|
29
30
|
} from 'react-native-reanimated';
|
|
30
31
|
|
|
32
|
+
const AnimationLinear = Animated.createAnimatedComponent(LinearGradient);
|
|
33
|
+
|
|
31
34
|
export interface ButtonProps extends TouchableOpacityProps {
|
|
32
35
|
/**
|
|
33
36
|
* Defines the visual style of the button.
|
|
@@ -356,7 +359,7 @@ const Button: FC<ButtonProps> = ({
|
|
|
356
359
|
{renderTitle()}
|
|
357
360
|
{renderIcon('right')}
|
|
358
361
|
{gradientPros && (
|
|
359
|
-
<
|
|
362
|
+
<AnimationLinear {...gradientPros} style={styles.gradientView} />
|
|
360
363
|
)}
|
|
361
364
|
{gradientPros && <View style={styles.strokeView} />}
|
|
362
365
|
</Reanimated.View>
|