react-native-input-select 1.3.18 → 2.1.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.
- package/README.md +40 -95
- package/lib/commonjs/components/CheckBox/index.js +19 -13
- package/lib/commonjs/components/CheckBox/index.js.map +1 -1
- package/lib/commonjs/components/CustomModal/index.js +12 -16
- package/lib/commonjs/components/CustomModal/index.js.map +1 -1
- package/lib/commonjs/components/Dropdown/Dropdown.js +3 -2
- package/lib/commonjs/components/Dropdown/Dropdown.js.map +1 -1
- package/lib/commonjs/components/Dropdown/DropdownListItem.js +2 -11
- package/lib/commonjs/components/Dropdown/DropdownListItem.js.map +1 -1
- package/lib/commonjs/components/Dropdown/DropdownSelectedItemsView.js +14 -14
- package/lib/commonjs/components/Dropdown/DropdownSelectedItemsView.js.map +1 -1
- package/lib/commonjs/components/Input/index.js.map +1 -1
- package/lib/commonjs/components/{Dropdown → List}/DropdownFlatList.js +7 -28
- package/lib/commonjs/components/List/DropdownFlatList.js.map +1 -0
- package/lib/commonjs/components/{Dropdown → List}/DropdownSectionList.js +6 -24
- package/lib/commonjs/components/List/DropdownSectionList.js.map +1 -0
- package/lib/commonjs/hooks/index.js +61 -0
- package/lib/commonjs/hooks/index.js.map +1 -0
- package/lib/commonjs/hooks/use-index-of-selected-item.js +49 -0
- package/lib/commonjs/hooks/use-index-of-selected-item.js.map +1 -0
- package/lib/commonjs/hooks/use-modal.js +37 -0
- package/lib/commonjs/hooks/use-modal.js.map +1 -0
- package/lib/commonjs/hooks/use-search.js +58 -0
- package/lib/commonjs/hooks/use-search.js.map +1 -0
- package/lib/commonjs/hooks/use-select-all.js +70 -0
- package/lib/commonjs/hooks/use-select-all.js.map +1 -0
- package/lib/commonjs/hooks/use-selection-handler.js +62 -0
- package/lib/commonjs/hooks/use-selection-handler.js.map +1 -0
- package/lib/commonjs/index.js +120 -260
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/index.js +40 -5
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/module/components/CheckBox/index.js +19 -13
- package/lib/module/components/CheckBox/index.js.map +1 -1
- package/lib/module/components/CustomModal/index.js +12 -15
- package/lib/module/components/CustomModal/index.js.map +1 -1
- package/lib/module/components/Dropdown/Dropdown.js +3 -2
- package/lib/module/components/Dropdown/Dropdown.js.map +1 -1
- package/lib/module/components/Dropdown/DropdownListItem.js +2 -11
- package/lib/module/components/Dropdown/DropdownListItem.js.map +1 -1
- package/lib/module/components/Dropdown/DropdownSelectedItemsView.js +14 -14
- package/lib/module/components/Dropdown/DropdownSelectedItemsView.js.map +1 -1
- package/lib/module/components/Input/index.js.map +1 -1
- package/lib/module/components/{Dropdown → List}/DropdownFlatList.js +7 -28
- package/lib/module/components/List/DropdownFlatList.js.map +1 -0
- package/lib/module/components/{Dropdown → List}/DropdownSectionList.js +6 -24
- package/lib/module/components/List/DropdownSectionList.js.map +1 -0
- package/lib/module/hooks/index.js +6 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/use-index-of-selected-item.js +42 -0
- package/lib/module/hooks/use-index-of-selected-item.js.map +1 -0
- package/lib/module/hooks/use-modal.js +30 -0
- package/lib/module/hooks/use-modal.js.map +1 -0
- package/lib/module/hooks/use-search.js +51 -0
- package/lib/module/hooks/use-search.js.map +1 -0
- package/lib/module/hooks/use-select-all.js +63 -0
- package/lib/module/hooks/use-select-all.js.map +1 -0
- package/lib/module/hooks/use-selection-handler.js +55 -0
- package/lib/module/hooks/use-selection-handler.js.map +1 -0
- package/lib/module/index.js +123 -262
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/index.js +36 -4
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/src/components/CheckBox/checkbox.types.d.ts +4 -2
- package/lib/typescript/src/components/CheckBox/checkbox.types.d.ts.map +1 -1
- package/lib/typescript/src/components/CheckBox/index.d.ts +2 -2
- package/lib/typescript/src/components/CheckBox/index.d.ts.map +1 -1
- package/lib/typescript/src/components/CustomModal/index.d.ts +3 -1
- package/lib/typescript/src/components/CustomModal/index.d.ts.map +1 -1
- package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +1 -1
- package/lib/typescript/src/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/lib/typescript/src/components/Dropdown/DropdownListItem.d.ts +1 -1
- package/lib/typescript/src/components/Dropdown/DropdownListItem.d.ts.map +1 -1
- package/lib/typescript/src/components/Dropdown/DropdownSelectedItemsView.d.ts +1 -1
- package/lib/typescript/src/components/Input/index.d.ts +5 -1
- package/lib/typescript/src/components/Input/index.d.ts.map +1 -1
- package/lib/typescript/src/components/List/DropdownFlatList.d.ts +6 -0
- package/lib/typescript/src/components/List/DropdownFlatList.d.ts.map +1 -0
- package/lib/typescript/src/components/List/DropdownSectionList.d.ts +4 -0
- package/lib/typescript/src/components/List/DropdownSectionList.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +6 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-index-of-selected-item.d.ts +23 -0
- package/lib/typescript/src/hooks/use-index-of-selected-item.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-modal.d.ts +13 -0
- package/lib/typescript/src/hooks/use-modal.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-search.d.ts +16 -0
- package/lib/typescript/src/hooks/use-search.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-select-all.d.ts +18 -0
- package/lib/typescript/src/hooks/use-select-all.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-selection-handler.d.ts +19 -0
- package/lib/typescript/src/hooks/use-selection-handler.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +19 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/index.types.d.ts +33 -53
- package/lib/typescript/src/types/index.types.d.ts.map +1 -1
- package/lib/typescript/src/utils/index.d.ts +17 -3
- package/lib/typescript/src/utils/index.d.ts.map +1 -1
- package/package.json +21 -7
- package/src/components/CheckBox/checkbox.types.ts +2 -2
- package/src/components/CheckBox/index.tsx +23 -47
- package/src/components/CustomModal/index.tsx +15 -23
- package/src/components/Dropdown/Dropdown.tsx +3 -2
- package/src/components/Dropdown/DropdownListItem.tsx +1 -14
- package/src/components/Dropdown/DropdownSelectedItemsView.tsx +13 -13
- package/src/components/Input/index.tsx +13 -2
- package/src/components/{Dropdown → List}/DropdownFlatList.tsx +11 -23
- package/src/components/{Dropdown → List}/DropdownSectionList.tsx +10 -22
- package/src/hooks/index.ts +5 -0
- package/src/hooks/use-index-of-selected-item.ts +49 -0
- package/src/hooks/use-modal.ts +40 -0
- package/src/hooks/use-search.ts +95 -0
- package/src/hooks/use-select-all.ts +79 -0
- package/src/hooks/use-selection-handler.ts +81 -0
- package/src/index.tsx +277 -443
- package/src/types/index.types.ts +41 -56
- package/src/utils/index.ts +60 -3
- package/lib/commonjs/components/Dropdown/DropdownFlatList.js.map +0 -1
- package/lib/commonjs/components/Dropdown/DropdownSectionList.js.map +0 -1
- package/lib/module/components/Dropdown/DropdownFlatList.js.map +0 -1
- package/lib/module/components/Dropdown/DropdownSectionList.js.map +0 -1
- package/lib/typescript/src/components/Dropdown/DropdownFlatList.d.ts +0 -6
- package/lib/typescript/src/components/Dropdown/DropdownFlatList.d.ts.map +0 -1
- package/lib/typescript/src/components/Dropdown/DropdownSectionList.d.ts +0 -4
- package/lib/typescript/src/components/Dropdown/DropdownSectionList.d.ts.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable react-native/no-inline-styles */
|
|
2
|
+
import React, { PropsWithChildren, ReactElement } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
KeyboardAvoidingView,
|
|
4
5
|
Modal,
|
|
@@ -12,15 +13,9 @@ import {
|
|
|
12
13
|
import { colors } from '../../styles/colors';
|
|
13
14
|
import { TCustomModalControls } from 'src/types/index.types';
|
|
14
15
|
|
|
15
|
-
type ScreenWrapperProps = {
|
|
16
|
-
children: React.ReactNode;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
16
|
// In iOS, `SafeAreaView` does not automatically account on keyboard.
|
|
20
17
|
// Therefore, for iOS we need to wrap the content in `KeyboardAvoidingView`.
|
|
21
|
-
const ModalContentWrapper = ({
|
|
22
|
-
children,
|
|
23
|
-
}: ScreenWrapperProps): ReactElement => {
|
|
18
|
+
const ModalContentWrapper = ({ children }: PropsWithChildren): ReactElement => {
|
|
24
19
|
return Platform.OS === 'ios' ? (
|
|
25
20
|
<KeyboardAvoidingView style={[{ flex: 1 }]} behavior="padding">
|
|
26
21
|
{children}
|
|
@@ -32,42 +27,39 @@ const ModalContentWrapper = ({
|
|
|
32
27
|
|
|
33
28
|
const CustomModal = ({
|
|
34
29
|
visible,
|
|
35
|
-
closeModal,
|
|
36
|
-
modalBackgroundStyle, //kept for backwards compatibility
|
|
37
|
-
modalOptionsContainerStyle, //kept for backwards compatibility
|
|
38
30
|
modalControls,
|
|
39
|
-
modalProps, //kept for backwards compatibility
|
|
40
31
|
children,
|
|
41
|
-
|
|
32
|
+
onRequestClose,
|
|
33
|
+
}: {
|
|
34
|
+
modalControls?: TCustomModalControls;
|
|
35
|
+
} & ModalProps) => {
|
|
42
36
|
return (
|
|
43
37
|
<Modal
|
|
44
|
-
transparent={true}
|
|
45
38
|
visible={visible}
|
|
46
|
-
|
|
39
|
+
testID="react-native-input-select-modal"
|
|
40
|
+
transparent={true}
|
|
47
41
|
animationType="fade"
|
|
48
42
|
{...modalControls?.modalProps}
|
|
49
|
-
{...modalProps} //kept for backwards compatibility
|
|
50
43
|
>
|
|
51
44
|
{/*Used to fix the select with search box behavior in iOS*/}
|
|
52
45
|
<ModalContentWrapper>
|
|
53
46
|
<TouchableOpacity
|
|
54
|
-
onPress={
|
|
55
|
-
closeModal?.() || modalControls?.modalProps?.closeModal?.()
|
|
56
|
-
}
|
|
47
|
+
onPress={onRequestClose}
|
|
57
48
|
style={[
|
|
58
49
|
styles.modalContainer,
|
|
59
50
|
styles.modalBackgroundStyle,
|
|
60
|
-
modalControls?.modalBackgroundStyle
|
|
51
|
+
modalControls?.modalBackgroundStyle,
|
|
61
52
|
]}
|
|
53
|
+
aria-label="close modal"
|
|
62
54
|
>
|
|
63
55
|
{/* Added this `TouchableWithoutFeedback` wrapper because of the closing modal on expo web */}
|
|
64
|
-
<TouchableWithoutFeedback
|
|
56
|
+
<TouchableWithoutFeedback accessible={false}>
|
|
65
57
|
<SafeAreaView
|
|
66
58
|
style={[
|
|
67
59
|
styles.modalOptionsContainer,
|
|
68
|
-
modalControls?.modalOptionsContainerStyle
|
|
69
|
-
modalOptionsContainerStyle,
|
|
60
|
+
modalControls?.modalOptionsContainerStyle,
|
|
70
61
|
]}
|
|
62
|
+
testID="react-native-input-select-modal-body"
|
|
71
63
|
>
|
|
72
64
|
{children}
|
|
73
65
|
</SafeAreaView>
|
|
@@ -10,7 +10,7 @@ const Dropdown = ({
|
|
|
10
10
|
placeholder,
|
|
11
11
|
helperText,
|
|
12
12
|
error,
|
|
13
|
-
|
|
13
|
+
labelsOfSelectedItems,
|
|
14
14
|
openModal,
|
|
15
15
|
closeModal,
|
|
16
16
|
isMultiple,
|
|
@@ -35,6 +35,7 @@ const Dropdown = ({
|
|
|
35
35
|
<View
|
|
36
36
|
style={[styles.dropdownInputContainer, dropdownContainerStyle]}
|
|
37
37
|
accessibilityRole="combobox"
|
|
38
|
+
pointerEvents="box-none"
|
|
38
39
|
testID={testID}
|
|
39
40
|
>
|
|
40
41
|
{label && label !== '' && (
|
|
@@ -44,7 +45,7 @@ const Dropdown = ({
|
|
|
44
45
|
<DropdownSelectedItemsView
|
|
45
46
|
placeholder={placeholder}
|
|
46
47
|
error={error}
|
|
47
|
-
|
|
48
|
+
labelsOfSelectedItems={labelsOfSelectedItems}
|
|
48
49
|
openModal={openModal}
|
|
49
50
|
closeModal={closeModal}
|
|
50
51
|
isMultiple={isMultiple}
|
|
@@ -10,19 +10,12 @@ const DropdownListItem = ({
|
|
|
10
10
|
selectedOption,
|
|
11
11
|
onChange,
|
|
12
12
|
primaryColor,
|
|
13
|
-
checkboxSize,
|
|
14
|
-
checkboxStyle,
|
|
15
|
-
checkboxLabelStyle,
|
|
16
|
-
checkboxComponentStyles,
|
|
17
|
-
checkboxComponent,
|
|
18
13
|
checkboxControls,
|
|
19
14
|
}: any) => {
|
|
20
15
|
return (
|
|
21
16
|
<TouchableOpacity
|
|
22
17
|
style={styles.listItemContainerStyle}
|
|
23
|
-
onPress={
|
|
24
|
-
item.disabled ? () => {} : () => onChange(item[optionValue]) // intentionally didn't use the disable property
|
|
25
|
-
}
|
|
18
|
+
onPress={item.disabled ? () => {} : () => onChange(item[optionValue])}
|
|
26
19
|
>
|
|
27
20
|
<CheckBox
|
|
28
21
|
value={
|
|
@@ -34,13 +27,7 @@ const DropdownListItem = ({
|
|
|
34
27
|
onChange={() => onChange(item[optionValue])}
|
|
35
28
|
primaryColor={primaryColor}
|
|
36
29
|
checkboxControls={checkboxControls}
|
|
37
|
-
checkboxSize={checkboxComponentStyles?.checkboxSize || checkboxSize}
|
|
38
|
-
checkboxStyle={checkboxComponentStyles?.checkboxStyle || checkboxStyle}
|
|
39
|
-
checkboxLabelStyle={
|
|
40
|
-
checkboxComponentStyles?.checkboxLabelStyle || checkboxLabelStyle
|
|
41
|
-
}
|
|
42
30
|
disabled={item.disabled}
|
|
43
|
-
checkboxComponent={checkboxComponent}
|
|
44
31
|
/>
|
|
45
32
|
</TouchableOpacity>
|
|
46
33
|
);
|
|
@@ -14,7 +14,7 @@ import { inputStyles } from '../../styles/input';
|
|
|
14
14
|
const DropdownSelectedItemsView = ({
|
|
15
15
|
placeholder,
|
|
16
16
|
error,
|
|
17
|
-
|
|
17
|
+
labelsOfSelectedItems,
|
|
18
18
|
openModal,
|
|
19
19
|
isMultiple,
|
|
20
20
|
selectedItem,
|
|
@@ -30,6 +30,10 @@ const DropdownSelectedItemsView = ({
|
|
|
30
30
|
disabled,
|
|
31
31
|
setIndexOfSelectedItem,
|
|
32
32
|
}: any) => {
|
|
33
|
+
const openActions = (label: string) => {
|
|
34
|
+
openModal();
|
|
35
|
+
setIndexOfSelectedItem(label); // immediately scrolls to list item with the specified label when modal
|
|
36
|
+
};
|
|
33
37
|
return (
|
|
34
38
|
<Pressable
|
|
35
39
|
onPress={() => openModal()}
|
|
@@ -47,6 +51,8 @@ const DropdownSelectedItemsView = ({
|
|
|
47
51
|
},
|
|
48
52
|
]}
|
|
49
53
|
disabled={disabled}
|
|
54
|
+
aria-disabled={disabled}
|
|
55
|
+
testID="react-native-input-select-dropdown-input-container"
|
|
50
56
|
>
|
|
51
57
|
<ScrollView
|
|
52
58
|
horizontal
|
|
@@ -58,13 +64,10 @@ const DropdownSelectedItemsView = ({
|
|
|
58
64
|
onStartShouldSetResponder={() => true}
|
|
59
65
|
>
|
|
60
66
|
{isMultiple ? (
|
|
61
|
-
|
|
67
|
+
labelsOfSelectedItems?.map((label: string, i: Number) => (
|
|
62
68
|
<DropdownContent
|
|
63
|
-
onPress={() =>
|
|
64
|
-
|
|
65
|
-
setIndexOfSelectedItem(label); // immediately scrolls to list item with the specified label when modal
|
|
66
|
-
}}
|
|
67
|
-
key={`react-native-input-select-${Math.random()}-${i}`}
|
|
69
|
+
onPress={() => openActions(label)}
|
|
70
|
+
key={`react-native-input-select-list-item-${Math.random()}-${i}`}
|
|
68
71
|
style={[
|
|
69
72
|
styles.selectedItems,
|
|
70
73
|
{ backgroundColor: primaryColor },
|
|
@@ -76,16 +79,13 @@ const DropdownSelectedItemsView = ({
|
|
|
76
79
|
))
|
|
77
80
|
) : (
|
|
78
81
|
<DropdownContent
|
|
79
|
-
onPress={() =>
|
|
80
|
-
openModal();
|
|
81
|
-
setIndexOfSelectedItem(getSelectedItemsLabel()); // immediately scrolls to list item with the specified label when modal
|
|
82
|
-
}}
|
|
82
|
+
onPress={() => openActions(labelsOfSelectedItems)}
|
|
83
83
|
style={[styles.blackText, selectedItemStyle]}
|
|
84
|
-
label={
|
|
84
|
+
label={labelsOfSelectedItems}
|
|
85
85
|
disabled={disabled}
|
|
86
86
|
/>
|
|
87
87
|
)}
|
|
88
|
-
{
|
|
88
|
+
{selectedItem === '' && selectedItems?.length === 0 && (
|
|
89
89
|
<DropdownContent
|
|
90
90
|
onPress={() => openModal()}
|
|
91
91
|
style={[styles.blackText, placeholderStyle]}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
TextInput,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
View,
|
|
6
|
+
Platform,
|
|
7
|
+
TextInputProps,
|
|
8
|
+
ViewStyle,
|
|
9
|
+
ColorValue,
|
|
10
|
+
} from 'react-native';
|
|
3
11
|
import { inputStyles } from '../../styles/input';
|
|
4
12
|
|
|
5
13
|
export const Input = ({
|
|
@@ -10,7 +18,10 @@ export const Input = ({
|
|
|
10
18
|
primaryColor,
|
|
11
19
|
textInputContainerStyle,
|
|
12
20
|
...rest
|
|
13
|
-
}:
|
|
21
|
+
}: {
|
|
22
|
+
primaryColor?: ColorValue;
|
|
23
|
+
textInputContainerStyle?: ViewStyle;
|
|
24
|
+
} & TextInputProps) => {
|
|
14
25
|
const [isFocused, setFocus] = useState(false);
|
|
15
26
|
|
|
16
27
|
return (
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* eslint-disable react-native/no-inline-styles */
|
|
2
2
|
import React, { useEffect, useRef } from 'react';
|
|
3
3
|
import { FlatList, FlatListProps, StyleSheet } from 'react-native';
|
|
4
|
-
import DropdownListItem from '
|
|
4
|
+
import DropdownListItem from '../Dropdown/DropdownListItem';
|
|
5
5
|
import { ItemSeparatorComponent, ListEmptyComponent } from '../Others';
|
|
6
|
-
import { TFlatList } from '
|
|
6
|
+
import { TFlatList } from '../../types/index.types';
|
|
7
7
|
|
|
8
8
|
const DropdownFlatList = ({
|
|
9
9
|
options,
|
|
@@ -16,11 +16,6 @@ const DropdownFlatList = ({
|
|
|
16
16
|
handleMultipleSelections,
|
|
17
17
|
handleSingleSelection,
|
|
18
18
|
primaryColor,
|
|
19
|
-
checkboxSize, // kept for backwards compatibility to be removed in future release
|
|
20
|
-
checkboxStyle, // kept for backwards compatibility to be removed in future release
|
|
21
|
-
checkboxLabelStyle, // kept for backwards compatibility to be removed in future release
|
|
22
|
-
checkboxComponentStyles,
|
|
23
|
-
checkboxComponent,
|
|
24
19
|
checkboxControls,
|
|
25
20
|
listComponentStyles,
|
|
26
21
|
listIndex,
|
|
@@ -31,7 +26,7 @@ const DropdownFlatList = ({
|
|
|
31
26
|
const flatlistRef = useRef<FlatList<TFlatList>>(null);
|
|
32
27
|
|
|
33
28
|
const scrollToItem = (index: number) => {
|
|
34
|
-
flatlistRef
|
|
29
|
+
flatlistRef?.current?.scrollToIndex({
|
|
35
30
|
index,
|
|
36
31
|
animated: true,
|
|
37
32
|
});
|
|
@@ -43,8 +38,15 @@ const DropdownFlatList = ({
|
|
|
43
38
|
}
|
|
44
39
|
}, [listIndex]);
|
|
45
40
|
|
|
41
|
+
const itemSeparator = () => (
|
|
42
|
+
<ItemSeparatorComponent
|
|
43
|
+
itemSeparatorStyle={listComponentStyles?.itemSeparatorStyle}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
|
|
46
47
|
return (
|
|
47
48
|
<FlatList
|
|
49
|
+
testID="react-native-input-select-flat-list"
|
|
48
50
|
data={options}
|
|
49
51
|
extraData={isMultiple ? selectedItems : selectedItem}
|
|
50
52
|
initialNumToRender={5}
|
|
@@ -61,11 +63,7 @@ const DropdownFlatList = ({
|
|
|
61
63
|
contentContainerStyle={[
|
|
62
64
|
isSearchable ? { paddingTop: 0 } : styles.contentContainerStyle,
|
|
63
65
|
]}
|
|
64
|
-
ItemSeparatorComponent={
|
|
65
|
-
<ItemSeparatorComponent
|
|
66
|
-
itemSeparatorStyle={listComponentStyles?.itemSeparatorStyle}
|
|
67
|
-
/>
|
|
68
|
-
)}
|
|
66
|
+
ItemSeparatorComponent={itemSeparator}
|
|
69
67
|
renderItem={(item) =>
|
|
70
68
|
_renderItem(item, {
|
|
71
69
|
optionLabel,
|
|
@@ -77,11 +75,6 @@ const DropdownFlatList = ({
|
|
|
77
75
|
: handleSingleSelection,
|
|
78
76
|
scrollToItem,
|
|
79
77
|
primaryColor,
|
|
80
|
-
checkboxSize, // kept for backwards compatibility
|
|
81
|
-
checkboxStyle, // kept for backwards compatibility
|
|
82
|
-
checkboxLabelStyle, // kept for backwards compatibility
|
|
83
|
-
checkboxComponentStyles, // kept for backwards compatibility
|
|
84
|
-
checkboxComponent, // kept for backwards compatibility
|
|
85
78
|
checkboxControls,
|
|
86
79
|
})
|
|
87
80
|
}
|
|
@@ -107,12 +100,7 @@ const _renderItem = ({ item }: any, props: any) => {
|
|
|
107
100
|
selectedOption={props.selectedOption}
|
|
108
101
|
onChange={props.onChange}
|
|
109
102
|
primaryColor={props.primaryColor}
|
|
110
|
-
checkboxSize={props.checkboxSize}
|
|
111
|
-
checkboxStyle={props.checkboxStyle}
|
|
112
|
-
checkboxLabelStyle={props.checkboxLabelStyle}
|
|
113
103
|
scrollToItem={props.scrollToItem}
|
|
114
|
-
checkboxComponentStyles={props.checkboxComponentStyles}
|
|
115
|
-
checkboxComponent={props.checkboxComponent}
|
|
116
104
|
checkboxControls={props.checkboxControls}
|
|
117
105
|
/>
|
|
118
106
|
);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/* eslint-disable react-native/no-inline-styles */
|
|
2
2
|
import React, { useEffect, useState, useRef } from 'react';
|
|
3
3
|
import { SectionList, StyleSheet } from 'react-native';
|
|
4
|
-
import DropdownListItem from '
|
|
4
|
+
import DropdownListItem from '../Dropdown/DropdownListItem';
|
|
5
5
|
import {
|
|
6
6
|
ItemSeparatorComponent,
|
|
7
7
|
ListEmptyComponent,
|
|
8
8
|
SectionHeaderTitle,
|
|
9
9
|
} from '../Others';
|
|
10
10
|
import { extractPropertyFromArray } from '../../utils';
|
|
11
|
-
import { TSectionList } from '
|
|
11
|
+
import { TSectionList } from '../../types/index.types';
|
|
12
12
|
|
|
13
13
|
const DropdownSectionList = ({
|
|
14
14
|
options,
|
|
@@ -21,11 +21,6 @@ const DropdownSectionList = ({
|
|
|
21
21
|
handleMultipleSelections,
|
|
22
22
|
handleSingleSelection,
|
|
23
23
|
primaryColor,
|
|
24
|
-
checkboxSize,
|
|
25
|
-
checkboxStyle,
|
|
26
|
-
checkboxLabelStyle,
|
|
27
|
-
checkboxComponentStyles,
|
|
28
|
-
checkboxComponent,
|
|
29
24
|
checkboxControls,
|
|
30
25
|
listComponentStyles,
|
|
31
26
|
listIndex,
|
|
@@ -79,8 +74,15 @@ const DropdownSectionList = ({
|
|
|
79
74
|
}
|
|
80
75
|
}, [listIndex]);
|
|
81
76
|
|
|
77
|
+
const itemSeparator = () => (
|
|
78
|
+
<ItemSeparatorComponent
|
|
79
|
+
itemSeparatorStyle={listComponentStyles?.itemSeparatorStyle}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
|
|
82
83
|
return (
|
|
83
84
|
<SectionList
|
|
85
|
+
testID="react-native-input-select-section-list"
|
|
84
86
|
sections={options}
|
|
85
87
|
extraData={isMultiple ? selectedItems : selectedItem}
|
|
86
88
|
initialNumToRender={5}
|
|
@@ -97,11 +99,7 @@ const DropdownSectionList = ({
|
|
|
97
99
|
contentContainerStyle={[
|
|
98
100
|
isSearchable ? { paddingTop: 0 } : styles.contentContainerStyle,
|
|
99
101
|
]}
|
|
100
|
-
ItemSeparatorComponent={
|
|
101
|
-
<ItemSeparatorComponent
|
|
102
|
-
itemSeparatorStyle={listComponentStyles?.itemSeparatorStyle}
|
|
103
|
-
/>
|
|
104
|
-
)}
|
|
102
|
+
ItemSeparatorComponent={itemSeparator}
|
|
105
103
|
renderItem={(item) =>
|
|
106
104
|
_renderItem(item, {
|
|
107
105
|
optionLabel,
|
|
@@ -112,11 +110,6 @@ const DropdownSectionList = ({
|
|
|
112
110
|
? handleMultipleSelections
|
|
113
111
|
: handleSingleSelection,
|
|
114
112
|
primaryColor,
|
|
115
|
-
checkboxSize, // kept for backwards compatibility
|
|
116
|
-
checkboxStyle, // kept for backwards compatibility
|
|
117
|
-
checkboxLabelStyle, // kept for backwards compatibility
|
|
118
|
-
checkboxComponentStyles, // kept for backwards compatibility
|
|
119
|
-
checkboxComponent, // kept for backwards compatibility
|
|
120
113
|
checkboxControls,
|
|
121
114
|
expandedSections,
|
|
122
115
|
})
|
|
@@ -157,11 +150,6 @@ const _renderItem = ({ section: { title }, item }: any, props: any) => {
|
|
|
157
150
|
selectedOption={props.selectedOption}
|
|
158
151
|
onChange={props.onChange}
|
|
159
152
|
primaryColor={props.primaryColor}
|
|
160
|
-
checkboxSize={props.checkboxSize}
|
|
161
|
-
checkboxStyle={props.checkboxStyle}
|
|
162
|
-
checkboxLabelStyle={props.checkboxLabelStyle}
|
|
163
|
-
checkboxComponentStyles={props.checkboxComponentStyles}
|
|
164
|
-
checkboxComponent={props.checkboxComponent}
|
|
165
153
|
checkboxControls={props.checkboxControls}
|
|
166
154
|
/>
|
|
167
155
|
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import type { TFlatListItem, TSectionListItem } from '../types/index.types';
|
|
3
|
+
|
|
4
|
+
interface UseIndexOfSelectedItemProps {
|
|
5
|
+
options: (TFlatListItem | TSectionListItem)[];
|
|
6
|
+
optionLabel: string;
|
|
7
|
+
isSectionList: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @description for scrollToIndex in Sectionlist and Flatlist
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const useIndexOfSelectedItem = ({
|
|
16
|
+
options,
|
|
17
|
+
optionLabel,
|
|
18
|
+
isSectionList,
|
|
19
|
+
}: UseIndexOfSelectedItemProps) => {
|
|
20
|
+
const [listIndex, setListIndex] = useState<{
|
|
21
|
+
sectionIndex?: number;
|
|
22
|
+
itemIndex: number;
|
|
23
|
+
}>({ itemIndex: -1, sectionIndex: -1 });
|
|
24
|
+
|
|
25
|
+
const setIndexOfSelectedItem = useCallback(
|
|
26
|
+
(selectedLabel: string) => {
|
|
27
|
+
if (isSectionList) {
|
|
28
|
+
(options as TSectionListItem[]).forEach((section, sectionIndex) => {
|
|
29
|
+
const itemIndex = section.data.findIndex(
|
|
30
|
+
(item) => item[optionLabel] === selectedLabel
|
|
31
|
+
);
|
|
32
|
+
if (itemIndex !== -1) {
|
|
33
|
+
setListIndex({ sectionIndex, itemIndex });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
const itemIndex = (options as TFlatListItem[]).findIndex(
|
|
38
|
+
(item) => item[optionLabel] === selectedLabel
|
|
39
|
+
);
|
|
40
|
+
if (itemIndex !== -1) {
|
|
41
|
+
setListIndex({ itemIndex });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
[options, optionLabel, isSectionList]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return { listIndex, setListIndex, setIndexOfSelectedItem };
|
|
49
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { TCustomModalControls } from '../types/index.types';
|
|
4
|
+
|
|
5
|
+
interface UseModalProps {
|
|
6
|
+
resetOptionsRelatedState: () => void;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
modalControls?: TCustomModalControls;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const useModal = ({
|
|
12
|
+
resetOptionsRelatedState,
|
|
13
|
+
disabled,
|
|
14
|
+
modalControls,
|
|
15
|
+
}: UseModalProps) => {
|
|
16
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
17
|
+
|
|
18
|
+
const openModal = () => {
|
|
19
|
+
if (disabled) return;
|
|
20
|
+
setIsVisible(true);
|
|
21
|
+
resetOptionsRelatedState();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const closeModal = () => {
|
|
25
|
+
setIsVisible(false);
|
|
26
|
+
resetOptionsRelatedState();
|
|
27
|
+
|
|
28
|
+
// iOS supports the onDismiss prop but android does not, so we do this explicitly here
|
|
29
|
+
// https://reactnative.dev/docs/modal#ondismiss-ios
|
|
30
|
+
if (Platform.OS === 'android') {
|
|
31
|
+
modalControls?.modalProps?.onDismiss?.();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
isVisible,
|
|
37
|
+
openModal: () => openModal(),
|
|
38
|
+
closeModal: () => closeModal(),
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
TFlatList,
|
|
4
|
+
TSectionList,
|
|
5
|
+
TFlatListItem,
|
|
6
|
+
TSectionListItem,
|
|
7
|
+
} from '../types/index.types';
|
|
8
|
+
import { escapeRegExp, isSectionList } from '../utils';
|
|
9
|
+
|
|
10
|
+
interface UseSearchProps {
|
|
11
|
+
initialOptions: TFlatList | TSectionList;
|
|
12
|
+
optionLabel: string;
|
|
13
|
+
optionValue: string;
|
|
14
|
+
searchCallback: (value: string) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useSearch = ({
|
|
18
|
+
initialOptions,
|
|
19
|
+
optionLabel,
|
|
20
|
+
optionValue,
|
|
21
|
+
searchCallback,
|
|
22
|
+
}: UseSearchProps) => {
|
|
23
|
+
const [searchValue, setSearchValue] = useState<string>('');
|
|
24
|
+
const [filteredOptions, setFilteredOptions] = useState<
|
|
25
|
+
TFlatList | TSectionList
|
|
26
|
+
>(initialOptions);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setFilteredOptions(initialOptions);
|
|
30
|
+
return () => {};
|
|
31
|
+
}, [initialOptions]);
|
|
32
|
+
|
|
33
|
+
const searchFlatList = useCallback(
|
|
34
|
+
(flatList: TFlatList, regexFilter: RegExp) => {
|
|
35
|
+
return flatList.filter((item: TFlatListItem) => {
|
|
36
|
+
return (
|
|
37
|
+
item[optionLabel]?.toString().toLowerCase().search(regexFilter) !==
|
|
38
|
+
-1 ||
|
|
39
|
+
item[optionValue]?.toString().toLowerCase().search(regexFilter) !== -1
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
[optionLabel, optionValue]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const searchSectionList = useCallback(
|
|
47
|
+
(sectionList: TSectionList, regexFilter: RegExp) => {
|
|
48
|
+
return sectionList.map((listItem: TSectionListItem) => {
|
|
49
|
+
// A section list is the combination of several flat lists
|
|
50
|
+
const filteredData = searchFlatList(listItem.data, regexFilter);
|
|
51
|
+
|
|
52
|
+
return { ...listItem, data: filteredData };
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
[searchFlatList]
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const isSection = isSectionList(initialOptions);
|
|
59
|
+
|
|
60
|
+
const onSearch = useCallback(
|
|
61
|
+
(value: string) => {
|
|
62
|
+
searchCallback?.(value);
|
|
63
|
+
|
|
64
|
+
const searchText = escapeRegExp(value).toLowerCase().trim();
|
|
65
|
+
const regexFilter = new RegExp(searchText, 'i');
|
|
66
|
+
|
|
67
|
+
const searchResults = isSection
|
|
68
|
+
? searchSectionList(initialOptions as TSectionList, regexFilter)
|
|
69
|
+
: searchFlatList(initialOptions as TFlatList, regexFilter);
|
|
70
|
+
|
|
71
|
+
setFilteredOptions(searchResults);
|
|
72
|
+
},
|
|
73
|
+
[
|
|
74
|
+
initialOptions,
|
|
75
|
+
isSection,
|
|
76
|
+
searchCallback,
|
|
77
|
+
searchFlatList,
|
|
78
|
+
searchSectionList,
|
|
79
|
+
]
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (searchValue) {
|
|
84
|
+
onSearch(searchValue);
|
|
85
|
+
}
|
|
86
|
+
}, [onSearch, searchValue]);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
searchValue,
|
|
90
|
+
setSearchValue,
|
|
91
|
+
filteredOptions,
|
|
92
|
+
setFilteredOptions,
|
|
93
|
+
isSectionList: isSection,
|
|
94
|
+
};
|
|
95
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { TFlatListItem, TSelectedItem } from '../types/index.types';
|
|
3
|
+
import { removeDisabledItems } from '../utils';
|
|
4
|
+
|
|
5
|
+
interface UseCheckSelectAllProps {
|
|
6
|
+
options: TFlatListItem[];
|
|
7
|
+
selectedItems: TSelectedItem[];
|
|
8
|
+
isMultiple: boolean;
|
|
9
|
+
onValueChange: (selectedValues: TSelectedItem[]) => void;
|
|
10
|
+
listControls?: {
|
|
11
|
+
selectAllCallback?: () => void;
|
|
12
|
+
unselectAllCallback?: () => void;
|
|
13
|
+
};
|
|
14
|
+
optionValue: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useSelectAll = ({
|
|
18
|
+
options,
|
|
19
|
+
selectedItems,
|
|
20
|
+
isMultiple,
|
|
21
|
+
onValueChange,
|
|
22
|
+
listControls,
|
|
23
|
+
optionValue,
|
|
24
|
+
}: UseCheckSelectAllProps) => {
|
|
25
|
+
const [selectAll, setSelectAll] = useState<boolean>(false);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @description Handle "Select All" logic
|
|
29
|
+
*/
|
|
30
|
+
const handleSelectAll = useCallback(() => {
|
|
31
|
+
setSelectAll((prevVal) => {
|
|
32
|
+
let selectedValues: TSelectedItem[] = [];
|
|
33
|
+
|
|
34
|
+
// Remove disabled items from selection
|
|
35
|
+
const filteredOptions = removeDisabledItems(options);
|
|
36
|
+
|
|
37
|
+
// if everything has not been selected, select all the values in the list
|
|
38
|
+
if (!prevVal) {
|
|
39
|
+
selectedValues = filteredOptions.map(
|
|
40
|
+
(obj) => obj[optionValue]
|
|
41
|
+
) as TSelectedItem[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onValueChange(selectedValues); // Send selected values to parent
|
|
45
|
+
return !prevVal;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (typeof listControls?.selectAllCallback === 'function' && !selectAll) {
|
|
49
|
+
listControls.selectAllCallback();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (typeof listControls?.unselectAllCallback === 'function' && selectAll) {
|
|
53
|
+
listControls.unselectAllCallback();
|
|
54
|
+
}
|
|
55
|
+
}, [options, optionValue, listControls, selectAll, onValueChange]);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if all items are selected
|
|
59
|
+
*/
|
|
60
|
+
const checkSelectAll = useCallback(() => {
|
|
61
|
+
if (removeDisabledItems(options)?.length === selectedItems?.length) {
|
|
62
|
+
setSelectAll(true);
|
|
63
|
+
} else {
|
|
64
|
+
setSelectAll(false);
|
|
65
|
+
}
|
|
66
|
+
}, [options, selectedItems]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* if the user decides to select the options one by one, this hook
|
|
70
|
+
* runs to check if everything has been selected so that the `selectAll checkbox` can be selected
|
|
71
|
+
*/
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (isMultiple) {
|
|
74
|
+
checkSelectAll();
|
|
75
|
+
}
|
|
76
|
+
}, [checkSelectAll, isMultiple, selectedItems]);
|
|
77
|
+
|
|
78
|
+
return { selectAll, handleSelectAll };
|
|
79
|
+
};
|