@momo-kits/foundation 0.81.51-beta.0 → 0.81.52

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 (71) hide show
  1. package/Application/{BottomTab/index.tsx → BottomTab.tsx} +18 -42
  2. package/Application/Components.tsx +91 -356
  3. package/Application/ModalScreen.tsx +185 -14
  4. package/Application/Navigation.ts +19 -5
  5. package/Application/NavigationContainer.tsx +72 -62
  6. package/Application/Navigator.ts +48 -154
  7. package/Application/StackScreen.tsx +32 -289
  8. package/Application/index.ts +15 -13
  9. package/Application/types.ts +35 -81
  10. package/Application/utils.tsx +30 -76
  11. package/Assets/icon_bank.json +1 -1
  12. package/Badge/Badge.tsx +1 -1
  13. package/Badge/index.tsx +1 -2
  14. package/Badge/styles.ts +6 -50
  15. package/Button/index.tsx +26 -44
  16. package/CheckBox/index.tsx +26 -37
  17. package/CheckBox/types.ts +3 -5
  18. package/Consts/colors+spacing+radius.ts +0 -14
  19. package/Icon/index.tsx +8 -9
  20. package/Icon/types.ts +2 -2
  21. package/IconButton/index.tsx +14 -24
  22. package/Image/index.tsx +8 -23
  23. package/Image/types.ts +0 -2
  24. package/Input/Input.tsx +26 -116
  25. package/Input/InputDropDown.tsx +51 -66
  26. package/Input/InputMoney.tsx +15 -106
  27. package/Input/InputOTP.tsx +26 -49
  28. package/Input/InputSearch.tsx +99 -252
  29. package/Input/InputTextArea.tsx +6 -26
  30. package/Input/common.tsx +22 -48
  31. package/Input/index.tsx +77 -112
  32. package/Input/styles.ts +11 -48
  33. package/Input/utils.ts +1 -1
  34. package/Layout/Card.tsx +3 -4
  35. package/Layout/GridSystem.tsx +1 -1
  36. package/Layout/ItemList.tsx +2 -3
  37. package/Layout/Screen.tsx +121 -242
  38. package/Layout/Section.tsx +3 -4
  39. package/Layout/styles.ts +13 -11
  40. package/Layout/types.ts +1 -1
  41. package/Layout/utils.ts +4 -4
  42. package/Loader/index.tsx +0 -2
  43. package/Pagination/PaginationScroll.tsx +2 -2
  44. package/Pagination/styles.ts +1 -1
  45. package/Popup/PopupNotify.tsx +46 -57
  46. package/Popup/PopupPromotion.tsx +8 -6
  47. package/Popup/types.ts +7 -1
  48. package/Radio/index.tsx +20 -35
  49. package/Radio/types.ts +3 -5
  50. package/Switch/index.tsx +18 -32
  51. package/Switch/types.ts +3 -5
  52. package/Tag/index.tsx +2 -9
  53. package/Tag/styles.ts +2 -3
  54. package/Tag/types.ts +0 -12
  55. package/Text/index.tsx +5 -24
  56. package/Text/styles.ts +8 -8
  57. package/Title/index.tsx +103 -170
  58. package/Title/styles.ts +9 -36
  59. package/Title/types.ts +48 -16
  60. package/code-scanner.js +16 -125
  61. package/index.ts +0 -7
  62. package/package.json +7 -8
  63. package/publish.sh +21 -16
  64. package/tsconfig.json +1 -1
  65. package/Application/BottomSheet.tsx +0 -216
  66. package/Application/BottomTab/BottomTabBar.tsx +0 -278
  67. package/Application/Localize.ts +0 -44
  68. package/Application/constants.ts +0 -9
  69. package/Badge/BadgeDotAnimation.tsx +0 -95
  70. package/Input/TextTyping.tsx +0 -113
  71. package/Layout/FloatingButton.tsx +0 -168
package/publish.sh CHANGED
@@ -1,18 +1,23 @@
1
1
  #!/bin/bash
2
+ rm -rf dist
3
+ mkdir dist
2
4
 
3
- if [ "$1" == "stable" ]; then
4
- npm version $(npm view @momo-kits/foundation@stable version)
5
- npm version patch
6
- npm publish --tag stable --access=public
7
- elif [ "$1" == "latest" ]; then
8
- npm version $(npm view @momo-kits/foundation@latest version)
9
- npm version prerelease --preid=rc
10
- npm publish --tag latest --access=public
11
- else
12
- npm version $(npm view @momo-kits/foundation@beta version)
13
- npm version prerelease --preid=beta
14
- npm publish --tag beta --access=public
15
- fi
16
-
17
- PACKAGE_NAME=$(npm pkg get name)
18
- NEW_PACKAGE_VERSION=$(npm pkg get version)
5
+ cp . ./dist
6
+
7
+
8
+ # GET VERSION from mck_package.json
9
+ VERSIONSTRING=( v$(jq .version package.json) )
10
+ VERSION=(${VERSIONSTRING//[\"]/})
11
+ echo VERSION: $VERSION
12
+
13
+ rsync -r --verbose --exclude '*.mdx' --exclude '*Demo.js' --exclude 'props-type.js' --exclude 'prop-types.js' ./* dist
14
+
15
+ cd dist
16
+ npm publish --tag beta --access=public
17
+
18
+ #clear dist and package json
19
+ cd ..
20
+ rm -rf dist
21
+
22
+
23
+ #curl -X POST -H 'Content-Type: application/json' 'https://chat.googleapis.com/v1/spaces/AAAAbP8987c/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=UGSFRvk_oYb9uGsAgs31bVvMm6jDkmD8zihGm3eyaQA%3D&threadKey=JoaXTEYaNNkl' -d '{"text": "@momo-kits/core new version release: '*"$VERSION"*' https://www.npmjs.com/package/@momo-kits/foundation"}'
package/tsconfig.json CHANGED
@@ -19,6 +19,6 @@
19
19
  "resolveJsonModule": true,
20
20
  "skipLibCheck": true,
21
21
  "strict": true,
22
- "target": "esnext"
22
+ "target": "esnext",
23
23
  }
24
24
  }
@@ -1,216 +0,0 @@
1
- import React, {useRef, useEffect, useCallback, useContext} from 'react';
2
- import {
3
- Animated,
4
- Dimensions,
5
- KeyboardAvoidingView,
6
- PanResponder,
7
- Platform,
8
- StyleSheet,
9
- TouchableOpacity,
10
- View,
11
- Modal,
12
- } from 'react-native';
13
- import {useSafeAreaInsets} from 'react-native-safe-area-context';
14
- import {ApplicationContext} from './index';
15
- import {BottomSheetParams} from './types';
16
- import {Colors, Radius, Spacing, Styles} from '../Consts';
17
- import {Text} from '../Text';
18
- import {Icon} from '../Icon';
19
-
20
- const BottomSheet: React.FC<BottomSheetParams> = props => {
21
- const {theme, navigator} = useContext(ApplicationContext);
22
- const heightDevice = Dimensions.get('screen').height;
23
- const insets = useSafeAreaInsets();
24
- const {
25
- screen: Screen,
26
- options,
27
- useNativeModal = false,
28
- surface,
29
- barrierDismissible = false,
30
- draggable = true,
31
- useBottomInset = true,
32
- keyboardVerticalOffset,
33
- }: BottomSheetParams = props.route.params;
34
- const pan = useRef(
35
- new Animated.ValueXY({
36
- y: heightDevice,
37
- x: 0,
38
- })
39
- ).current;
40
-
41
- const panResponder = useRef(
42
- PanResponder.create({
43
- onStartShouldSetPanResponder: () => draggable,
44
- onMoveShouldSetPanResponder: (_, gestureState) => {
45
- return draggable && gestureState.dy > 0;
46
- },
47
- onPanResponderMove: (e, gestureState) => {
48
- gestureState.dy > 0 &&
49
- Animated.event([null, {dy: pan.y}], {useNativeDriver: false})(
50
- e,
51
- gestureState
52
- );
53
- },
54
- onPanResponderRelease: (_, gestureState) => {
55
- if (gestureState.dy > 100) {
56
- onDismiss();
57
- } else {
58
- Animated.spring(pan, {
59
- toValue: {x: 0, y: 0},
60
- useNativeDriver: false,
61
- }).start();
62
- }
63
- },
64
- })
65
- ).current;
66
- let Container: any = View;
67
- if (useNativeModal) {
68
- Container = Modal;
69
- }
70
- let backgroundColor = theme.colors.background.default;
71
- if (surface) {
72
- backgroundColor = theme.colors.background.surface;
73
- }
74
-
75
- /**
76
- * emit dismiss event
77
- */
78
- useEffect(() => {
79
- Animated.timing(pan, {
80
- toValue: {x: 0, y: 0},
81
- useNativeDriver: false,
82
- duration: 150,
83
- }).start();
84
- return () => {
85
- props.route.params?.onDismiss?.();
86
- };
87
- }, []);
88
-
89
- /**
90
- * handler dismiss
91
- */
92
- const onDismiss = (force = false, callback?: () => void) => {
93
- if (barrierDismissible && !force) {
94
- return;
95
- }
96
- setTimeout(() => {
97
- callback?.();
98
- }, 300);
99
- Animated.timing(pan, {
100
- toValue: {x: 0, y: heightDevice},
101
- useNativeDriver: false,
102
- duration: 200,
103
- }).start(() => {
104
- navigator?.pop();
105
- });
106
- };
107
-
108
- /**
109
- * on request close
110
- */
111
- const onRequestClose = useCallback((callback?: () => void) => {
112
- onDismiss(true, callback);
113
- }, []);
114
-
115
- /**
116
- * render header
117
- */
118
- const renderHeader = useCallback(() => {
119
- return (
120
- <View
121
- style={{
122
- backgroundColor,
123
- borderTopLeftRadius: Radius.M,
124
- borderTopRightRadius: Radius.M,
125
- }}
126
- {...panResponder.panHandlers}>
127
- <View style={{height: 16}}>
128
- <View style={styles.indicator} />
129
- </View>
130
- <View
131
- style={[
132
- styles.header,
133
- surface && {
134
- borderBottomColor: theme.colors.border.default,
135
- borderBottomWidth: 1,
136
- },
137
- ]}>
138
- <View style={styles.iconButton} />
139
- <Text
140
- style={[Styles.flex, {textAlign: 'center'}]}
141
- numberOfLines={1}
142
- typography="header_default_bold">
143
- {options.title ?? ''}
144
- </Text>
145
- <TouchableOpacity
146
- style={styles.iconButton}
147
- onPress={() => onDismiss(true)}>
148
- <Icon source="navigation_close" />
149
- </TouchableOpacity>
150
- </View>
151
- </View>
152
- );
153
- }, []);
154
-
155
- return (
156
- <Container
157
- transparent
158
- visible={true}
159
- onRequestClose={() => onDismiss()}
160
- style={styles.overlay}>
161
- <KeyboardAvoidingView
162
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
163
- keyboardVerticalOffset={keyboardVerticalOffset ?? -20}
164
- style={[Styles.flex, {justifyContent: 'flex-end'}]}>
165
- <TouchableOpacity
166
- style={Styles.flex}
167
- activeOpacity={1}
168
- onPress={() => onDismiss()}
169
- />
170
- <Animated.View style={{transform: pan.getTranslateTransform()}}>
171
- {renderHeader()}
172
- <View style={{backgroundColor: backgroundColor}}>
173
- <Screen
174
- {...props}
175
- {...props.route.params}
176
- onRequestClose={onRequestClose}
177
- />
178
- {useBottomInset && (
179
- <View style={{height: Math.min(insets.bottom, 21)}} />
180
- )}
181
- </View>
182
- </Animated.View>
183
- </KeyboardAvoidingView>
184
- </Container>
185
- );
186
- };
187
-
188
- const styles = StyleSheet.create({
189
- overlay: {
190
- ...StyleSheet.absoluteFillObject,
191
- justifyContent: 'flex-end',
192
- },
193
- indicator: {
194
- width: 40,
195
- height: 4,
196
- borderRadius: Radius.S,
197
- backgroundColor: Colors.black_06,
198
- position: 'absolute',
199
- alignSelf: 'center',
200
- top: Spacing.S,
201
- },
202
- header: {
203
- height: 56,
204
- flexDirection: 'row',
205
- alignItems: 'center',
206
- },
207
- iconButton: {
208
- width: 24,
209
- height: 24,
210
- alignItems: 'center',
211
- justifyContent: 'center',
212
- marginHorizontal: Spacing.M,
213
- },
214
- });
215
-
216
- export default BottomSheet;
@@ -1,278 +0,0 @@
1
- import {BottomTabBarProps} from '@react-navigation/bottom-tabs';
2
- import BottomTabBarItem from '@react-navigation/bottom-tabs/src/views/BottomTabItem';
3
- import {
4
- CommonActions,
5
- NavigationContext,
6
- NavigationRouteContext,
7
- useLinkBuilder,
8
- } from '@react-navigation/native';
9
- import React, {useCallback, useContext} from 'react';
10
- import {
11
- Animated,
12
- Platform,
13
- StyleSheet,
14
- TouchableOpacity,
15
- useWindowDimensions,
16
- View,
17
- } from 'react-native';
18
- import {EdgeInsets, useSafeAreaInsets} from 'react-native-safe-area-context';
19
- import {Radius} from '../../Consts';
20
- import {Icon} from '../../Icon';
21
- import {Text} from '../../Text';
22
- import {FloatingButtonProps} from '../types';
23
- import {ApplicationContext} from '../index';
24
-
25
- type Props = BottomTabBarProps & {
26
- activeTintColor?: string;
27
- inactiveTintColor?: string;
28
- floatingButton?: FloatingButtonProps;
29
- };
30
-
31
- const getPaddingBottom = (insets: EdgeInsets) => {
32
- return Math.max(insets.bottom - Platform.select({ios: 4, default: 0}), 0);
33
- };
34
-
35
- export default function BottomTabBar({
36
- state,
37
- navigation,
38
- descriptors,
39
- activeBackgroundColor,
40
- activeTintColor,
41
- allowFontScaling,
42
- inactiveBackgroundColor,
43
- inactiveTintColor,
44
- labelStyle,
45
- iconStyle,
46
- showLabel,
47
- style,
48
- tabStyle,
49
- floatingButton,
50
- }: Props) {
51
- const {theme} = useContext(ApplicationContext);
52
- const {routes} = state;
53
- const widthDevice = useWindowDimensions()?.width;
54
- const useFloating = floatingButton && state.routes.length % 2 === 0;
55
- const itemWidth = widthDevice / (state.routes.length + (useFloating ? 1 : 0));
56
- const buildLink = useLinkBuilder();
57
- const indicatorAnimated = React.useRef(new Animated.Value(0)).current;
58
- const insets = useSafeAreaInsets();
59
- const paddingBottom = getPaddingBottom(insets);
60
- const focusedTab = state?.routes[state.index]?.name || routes[0]?.params;
61
-
62
- /**
63
- * render tab item
64
- */
65
- const renderTabItem = useCallback(
66
- (data: any[]) => {
67
- return data?.map((route, _) => {
68
- const focused = route.params.name === focusedTab;
69
- const {options} = descriptors[route?.key] as any;
70
- const onPress = () => {
71
- const event = navigation.emit({
72
- type: 'tabPress',
73
- target: route.key,
74
- canPreventDefault: true,
75
- });
76
-
77
- if (!focused && !event.defaultPrevented) {
78
- navigation.dispatch({
79
- ...CommonActions.navigate(route.name),
80
- target: state.key,
81
- });
82
- }
83
- };
84
-
85
- const onLongPress = () => {
86
- navigation.emit({
87
- type: 'tabLongPress',
88
- target: route.key,
89
- });
90
- };
91
-
92
- const label = options.tabBarLabel || options.title || route.name;
93
-
94
- return (
95
- <NavigationContext.Provider
96
- key={route.key}
97
- value={(descriptors as any)[route.key].navigation}>
98
- <NavigationRouteContext.Provider value={route}>
99
- <BottomTabBarItem
100
- route={route}
101
- focused={focused}
102
- horizontal={false}
103
- onPress={onPress}
104
- onLongPress={onLongPress}
105
- accessibilityLabel={`tab_item_${route.name}`}
106
- to={buildLink(route.name, route.params)}
107
- testID={options.tabBarTestID}
108
- allowFontScaling={allowFontScaling}
109
- activeTintColor={activeTintColor}
110
- inactiveTintColor={inactiveTintColor}
111
- activeBackgroundColor={activeBackgroundColor}
112
- inactiveBackgroundColor={inactiveBackgroundColor}
113
- button={options.tabBarButton}
114
- icon={options.tabBarIcon}
115
- badge={options.tabBarBadge}
116
- badgeStyle={options.tabBarBadgeStyle}
117
- label={label}
118
- showLabel={showLabel}
119
- labelStyle={labelStyle}
120
- iconStyle={iconStyle}
121
- style={tabStyle}
122
- />
123
- </NavigationRouteContext.Provider>
124
- </NavigationContext.Provider>
125
- );
126
- });
127
- },
128
- [JSON.stringify(routes), state, descriptors, focusedTab]
129
- );
130
-
131
- /**
132
- * render floating button
133
- */
134
- const renderFloatingButton = useCallback(() => {
135
- const renderFloatingButton = () => {
136
- if (typeof floatingButton?.icon === 'string') {
137
- return <Icon source={floatingButton?.icon} size={32} color={'white'} />;
138
- }
139
- return floatingButton?.icon;
140
- };
141
-
142
- return (
143
- <View style={{flex: 1}}>
144
- <TouchableOpacity
145
- onPress={floatingButton?.onPress}
146
- style={styles.floatingContainer}>
147
- <View
148
- style={{
149
- ...styles.floatingContent,
150
- backgroundColor: activeTintColor ?? theme.colors.primary,
151
- }}>
152
- {renderFloatingButton()}
153
- </View>
154
- <View
155
- style={{
156
- top: -4,
157
- backgroundColor: activeTintColor ?? theme.colors.primary,
158
- borderRadius: Radius.XL,
159
- paddingHorizontal: 6,
160
- }}>
161
- <Text
162
- numberOfLines={1}
163
- typography={'description_xs_regular'}
164
- color={'white'}>
165
- {floatingButton?.label}
166
- </Text>
167
- </View>
168
- </TouchableOpacity>
169
- </View>
170
- );
171
- }, [useFloating]);
172
-
173
- /**
174
- * animated indicator
175
- */
176
- React.useEffect(() => {
177
- let index = state.index;
178
- if (useFloating && index > (state.routes.length - 1) / 2) {
179
- index += 1;
180
- }
181
- Animated.timing(indicatorAnimated, {
182
- toValue: itemWidth * index,
183
- useNativeDriver: true,
184
- duration: 200,
185
- }).start();
186
- }, [state.index, itemWidth, indicatorAnimated, useFloating]);
187
-
188
- /**
189
- * render tab bar
190
- */
191
- const renderTabBar = () => {
192
- if (useFloating) {
193
- const middleIndex = routes.length / 2;
194
- const leftArr = routes.slice(0, middleIndex);
195
- const rightArr = routes.slice(middleIndex);
196
- return (
197
- <>
198
- {renderTabItem(leftArr)}
199
- {renderFloatingButton()}
200
- {renderTabItem(rightArr)}
201
- </>
202
- );
203
- }
204
- return renderTabItem(routes);
205
- };
206
-
207
- return (
208
- <Animated.View
209
- style={[
210
- styles.tabBar,
211
- {
212
- backgroundColor: theme.colors.background.surface,
213
- borderTopColor: theme.colors.border.default,
214
- },
215
- {
216
- paddingBottom: paddingBottom,
217
- paddingHorizontal: Math.max(insets.left, insets.right),
218
- },
219
- style,
220
- ]}
221
- pointerEvents={'auto'}>
222
- <View style={styles.content} accessibilityLabel={'bottom_tab_bar'}>
223
- {useFloating && floatingButton?.container}
224
- <Animated.View
225
- style={{
226
- width: itemWidth,
227
- position: 'absolute',
228
- top: 0,
229
- transform: [{translateX: indicatorAnimated}],
230
- }}>
231
- <View
232
- style={[
233
- styles.indicator,
234
- {backgroundColor: activeTintColor ?? theme.colors.primary},
235
- ]}
236
- />
237
- </Animated.View>
238
- {renderTabBar()}
239
- </View>
240
- </Animated.View>
241
- );
242
- }
243
-
244
- const styles = StyleSheet.create({
245
- content: {
246
- flex: 1,
247
- flexDirection: 'row',
248
- },
249
- tabBar: {
250
- left: 0,
251
- right: 0,
252
- bottom: 0,
253
- borderTopWidth: StyleSheet.hairlineWidth,
254
- elevation: 8,
255
- },
256
- floatingContainer: {
257
- position: 'absolute',
258
- alignItems: 'center',
259
- left: 0,
260
- right: 0,
261
- bottom: Platform.OS === 'ios' ? -6 : 0,
262
- },
263
- floatingContent: {
264
- alignItems: 'center',
265
- justifyContent: 'center',
266
- height: 48,
267
- width: 48,
268
- borderRadius: 24,
269
- top: -10,
270
- },
271
- indicator: {
272
- height: 2,
273
- width: 44,
274
- alignSelf: 'center',
275
- borderBottomLeftRadius: 1,
276
- borderBottomRightRadius: 1,
277
- },
278
- });
@@ -1,44 +0,0 @@
1
- import {NativeModules} from 'react-native';
2
- import {LocalizationObject} from './types';
3
- import defaultLanguage from '../Assets/language.json';
4
-
5
- class Localize {
6
- private assets: LocalizationObject;
7
- private currentLanguage: 'en' | 'vi';
8
-
9
- constructor(assets: LocalizationObject) {
10
- this.assets = {
11
- vi: {...assets?.vi, ...defaultLanguage.vi},
12
- en: {...assets?.en, ...defaultLanguage.en},
13
- };
14
- this.currentLanguage = 'vi';
15
- if (NativeModules?.RNResource?.language === 'en') {
16
- this.currentLanguage = 'en';
17
- }
18
- }
19
-
20
- get getCurrentLanguage() {
21
- return this.currentLanguage;
22
- }
23
-
24
- get getAssets() {
25
- return this.assets;
26
- }
27
-
28
- translate(key: string) {
29
- return this.assets[this.currentLanguage]?.[key] || key;
30
- }
31
-
32
- translateData(data: {vi: string; en: string}) {
33
- return data[this.currentLanguage] || JSON.stringify(data);
34
- }
35
-
36
- addTranslations(translations: LocalizationObject) {
37
- this.assets = {
38
- vi: {...translations?.vi, ...this.assets.vi},
39
- en: {...translations?.en, ...this.assets.en},
40
- };
41
- }
42
- }
43
-
44
- export default Localize;
@@ -1,9 +0,0 @@
1
- export enum NavigationActionCallbackStatusEnum {
2
- Success = 'success',
3
- Failed = 'failed',
4
- }
5
-
6
- export enum NavigationActionCallbackErrorEnum {
7
- NotReady = 'not_ready',
8
- Error = 'error',
9
- }
@@ -1,95 +0,0 @@
1
- import React, {useEffect, useRef} from 'react';
2
- import {Animated, View} from 'react-native';
3
- import {BadgeDotProps} from './types';
4
- import styles from './styles';
5
-
6
- const DURATION = 500;
7
-
8
- const BadgeDotAnimation = ({size, style}: BadgeDotProps) => {
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;
13
-
14
- const dotStyle =
15
- size === 'small' ? styles.dotAnimationSmall : styles.dotAnimation;
16
- const waveStyle = size === 'small' ? styles.waveSmall : styles.wave;
17
-
18
- useEffect(() => {
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
- ])
62
- );
63
- animation.start();
64
-
65
- return () => {
66
- animation.stop();
67
- };
68
- }, []);
69
-
70
- return (
71
- <View style={[styles.dotAnimationContainer, style]}>
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
- />
91
- </View>
92
- );
93
- };
94
-
95
- export default BadgeDotAnimation;