@hero-design/rn 8.10.0 → 8.11.0

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 (37) hide show
  1. package/.turbo/turbo-build.log +9 -9
  2. package/es/index.js +293 -82
  3. package/lib/index.js +293 -82
  4. package/package.json +5 -5
  5. package/src/components/Card/index.tsx +1 -1
  6. package/src/components/Carousel/CardCarousel.tsx +218 -0
  7. package/src/components/Carousel/StyledCardCarousel.tsx +40 -0
  8. package/src/components/Carousel/__tests__/CardCarousel.spec.tsx +105 -0
  9. package/src/components/Carousel/__tests__/StyledCardCarousel.spec.tsx +38 -0
  10. package/src/components/Carousel/__tests__/__snapshots__/CardCarousel.spec.tsx.snap +289 -0
  11. package/src/components/Carousel/__tests__/__snapshots__/StyledCardCarousel.spec.tsx.snap +109 -0
  12. package/src/components/Carousel/contants.ts +10 -0
  13. package/src/components/Carousel/index.tsx +4 -1
  14. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerAndroid.spec.tsx.snap +0 -1
  15. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerIOS.spec.tsx.snap +0 -1
  16. package/src/components/RichTextEditor/__tests__/__snapshots__/RichTextEditor.spec.tsx.snap +2 -2
  17. package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +1 -6
  18. package/src/components/Select/SingleSelect/__tests__/__snapshots__/index.spec.tsx.snap +1 -6
  19. package/src/components/TextInput/StyledTextInput.tsx +1 -2
  20. package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +5 -6
  21. package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +6 -20
  22. package/src/components/TimePicker/__tests__/__snapshots__/TimePickerAndroid.spec.tsx.snap +0 -2
  23. package/src/components/TimePicker/__tests__/__snapshots__/TimePickerIOS.spec.tsx.snap +0 -2
  24. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +24 -4
  25. package/src/theme/components/cardCarousel.ts +28 -0
  26. package/src/theme/components/textInput.ts +2 -6
  27. package/src/theme/getTheme.ts +3 -0
  28. package/src/types.ts +2 -0
  29. package/types/components/Card/index.d.ts +1 -1
  30. package/types/components/Carousel/CardCarousel.d.ts +40 -0
  31. package/types/components/Carousel/StyledCardCarousel.d.ts +31 -0
  32. package/types/components/Carousel/contants.d.ts +2 -0
  33. package/types/components/Carousel/index.d.ts +5 -3
  34. package/types/theme/components/cardCarousel.d.ts +25 -0
  35. package/types/theme/components/textInput.d.ts +1 -4
  36. package/types/theme/getTheme.d.ts +2 -0
  37. package/types/types.d.ts +2 -1
@@ -0,0 +1,218 @@
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useEffect,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
8
+ import { FlatList, StyleProp, ViewStyle } from 'react-native';
9
+ import { useTheme } from '../../theme';
10
+ import { ITEM_WIDTH_RATE, VIEW_POSITION_CENTER } from './contants';
11
+ import {
12
+ StyledCard,
13
+ StyledItemWrapper,
14
+ StyledPageControl,
15
+ StyledShadow,
16
+ StyledWrapper,
17
+ } from './StyledCardCarousel';
18
+
19
+ export type CardCarouselHandles = {
20
+ snapToIndex: (index: number) => void;
21
+ };
22
+
23
+ export interface CardCarouselProps {
24
+ /**
25
+ * Whether to scroll automatically.
26
+ */
27
+ autoPlay?: boolean;
28
+ /**
29
+ * Set interval of each slide.
30
+ */
31
+ autoPlayInterval?: number;
32
+ /**
33
+ * onItemIndexChange event handler receiving index of selected Item.
34
+ */
35
+ onItemIndexChange?: (index: number) => void;
36
+ /**
37
+ * Carousel data.
38
+ */
39
+ items: any[];
40
+ /**
41
+ * Indicates hide or show page control.
42
+ */
43
+ hidePageControl?: boolean;
44
+ /**
45
+ * Additional styles
46
+ */
47
+ style?: StyleProp<ViewStyle>;
48
+ /**
49
+ * Testing id of the component.
50
+ */
51
+ testID?: string;
52
+ /**
53
+ * Component ref.
54
+ */
55
+ ref?: React.Ref<CardCarouselHandles>;
56
+ }
57
+
58
+ export const CardCarousel = forwardRef<CardCarouselHandles, CardCarouselProps>(
59
+ (
60
+ {
61
+ onItemIndexChange,
62
+ items,
63
+ hidePageControl = false,
64
+ style,
65
+ testID,
66
+ autoPlay = false,
67
+ autoPlayInterval = 3000,
68
+ }: CardCarouselProps,
69
+ ref?: React.Ref<CardCarouselHandles>
70
+ ) => {
71
+ const [currentIndex, setCurrentIndex] = useState(0);
72
+
73
+ const theme = useTheme();
74
+ const [flatListWidth, setFlatListWidth] = useState(0);
75
+ const itemWidth = flatListWidth * ITEM_WIDTH_RATE;
76
+ const carouselRef = useRef<FlatList>(null);
77
+
78
+ const snapToIndex = useCallback(
79
+ (index) => {
80
+ let validIndex = 0;
81
+ if (index < 0) {
82
+ validIndex = 0;
83
+ } else if (index >= items.length) {
84
+ validIndex = items.length - 1;
85
+ } else {
86
+ validIndex = index;
87
+ }
88
+
89
+ carouselRef.current?.scrollToIndex({
90
+ index: validIndex,
91
+ animated: true,
92
+ viewPosition: VIEW_POSITION_CENTER,
93
+ });
94
+ },
95
+ [carouselRef, itemWidth]
96
+ );
97
+
98
+ /*
99
+ * snap to the next index. If the curent index is the last one, snap to the first one.
100
+ */
101
+ const snapToNext = useCallback(() => {
102
+ let nextIndex = currentIndex + 1;
103
+ if (nextIndex >= items.length) {
104
+ nextIndex = 0;
105
+ }
106
+ carouselRef.current?.scrollToIndex({
107
+ index: nextIndex,
108
+ animated: true,
109
+ viewPosition: VIEW_POSITION_CENTER,
110
+ });
111
+ }, [carouselRef, currentIndex, itemWidth, items.length]);
112
+
113
+ React.useImperativeHandle(
114
+ ref,
115
+ () => ({
116
+ snapToIndex: (index: number) => {
117
+ snapToIndex(index);
118
+ },
119
+ // we don't expose this method, it's for testing https://medium.com/developer-rants/how-to-test-useref-without-mocking-useref-699165f4994e
120
+ getFlatListRef: () => carouselRef.current,
121
+ }),
122
+ [snapToIndex]
123
+ );
124
+
125
+ useEffect(() => {
126
+ let timer: number;
127
+ if (autoPlay) {
128
+ timer = setInterval(() => {
129
+ snapToNext();
130
+ }, autoPlayInterval);
131
+ }
132
+ return () => {
133
+ clearInterval(timer);
134
+ };
135
+ }, [autoPlay, snapToNext, currentIndex, autoPlayInterval]);
136
+
137
+ const visibleSlideChanged = useCallback(
138
+ ({ viewableItems }) => {
139
+ if (!viewableItems || (viewableItems && !viewableItems.length)) return;
140
+ const { index } = viewableItems[0];
141
+ setCurrentIndex(index);
142
+ if (onItemIndexChange) {
143
+ onItemIndexChange(index);
144
+ }
145
+ },
146
+ [onItemIndexChange]
147
+ );
148
+
149
+ const getItemLayout = useCallback(
150
+ (_: React.ReactNode, index: number) => ({
151
+ length: itemWidth,
152
+ offset: itemWidth * index,
153
+ index,
154
+ }),
155
+ [itemWidth]
156
+ );
157
+
158
+ const onLayout = useCallback(
159
+ (e) => {
160
+ setFlatListWidth(e.nativeEvent.layout.width);
161
+ },
162
+ [setFlatListWidth]
163
+ );
164
+
165
+ const renderItem = useCallback(
166
+ ({ item }) => {
167
+ return (
168
+ <StyledItemWrapper style={{ width: itemWidth }}>
169
+ {/* using StyledShadow to fix border not shown on Android */}
170
+ <StyledShadow>
171
+ <StyledCard>{item}</StyledCard>
172
+ </StyledShadow>
173
+ </StyledItemWrapper>
174
+ );
175
+ },
176
+ [itemWidth]
177
+ );
178
+
179
+ return (
180
+ <StyledWrapper style={style} testID={testID}>
181
+ <FlatList
182
+ contentContainerStyle={{
183
+ paddingHorizontal:
184
+ theme.__hd__.cardCarousel.space.contentContainerPaddingHorizontal,
185
+ }}
186
+ onLayout={onLayout}
187
+ data={items}
188
+ horizontal
189
+ showsHorizontalScrollIndicator={false}
190
+ pagingEnabled
191
+ bounces={false}
192
+ scrollEventThrottle={32}
193
+ snapToAlignment="center"
194
+ getItemLayout={getItemLayout}
195
+ ref={carouselRef}
196
+ renderItem={renderItem}
197
+ keyExtractor={(_, index) => `${index}`}
198
+ decelerationRate="fast"
199
+ renderToHardwareTextureAndroid
200
+ snapToInterval={
201
+ itemWidth + theme.__hd__.cardCarousel.space.carouselItemSpacing
202
+ }
203
+ onViewableItemsChanged={visibleSlideChanged}
204
+ viewabilityConfig={{
205
+ itemVisiblePercentThreshold: 80,
206
+ }}
207
+ />
208
+ {!hidePageControl && (
209
+ <StyledPageControl
210
+ testID="pageControl"
211
+ currentPage={currentIndex}
212
+ numberOfPages={items.length}
213
+ />
214
+ )}
215
+ </StyledWrapper>
216
+ );
217
+ }
218
+ );
@@ -0,0 +1,40 @@
1
+ import styled from '@emotion/native';
2
+ import { View, ViewProps } from 'react-native';
3
+ import Card, { CardProps } from '../Card';
4
+ import PageControl, { PageControlProps } from '../PageControl';
5
+
6
+ const StyledPageControl = styled(PageControl)<PageControlProps>(
7
+ ({ theme }) => ({
8
+ alignSelf: 'center',
9
+ marginTop: theme.__hd__.cardCarousel.space.pageControlMarginTop,
10
+ })
11
+ );
12
+
13
+ const StyledWrapper = styled(View)<ViewProps>({});
14
+
15
+ const StyledCard = styled(Card)<CardProps>(({ theme }) => ({
16
+ borderRadius: theme.__hd__.cardCarousel.radii.card,
17
+ overflow: 'hidden',
18
+ flex: 1,
19
+ }));
20
+ const StyledShadow = styled(View)<ViewProps>(({ theme }) => ({
21
+ borderRadius: theme.__hd__.cardCarousel.radii.card,
22
+ shadowColor: theme.__hd__.cardCarousel.colors.shadow,
23
+ shadowOffset: theme.__hd__.cardCarousel.shadows.offset,
24
+ shadowRadius: theme.__hd__.cardCarousel.shadows.radius,
25
+ shadowOpacity: theme.__hd__.cardCarousel.shadows.opacity,
26
+ elevation: theme.__hd__.cardCarousel.shadows.elevation,
27
+ flex: 1,
28
+ }));
29
+
30
+ const StyledItemWrapper = styled(View)<ViewProps>(({ theme }) => ({
31
+ padding: theme.__hd__.cardCarousel.space.carouselItemSpacing,
32
+ }));
33
+
34
+ export {
35
+ StyledCard,
36
+ StyledShadow,
37
+ StyledItemWrapper,
38
+ StyledWrapper,
39
+ StyledPageControl,
40
+ };
@@ -0,0 +1,105 @@
1
+ import { waitFor } from '@testing-library/react-native';
2
+ import React from 'react';
3
+ import { FlatList } from 'react-native';
4
+ import { CardCarousel, CardCarouselHandles } from '../CardCarousel';
5
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
6
+ import Typography from '../../Typography';
7
+
8
+ describe('CardCarousel', () => {
9
+ it('should render correctly', () => {
10
+ const wrapper = renderWithTheme(
11
+ <CardCarousel
12
+ testID="cardCarousel"
13
+ style={{ width: 100, height: 100 }}
14
+ items={[
15
+ <Typography.Text> screen 1</Typography.Text>,
16
+ <Typography.Text> screen 2</Typography.Text>,
17
+ ]}
18
+ />
19
+ );
20
+
21
+ expect(wrapper.toJSON()).toMatchSnapshot();
22
+ expect(wrapper.queryAllByText('screen 1')).toHaveLength(1);
23
+ expect(wrapper.queryAllByText('screen 2')).toHaveLength(1);
24
+ expect(wrapper.queryAllByTestId('pageControl')).toHaveLength(1);
25
+ });
26
+
27
+ describe('autoPlay', () => {
28
+ it('should call scrollToIndex 1', () => {
29
+ jest.useFakeTimers();
30
+ const carouselRef = React.createRef<
31
+ CardCarouselHandles & {
32
+ getFlatListRef: () => FlatList;
33
+ }
34
+ >();
35
+
36
+ renderWithTheme(
37
+ <CardCarousel
38
+ ref={carouselRef}
39
+ autoPlay
40
+ autoPlayInterval={3000}
41
+ items={[
42
+ <Typography.Text> screen 1</Typography.Text>,
43
+ <Typography.Text> screen 2</Typography.Text>,
44
+ ]}
45
+ />
46
+ );
47
+ const flatListRef = carouselRef.current!.getFlatListRef()!;
48
+ const snapToIndexSpy = jest.spyOn(flatListRef, 'scrollToIndex');
49
+ jest.advanceTimersByTime(3000);
50
+ expect(snapToIndexSpy).toHaveBeenCalledWith({
51
+ animated: true,
52
+ index: 1,
53
+ viewPosition: 0.5,
54
+ });
55
+
56
+ jest.useRealTimers();
57
+ });
58
+ });
59
+
60
+ describe('hidePageControl', () => {
61
+ const wrapper = renderWithTheme(
62
+ <CardCarousel
63
+ style={{ width: 100, height: 100 }}
64
+ hidePageControl
65
+ items={[
66
+ <Typography.Text> screen 1</Typography.Text>,
67
+ <Typography.Text> screen 2</Typography.Text>,
68
+ ]}
69
+ />
70
+ );
71
+ expect(wrapper.queryAllByTestId('pageControl')).toHaveLength(0);
72
+ });
73
+
74
+ describe('snapToIndex', () => {
75
+ it('should render correctly', () => {
76
+ const carouselRef = React.createRef<
77
+ CardCarouselHandles & {
78
+ getFlatListRef: () => FlatList;
79
+ }
80
+ >();
81
+
82
+ renderWithTheme(
83
+ <CardCarousel
84
+ ref={carouselRef}
85
+ items={[
86
+ <Typography.Text> screen 1</Typography.Text>,
87
+ <Typography.Text> screen 2</Typography.Text>,
88
+ <Typography.Text> screen 3</Typography.Text>,
89
+ ]}
90
+ />
91
+ );
92
+
93
+ const flatListRef = carouselRef.current!.getFlatListRef()!;
94
+ const snapToIndexSpy = jest.spyOn(flatListRef, 'scrollToIndex');
95
+ carouselRef.current?.snapToIndex(2);
96
+ waitFor(() => expect(snapToIndexSpy).toHaveBeenCalled());
97
+
98
+ expect(snapToIndexSpy).toHaveBeenCalledWith({
99
+ animated: true,
100
+ index: 2,
101
+ viewPosition: 0.5,
102
+ });
103
+ });
104
+ });
105
+ });
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
3
+ import {
4
+ StyledCard,
5
+ StyledItemWrapper,
6
+ StyledPageControl,
7
+ StyledWrapper,
8
+ } from '../StyledCardCarousel';
9
+
10
+ describe('StyledPageControl', () => {
11
+ it('should render correctly', () => {
12
+ const { toJSON } = renderWithTheme(
13
+ <StyledPageControl numberOfPages={3} currentPage={1} />
14
+ );
15
+ expect(toJSON()).toMatchSnapshot();
16
+ });
17
+ });
18
+
19
+ describe('StyledWrapper', () => {
20
+ it('should render correctly', () => {
21
+ const { toJSON } = renderWithTheme(<StyledWrapper />);
22
+ expect(toJSON()).toMatchSnapshot();
23
+ });
24
+ });
25
+
26
+ describe('StyledCard', () => {
27
+ it('should render correctly', () => {
28
+ const { toJSON } = renderWithTheme(<StyledCard />);
29
+ expect(toJSON()).toMatchSnapshot();
30
+ });
31
+ });
32
+
33
+ describe('StyledItemWrapper', () => {
34
+ it('should render correctly', () => {
35
+ const { toJSON } = renderWithTheme(<StyledItemWrapper />);
36
+ expect(toJSON()).toMatchSnapshot();
37
+ });
38
+ });
@@ -0,0 +1,289 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`CardCarousel should render correctly 1`] = `
4
+ <View
5
+ style={
6
+ Array [
7
+ Object {},
8
+ Object {
9
+ "height": 100,
10
+ "width": 100,
11
+ },
12
+ ]
13
+ }
14
+ testID="cardCarousel"
15
+ >
16
+ <RCTScrollView
17
+ bounces={false}
18
+ contentContainerStyle={
19
+ Object {
20
+ "paddingHorizontal": 24,
21
+ }
22
+ }
23
+ data={
24
+ Array [
25
+ <Text>
26
+ screen 1
27
+ </Text>,
28
+ <Text>
29
+ screen 2
30
+ </Text>,
31
+ ]
32
+ }
33
+ decelerationRate="fast"
34
+ getItem={[Function]}
35
+ getItemCount={[Function]}
36
+ getItemLayout={[Function]}
37
+ horizontal={true}
38
+ keyExtractor={[Function]}
39
+ onContentSizeChange={[Function]}
40
+ onLayout={[Function]}
41
+ onMomentumScrollBegin={[Function]}
42
+ onMomentumScrollEnd={[Function]}
43
+ onScroll={[Function]}
44
+ onScrollBeginDrag={[Function]}
45
+ onScrollEndDrag={[Function]}
46
+ onViewableItemsChanged={[Function]}
47
+ pagingEnabled={true}
48
+ removeClippedSubviews={false}
49
+ renderItem={[Function]}
50
+ renderToHardwareTextureAndroid={true}
51
+ scrollEventThrottle={32}
52
+ showsHorizontalScrollIndicator={false}
53
+ snapToAlignment="center"
54
+ snapToInterval={8}
55
+ stickyHeaderIndices={Array []}
56
+ viewabilityConfig={
57
+ Object {
58
+ "itemVisiblePercentThreshold": 80,
59
+ }
60
+ }
61
+ viewabilityConfigCallbackPairs={
62
+ Array [
63
+ Object {
64
+ "onViewableItemsChanged": [Function],
65
+ "viewabilityConfig": Object {
66
+ "itemVisiblePercentThreshold": 80,
67
+ },
68
+ },
69
+ ]
70
+ }
71
+ >
72
+ <View>
73
+ <View
74
+ style={
75
+ Array [
76
+ Object {
77
+ "flexDirection": "row",
78
+ },
79
+ null,
80
+ ]
81
+ }
82
+ >
83
+ <View
84
+ style={
85
+ Array [
86
+ Object {
87
+ "padding": 8,
88
+ },
89
+ Object {
90
+ "width": 0,
91
+ },
92
+ ]
93
+ }
94
+ >
95
+ <View
96
+ style={
97
+ Array [
98
+ Object {
99
+ "borderRadius": 8,
100
+ "elevation": 4,
101
+ "flex": 1,
102
+ "shadowColor": "#001f23",
103
+ "shadowOffset": Object {
104
+ "height": 2,
105
+ "width": 0,
106
+ },
107
+ "shadowOpacity": 0.12,
108
+ "shadowRadius": 8,
109
+ },
110
+ undefined,
111
+ ]
112
+ }
113
+ >
114
+ <View
115
+ style={
116
+ Array [
117
+ Object {
118
+ "borderRadius": 12,
119
+ "overflow": "hidden",
120
+ },
121
+ Array [
122
+ Object {
123
+ "borderRadius": 8,
124
+ "flex": 1,
125
+ "overflow": "hidden",
126
+ },
127
+ undefined,
128
+ ],
129
+ ]
130
+ }
131
+ >
132
+ <Text
133
+ style={
134
+ Array [
135
+ Object {
136
+ "color": "#001f23",
137
+ "fontFamily": "BeVietnamPro-Regular",
138
+ "fontSize": 14,
139
+ "letterSpacing": 0.42,
140
+ "lineHeight": 22,
141
+ },
142
+ undefined,
143
+ ]
144
+ }
145
+ themeFontSize="medium"
146
+ themeFontWeight="regular"
147
+ themeIntent="body"
148
+ themeTypeface="neutral"
149
+ >
150
+ screen 1
151
+ </Text>
152
+ </View>
153
+ </View>
154
+ </View>
155
+ </View>
156
+ <View
157
+ style={
158
+ Array [
159
+ Object {
160
+ "flexDirection": "row",
161
+ },
162
+ null,
163
+ ]
164
+ }
165
+ >
166
+ <View
167
+ style={
168
+ Array [
169
+ Object {
170
+ "padding": 8,
171
+ },
172
+ Object {
173
+ "width": 0,
174
+ },
175
+ ]
176
+ }
177
+ >
178
+ <View
179
+ style={
180
+ Array [
181
+ Object {
182
+ "borderRadius": 8,
183
+ "elevation": 4,
184
+ "flex": 1,
185
+ "shadowColor": "#001f23",
186
+ "shadowOffset": Object {
187
+ "height": 2,
188
+ "width": 0,
189
+ },
190
+ "shadowOpacity": 0.12,
191
+ "shadowRadius": 8,
192
+ },
193
+ undefined,
194
+ ]
195
+ }
196
+ >
197
+ <View
198
+ style={
199
+ Array [
200
+ Object {
201
+ "borderRadius": 12,
202
+ "overflow": "hidden",
203
+ },
204
+ Array [
205
+ Object {
206
+ "borderRadius": 8,
207
+ "flex": 1,
208
+ "overflow": "hidden",
209
+ },
210
+ undefined,
211
+ ],
212
+ ]
213
+ }
214
+ >
215
+ <Text
216
+ style={
217
+ Array [
218
+ Object {
219
+ "color": "#001f23",
220
+ "fontFamily": "BeVietnamPro-Regular",
221
+ "fontSize": 14,
222
+ "letterSpacing": 0.42,
223
+ "lineHeight": 22,
224
+ },
225
+ undefined,
226
+ ]
227
+ }
228
+ themeFontSize="medium"
229
+ themeFontWeight="regular"
230
+ themeIntent="body"
231
+ themeTypeface="neutral"
232
+ >
233
+ screen 2
234
+ </Text>
235
+ </View>
236
+ </View>
237
+ </View>
238
+ </View>
239
+ </View>
240
+ </RCTScrollView>
241
+ <View
242
+ style={
243
+ Array [
244
+ Object {
245
+ "alignItems": "center",
246
+ "flexDirection": "row",
247
+ },
248
+ Array [
249
+ Object {
250
+ "alignSelf": "center",
251
+ "marginTop": 16,
252
+ },
253
+ undefined,
254
+ ],
255
+ ]
256
+ }
257
+ testID="pageControl"
258
+ >
259
+ <View
260
+ collapsable={false}
261
+ style={
262
+ Object {
263
+ "backgroundColor": "#401960",
264
+ "borderRadius": 999,
265
+ "height": 8,
266
+ "marginHorizontal": 8,
267
+ "opacity": 1,
268
+ "width": 24,
269
+ }
270
+ }
271
+ testID="page-control-indicator0"
272
+ />
273
+ <View
274
+ collapsable={false}
275
+ style={
276
+ Object {
277
+ "backgroundColor": "#401960",
278
+ "borderRadius": 999,
279
+ "height": 8,
280
+ "marginHorizontal": 8,
281
+ "opacity": 0.5,
282
+ "width": 8,
283
+ }
284
+ }
285
+ testID="page-control-indicator1"
286
+ />
287
+ </View>
288
+ </View>
289
+ `;