@momo-kits/foundation 0.74.2-react-native.1

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 (105) hide show
  1. package/Application/BottomTab.tsx +120 -0
  2. package/Application/Components.tsx +534 -0
  3. package/Application/ModalScreen.tsx +268 -0
  4. package/Application/Navigation.ts +50 -0
  5. package/Application/NavigationContainer.tsx +120 -0
  6. package/Application/Navigator.ts +131 -0
  7. package/Application/StackScreen.tsx +71 -0
  8. package/Application/index.ts +41 -0
  9. package/Application/types.ts +216 -0
  10. package/Application/utils.tsx +151 -0
  11. package/Assets/DotAnimation.json +256 -0
  12. package/Assets/SpinnerAnimation.json +1027 -0
  13. package/Assets/icon.json +4031 -0
  14. package/Assets/icon_bank.json +506 -0
  15. package/Assets/language.json +202 -0
  16. package/Badge/Badge.tsx +56 -0
  17. package/Badge/BadgeDot.tsx +11 -0
  18. package/Badge/BadgeRibbon.tsx +125 -0
  19. package/Badge/Shape.tsx +29 -0
  20. package/Badge/index.tsx +7 -0
  21. package/Badge/styles.ts +58 -0
  22. package/Badge/types.ts +63 -0
  23. package/Button/index.tsx +310 -0
  24. package/Button/styles.ts +60 -0
  25. package/CheckBox/index.tsx +65 -0
  26. package/CheckBox/styles.ts +15 -0
  27. package/CheckBox/types.ts +38 -0
  28. package/Consts/colors+spacing+radius.ts +218 -0
  29. package/Consts/index.ts +4 -0
  30. package/Consts/styles.ts +52 -0
  31. package/Consts/theme.ts +125 -0
  32. package/Divider/index.tsx +21 -0
  33. package/Icon/index.tsx +41 -0
  34. package/Icon/types.ts +27 -0
  35. package/IconButton/index.tsx +139 -0
  36. package/IconButton/styles.ts +19 -0
  37. package/Image/index.tsx +83 -0
  38. package/Image/styles.ts +5 -0
  39. package/Image/types.ts +5 -0
  40. package/Input/Input.tsx +192 -0
  41. package/Input/InputDropDown.tsx +114 -0
  42. package/Input/InputMoney.tsx +163 -0
  43. package/Input/InputOTP.tsx +235 -0
  44. package/Input/InputSearch.tsx +151 -0
  45. package/Input/InputTextArea.tsx +159 -0
  46. package/Input/common.tsx +129 -0
  47. package/Input/index.tsx +251 -0
  48. package/Input/styles.ts +160 -0
  49. package/Input/utils.ts +69 -0
  50. package/Layout/Card.tsx +180 -0
  51. package/Layout/GridSystem.tsx +136 -0
  52. package/Layout/Item.tsx +56 -0
  53. package/Layout/ItemList.tsx +55 -0
  54. package/Layout/ItemSectionList.tsx +39 -0
  55. package/Layout/Screen.tsx +355 -0
  56. package/Layout/Section.tsx +179 -0
  57. package/Layout/index.ts +29 -0
  58. package/Layout/styles.ts +97 -0
  59. package/Layout/types.ts +23 -0
  60. package/Layout/utils.ts +55 -0
  61. package/Loader/DotLoader.tsx +37 -0
  62. package/Loader/Loader.tsx +13 -0
  63. package/Loader/ProgressBar.tsx +44 -0
  64. package/Loader/Spinner.tsx +28 -0
  65. package/Loader/index.tsx +4 -0
  66. package/Loader/styles.ts +10 -0
  67. package/Loader/types.ts +35 -0
  68. package/Loader/utils.ts +25 -0
  69. package/Pagination/Dot.tsx +16 -0
  70. package/Pagination/PaginationDot.tsx +38 -0
  71. package/Pagination/PaginationNumber.tsx +24 -0
  72. package/Pagination/PaginationScroll.tsx +88 -0
  73. package/Pagination/PaginationWhiteDot.tsx +35 -0
  74. package/Pagination/index.tsx +25 -0
  75. package/Pagination/styles.ts +50 -0
  76. package/Pagination/types.ts +40 -0
  77. package/Popup/PopupNotify.tsx +266 -0
  78. package/Popup/PopupPromotion.tsx +120 -0
  79. package/Popup/index.tsx +4 -0
  80. package/Popup/types.ts +87 -0
  81. package/Radio/index.tsx +64 -0
  82. package/Radio/styles.ts +11 -0
  83. package/Radio/types.ts +38 -0
  84. package/Skeleton/index.tsx +72 -0
  85. package/Skeleton/styles.ts +5 -0
  86. package/Skeleton/types.ts +6 -0
  87. package/Switch/index.tsx +37 -0
  88. package/Switch/styles.ts +23 -0
  89. package/Switch/types.ts +26 -0
  90. package/Tag/index.tsx +79 -0
  91. package/Tag/styles.ts +24 -0
  92. package/Tag/types.ts +36 -0
  93. package/Text/index.tsx +110 -0
  94. package/Text/styles.ts +73 -0
  95. package/Text/types.ts +34 -0
  96. package/Text/utils.ts +14 -0
  97. package/Title/index.tsx +132 -0
  98. package/Title/styles.ts +52 -0
  99. package/Title/types.ts +52 -0
  100. package/code-scanner.js +51 -0
  101. package/index.ts +51 -0
  102. package/package.json +36 -0
  103. package/publish.sh +23 -0
  104. package/tsconfig.json +24 -0
  105. package/verify.js +44 -0
@@ -0,0 +1,266 @@
1
+ import React, {useContext, useEffect, useRef, useState} from 'react';
2
+ import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native';
3
+ import {PopupNotifyProps} from './types';
4
+ import {Radius, Spacing, Styles} from '../Consts';
5
+ import {Image} from '../Image';
6
+ import {Text} from '../Text';
7
+ import {ApplicationContext, MiniAppContext} from '../Application';
8
+ import {Button} from '../Button';
9
+ import {Icon} from '../Icon';
10
+
11
+ const PopupNotify: React.FC<PopupNotifyProps> = ({
12
+ id,
13
+ image,
14
+ title = 'Title',
15
+ description = 'Description',
16
+ error,
17
+ secondary,
18
+ primary,
19
+ buttonDirection = 'row',
20
+ onIconClose,
21
+ }) => {
22
+ const context = useContext(MiniAppContext);
23
+ const {theme, navigator, translate} = useContext(ApplicationContext);
24
+ const [scrollContent, setScrollContent] = useState(false);
25
+ const closeAction = useRef('touch_outside');
26
+
27
+ let descriptionStyle = {};
28
+ let Description: any = View;
29
+ if (scrollContent) {
30
+ Description = ScrollView;
31
+ descriptionStyle = {height: 80};
32
+ }
33
+
34
+ /**
35
+ * tracking
36
+ */
37
+ useEffect(() => {
38
+ const routes = navigator?.ref.current?.getRootState()?.routes || [];
39
+ const routesLength = routes.length;
40
+ let screen_name = routes?.[0]?.params?.screen?.name;
41
+ if (routesLength > 1) {
42
+ screen_name = routes[routesLength - 2]?.params?.screen?.name;
43
+ }
44
+ const tracking = {
45
+ ...context,
46
+ screen_name,
47
+ component_type: 'popup',
48
+ component_name: id,
49
+ error_code: error ? error : undefined,
50
+ };
51
+ navigator?.maxApi?.trackEvent?.('service_component_displayed', {
52
+ ...tracking,
53
+ trigger_id: '111012100000000000',
54
+ });
55
+
56
+ return () => {
57
+ navigator?.maxApi?.trackEvent?.('service_popup_dismissed', {
58
+ ...tracking,
59
+ trigger_id: '111154100000000001',
60
+ action_type: closeAction.current,
61
+ });
62
+ };
63
+ }, []);
64
+
65
+ /**
66
+ * on action popup
67
+ * @param callback
68
+ */
69
+ const onAction = (callback?: () => void) => {
70
+ navigator?.pop();
71
+ callback?.();
72
+ };
73
+
74
+ /**
75
+ * build main action of popup
76
+ */
77
+ const buildAction = () => {
78
+ const renderRow = () => {
79
+ return (
80
+ <View style={Styles.row}>
81
+ {!!secondary?.title && (
82
+ <>
83
+ <View style={Styles.flex}>
84
+ <Button
85
+ title={secondary?.title}
86
+ type="text"
87
+ size="medium"
88
+ onPress={() => {
89
+ closeAction.current = 'button_action';
90
+ onAction(secondary?.onPress);
91
+ }}
92
+ />
93
+ </View>
94
+ <View style={styles.buttonSpace} />
95
+ </>
96
+ )}
97
+ <View style={Styles.flex}>
98
+ <Button
99
+ title={primary.title}
100
+ size="medium"
101
+ onPress={() => {
102
+ closeAction.current = 'button_action';
103
+ onAction(primary.onPress);
104
+ }}
105
+ />
106
+ </View>
107
+ </View>
108
+ );
109
+ };
110
+ const renderColumn = () => {
111
+ return (
112
+ <View style={Styles.columnCenter}>
113
+ <Button
114
+ title={primary.title}
115
+ size="medium"
116
+ onPress={() => {
117
+ closeAction.current = 'button_action';
118
+ onAction(primary.onPress);
119
+ }}
120
+ />
121
+ {!!secondary?.title && (
122
+ <>
123
+ <View style={styles.buttonSpace} />
124
+ <Button
125
+ title={secondary?.title}
126
+ type="text"
127
+ size="medium"
128
+ onPress={() => {
129
+ closeAction.current = 'button_action';
130
+ onAction(secondary?.onPress);
131
+ }}
132
+ />
133
+ </>
134
+ )}
135
+ </View>
136
+ );
137
+ };
138
+
139
+ if (buttonDirection == 'auto') {
140
+ if (
141
+ secondary?.title &&
142
+ (secondary.title.length > 12 || primary.title.length > 12)
143
+ ) {
144
+ return renderColumn();
145
+ }
146
+ return renderRow();
147
+ }
148
+ if (buttonDirection == 'row') {
149
+ return renderRow();
150
+ }
151
+ return renderColumn();
152
+ };
153
+
154
+ /**
155
+ * build close action
156
+ */
157
+ const buildCloseIcon = () => {
158
+ return (
159
+ <TouchableOpacity
160
+ style={styles.iconCloseContainer}
161
+ onPress={() => {
162
+ closeAction.current = 'icon_close';
163
+ onAction(onIconClose);
164
+ }}>
165
+ <View
166
+ style={[
167
+ styles.iconClose,
168
+ {
169
+ backgroundColor: theme.colors.text.default,
170
+ borderColor: theme.colors.background.surface,
171
+ },
172
+ ]}>
173
+ <Icon
174
+ source="navigation_close"
175
+ color={theme.colors.background.surface}
176
+ size={14}
177
+ />
178
+ </View>
179
+ </TouchableOpacity>
180
+ );
181
+ };
182
+
183
+ return (
184
+ <View
185
+ style={[
186
+ styles.container,
187
+ {backgroundColor: theme.colors.background.surface},
188
+ ]}>
189
+ {!!image && <Image source={{uri: image}} style={styles.image} />}
190
+ <View style={styles.content}>
191
+ <Text typography={'header_default_bold'} numberOfLines={1}>
192
+ {title}
193
+ </Text>
194
+ <Description style={[styles.description, descriptionStyle]}>
195
+ <Text
196
+ typography={'body_default_regular'}
197
+ onTextLayout={({nativeEvent: {lines}}) => {
198
+ const enableScroll = lines.length > 3;
199
+ if (enableScroll != scrollContent) {
200
+ setScrollContent(enableScroll);
201
+ }
202
+ }}>
203
+ {description}
204
+ </Text>
205
+ </Description>
206
+ {!!error && (
207
+ <View style={styles.information}>
208
+ <Text
209
+ typography={'description_xs_regular'}
210
+ color={theme.colors.text.hint}
211
+ numberOfLines={1}>
212
+ {translate?.('errorCode')}
213
+ {error}
214
+ </Text>
215
+ </View>
216
+ )}
217
+ </View>
218
+ <View style={styles.contentAction}>{buildAction()}</View>
219
+ {buildCloseIcon()}
220
+ </View>
221
+ );
222
+ };
223
+
224
+ const styles = StyleSheet.create({
225
+ container: {
226
+ borderRadius: Radius.L,
227
+ minWidth: '100%',
228
+ },
229
+ image: {
230
+ borderTopLeftRadius: Radius.L,
231
+ borderTopRightRadius: Radius.L,
232
+ aspectRatio: 1.7777,
233
+ overflow: 'hidden',
234
+ },
235
+ content: {padding: Spacing.XL},
236
+ description: {
237
+ marginTop: Spacing.S,
238
+ },
239
+ information: {
240
+ marginTop: Spacing.S,
241
+ },
242
+ contentAction: {
243
+ paddingHorizontal: Spacing.XL,
244
+ paddingBottom: Spacing.XL,
245
+ },
246
+ buttonSpace: {
247
+ width: Spacing.S,
248
+ height: Spacing.S,
249
+ },
250
+ iconCloseContainer: {
251
+ position: 'absolute',
252
+ top: -Spacing.M,
253
+ right: -Spacing.M,
254
+ padding: Spacing.XS,
255
+ },
256
+ iconClose: {
257
+ width: 20,
258
+ height: 20,
259
+ alignItems: 'center',
260
+ justifyContent: 'center',
261
+ borderRadius: Radius.M,
262
+ borderWidth: 2,
263
+ },
264
+ });
265
+
266
+ export default PopupNotify;
@@ -0,0 +1,120 @@
1
+ import React, {useContext, useEffect, useRef} from 'react';
2
+ import {StyleSheet, TouchableOpacity, View} from 'react-native';
3
+ import {PopupPromotionProps} from './types';
4
+ import {ApplicationContext, MiniAppContext} from '../Application';
5
+ import {Image} from '../Image';
6
+ import {Radius, Spacing} from '../Consts';
7
+ import {Icon} from '../Icon';
8
+
9
+ const PopupPromotion: React.FC<PopupPromotionProps> = ({
10
+ id,
11
+ image,
12
+ onIconClose,
13
+ }) => {
14
+ const context = useContext(MiniAppContext);
15
+ const {theme, navigator} = useContext(ApplicationContext);
16
+ const closeAction = useRef('touch_outside');
17
+
18
+ /**
19
+ * tracking
20
+ */
21
+ useEffect(() => {
22
+ const routes = navigator?.ref.current?.getRootState()?.routes || [];
23
+ const routesLength = routes.length;
24
+ let screen_name = routes?.[0]?.params?.screen?.name;
25
+ if (routesLength > 1) {
26
+ screen_name = routes[routesLength - 2]?.params?.screen?.name;
27
+ }
28
+ const tracking = {
29
+ ...context,
30
+ screen_name,
31
+ component_type: 'popup',
32
+ component_name: id,
33
+ };
34
+ navigator?.maxApi?.trackEvent?.('service_component_displayed', {
35
+ ...tracking,
36
+ trigger_id: '111012100000000000',
37
+ });
38
+ return () => {
39
+ navigator?.maxApi?.trackEvent?.('service_popup_dismissed', {
40
+ ...tracking,
41
+ trigger_id: '111154100000000001',
42
+ action_type: closeAction.current,
43
+ });
44
+ };
45
+ }, []);
46
+
47
+ /**
48
+ * build close action
49
+ */
50
+ const buildCloseIcon = () => {
51
+ return (
52
+ <View style={styles.iconCloseContainer}>
53
+ <TouchableOpacity
54
+ onPress={() => {
55
+ closeAction.current = 'icon_close';
56
+ navigator?.pop();
57
+ onIconClose?.();
58
+ }}
59
+ style={styles.iconButton}>
60
+ <View
61
+ style={[
62
+ styles.iconClose,
63
+ {
64
+ backgroundColor: theme.colors.text.default,
65
+ borderColor: theme.colors.background.surface,
66
+ },
67
+ ]}>
68
+ <Icon
69
+ source="navigation_close"
70
+ color={theme.colors.background.surface}
71
+ size={14}
72
+ />
73
+ </View>
74
+ </TouchableOpacity>
75
+ </View>
76
+ );
77
+ };
78
+
79
+ return (
80
+ <View>
81
+ <Image
82
+ source={{
83
+ uri: image,
84
+ }}
85
+ style={styles.container}
86
+ />
87
+ {buildCloseIcon()}
88
+ </View>
89
+ );
90
+ };
91
+
92
+ const styles = StyleSheet.create({
93
+ container: {
94
+ aspectRatio: 0.72,
95
+ width: '100%',
96
+ },
97
+ iconCloseContainer: {
98
+ width: '100%',
99
+ flexDirection: 'row',
100
+ justifyContent: 'center',
101
+ marginTop: Spacing.S,
102
+ },
103
+ iconButton: {
104
+ padding: 8,
105
+ },
106
+ iconClose: {
107
+ width: 20,
108
+ height: 20,
109
+ alignItems: 'center',
110
+ justifyContent: 'center',
111
+ borderRadius: Radius.M,
112
+ borderWidth: 2,
113
+ },
114
+ });
115
+
116
+ PopupPromotion.defaultProps = {
117
+ image: 'https://google.com',
118
+ };
119
+
120
+ export default PopupPromotion;
@@ -0,0 +1,4 @@
1
+ import PopupNotify from './PopupNotify';
2
+ import PopupPromotion from './PopupPromotion';
3
+
4
+ export {PopupNotify, PopupPromotion};
package/Popup/types.ts ADDED
@@ -0,0 +1,87 @@
1
+ import {TextStyle} from 'react-native';
2
+ import React from 'react';
3
+
4
+ export type PopupNotifyProps = {
5
+ /**
6
+ * `id`: Optional. id component_name for tracking component.
7
+ */
8
+ id?: string;
9
+ /**
10
+ * `image`: Optional. Represents the URL or path of the image to be displayed in the PopupNotify component.
11
+ */
12
+ image?: string;
13
+
14
+ /**
15
+ * `title`: Represents the title text to be displayed in the PopupNotify component.
16
+ */
17
+ title: string;
18
+
19
+ /**
20
+ * `description`: Represents the description text to be displayed in the PopupNotify component.
21
+ */
22
+ description: string | React.ReactNode;
23
+
24
+ /**
25
+ * `error`: Optional. Represents additional error text to be displayed in the PopupNotify component.
26
+ */
27
+ error?: string;
28
+
29
+ /**
30
+ * `secondary`: Optional. Represents the secondary action that can be performed from the PopupNotify component.
31
+ */
32
+ secondary?: PopupAction;
33
+
34
+ /**
35
+ * `primary`: Represents the primary action that can be performed from the PopupNotify component.
36
+ */
37
+ primary: PopupAction;
38
+
39
+ /**
40
+ * `buttonDirection`: Optional. Represents the direction in which the action buttons are laid out.
41
+ * - 'row': Buttons are laid out horizontally.
42
+ * - 'column': Buttons are laid out vertically.
43
+ * - 'auto': The layout is automatically determined by title length.
44
+ */
45
+ buttonDirection?: PopupActionDirection;
46
+
47
+ /**
48
+ * `onIconClose`: Optional. A callback function that is called when the close icon in the PopupNotify component is pressed.
49
+ */
50
+ onIconClose?: () => void;
51
+ };
52
+
53
+ export type PopupPromotionProps = {
54
+ /**
55
+ * `id`: Optional. id component_name for tracking component.
56
+ */
57
+ id?: string;
58
+
59
+ /**
60
+ * `image`: Represents the URL or path of the image to be displayed in the PopupPromotion component.
61
+ */
62
+ image: string;
63
+
64
+ /**
65
+ * `onClose`: Optional. A callback function that is called when the PopupPromotion component is closed.
66
+ */
67
+ onIconClose?: () => void;
68
+ };
69
+
70
+ type PopupAction = {
71
+ /**
72
+ * `title`: Represents the title text of the action button.
73
+ */
74
+ title: string;
75
+
76
+ /**
77
+ * `onPress`: A callback function that is called when the action button is pressed.
78
+ */
79
+ onPress: () => void;
80
+ };
81
+
82
+ export type HighlightText = {
83
+ text: string;
84
+ style: TextStyle;
85
+ };
86
+
87
+ type PopupActionDirection = 'row' | 'column' | 'auto';
@@ -0,0 +1,64 @@
1
+ import React, {FC, useContext} from 'react';
2
+ import {TouchableOpacity, View} from 'react-native';
3
+
4
+ import {RadioProps} from './types';
5
+ import {Text} from '../Text';
6
+ import styles from './styles';
7
+ import {ApplicationContext} from '../Application';
8
+ import {Spacing} from '../Consts';
9
+
10
+ const Radio: FC<RadioProps> = ({
11
+ value,
12
+ groupValue,
13
+ disabled,
14
+ onChange,
15
+ label,
16
+ style,
17
+ }) => {
18
+ const {theme} = useContext(ApplicationContext);
19
+ const selected = value === groupValue;
20
+ let disabledStyle = {};
21
+ let checkBoxStyle = {
22
+ borderWidth: 2,
23
+ borderColor: theme.colors.text.default,
24
+ };
25
+
26
+ if (selected) {
27
+ checkBoxStyle = {
28
+ borderWidth: 6,
29
+ borderColor: theme.colors.primary,
30
+ };
31
+ }
32
+ if (disabled) {
33
+ disabledStyle = {
34
+ borderColor: selected
35
+ ? theme.colors.background.tonal
36
+ : theme.colors.text.disable,
37
+ };
38
+ }
39
+
40
+ return (
41
+ <TouchableOpacity
42
+ onPress={onChange}
43
+ disabled={disabled}
44
+ style={[
45
+ style,
46
+ {
47
+ flexDirection: 'row',
48
+ alignItems: 'center',
49
+ },
50
+ ]}>
51
+ <View
52
+ style={[
53
+ styles.radio,
54
+ checkBoxStyle,
55
+ disabledStyle,
56
+ {marginRight: label ? Spacing.XS : 0},
57
+ ]}
58
+ />
59
+ {!!label && <Text typography={'body_default_regular'}>{label}</Text>}
60
+ </TouchableOpacity>
61
+ );
62
+ };
63
+
64
+ export {Radio};
@@ -0,0 +1,11 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {Radius} from '../Consts';
3
+
4
+ export default StyleSheet.create({
5
+ radio: {
6
+ height: 20,
7
+ width: 20,
8
+ borderRadius: Radius.M,
9
+ },
10
+ container: {flex: 1},
11
+ });
package/Radio/types.ts ADDED
@@ -0,0 +1,38 @@
1
+ import {ViewStyle} from 'react-native';
2
+
3
+ export type RadioProps = {
4
+ /**
5
+ * `value`: Represents the value associated with the Radio component.
6
+ * It is used to determine whether the Radio component is selected or not in comparison with the `groupValue`.
7
+ */
8
+ value: any;
9
+
10
+ /**
11
+ * `disabled`: Optional. If `true`, the user won't be able to interact with the Radio component.
12
+ * Defaults to `false` if not provided.
13
+ */
14
+ disabled?: boolean;
15
+
16
+ /**
17
+ * `label`: Optional. Represents the text label displayed next to the Radio component.
18
+ */
19
+ label?: string;
20
+
21
+ /**
22
+ * `onChange`: A callback function that is called when the value of the Radio component changes.
23
+ * It is triggered when the user interacts with the Radio component.
24
+ */
25
+ onChange: () => void;
26
+
27
+ /**
28
+ * `groupValue`: Represents the value of the selected Radio component within a group of Radio components.
29
+ * The Radio component for which `value` equals `groupValue` will be selected.
30
+ */
31
+ groupValue: any;
32
+
33
+ /**
34
+ * `style`: Optional. Used to apply custom styling to the Radio component.
35
+ * Accepts an object of style properties.
36
+ */
37
+ style?: ViewStyle;
38
+ };
@@ -0,0 +1,72 @@
1
+ import React, {useEffect, useMemo, useRef, useState} from 'react';
2
+ import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
3
+ import LinearGradient from 'react-native-linear-gradient';
4
+ import {SkeletonTypes} from './types';
5
+ import {Colors, Styles} from '../Consts';
6
+ import styles from './styles';
7
+
8
+ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
9
+ const [width, setWidth] = useState(0);
10
+ const PRIMARY_COLOR = Colors.black_05;
11
+ const HIGHLIGHT_COLOR1 = Colors.black_05;
12
+ const HIGHLIGHT_COLOR2 = Colors.black_03;
13
+ const beginShimmerPosition = useRef(new Animated.Value(0)).current;
14
+
15
+ const shimmerColors = [HIGHLIGHT_COLOR1, HIGHLIGHT_COLOR2, HIGHLIGHT_COLOR1];
16
+ const linearTranslate = beginShimmerPosition.interpolate({
17
+ inputRange: [0, 1],
18
+ outputRange: [-width, width],
19
+ });
20
+ const animatedValue = useMemo(() => {
21
+ return Animated.loop(
22
+ Animated.timing(beginShimmerPosition, {
23
+ toValue: 1,
24
+ duration: 1000,
25
+ easing: Easing.linear,
26
+ useNativeDriver: Platform.OS !== 'web',
27
+ }),
28
+ );
29
+ }, [beginShimmerPosition]);
30
+
31
+ useEffect(() => {
32
+ animatedValue.start();
33
+ return () => {
34
+ animatedValue.stop();
35
+ };
36
+ }, [animatedValue]);
37
+
38
+ const onLayout = (newWidth: number) => {
39
+ if (newWidth !== width) {
40
+ setWidth(newWidth);
41
+ }
42
+ };
43
+ return (
44
+ <View style={[styles.container, style]}>
45
+ <View
46
+ onLayout={e => onLayout(e.nativeEvent.layout.width)}
47
+ style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
48
+ <Animated.View
49
+ style={{
50
+ transform: [{translateX: linearTranslate}],
51
+ width: '60%',
52
+ height: '100%',
53
+ }}>
54
+ <LinearGradient
55
+ style={[StyleSheet.absoluteFill]}
56
+ colors={shimmerColors}
57
+ start={{
58
+ x: 0,
59
+ y: 0,
60
+ }}
61
+ end={{
62
+ x: 1,
63
+ y: 0,
64
+ }}
65
+ />
66
+ </Animated.View>
67
+ </View>
68
+ </View>
69
+ );
70
+ };
71
+
72
+ export {Skeleton};
@@ -0,0 +1,5 @@
1
+ import {StyleSheet} from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ container: {overflow: 'hidden', width: '100%', height: '100%'},
5
+ });
@@ -0,0 +1,6 @@
1
+ export type SkeletonTypes = {
2
+ /**
3
+ * Optional. Custom styles for the Skeleton component.
4
+ */
5
+ style?: object;
6
+ };