react-native-country-select 0.1.3 → 0.2.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.
@@ -1,13 +1,17 @@
1
1
  /* eslint-disable react-native/no-inline-styles */
2
2
  /* eslint-disable react-hooks/exhaustive-deps */
3
- import React, {useCallback, useMemo, useState} from 'react';
3
+ import React, {useCallback, useMemo, useState, useRef, useEffect} from 'react';
4
4
  import {
5
5
  View,
6
6
  TextInput,
7
7
  FlatList,
8
+ useWindowDimensions,
8
9
  Pressable,
10
+ Animated,
11
+ PanResponder,
9
12
  ListRenderItem,
10
13
  Modal,
14
+ Keyboard,
11
15
  Text,
12
16
  TouchableOpacity,
13
17
  } from 'react-native';
@@ -15,6 +19,7 @@ import {
15
19
  import {CountryItem} from '../CountryItem';
16
20
 
17
21
  import {createStyles} from '../styles';
22
+ import parseHeight from '../../utils/parseHeight';
18
23
  import countries from '../../constants/countries.json';
19
24
  import {translations} from '../../utils/getTranslation';
20
25
  import {
@@ -24,12 +29,20 @@ import {
24
29
  IListItem,
25
30
  } from '../../interface';
26
31
 
32
+ const ITEM_HEIGHT = 56;
33
+ const SECTION_HEADER_HEIGHT = 40;
34
+
35
+ const MIN_HEIGHT_PERCENTAGE = 0.3;
36
+ const MAX_HEIGHT_PERCENTAGE = 0.9;
37
+ const INITIAL_HEIGHT_PERCENTAGE = 0.5;
38
+
27
39
  const DEFAULT_LANGUAGE: ICountrySelectLanguages = 'eng';
28
40
 
29
41
  export const CountrySelect: React.FC<ICountrySelectProps> = ({
30
42
  visible,
31
43
  onClose,
32
44
  onSelect,
45
+ modalType = 'bottomSheet',
33
46
  theme = 'light',
34
47
  isFullScreen = false,
35
48
  countrySelectStyle,
@@ -39,19 +52,185 @@ export const CountrySelect: React.FC<ICountrySelectProps> = ({
39
52
  language = DEFAULT_LANGUAGE,
40
53
  showSearchInput = true,
41
54
  searchPlaceholder,
55
+ showCloseButton = false,
56
+ minBottomsheetHeight,
57
+ maxBottomsheetHeight,
58
+ initialBottomsheetHeight,
42
59
  disabledBackdropPress,
43
60
  removedBackdrop,
44
61
  onBackdropPress,
45
62
  sectionTitleComponent,
46
63
  countryItemComponent,
64
+ closeButtonComponent,
47
65
  popularCountriesTitle,
48
66
  allCountriesTitle,
49
67
  showsVerticalScrollIndicator = false,
68
+ countryNotFoundMessage,
50
69
  ...props
51
70
  }) => {
71
+ const {height: windowHeight} = useWindowDimensions();
52
72
  const styles = createStyles(theme);
53
73
 
54
74
  const [searchQuery, setSearchQuery] = useState('');
75
+ const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
76
+ const [bottomSheetSize, setBottomSheetSize] = useState({
77
+ minHeight: MIN_HEIGHT_PERCENTAGE * windowHeight,
78
+ maxHeight: MAX_HEIGHT_PERCENTAGE * windowHeight,
79
+ initialHeight: INITIAL_HEIGHT_PERCENTAGE * windowHeight,
80
+ });
81
+
82
+ const sheetHeight = useRef(
83
+ new Animated.Value(bottomSheetSize.initialHeight),
84
+ ).current;
85
+ const lastHeight = useRef(bottomSheetSize.initialHeight);
86
+ const dragStartY = useRef(0);
87
+
88
+ useEffect(() => {
89
+ if (modalType === 'popup') {
90
+ return;
91
+ }
92
+
93
+ const DRAG_HANDLE_HEIGHT = 20;
94
+ const availableHeight = windowHeight - DRAG_HANDLE_HEIGHT;
95
+
96
+ const parsedMinHeight = parseHeight(minBottomsheetHeight, availableHeight);
97
+ const parsedMaxHeight = parseHeight(maxBottomsheetHeight, availableHeight);
98
+ const parsedInitialHeight = parseHeight(
99
+ initialBottomsheetHeight,
100
+ availableHeight,
101
+ );
102
+
103
+ setBottomSheetSize({
104
+ minHeight: parsedMinHeight || MIN_HEIGHT_PERCENTAGE * availableHeight,
105
+ maxHeight: parsedMaxHeight || MAX_HEIGHT_PERCENTAGE * availableHeight,
106
+ initialHeight:
107
+ parsedInitialHeight || INITIAL_HEIGHT_PERCENTAGE * availableHeight,
108
+ });
109
+ }, [
110
+ minBottomsheetHeight,
111
+ maxBottomsheetHeight,
112
+ initialBottomsheetHeight,
113
+ windowHeight,
114
+ modalType,
115
+ ]);
116
+
117
+ // Resets to initial height when the modal is opened
118
+ useEffect(() => {
119
+ if (modalType === 'popup') {
120
+ return;
121
+ }
122
+
123
+ if (visible) {
124
+ sheetHeight.setValue(bottomSheetSize.initialHeight);
125
+ lastHeight.current = bottomSheetSize.initialHeight;
126
+ }
127
+ }, [visible, bottomSheetSize.initialHeight, modalType]);
128
+
129
+ useEffect(() => {
130
+ if (modalType === 'popup') {
131
+ return;
132
+ }
133
+
134
+ if (isKeyboardVisible) {
135
+ sheetHeight.setValue(
136
+ parseHeight(bottomSheetSize.maxHeight, windowHeight),
137
+ );
138
+ lastHeight.current = bottomSheetSize.maxHeight;
139
+ } else {
140
+ sheetHeight.setValue(parseHeight(lastHeight.current, windowHeight));
141
+ }
142
+ }, [isKeyboardVisible, modalType]);
143
+
144
+ // Monitors keyboard events
145
+ useEffect(() => {
146
+ if (modalType === 'popup') {
147
+ return;
148
+ }
149
+
150
+ const keyboardDidShowListener = Keyboard.addListener(
151
+ 'keyboardDidShow',
152
+ () => {
153
+ setIsKeyboardVisible(true);
154
+ },
155
+ );
156
+ const keyboardDidHideListener = Keyboard.addListener(
157
+ 'keyboardDidHide',
158
+ () => {
159
+ setIsKeyboardVisible(false);
160
+ },
161
+ );
162
+
163
+ return () => {
164
+ keyboardDidShowListener?.remove();
165
+ keyboardDidHideListener?.remove();
166
+ };
167
+ }, [modalType]);
168
+
169
+ const handlePanResponder = useMemo(
170
+ () =>
171
+ PanResponder.create({
172
+ onStartShouldSetPanResponder: () => {
173
+ // Only respond to touches on the drag handle
174
+ return true;
175
+ },
176
+ onMoveShouldSetPanResponder: (evt, gestureState) => {
177
+ // Only respond to vertical movements with sufficient distance
178
+ return Math.abs(gestureState.dy) > 5;
179
+ },
180
+ onPanResponderGrant: e => {
181
+ dragStartY.current = e.nativeEvent.pageY;
182
+ sheetHeight.stopAnimation();
183
+ },
184
+ onPanResponderMove: e => {
185
+ const currentY = e.nativeEvent.pageY;
186
+ const dy = currentY - dragStartY.current;
187
+ const proposedHeight = lastHeight.current - dy;
188
+
189
+ // Allows free dragging but with smooth limits
190
+ sheetHeight.setValue(proposedHeight);
191
+ },
192
+ onPanResponderRelease: e => {
193
+ const currentY = e.nativeEvent.pageY;
194
+ const dy = currentY - dragStartY.current;
195
+ const currentHeight = lastHeight.current - dy;
196
+
197
+ // Close modal if the final height is less than minHeight
198
+ if (currentHeight < bottomSheetSize.minHeight) {
199
+ Animated.timing(sheetHeight, {
200
+ toValue: 0,
201
+ duration: 200,
202
+ useNativeDriver: false,
203
+ }).start(onClose);
204
+ return;
205
+ }
206
+
207
+ // Snap to nearest limit
208
+ const finalHeight = Math.min(
209
+ Math.max(currentHeight, bottomSheetSize.minHeight),
210
+ bottomSheetSize.maxHeight,
211
+ );
212
+
213
+ Animated.spring(sheetHeight, {
214
+ toValue: finalHeight,
215
+ useNativeDriver: false,
216
+ tension: 50,
217
+ friction: 12,
218
+ }).start(() => {
219
+ lastHeight.current = finalHeight;
220
+ });
221
+ },
222
+ onPanResponderTerminate: () => {
223
+ // Reset to last stable height if gesture is terminated
224
+ Animated.spring(sheetHeight, {
225
+ toValue: lastHeight.current,
226
+ useNativeDriver: false,
227
+ tension: 50,
228
+ friction: 12,
229
+ }).start();
230
+ },
231
+ }),
232
+ [bottomSheetSize, sheetHeight, onClose],
233
+ );
55
234
 
56
235
  // Obtain the country name in the selected language
57
236
  const getCountryNameInLanguage = (country: ICountry): string => {
@@ -177,6 +356,122 @@ export const CountrySelect: React.FC<ICountrySelectProps> = ({
177
356
  [],
178
357
  );
179
358
 
359
+ const getItemLayout = useCallback(
360
+ (data: IListItem[] | null | undefined, index: number) => {
361
+ let offset = 0;
362
+ let length = ITEM_HEIGHT;
363
+
364
+ if (data) {
365
+ const item = data[index];
366
+ if ('isSection' in item) {
367
+ length = SECTION_HEADER_HEIGHT;
368
+ }
369
+ }
370
+
371
+ return {
372
+ length,
373
+ offset: offset + index * ITEM_HEIGHT,
374
+ index,
375
+ };
376
+ },
377
+ [],
378
+ );
379
+
380
+ const renderCloseButton = () => {
381
+ if (closeButtonComponent) {
382
+ return closeButtonComponent();
383
+ }
384
+
385
+ return (
386
+ <TouchableOpacity
387
+ testID="countrySelectCloseButton"
388
+ accessibilityRole="button"
389
+ accessibilityLabel="Country Select Modal Close Button"
390
+ accessibilityHint="Click to close the Country Select modal"
391
+ style={[styles.closeButton, countrySelectStyle?.popup?.closeButton]}
392
+ activeOpacity={0.6}
393
+ onPress={onClose}>
394
+ <Text
395
+ style={[
396
+ styles.closeButtonText,
397
+ countrySelectStyle?.popup?.closeButtonText,
398
+ ]}>
399
+ {'\u00D7'}
400
+ </Text>
401
+ </TouchableOpacity>
402
+ );
403
+ };
404
+
405
+ const renderSearchInput = () => {
406
+ return (
407
+ <TextInput
408
+ testID="countrySelectSearchInput"
409
+ accessibilityRole="text"
410
+ accessibilityLabel="Country Select Search Input"
411
+ accessibilityHint="Type to search for a country"
412
+ style={[
413
+ styles.searchInput,
414
+ modalType === 'popup'
415
+ ? countrySelectStyle?.popup?.searchInput
416
+ : countrySelectStyle?.bottomSheet?.searchInput,
417
+ ]}
418
+ placeholder={
419
+ searchPlaceholder ||
420
+ translations.searchPlaceholder[language as ICountrySelectLanguages]
421
+ }
422
+ placeholderTextColor={
423
+ (modalType === 'popup'
424
+ ? countrySelectStyle?.popup?.searchInputPlaceholder?.color
425
+ : countrySelectStyle?.bottomSheet?.searchInputPlaceholder?.color) ||
426
+ styles.searchInputPlaceholder.color
427
+ }
428
+ value={searchQuery}
429
+ onChangeText={setSearchQuery}
430
+ />
431
+ );
432
+ };
433
+
434
+ const renderFlatList = () => {
435
+ if (getCountries.length === 0) {
436
+ return (
437
+ <View
438
+ style={[
439
+ styles.countryNotFoundContainer,
440
+ modalType === 'popup'
441
+ ? countrySelectStyle?.popup?.countryNotFoundContainer
442
+ : countrySelectStyle?.bottomSheet?.countryNotFoundContainer,
443
+ ]}>
444
+ <Text
445
+ style={[
446
+ styles.countryNotFoundMessage,
447
+ modalType === 'popup'
448
+ ? countrySelectStyle?.popup?.countryNotFoundMessage
449
+ : countrySelectStyle?.bottomSheet?.countryNotFoundMessage,
450
+ ]}>
451
+ {countryNotFoundMessage ||
452
+ translations.searchNotFoundMessage[
453
+ language as ICountrySelectLanguages
454
+ ]}
455
+ </Text>
456
+ </View>
457
+ );
458
+ }
459
+ return (
460
+ <FlatList
461
+ testID="countrySelectList"
462
+ accessibilityRole="list"
463
+ accessibilityLabel="Country Select List"
464
+ accessibilityHint="List of countries"
465
+ data={getCountries}
466
+ keyExtractor={keyExtractor}
467
+ renderItem={renderItem}
468
+ getItemLayout={getItemLayout}
469
+ keyboardShouldPersistTaps="handled"
470
+ showsVerticalScrollIndicator={showsVerticalScrollIndicator || false}
471
+ />
472
+ );
473
+ };
474
+
180
475
  const renderItem: ListRenderItem<IListItem> = useCallback(
181
476
  ({item, index}) => {
182
477
  if ('isSection' in item) {
@@ -189,7 +484,9 @@ export const CountrySelect: React.FC<ICountrySelectProps> = ({
189
484
  accessibilityRole="header"
190
485
  style={[
191
486
  styles.sectionTitle,
192
- countrySelectStyle?.popup?.sectionTitle,
487
+ modalType === 'popup'
488
+ ? countrySelectStyle?.popup?.sectionTitle
489
+ : countrySelectStyle?.bottomSheet?.sectionTitle,
193
490
  ]}>
194
491
  {popularCountriesTitle && index === 0
195
492
  ? popularCountriesTitle
@@ -211,6 +508,7 @@ export const CountrySelect: React.FC<ICountrySelectProps> = ({
211
508
  onClose={onClose}
212
509
  theme={theme}
213
510
  language={language}
511
+ modalType={modalType}
214
512
  countrySelectStyle={countrySelectStyle}
215
513
  />
216
514
  );
@@ -225,95 +523,111 @@ export const CountrySelect: React.FC<ICountrySelectProps> = ({
225
523
  ],
226
524
  );
227
525
 
526
+ if (modalType === 'popup' || isFullScreen) {
527
+ return (
528
+ <Modal
529
+ visible={visible}
530
+ transparent
531
+ animationType="fade"
532
+ onRequestClose={onClose}
533
+ statusBarTranslucent
534
+ {...props}>
535
+ <Pressable
536
+ testID="countrySelectBackdrop"
537
+ accessibilityRole="button"
538
+ accessibilityLabel="Country Select Modal Backdrop"
539
+ accessibilityHint="Click to close the Country Select modal"
540
+ disabled={disabledBackdropPress || removedBackdrop}
541
+ style={[
542
+ styles.backdrop,
543
+ {alignItems: 'center', justifyContent: 'center'},
544
+ countrySelectStyle?.popup?.backdrop,
545
+ removedBackdrop && {backgroundColor: 'transparent'},
546
+ ]}
547
+ onPress={onBackdropPress || onClose}>
548
+ <Pressable
549
+ style={[
550
+ styles.popupContainer,
551
+ countrySelectStyle?.popup?.popupContainer,
552
+ isFullScreen && {
553
+ flex: 1,
554
+ width: '100%',
555
+ height: '100%',
556
+ },
557
+ ]}>
558
+ <View
559
+ style={[
560
+ styles.popupContent,
561
+ countrySelectStyle?.popup?.popupContent,
562
+ isFullScreen && {
563
+ borderRadius: 0,
564
+ },
565
+ ]}>
566
+ {(isFullScreen || showSearchInput || showCloseButton) && (
567
+ <View
568
+ style={[
569
+ styles.searchContainer,
570
+ countrySelectStyle?.popup?.searchContainer,
571
+ ]}>
572
+ {(isFullScreen || showCloseButton) && renderCloseButton()}
573
+ {showSearchInput && renderSearchInput()}
574
+ </View>
575
+ )}
576
+
577
+ {renderFlatList()}
578
+ </View>
579
+ </Pressable>
580
+ </Pressable>
581
+ </Modal>
582
+ );
583
+ }
584
+
228
585
  return (
229
586
  <Modal
230
587
  visible={visible}
231
588
  transparent
232
- animationType="fade"
589
+ animationType="slide"
233
590
  onRequestClose={onClose}
234
591
  statusBarTranslucent
235
592
  {...props}>
236
- <Pressable
593
+ <View
237
594
  style={[
238
595
  styles.backdrop,
239
- {alignItems: 'center', justifyContent: 'center'},
240
- countrySelectStyle?.popup?.backdrop,
241
596
  removedBackdrop && {backgroundColor: 'transparent'},
242
- ]}
243
- disabled={disabledBackdropPress || removedBackdrop}
244
- onPress={onBackdropPress || onClose}>
597
+ ]}>
245
598
  <Pressable
246
- style={[
247
- styles.popupContainer,
248
- countrySelectStyle?.popup?.popupContainer,
249
- isFullScreen && {flex: 1, width: '100%', height: '100%'},
250
- ]}>
251
- <View
599
+ testID="countrySelectBackdrop"
600
+ accessibilityRole="button"
601
+ accessibilityLabel="Country Select Modal Backdrop"
602
+ accessibilityHint="Click to close the Country Select modal"
603
+ disabled={disabledBackdropPress || removedBackdrop}
604
+ style={{flex: 1}}
605
+ onPress={onBackdropPress || onClose}
606
+ />
607
+ <View style={styles.sheetContainer} pointerEvents="auto">
608
+ <View {...handlePanResponder.panHandlers} style={styles.dragHandle}>
609
+ <View style={styles.dragIndicator} />
610
+ </View>
611
+ <Animated.View
252
612
  style={[
253
- styles.popupContent,
254
- countrySelectStyle?.popup?.popupContent,
613
+ styles.sheetContent,
614
+ {
615
+ height: sheetHeight,
616
+ minHeight: bottomSheetSize.minHeight,
617
+ maxHeight: bottomSheetSize.maxHeight,
618
+ },
255
619
  ]}>
256
- <View
257
- style={[
258
- styles.searchContainer,
259
- countrySelectStyle?.popup?.searchContainer,
260
- ]}>
261
- {isFullScreen && (
262
- <TouchableOpacity
263
- style={[
264
- styles.closeButton,
265
- countrySelectStyle?.popup?.closeButton,
266
- ]}
267
- activeOpacity={0.6}
268
- onPress={onClose}>
269
- <Text
270
- style={[
271
- styles.closeButtonText,
272
- countrySelectStyle?.popup?.closeButtonText,
273
- ]}>
274
- {'\u00D7'}
275
- </Text>
276
- </TouchableOpacity>
277
- )}
278
- {showSearchInput && (
279
- <TextInput
280
- testID="countrySelectSearchInput"
281
- accessibilityRole="text"
282
- accessibilityLabel="Country Select Search Input"
283
- accessibilityHint="Type to search for a country"
284
- style={[
285
- styles.searchInput,
286
- countrySelectStyle?.popup?.searchInput,
287
- ]}
288
- placeholder={
289
- searchPlaceholder ||
290
- translations.searchPlaceholder[
291
- language as ICountrySelectLanguages
292
- ]
293
- }
294
- placeholderTextColor={styles.searchInputPlaceholder.color}
295
- value={searchQuery}
296
- onChangeText={setSearchQuery}
297
- />
298
- )}
299
- </View>
620
+ {(showSearchInput || showCloseButton) && (
621
+ <View style={styles.searchContainer}>
622
+ {showCloseButton && renderCloseButton()}
623
+ {showSearchInput && renderSearchInput()}
624
+ </View>
625
+ )}
300
626
 
301
- <FlatList
302
- testID="countrySelectList"
303
- accessibilityRole="list"
304
- accessibilityLabel="Country Select List"
305
- accessibilityHint="List of countries"
306
- data={getCountries}
307
- keyExtractor={keyExtractor}
308
- renderItem={renderItem}
309
- keyboardShouldPersistTaps="handled"
310
- showsVerticalScrollIndicator={
311
- showsVerticalScrollIndicator || false
312
- }
313
- />
314
- </View>
315
- </Pressable>
316
- </Pressable>
627
+ <Animated.View style={{flex: 1}}>{renderFlatList()}</Animated.View>
628
+ </Animated.View>
629
+ </View>
630
+ </View>
317
631
  </Modal>
318
632
  );
319
633
  };
@@ -1,13 +1,13 @@
1
- import {StatusBar, StyleSheet} from 'react-native';
1
+ import {Platform, StatusBar, StyleSheet} from 'react-native';
2
2
 
3
- export const createStyles = (theme: 'light' | 'dark') =>
3
+ export const createStyles = theme =>
4
4
  StyleSheet.create({
5
5
  backdrop: {
6
6
  flex: 1,
7
7
  backgroundColor: 'rgba(0, 0, 0, 0.5)',
8
8
  },
9
9
  popupContainer: {
10
- paddingTop: StatusBar.currentHeight,
10
+ marginTop: StatusBar.currentHeight,
11
11
  width: '90%',
12
12
  maxWidth: 600,
13
13
  height: '60%',
@@ -23,9 +23,40 @@ export const createStyles = (theme: 'light' | 'dark') =>
23
23
  alignSelf: 'center',
24
24
  padding: 16,
25
25
  },
26
+ sheetContainer: {
27
+ marginTop: StatusBar.currentHeight,
28
+ position: 'absolute',
29
+ bottom: 0,
30
+ left: 0,
31
+ right: 0,
32
+ width: '100%',
33
+ alignItems: 'center',
34
+ },
35
+ sheetContent: {
36
+ width: '100%',
37
+ backgroundColor: theme === 'dark' ? '#202020' : '#FFFFFF',
38
+ padding: 16,
39
+ paddingTop: 0,
40
+ },
41
+ dragHandle: {
42
+ width: '100%',
43
+ height: 24,
44
+ justifyContent: 'center',
45
+ alignItems: 'center',
46
+ backgroundColor: theme === 'dark' ? '#202020' : '#FFFFFF',
47
+ borderTopLeftRadius: 20,
48
+ borderTopRightRadius: 20,
49
+ marginBottom: -1,
50
+ },
51
+ dragIndicator: {
52
+ width: 40,
53
+ height: 4,
54
+ backgroundColor: theme === 'dark' ? '#FFFFFF40' : '#00000040',
55
+ borderRadius: 2,
56
+ },
26
57
  searchContainer: {
27
58
  marginBottom: 16,
28
- paddingTop: 16,
59
+ paddingTop: 8,
29
60
  flexDirection: 'row',
30
61
  },
31
62
  searchInput: {
@@ -57,8 +88,17 @@ export const createStyles = (theme: 'light' | 'dark') =>
57
88
  },
58
89
  flag: {
59
90
  flex: 0.1,
91
+ marginRight: 10,
60
92
  fontSize: 16,
61
93
  color: theme === 'dark' ? '#FFFFFF' : '#000000',
94
+ textAlign: 'center',
95
+ fontFamily:
96
+ Platform.OS === 'web'
97
+ ? typeof navigator !== 'undefined' &&
98
+ navigator?.userAgent?.includes('Win')
99
+ ? 'TwemojiMozilla'
100
+ : 'System'
101
+ : 'System',
62
102
  },
63
103
  countryInfo: {
64
104
  flex: 0.9,
@@ -87,7 +127,9 @@ export const createStyles = (theme: 'light' | 'dark') =>
87
127
  paddingHorizontal: 18,
88
128
  alignItems: 'center',
89
129
  justifyContent: 'center',
90
- backgroundColor: theme === 'dark' ? '#303030' : '#F5F5F5',
130
+ backgroundColor: theme === 'dark' ? '#303030' : '#F3F3F3',
131
+ borderColor: theme === 'dark' ? '#F3F3F3' : '#303030',
132
+ borderWidth: 1,
91
133
  borderRadius: 12,
92
134
  },
93
135
  closeButtonText: {
@@ -95,4 +137,13 @@ export const createStyles = (theme: 'light' | 'dark') =>
95
137
  lineHeight: 28,
96
138
  color: theme === 'dark' ? '#FFFFFF' : '#000000',
97
139
  },
140
+ countryNotFoundContainer: {
141
+ flex: 1,
142
+ justifyContent: 'center',
143
+ alignItems: 'center',
144
+ },
145
+ countryNotFoundMessage: {
146
+ fontSize: 16,
147
+ color: theme === 'dark' ? '#FFFFFF' : '#000000',
148
+ },
98
149
  });