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.
- package/README.md +84 -27
- package/lib/assets/fonts/TwemojiMozilla.woff2 +0 -0
- package/lib/assets/images/preview.png +0 -0
- package/lib/components/CountryItem/index.tsx +26 -6
- package/lib/components/CountrySelect/index.tsx +391 -77
- package/lib/components/{styles.ts → styles.js} +56 -5
- package/lib/constants/countries.json +1078 -4020
- package/lib/index.d.ts +34 -0
- package/lib/index.tsx +25 -0
- package/lib/interface/countryItemProps.ts +1 -0
- package/lib/interface/countrySelectProps.ts +10 -4
- package/lib/interface/countrySelectStyles.ts +8 -0
- package/lib/utils/countryHelpers.ts +59 -0
- package/lib/utils/getTranslation.ts +37 -1
- package/lib/utils/parseHeight.ts +35 -0
- package/package.json +1 -1
@@ -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
|
-
|
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="
|
589
|
+
animationType="slide"
|
233
590
|
onRequestClose={onClose}
|
234
591
|
statusBarTranslucent
|
235
592
|
{...props}>
|
236
|
-
<
|
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
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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.
|
254
|
-
|
613
|
+
styles.sheetContent,
|
614
|
+
{
|
615
|
+
height: sheetHeight,
|
616
|
+
minHeight: bottomSheetSize.minHeight,
|
617
|
+
maxHeight: bottomSheetSize.maxHeight,
|
618
|
+
},
|
255
619
|
]}>
|
256
|
-
|
257
|
-
style={
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
-
<
|
302
|
-
|
303
|
-
|
304
|
-
|
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 =
|
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
|
-
|
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:
|
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' : '#
|
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
|
});
|