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.
Files changed (125) hide show
  1. package/README.md +40 -95
  2. package/lib/commonjs/components/CheckBox/index.js +19 -13
  3. package/lib/commonjs/components/CheckBox/index.js.map +1 -1
  4. package/lib/commonjs/components/CustomModal/index.js +12 -16
  5. package/lib/commonjs/components/CustomModal/index.js.map +1 -1
  6. package/lib/commonjs/components/Dropdown/Dropdown.js +3 -2
  7. package/lib/commonjs/components/Dropdown/Dropdown.js.map +1 -1
  8. package/lib/commonjs/components/Dropdown/DropdownListItem.js +2 -11
  9. package/lib/commonjs/components/Dropdown/DropdownListItem.js.map +1 -1
  10. package/lib/commonjs/components/Dropdown/DropdownSelectedItemsView.js +14 -14
  11. package/lib/commonjs/components/Dropdown/DropdownSelectedItemsView.js.map +1 -1
  12. package/lib/commonjs/components/Input/index.js.map +1 -1
  13. package/lib/commonjs/components/{Dropdown → List}/DropdownFlatList.js +7 -28
  14. package/lib/commonjs/components/List/DropdownFlatList.js.map +1 -0
  15. package/lib/commonjs/components/{Dropdown → List}/DropdownSectionList.js +6 -24
  16. package/lib/commonjs/components/List/DropdownSectionList.js.map +1 -0
  17. package/lib/commonjs/hooks/index.js +61 -0
  18. package/lib/commonjs/hooks/index.js.map +1 -0
  19. package/lib/commonjs/hooks/use-index-of-selected-item.js +49 -0
  20. package/lib/commonjs/hooks/use-index-of-selected-item.js.map +1 -0
  21. package/lib/commonjs/hooks/use-modal.js +37 -0
  22. package/lib/commonjs/hooks/use-modal.js.map +1 -0
  23. package/lib/commonjs/hooks/use-search.js +58 -0
  24. package/lib/commonjs/hooks/use-search.js.map +1 -0
  25. package/lib/commonjs/hooks/use-select-all.js +70 -0
  26. package/lib/commonjs/hooks/use-select-all.js.map +1 -0
  27. package/lib/commonjs/hooks/use-selection-handler.js +62 -0
  28. package/lib/commonjs/hooks/use-selection-handler.js.map +1 -0
  29. package/lib/commonjs/index.js +120 -260
  30. package/lib/commonjs/index.js.map +1 -1
  31. package/lib/commonjs/utils/index.js +40 -5
  32. package/lib/commonjs/utils/index.js.map +1 -1
  33. package/lib/module/components/CheckBox/index.js +19 -13
  34. package/lib/module/components/CheckBox/index.js.map +1 -1
  35. package/lib/module/components/CustomModal/index.js +12 -15
  36. package/lib/module/components/CustomModal/index.js.map +1 -1
  37. package/lib/module/components/Dropdown/Dropdown.js +3 -2
  38. package/lib/module/components/Dropdown/Dropdown.js.map +1 -1
  39. package/lib/module/components/Dropdown/DropdownListItem.js +2 -11
  40. package/lib/module/components/Dropdown/DropdownListItem.js.map +1 -1
  41. package/lib/module/components/Dropdown/DropdownSelectedItemsView.js +14 -14
  42. package/lib/module/components/Dropdown/DropdownSelectedItemsView.js.map +1 -1
  43. package/lib/module/components/Input/index.js.map +1 -1
  44. package/lib/module/components/{Dropdown → List}/DropdownFlatList.js +7 -28
  45. package/lib/module/components/List/DropdownFlatList.js.map +1 -0
  46. package/lib/module/components/{Dropdown → List}/DropdownSectionList.js +6 -24
  47. package/lib/module/components/List/DropdownSectionList.js.map +1 -0
  48. package/lib/module/hooks/index.js +6 -0
  49. package/lib/module/hooks/index.js.map +1 -0
  50. package/lib/module/hooks/use-index-of-selected-item.js +42 -0
  51. package/lib/module/hooks/use-index-of-selected-item.js.map +1 -0
  52. package/lib/module/hooks/use-modal.js +30 -0
  53. package/lib/module/hooks/use-modal.js.map +1 -0
  54. package/lib/module/hooks/use-search.js +51 -0
  55. package/lib/module/hooks/use-search.js.map +1 -0
  56. package/lib/module/hooks/use-select-all.js +63 -0
  57. package/lib/module/hooks/use-select-all.js.map +1 -0
  58. package/lib/module/hooks/use-selection-handler.js +55 -0
  59. package/lib/module/hooks/use-selection-handler.js.map +1 -0
  60. package/lib/module/index.js +123 -262
  61. package/lib/module/index.js.map +1 -1
  62. package/lib/module/utils/index.js +36 -4
  63. package/lib/module/utils/index.js.map +1 -1
  64. package/lib/typescript/src/components/CheckBox/checkbox.types.d.ts +4 -2
  65. package/lib/typescript/src/components/CheckBox/checkbox.types.d.ts.map +1 -1
  66. package/lib/typescript/src/components/CheckBox/index.d.ts +2 -2
  67. package/lib/typescript/src/components/CheckBox/index.d.ts.map +1 -1
  68. package/lib/typescript/src/components/CustomModal/index.d.ts +3 -1
  69. package/lib/typescript/src/components/CustomModal/index.d.ts.map +1 -1
  70. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts +1 -1
  71. package/lib/typescript/src/components/Dropdown/Dropdown.d.ts.map +1 -1
  72. package/lib/typescript/src/components/Dropdown/DropdownListItem.d.ts +1 -1
  73. package/lib/typescript/src/components/Dropdown/DropdownListItem.d.ts.map +1 -1
  74. package/lib/typescript/src/components/Dropdown/DropdownSelectedItemsView.d.ts +1 -1
  75. package/lib/typescript/src/components/Input/index.d.ts +5 -1
  76. package/lib/typescript/src/components/Input/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/List/DropdownFlatList.d.ts +6 -0
  78. package/lib/typescript/src/components/List/DropdownFlatList.d.ts.map +1 -0
  79. package/lib/typescript/src/components/List/DropdownSectionList.d.ts +4 -0
  80. package/lib/typescript/src/components/List/DropdownSectionList.d.ts.map +1 -0
  81. package/lib/typescript/src/hooks/index.d.ts +6 -0
  82. package/lib/typescript/src/hooks/index.d.ts.map +1 -0
  83. package/lib/typescript/src/hooks/use-index-of-selected-item.d.ts +23 -0
  84. package/lib/typescript/src/hooks/use-index-of-selected-item.d.ts.map +1 -0
  85. package/lib/typescript/src/hooks/use-modal.d.ts +13 -0
  86. package/lib/typescript/src/hooks/use-modal.d.ts.map +1 -0
  87. package/lib/typescript/src/hooks/use-search.d.ts +16 -0
  88. package/lib/typescript/src/hooks/use-search.d.ts.map +1 -0
  89. package/lib/typescript/src/hooks/use-select-all.d.ts +18 -0
  90. package/lib/typescript/src/hooks/use-select-all.d.ts.map +1 -0
  91. package/lib/typescript/src/hooks/use-selection-handler.d.ts +19 -0
  92. package/lib/typescript/src/hooks/use-selection-handler.d.ts.map +1 -0
  93. package/lib/typescript/src/index.d.ts +19 -2
  94. package/lib/typescript/src/index.d.ts.map +1 -1
  95. package/lib/typescript/src/types/index.types.d.ts +33 -53
  96. package/lib/typescript/src/types/index.types.d.ts.map +1 -1
  97. package/lib/typescript/src/utils/index.d.ts +17 -3
  98. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  99. package/package.json +21 -7
  100. package/src/components/CheckBox/checkbox.types.ts +2 -2
  101. package/src/components/CheckBox/index.tsx +23 -47
  102. package/src/components/CustomModal/index.tsx +15 -23
  103. package/src/components/Dropdown/Dropdown.tsx +3 -2
  104. package/src/components/Dropdown/DropdownListItem.tsx +1 -14
  105. package/src/components/Dropdown/DropdownSelectedItemsView.tsx +13 -13
  106. package/src/components/Input/index.tsx +13 -2
  107. package/src/components/{Dropdown → List}/DropdownFlatList.tsx +11 -23
  108. package/src/components/{Dropdown → List}/DropdownSectionList.tsx +10 -22
  109. package/src/hooks/index.ts +5 -0
  110. package/src/hooks/use-index-of-selected-item.ts +49 -0
  111. package/src/hooks/use-modal.ts +40 -0
  112. package/src/hooks/use-search.ts +95 -0
  113. package/src/hooks/use-select-all.ts +79 -0
  114. package/src/hooks/use-selection-handler.ts +81 -0
  115. package/src/index.tsx +277 -443
  116. package/src/types/index.types.ts +41 -56
  117. package/src/utils/index.ts +60 -3
  118. package/lib/commonjs/components/Dropdown/DropdownFlatList.js.map +0 -1
  119. package/lib/commonjs/components/Dropdown/DropdownSectionList.js.map +0 -1
  120. package/lib/module/components/Dropdown/DropdownFlatList.js.map +0 -1
  121. package/lib/module/components/Dropdown/DropdownSectionList.js.map +0 -1
  122. package/lib/typescript/src/components/Dropdown/DropdownFlatList.d.ts +0 -6
  123. package/lib/typescript/src/components/Dropdown/DropdownFlatList.d.ts.map +0 -1
  124. package/lib/typescript/src/components/Dropdown/DropdownSectionList.d.ts +0 -4
  125. package/lib/typescript/src/components/Dropdown/DropdownSectionList.d.ts.map +0 -1
@@ -1,4 +1,5 @@
1
- import React, { ReactElement } from 'react';
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
- }: TCustomModalControls & ModalProps) => {
32
+ onRequestClose,
33
+ }: {
34
+ modalControls?: TCustomModalControls;
35
+ } & ModalProps) => {
42
36
  return (
43
37
  <Modal
44
- transparent={true}
45
38
  visible={visible}
46
- onRequestClose={() => closeModal?.()}
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 || 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 onPress={() => {}}>
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
- getSelectedItemsLabel,
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
- getSelectedItemsLabel={getSelectedItemsLabel}
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
- getSelectedItemsLabel,
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
- getSelectedItemsLabel()?.map((label: string, i: Number) => (
67
+ labelsOfSelectedItems?.map((label: string, i: Number) => (
62
68
  <DropdownContent
63
- onPress={() => {
64
- openModal();
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={getSelectedItemsLabel()}
84
+ label={labelsOfSelectedItems}
85
85
  disabled={disabled}
86
86
  />
87
87
  )}
88
- {!selectedItem && selectedItems?.length === 0 && (
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 { TextInput, StyleSheet, View, Platform } from 'react-native';
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
- }: any) => {
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 './DropdownListItem';
4
+ import DropdownListItem from '../Dropdown/DropdownListItem';
5
5
  import { ItemSeparatorComponent, ListEmptyComponent } from '../Others';
6
- import { TFlatList } from 'src/types/index.types';
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.current?.scrollToIndex({
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 './DropdownListItem';
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 'src/types/index.types';
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,5 @@
1
+ export * from './use-search';
2
+ export * from './use-selection-handler';
3
+ export * from './use-index-of-selected-item';
4
+ export * from './use-modal';
5
+ export * from './use-select-all';
@@ -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
+ };