@momo-kits/foundation 0.75.1-beta.3

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 (76) hide show
  1. package/Assets/header-background.png +0 -0
  2. package/Assets/icon.json +3947 -0
  3. package/Button/index.tsx +247 -0
  4. package/Button/styles.ts +41 -0
  5. package/CheckBox/index.tsx +61 -0
  6. package/CheckBox/styles.ts +15 -0
  7. package/CheckBox/types.ts +10 -0
  8. package/Consts/colors+spacing+radius.ts +214 -0
  9. package/Consts/index.ts +3 -0
  10. package/Consts/styles.ts +78 -0
  11. package/Consts/theme.ts +121 -0
  12. package/Divider/index.tsx +19 -0
  13. package/Icon/index.tsx +37 -0
  14. package/Icon/types.ts +8 -0
  15. package/IconButton/index.tsx +128 -0
  16. package/IconButton/styles.ts +19 -0
  17. package/Image/index.tsx +80 -0
  18. package/Image/styles.ts +13 -0
  19. package/Image/types.ts +3 -0
  20. package/Input/Input.tsx +142 -0
  21. package/Input/InputMoney.tsx +132 -0
  22. package/Input/InputSearch.tsx +161 -0
  23. package/Input/InputTextArea.tsx +152 -0
  24. package/Input/common.tsx +125 -0
  25. package/Input/index.tsx +41 -0
  26. package/Input/styles.ts +122 -0
  27. package/Input/utils.ts +63 -0
  28. package/Layout/Card.tsx +87 -0
  29. package/Layout/GridSystem.tsx +124 -0
  30. package/Layout/ScreenContainer.tsx +122 -0
  31. package/Layout/Section.tsx +143 -0
  32. package/Layout/index.ts +16 -0
  33. package/Layout/types.ts +21 -0
  34. package/Layout/utils.ts +50 -0
  35. package/Navigation/BottomTab.tsx +39 -0
  36. package/Navigation/Components.tsx +329 -0
  37. package/Navigation/ModalScreen.tsx +207 -0
  38. package/Navigation/Navigation.ts +38 -0
  39. package/Navigation/NavigationButton.tsx +54 -0
  40. package/Navigation/NavigationContainer.tsx +82 -0
  41. package/Navigation/Navigator.ts +66 -0
  42. package/Navigation/Observer.ts +79 -0
  43. package/Navigation/StackScreen.tsx +40 -0
  44. package/Navigation/index.ts +14 -0
  45. package/Navigation/types.ts +149 -0
  46. package/Navigation/utils.tsx +167 -0
  47. package/Pagination/Dot.tsx +16 -0
  48. package/Pagination/PaginationDot.tsx +33 -0
  49. package/Pagination/PaginationNumber.tsx +23 -0
  50. package/Pagination/PaginationScroll.tsx +88 -0
  51. package/Pagination/PaginationWhiteDot.tsx +32 -0
  52. package/Pagination/index.tsx +25 -0
  53. package/Pagination/styles.ts +47 -0
  54. package/Pagination/types.ts +19 -0
  55. package/Popup/PopupNotify.tsx +215 -0
  56. package/Popup/PopupPromotion.tsx +77 -0
  57. package/Popup/index.tsx +4 -0
  58. package/Popup/types.ts +22 -0
  59. package/Radio/index.tsx +65 -0
  60. package/Radio/styles.ts +11 -0
  61. package/Radio/types.ts +10 -0
  62. package/Skeleton/index.tsx +72 -0
  63. package/Skeleton/styles.ts +5 -0
  64. package/Skeleton/types.ts +3 -0
  65. package/Switch/index.tsx +40 -0
  66. package/Switch/styles.ts +23 -0
  67. package/Switch/types.ts +8 -0
  68. package/Tag/index.tsx +79 -0
  69. package/Tag/styles.ts +24 -0
  70. package/Tag/types.ts +10 -0
  71. package/Text/index.tsx +110 -0
  72. package/Text/styles.ts +35 -0
  73. package/Text/types.ts +40 -0
  74. package/index.ts +38 -0
  75. package/package.json +41 -0
  76. package/publish.sh +26 -0
@@ -0,0 +1,66 @@
1
+ import {StackActions} from '@react-navigation/native';
2
+ import {BottomSheetParams, ModalParams, ScreenParams} from './types';
3
+ import {requestApi} from './utils';
4
+
5
+ class Navigator {
6
+ ref?: any;
7
+ utilityToolConfig: any;
8
+
9
+ constructor(navigation: any) {
10
+ this.ref = navigation;
11
+ }
12
+
13
+ push = (params: ScreenParams) => {
14
+ this.ref.current.dispatch(StackActions.push('Stack', params));
15
+ };
16
+
17
+ replace = (params: ScreenParams) => {
18
+ this.ref.current.dispatch(StackActions.replace('Stack', params));
19
+ };
20
+
21
+ pop = (count?: number) => {
22
+ this.ref.current.dispatch(StackActions.pop(count ?? 1));
23
+ };
24
+
25
+ present = (params: ScreenParams) => {
26
+ this.ref.current.dispatch(StackActions.push('Dialog', params));
27
+ };
28
+
29
+ showModal = (params: ModalParams) => {
30
+ this.ref.current.dispatch(StackActions.push('Modal', params));
31
+ };
32
+
33
+ showBottomSheet = (params: BottomSheetParams) => {
34
+ this.ref.current.dispatch(
35
+ StackActions.push('Modal', {
36
+ ...params,
37
+ isBottomSheet: true,
38
+ }),
39
+ );
40
+ };
41
+
42
+ popToTop = () => {
43
+ this.ref.current.dispatch(StackActions.popToTop());
44
+ };
45
+
46
+ getToolkit = async () => {
47
+ if (this.utilityToolConfig) return this.utilityToolConfig;
48
+ return new Promise(resolve => {
49
+ requestApi('getToolkit', [null], (result: any) => {
50
+ if (result === true) {
51
+ requestApi('getToolkitConfig', [null], (config: any) => {
52
+ this.utilityToolConfig = {
53
+ ...config?.utilityToolConfig,
54
+ appCode: config?.appCode,
55
+ };
56
+ resolve(this.utilityToolConfig);
57
+ });
58
+ } else {
59
+ resolve(undefined);
60
+ }
61
+ });
62
+ });
63
+ };
64
+ }
65
+
66
+ export default Navigator;
@@ -0,0 +1,79 @@
1
+ class Subject {
2
+ private observers: any[];
3
+ constructor() {
4
+ this.observers = [];
5
+ }
6
+
7
+ attach(observer: any) {
8
+ observer && this.observers.push(observer);
9
+ }
10
+
11
+ detach(observer: any) {
12
+ this.observers = this.observers.filter(item => item !== observer);
13
+ }
14
+
15
+ notify(newState: any) {
16
+ this.observers.forEach(observer => {
17
+ if (typeof observer === 'function') {
18
+ observer(newState);
19
+ } else {
20
+ observer.updateData && observer.updateData(newState);
21
+ }
22
+ });
23
+ }
24
+ }
25
+
26
+ class ObserverInstance {
27
+ private readonly props: any;
28
+ constructor(props: any) {
29
+ this.props = props;
30
+ }
31
+
32
+ remove() {
33
+ const {detach, observer} = this.props;
34
+ detach && detach(observer);
35
+ }
36
+ }
37
+
38
+ export default class Observer {
39
+ static SCHEMA = 'Observer';
40
+
41
+ static instances: any = {};
42
+ private schema: any;
43
+ private subject: Subject;
44
+ private data: null;
45
+ private loaded: boolean;
46
+
47
+ constructor(props: any) {
48
+ this.schema = props.schema;
49
+ this.subject = new Subject();
50
+ this.data = null;
51
+ this.loaded = false;
52
+ this.initilize();
53
+ }
54
+
55
+ static getInstance(schema: string, Class = Observer) {
56
+ schema = schema || Class.SCHEMA;
57
+ let instance = Observer.instances[schema];
58
+ if (!instance) {
59
+ instance = new Class({schema});
60
+ Observer.instances[schema] = instance;
61
+ }
62
+ return instance;
63
+ }
64
+
65
+ initilize = () => {};
66
+
67
+ notify = (state: any) => {
68
+ this.subject.notify(state);
69
+ };
70
+
71
+ attach = (observer: any) => {
72
+ this.subject.attach(observer);
73
+ return new ObserverInstance({observer, detach: this.detach});
74
+ };
75
+
76
+ detach = (observer: any) => {
77
+ this.subject.detach(observer);
78
+ };
79
+ }
@@ -0,0 +1,40 @@
1
+ import React, {useContext, useEffect} from 'react';
2
+ import {ScreenParams} from './types';
3
+ import Navigation from './Navigation';
4
+ import {ApplicationContext} from './NavigationContainer';
5
+ import {HeaderToolkitAction} from './Components';
6
+
7
+ const StackScreen: React.FC<any> = props => {
8
+ const {route, navigation} = props;
9
+ const {screen: Component, options}: ScreenParams = route.params;
10
+ const {theme, navigator} = useContext(ApplicationContext);
11
+
12
+ const params = {
13
+ ...route.params,
14
+ navigation: new Navigation(navigation, theme),
15
+ };
16
+
17
+ delete params.screen;
18
+
19
+ useEffect(() => {
20
+ navigator?.getToolkit().then(utilityToolConfig => {
21
+ if (utilityToolConfig) {
22
+ params.navigation.setOptions({
23
+ headerRight: (props: any) => (
24
+ <HeaderToolkitAction
25
+ {...props}
26
+ utilityToolConfig={utilityToolConfig}
27
+ />
28
+ ),
29
+ });
30
+ }
31
+ });
32
+ if (options) {
33
+ params.navigation.setOptions(options);
34
+ }
35
+ }, [options]);
36
+
37
+ return <Component {...params} />;
38
+ };
39
+
40
+ export default StackScreen;
@@ -0,0 +1,14 @@
1
+ import {NavigationContainer, ApplicationContext} from './NavigationContainer';
2
+ import ScreenContainer from '../Layout/ScreenContainer';
3
+ import NavigationButton from './NavigationButton';
4
+ import {HeaderRightAction} from './Components';
5
+ import BottomTab from './BottomTab';
6
+
7
+ export {
8
+ NavigationContainer,
9
+ ApplicationContext,
10
+ ScreenContainer,
11
+ NavigationButton,
12
+ HeaderRightAction,
13
+ BottomTab,
14
+ };
@@ -0,0 +1,149 @@
1
+ import {Animated, ScrollViewProps, ViewProps} from 'react-native';
2
+ import React from 'react';
3
+ import Navigator from './Navigator';
4
+ import {PopupNotifyProps} from '../Popup/types';
5
+
6
+ export type Theme = {
7
+ dark: boolean;
8
+ colors: {
9
+ primary: string;
10
+ secondary: string;
11
+ background: {
12
+ default: string;
13
+ surface: string;
14
+ tonal: string;
15
+ pressed: string;
16
+ selected: string;
17
+ disable: string;
18
+ };
19
+ text: {
20
+ default: string;
21
+ secondary: string;
22
+ hint: string;
23
+ disable: string;
24
+ };
25
+ border: {
26
+ default: string;
27
+ disable: string;
28
+ };
29
+ success: {
30
+ primary: string;
31
+ secondary: string;
32
+ container: string;
33
+ };
34
+ warning: {
35
+ primary: string;
36
+ secondary: string;
37
+ container: string;
38
+ };
39
+ error: {
40
+ primary: string;
41
+ secondary: string;
42
+ container: string;
43
+ };
44
+ highlight: {
45
+ primary: string;
46
+ secondary: string;
47
+ container: string;
48
+ };
49
+ interactive: {
50
+ primary: string;
51
+ secondary: string;
52
+ container: string;
53
+ };
54
+ };
55
+ font: string;
56
+ assets?: {
57
+ headerBackground?: string;
58
+ };
59
+ };
60
+
61
+ export type Context = {
62
+ theme: Theme;
63
+ navigator?: Navigator;
64
+ };
65
+
66
+ export type NavigationContainerProps = {
67
+ screen: React.ElementType;
68
+ options?: NavigationOptions;
69
+ theme: Theme;
70
+ };
71
+
72
+ export interface ScreenContainerProps extends ViewProps {
73
+ enableKeyboardAvoidingView?: boolean;
74
+ headerBackground?: string;
75
+ scrollable?: boolean;
76
+ scrollY?: Animated.Value;
77
+ scrollViewProps?: ScrollViewProps;
78
+ footerComponent?: React.ElementType;
79
+ }
80
+
81
+ export type ScreenParams = {
82
+ [key: string]: any;
83
+ screen: React.ElementType;
84
+ options?: NavigationOptions;
85
+ };
86
+
87
+ export interface ModalParams extends ScreenParams {
88
+ [key: string]: any;
89
+ screen: React.ElementType;
90
+ onDismiss?: (mounted?: boolean) => void;
91
+ barrierDismissible?: boolean;
92
+ }
93
+
94
+ export interface BottomSheetParams extends ScreenParams {
95
+ [key: string]: any;
96
+ onDismiss?: () => void;
97
+ }
98
+
99
+ export type NavigationButtonProps = {
100
+ icon: string;
101
+ tintColor?: string;
102
+ backgroundColor?: string;
103
+ useBorder?: boolean;
104
+ onPress: () => void;
105
+ accessibilityLabel?: string;
106
+ };
107
+
108
+ export type NavigationOptions = {
109
+ preventBack?: PopupNotifyProps;
110
+ surface?: boolean;
111
+ title?: string;
112
+ headerTitleAlign?: 'left' | 'center';
113
+ customTitle?: TitleCustomProps;
114
+ headerRight?: (props?: any) => React.ReactElement;
115
+ animatedValue?: Animated.Value;
116
+ };
117
+
118
+ export type HeaderBackProps = {
119
+ tintColor?: string;
120
+ preventBack?: PopupNotifyProps;
121
+ };
122
+
123
+ export type HeaderBackgroundProps = {
124
+ image?: string | null;
125
+ backgroundColor?: string | null;
126
+ animatedValue?: Animated.Value;
127
+ };
128
+
129
+ export type TitleCustomProps = {
130
+ title?: string;
131
+ subTitle?: string;
132
+ image?: string;
133
+ imageShape?: 'circle' | 'square';
134
+ dotColor?: string;
135
+ tintColor?: string;
136
+ content?: React.ReactNode;
137
+ };
138
+
139
+ export type BottomTabItemProps = {
140
+ label: string;
141
+ icon: string;
142
+ showDot?: boolean;
143
+ badgeLabel?: string;
144
+ screen: React.ComponentType<any>;
145
+ };
146
+
147
+ export type BottomTabProps = {
148
+ tabs: BottomTabItemProps[];
149
+ };
@@ -0,0 +1,167 @@
1
+ import React from 'react';
2
+ import {
3
+ StackNavigationOptions,
4
+ TransitionPresets,
5
+ } from '@react-navigation/stack';
6
+ import {DeviceEventEmitter} from 'react-native';
7
+ import {
8
+ HeaderBackground,
9
+ HeaderCustom,
10
+ HeaderLeft,
11
+ HeaderTitle,
12
+ } from './Components';
13
+ import {NavigationOptions, Theme} from './types';
14
+ import {Colors} from '../Consts';
15
+
16
+ const requestApi = (func: any, args: any = [], callback: any) => {
17
+ const instance: any = global;
18
+ if (instance?.miniAppApi?.dispatch) {
19
+ instance?.miniAppApi?.dispatch?.(func, ...args, callback);
20
+ } else {
21
+ let listener: any;
22
+ const responseId = new Date().getTime();
23
+ const responseListener = `KIT_RESPONSE_MESSAGE_${responseId}`;
24
+ const TIME_OUT = 5000;
25
+ const timeout = setTimeout(() => {
26
+ listener?.remove?.();
27
+ }, TIME_OUT);
28
+ listener = DeviceEventEmitter.addListener(responseListener, result => {
29
+ listener?.remove?.();
30
+ clearTimeout(timeout);
31
+ callback?.(result);
32
+ });
33
+ DeviceEventEmitter.emit('KITS_REQUEST_MESSAGE', {
34
+ func,
35
+ args,
36
+ responseListener,
37
+ });
38
+ }
39
+ };
40
+
41
+ const getTintColor = (theme: Theme): any => {
42
+ if (theme.assets?.headerBackground) {
43
+ return {
44
+ headerTintColor: Colors.black_01,
45
+ };
46
+ }
47
+ return {
48
+ headerTintColor: theme.colors.text.default,
49
+ };
50
+ };
51
+
52
+ const getStackOptions = (theme: Theme): StackNavigationOptions => {
53
+ return {
54
+ headerTitleAlign: 'center',
55
+ headerTitle: HeaderTitle,
56
+ headerBackground: HeaderBackground,
57
+ headerLeft: (props: any) => <HeaderLeft {...props} />,
58
+ ...getTintColor(theme),
59
+ };
60
+ };
61
+
62
+ const getDialogOptions = (theme: Theme): StackNavigationOptions => {
63
+ return {
64
+ headerTitleAlign: 'center',
65
+ headerTitle: HeaderTitle,
66
+ headerLeft: (props: any) => <HeaderLeft {...props} />,
67
+ headerBackground: HeaderBackground,
68
+ ...getTintColor(theme),
69
+ ...TransitionPresets.ModalTransition,
70
+ };
71
+ };
72
+
73
+ const getModalOptions = (): StackNavigationOptions => {
74
+ return {
75
+ headerShown: false,
76
+ headerBackground: undefined,
77
+ cardStyle: {backgroundColor: 'transparent'},
78
+ cardOverlayEnabled: true,
79
+ animationEnabled: false,
80
+ cardStyleInterpolator: ({current: {progress}}) => ({
81
+ cardStyle: {
82
+ opacity: progress.interpolate({
83
+ inputRange: [0, 0.5, 0.9, 1],
84
+ outputRange: [0, 0.25, 0.7, 1],
85
+ }),
86
+ },
87
+ overlayStyle: {
88
+ opacity: progress.interpolate({
89
+ inputRange: [0, 0.5, 0.9, 1],
90
+ outputRange: [0, 0.2, 0.4, 0.6],
91
+ extrapolate: 'clamp',
92
+ }),
93
+ },
94
+ }),
95
+ };
96
+ };
97
+
98
+ const getOptions = (params: NavigationOptions, theme: Theme) => {
99
+ let backgroundProps = {};
100
+ let titleProps = {};
101
+ let options = {};
102
+
103
+ if (params.preventBack) {
104
+ options = {
105
+ ...options,
106
+ headerLeft: (props: any) => (
107
+ <HeaderLeft {...props} preventBack={params.preventBack} />
108
+ ),
109
+ };
110
+ }
111
+ if (params.surface == true) {
112
+ options = {
113
+ ...options,
114
+ ...getTintColor({
115
+ ...theme,
116
+ assets: {...theme.assets, headerBackground: undefined},
117
+ }),
118
+ };
119
+ backgroundProps = {
120
+ ...backgroundProps,
121
+ image: null,
122
+ backgroundColor: theme.colors.background.surface,
123
+ };
124
+ } else {
125
+ backgroundProps = {};
126
+ options = {...options, ...getTintColor(theme)};
127
+ }
128
+
129
+ if (params.animatedValue) {
130
+ backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
131
+ titleProps = {...titleProps, animatedValue: params.animatedValue};
132
+ options = {...options, headerTransparent: true};
133
+ } else {
134
+ options = {...options, headerTransparent: false};
135
+ }
136
+
137
+ if (params.customTitle) {
138
+ options = {
139
+ ...options,
140
+ headerTitleAlign: 'left',
141
+ headerTitle: (props: any) => {
142
+ return <HeaderCustom {...params.customTitle} {...props} />;
143
+ },
144
+ };
145
+ } else {
146
+ options = {
147
+ ...options,
148
+ headerTitle: (props: any) => {
149
+ return <HeaderTitle {...titleProps} {...props} />;
150
+ },
151
+ };
152
+ }
153
+
154
+ return {
155
+ ...params,
156
+ ...options,
157
+ headerBackground: () => <HeaderBackground {...backgroundProps} />,
158
+ };
159
+ };
160
+
161
+ export {
162
+ requestApi,
163
+ getStackOptions,
164
+ getDialogOptions,
165
+ getModalOptions,
166
+ getOptions,
167
+ };
@@ -0,0 +1,16 @@
1
+ import React, {FC, useContext} from 'react';
2
+ import {Animated} from 'react-native';
3
+ import styles from './styles';
4
+ import {DotProps} from './types';
5
+ import {ApplicationContext} from '../Navigation';
6
+
7
+ const Dot: FC<DotProps> = ({active, style}) => {
8
+ const {theme} = useContext(ApplicationContext);
9
+ const dotStyle = active
10
+ ? [styles.activeDot]
11
+ : [styles.inactiveDot, {backgroundColor: theme.colors.background.pressed}];
12
+
13
+ return <Animated.View style={[style, dotStyle]} />;
14
+ };
15
+
16
+ export default Dot;
@@ -0,0 +1,33 @@
1
+ import React, {FC, useContext} from 'react';
2
+ import {View} from 'react-native';
3
+ import {ChildPaginationProps} from './types';
4
+ import Dot from './Dot';
5
+ import styles from './styles';
6
+ import {Spacing} from '../Consts';
7
+ import {ApplicationContext} from '../Navigation';
8
+
9
+ const PaginationDot: FC<ChildPaginationProps> = ({
10
+ dataLength = 2,
11
+ activeIndex = 0,
12
+ }) => {
13
+ const {theme} = useContext(ApplicationContext);
14
+ const renderDots = () => {
15
+ const dots = [];
16
+ for (let i = 0; i < dataLength; i++) {
17
+ dots.push(
18
+ <Dot
19
+ key={`Dot${i}`}
20
+ style={[
21
+ i !== dataLength - 1 ? {marginRight: Spacing.XS} : {},
22
+ {backgroundColor: theme.colors.primary},
23
+ ]}
24
+ active={activeIndex === i}
25
+ />,
26
+ );
27
+ }
28
+ return dots;
29
+ };
30
+ return <View style={styles.paginationPinkContainer}>{renderDots()}</View>;
31
+ };
32
+
33
+ export default PaginationDot;
@@ -0,0 +1,23 @@
1
+ import React, {FC, useContext} from 'react';
2
+ import {View} from 'react-native';
3
+ import {ChildPaginationProps} from './types';
4
+ import styles from './styles';
5
+ import {Text} from '../Text';
6
+ import {ApplicationContext} from '../Navigation';
7
+ import {Colors} from '../Consts';
8
+
9
+ const PaginationNumber: FC<ChildPaginationProps> = ({
10
+ activeIndex = 0,
11
+ dataLength = 2,
12
+ }) => {
13
+ const {theme} = useContext(ApplicationContext);
14
+ return (
15
+ <View style={[styles.paginationNumberContainer]}>
16
+ <Text color={Colors.black_01} typography={'label_default'}>{`${
17
+ activeIndex + 1
18
+ }/${dataLength}`}</Text>
19
+ </View>
20
+ );
21
+ };
22
+
23
+ export default PaginationNumber;
@@ -0,0 +1,88 @@
1
+ import React, {FC, useContext, useRef, useState} from 'react';
2
+ import {Animated, View} from 'react-native';
3
+ import {ScrollIndicatorProps} from './types';
4
+ import styles from './styles';
5
+ import {ApplicationContext} from '../Navigation';
6
+
7
+ const INDICATOR_WIDTH = 24;
8
+ const INDICATOR_CONTAINER_WIDTH = 72;
9
+ const PaginationScroll: FC<ScrollIndicatorProps> = ({
10
+ style,
11
+ children,
12
+ scrollViewRef,
13
+ }) => {
14
+ const {theme} = useContext(ApplicationContext);
15
+ const left = useRef(new Animated.Value(0)).current;
16
+ const [scrollViewWidth, setScrollViewWidth] = useState(0);
17
+ const [scrollContentWidth, setScrollContentWidth] = useState(0);
18
+
19
+ const translateX = () => {
20
+ if (scrollViewWidth && scrollContentWidth) {
21
+ const value = left.interpolate({
22
+ inputRange: [0, scrollContentWidth - scrollViewWidth],
23
+ outputRange: [0, INDICATOR_CONTAINER_WIDTH - INDICATOR_WIDTH],
24
+ extrapolate: 'clamp',
25
+ });
26
+ return {transform: [{translateX: value}]};
27
+ }
28
+ return {};
29
+ };
30
+
31
+ const renderScrollView = () => {
32
+ return (
33
+ <Animated.ScrollView
34
+ ref={scrollViewRef}
35
+ onScroll={Animated.event(
36
+ [
37
+ {
38
+ nativeEvent: {
39
+ contentOffset: {
40
+ x: left,
41
+ },
42
+ },
43
+ },
44
+ ],
45
+ {useNativeDriver: true},
46
+ )}
47
+ alwaysBounceHorizontal={false}
48
+ showsHorizontalScrollIndicator={false}
49
+ horizontal
50
+ style={styles.scrollView}
51
+ onContentSizeChange={width => {
52
+ setScrollContentWidth(width);
53
+ }}
54
+ onLayout={e => {
55
+ setScrollViewWidth(e.nativeEvent.layout.width);
56
+ }}>
57
+ {children}
58
+ </Animated.ScrollView>
59
+ );
60
+ };
61
+ const renderIndicator = () => {
62
+ return (
63
+ <View
64
+ style={[
65
+ styles.indicatorContainer,
66
+ {backgroundColor: theme.colors.background.pressed},
67
+ ]}>
68
+ <Animated.View
69
+ style={[
70
+ styles.indicator,
71
+ {
72
+ backgroundColor: theme.colors.primary,
73
+ },
74
+ translateX(),
75
+ ]}
76
+ />
77
+ </View>
78
+ );
79
+ };
80
+ return (
81
+ <View style={[style, styles.scrollContainer]}>
82
+ {renderScrollView()}
83
+ {renderIndicator()}
84
+ </View>
85
+ );
86
+ };
87
+
88
+ export default PaginationScroll;