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
package/src/index.tsx CHANGED
@@ -1,468 +1,302 @@
1
- import React, { useState, useEffect, useCallback, useRef } from 'react';
2
- import { TouchableOpacity, StyleSheet, View, Platform } from 'react-native';
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useEffect,
5
+ useImperativeHandle,
6
+ } from 'react';
7
+ import { TouchableOpacity, StyleSheet, View } from 'react-native';
3
8
  import Input from './components/Input';
4
9
  import CheckBox from './components/CheckBox';
5
10
  import Dropdown from './components/Dropdown/Dropdown';
6
- import DropdownFlatList from './components/Dropdown/DropdownFlatList';
7
- import DropdownSectionList from './components/Dropdown/DropdownSectionList';
11
+ import DropdownFlatList from './components/List/DropdownFlatList';
12
+ import DropdownSectionList from './components/List/DropdownSectionList';
8
13
  import CustomModal from './components/CustomModal';
9
14
  import { colors } from './styles/colors';
10
15
  import { DEFAULT_OPTION_LABEL, DEFAULT_OPTION_VALUE } from './constants';
11
16
  import type {
12
17
  DropdownProps,
13
- TFlatList,
14
- TFlatListItem,
15
- TSectionList,
16
- TSectionListItem,
18
+ DropdownSelectHandle,
17
19
  TSelectedItem,
18
20
  } from './types/index.types';
19
- import { escapeRegExp, extractPropertyFromArray } from './utils';
20
-
21
- export const DropdownSelect: React.FC<DropdownProps> = ({
22
- testID,
23
- placeholder,
24
- label,
25
- error,
26
- helperText,
27
- options,
28
- optionLabel = DEFAULT_OPTION_LABEL,
29
- optionValue = DEFAULT_OPTION_VALUE,
30
- onValueChange,
31
- selectedValue,
32
- isMultiple,
33
- isSearchable,
34
- dropdownIcon,
35
- labelStyle,
36
- placeholderStyle,
37
- dropdownStyle,
38
- dropdownIconStyle,
39
- dropdownContainerStyle,
40
- dropdownErrorStyle,
41
- dropdownErrorTextStyle,
42
- dropdownHelperTextStyle,
43
- selectedItemStyle,
44
- multipleSelectedItemStyle,
45
- modalBackgroundStyle, // kept for backwards compatibility
46
- modalOptionsContainerStyle, // kept for backwards compatibility
47
- searchInputStyle, // kept for backwards compatibility
48
- primaryColor = colors.gray,
49
- disabled,
50
- checkboxSize, // kept for backwards compatibility
51
- checkboxStyle, // kept for backwards compatibility
52
- checkboxLabelStyle, // kept for backwards compatibility
53
- checkboxComponentStyles, // kept for backwards compatibility
54
- checkboxComponent, // kept for backwards compatibility
55
- listHeaderComponent,
56
- listFooterComponent,
57
- listComponentStyles,
58
- listEmptyComponent,
59
- modalProps, // kept for backwards compatibility
60
- hideModal = false,
61
- listControls,
62
- searchControls,
63
- modalControls,
64
- checkboxControls,
65
- autoCloseOnSelect = true,
66
- ...rest
67
- }) => {
68
- const [newOptions, setNewOptions] = useState<TFlatList | TSectionList>([]);
69
- const [open, setOpen] = useState<boolean>(false);
70
- const [selectAll, setSelectAll] = useState<boolean>(false);
71
- const [selectedItem, setSelectedItem] = useState<TSelectedItem>(''); // for single selection
72
- const [selectedItems, setSelectedItems] = useState<TSelectedItem[]>([]); // for multiple selection
73
- const [searchValue, setSearchValue] = useState<string>('');
74
- const [listIndex, setListIndex] = useState<{
75
- sectionIndex?: number;
76
- itemIndex: number;
77
- }>({ itemIndex: -1, sectionIndex: -1 }); // for scrollToIndex in Sectionlist and Flatlist
78
-
79
- useEffect(() => {
80
- setNewOptions(options);
81
- return () => {};
82
- }, [options]);
83
-
84
- useEffect(() => {
85
- isMultiple
86
- ? setSelectedItems(Array.isArray(selectedValue) ? selectedValue : [])
87
- : setSelectedItem((selectedValue as TSelectedItem) || '');
88
-
89
- return () => {};
90
- }, [selectedValue, isMultiple, onValueChange]);
91
-
92
- /*===========================================
93
- * List type
94
- *==========================================*/
95
-
96
- // check the structure of the new options array to determine if it is a section list or a
97
- const isSectionList = newOptions?.some(
98
- (item) => item.title && item.data && Array.isArray(item.data)
99
- );
100
-
101
- const ListTypeComponent = isSectionList
102
- ? DropdownSectionList
103
- : DropdownFlatList;
104
- const modifiedSectionData = extractPropertyFromArray(
105
- newOptions,
106
- 'data'
107
- )?.flat();
108
-
109
- /**
110
- * `options` is the original array, it never changes. (Do not use except you really need the original array) .
111
- * `newOptions` is a copy of options but can be mutated by `setNewOptions`, as a result, the value may change.
112
- * `modifiedOptions` should only be used for computations. It has the same structure for both `FlatList` and `SectionList`
113
- */
114
- const modifiedOptions = isSectionList ? modifiedSectionData : newOptions;
115
-
116
- /*===========================================
117
- * Selection handlers
118
- *==========================================*/
119
- const handleSingleSelection = (value: TSelectedItem) => {
120
- if (selectedItem === value) {
121
- setSelectedItem('');
122
- onValueChange(null); // send value to parent
123
- } else {
124
- setSelectedItem(value);
125
- onValueChange(value); // send value to parent
126
-
127
- if (autoCloseOnSelect) {
128
- setOpen(false); // close modal upon selection
129
- }
130
- }
131
- };
132
-
133
- const handleMultipleSelections = (value: TSelectedItem) => {
134
- setSelectedItems((prevVal) => {
135
- let selectedValues = [...prevVal];
136
-
137
- if (selectedValues?.includes(value)) {
138
- selectedValues = selectedValues.filter((item) => item !== value);
139
- } else {
140
- selectedValues.push(value);
141
- }
142
- onValueChange(selectedValues); // send value to parent
143
- return selectedValues;
144
- });
145
- };
146
-
147
- const removeDisabledItems = (items: TFlatList) => {
148
- return items?.filter((item: TFlatListItem) => !item.disabled);
149
- };
150
-
151
- const handleSelectAll = () => {
152
- setSelectAll((prevVal) => {
153
- let selectedValues: TSelectedItem[] = [];
154
-
155
- // don't select disabled items
156
- const filteredOptions = removeDisabledItems(
157
- isSectionList
158
- ? extractPropertyFromArray(options, 'data').flat()
159
- : options
160
- );
161
-
162
- if (!prevVal) {
163
- selectedValues = filteredOptions.map(
164
- (obj) => obj[optionValue]
165
- ) as TSelectedItem[];
166
- }
167
-
168
- setSelectedItems(selectedValues);
169
- onValueChange(selectedValues); // send value to parent
170
- return !prevVal;
171
- });
172
-
173
- if (typeof listControls?.selectAllCallback === 'function' && !selectAll) {
174
- listControls.selectAllCallback();
175
- }
176
-
177
- if (typeof listControls?.unselectAllCallback === 'function' && selectAll) {
178
- listControls.unselectAllCallback();
179
- }
180
- };
181
-
182
- /*===========================================
183
- * Handle side effects
184
- *==========================================*/
185
- const checkSelectAll = useCallback(
186
- (selectedValues: TSelectedItem[]) => {
187
- //if the list contains disabled values, those values will not be selected
188
- if (
189
- removeDisabledItems(modifiedOptions)?.length === selectedValues?.length
190
- ) {
191
- setSelectAll(true);
192
- } else {
193
- setSelectAll(false);
194
- }
21
+ import { extractPropertyFromArray, getLabelsOfSelectedItems } from './utils';
22
+ import {
23
+ useSelectionHandler,
24
+ useModal,
25
+ useSearch,
26
+ useIndexOfSelectedItem,
27
+ useSelectAll,
28
+ } from './hooks';
29
+
30
+ export const DropdownSelect = forwardRef<DropdownSelectHandle, DropdownProps>(
31
+ (
32
+ {
33
+ testID,
34
+ placeholder,
35
+ label,
36
+ error,
37
+ helperText,
38
+ options,
39
+ optionLabel = DEFAULT_OPTION_LABEL,
40
+ optionValue = DEFAULT_OPTION_VALUE,
41
+ onValueChange,
42
+ isMultiple = false,
43
+ selectedValue = isMultiple ? [] : '',
44
+ isSearchable,
45
+ dropdownIcon,
46
+ labelStyle,
47
+ placeholderStyle,
48
+ dropdownStyle,
49
+ dropdownIconStyle,
50
+ dropdownContainerStyle,
51
+ dropdownErrorStyle,
52
+ dropdownErrorTextStyle,
53
+ dropdownHelperTextStyle,
54
+ selectedItemStyle,
55
+ multipleSelectedItemStyle,
56
+ primaryColor = colors.gray,
57
+ disabled = false,
58
+ listHeaderComponent,
59
+ listFooterComponent,
60
+ listComponentStyles,
61
+ listEmptyComponent,
62
+ listControls,
63
+ searchControls,
64
+ modalControls,
65
+ checkboxControls,
66
+ autoCloseOnSelect = true,
67
+ maxSelectableItems,
68
+ ...rest
195
69
  },
196
- [modifiedOptions]
197
- );
198
-
199
- // anytime the selected items change, check if it is time to set `selectAll` to true
200
- useEffect(() => {
201
- if (isMultiple) {
202
- checkSelectAll(selectedItems);
203
- }
204
- return () => {};
205
- }, [checkSelectAll, isMultiple, selectedItems]);
206
-
207
- /*===========================================
208
- * Get label handler
209
- *==========================================*/
210
- const getSelectedItemsLabel = () => {
211
- if (isMultiple && Array.isArray(selectedItems)) {
212
- let selectedLabels: Array<string> = [];
213
-
214
- selectedItems?.forEach((element: TSelectedItem) => {
215
- let selectedItemLabel = modifiedOptions?.find(
216
- (item: TFlatListItem) => item[optionValue] === element
217
- )?.[optionLabel];
218
- selectedLabels.push(selectedItemLabel);
219
- });
220
- return selectedLabels;
221
- }
222
-
223
- let selectedItemLabel = modifiedOptions?.find(
224
- (item: TFlatListItem) => item[optionValue] === selectedItem
225
- );
226
- return selectedItemLabel?.[optionLabel];
227
- };
228
-
229
- /*===========================================
230
- * Search
231
- *==========================================*/
232
- const onSearch = (value: string) => {
233
- setSearchValue(value);
234
- searchControls?.searchCallback?.(value);
235
-
236
- let searchText = escapeRegExp(value).toString().toLocaleLowerCase().trim();
237
-
238
- const regexFilter = new RegExp(searchText, 'i');
239
-
240
- // Because the options array will be mutated while searching, we have to search with the original array
241
- const searchResults = isSectionList
242
- ? searchSectionList(options as TSectionList, regexFilter)
243
- : searchFlatList(options as TFlatList, regexFilter);
244
-
245
- setNewOptions(searchResults);
246
- };
247
-
248
- const searchFlatList = (flatList: TFlatList, regexFilter: RegExp) => {
249
- const searchResults = flatList.filter((item: TFlatListItem) => {
250
- if (
251
- item[optionLabel].toString().toLowerCase().search(regexFilter) !== -1 ||
252
- item[optionValue].toString().toLowerCase().search(regexFilter) !== -1
253
- ) {
254
- return true;
255
- }
256
- return false;
70
+ ref
71
+ ) => {
72
+ /*===========================================
73
+ * Expose the methods to the parent using
74
+ * useImperativeHandle
75
+ *==========================================*/
76
+ useImperativeHandle(ref, () => ({
77
+ open: () => openModal(),
78
+ close: () => closeModal(),
79
+ }));
80
+
81
+ /*===========================================
82
+ * Search
83
+ *==========================================*/
84
+ const {
85
+ searchValue,
86
+ setSearchValue,
87
+ setFilteredOptions,
88
+ filteredOptions,
89
+ isSectionList,
90
+ } = useSearch({
91
+ initialOptions: options,
92
+ optionLabel,
93
+ optionValue,
94
+ searchCallback: useCallback(
95
+ (value) => searchControls?.searchCallback?.(value),
96
+ [searchControls]
97
+ ),
257
98
  });
258
- return searchResults;
259
- };
260
99
 
261
- const searchSectionList = (
262
- sectionList: TSectionList,
263
- regexFilter: RegExp
264
- ) => {
265
- const searchResults = sectionList.map((listItem: TSectionListItem) => {
266
- const filteredData = listItem.data.filter((item: TFlatListItem) => {
267
- if (
268
- item[optionLabel].toString().toLowerCase().search(regexFilter) !==
269
- -1 ||
270
- item[optionValue].toString().toLowerCase().search(regexFilter) !== -1
271
- ) {
272
- return true;
273
- }
274
- return false;
100
+ /*===========================================
101
+ * setIndexOfSelectedItem - For ScrollToIndex
102
+ *==========================================*/
103
+ const { listIndex, setListIndex, setIndexOfSelectedItem } =
104
+ useIndexOfSelectedItem({
105
+ options,
106
+ optionLabel,
107
+ isSectionList,
275
108
  });
276
109
 
277
- return { ...listItem, data: filteredData };
110
+ /*===========================================
111
+ * Reset component states
112
+ *==========================================*/
113
+ const resetOptionsRelatedState = useCallback(() => {
114
+ setSearchValue('');
115
+ setFilteredOptions(options);
116
+ setListIndex({ itemIndex: -1, sectionIndex: -1 });
117
+ }, [options, setFilteredOptions, setListIndex, setSearchValue]);
118
+
119
+ /*===========================================
120
+ * Modal
121
+ *==========================================*/
122
+ const { isVisible, openModal, closeModal } = useModal({
123
+ resetOptionsRelatedState,
124
+ disabled,
125
+ modalControls,
278
126
  });
279
127
 
280
- return searchResults;
281
- };
282
-
283
- /**
284
- * To prevent triggering on modalProps.onDismiss on first render, we perform this check
285
- */
286
- const hasComponentBeenRendered = useRef(false);
287
-
288
- /**
289
- * Explicitly adding this here because the onDismiss only works on iOS Modals
290
- * https://reactnative.dev/docs/modal#ondismiss-ios
291
- */
292
- useEffect(() => {
293
- if (
294
- hasComponentBeenRendered.current &&
295
- !open &&
296
- Platform.OS === 'android'
297
- ) {
298
- modalControls?.modalProps?.onDismiss?.();
299
- }
300
-
301
- hasComponentBeenRendered.current = true;
302
- }, [open]);
303
-
304
- /*===========================================
305
- * Modal
306
- *==========================================*/
307
- const openModal = () => {
308
- if (disabled) {
309
- return;
310
- }
311
- setOpen(true);
312
- resetComponent();
313
- };
314
-
315
- const closeModal = () => {
316
- setOpen(false);
317
- resetComponent();
318
- };
319
-
320
- const resetComponent = () => {
321
- setSearchValue('');
322
- setNewOptions(options);
323
- setListIndex({ itemIndex: -1, sectionIndex: -1 });
324
- };
325
-
326
- useEffect(() => {
327
- if (hideModal) {
328
- setOpen(false);
329
- }
330
- return () => {};
331
- }, [hideModal]);
128
+ /*===========================================
129
+ * Single and multiple selection Hook
130
+ *==========================================*/
131
+ const {
132
+ selectedItem,
133
+ selectedItems,
134
+ setSelectedItem,
135
+ setSelectedItems,
136
+ handleSingleSelection,
137
+ handleMultipleSelections,
138
+ } = useSelectionHandler({
139
+ initialSelectedValue: selectedValue,
140
+ isMultiple,
141
+ maxSelectableItems,
142
+ onValueChange,
143
+ closeModal: () => closeModal(),
144
+ autoCloseOnSelect,
145
+ });
332
146
 
333
- /*===========================================
334
- * setIndexOfSelectedItem - For ScrollToIndex
335
- *==========================================*/
336
- const setIndexOfSelectedItem = (selectedLabel: string) => {
337
- isSectionList
338
- ? (options as TSectionListItem[] | undefined)?.map(
339
- (item: TSectionListItem, sectionIndex: number) => {
340
- item?.data?.find((dataItem: TFlatListItem, itemIndex: number) => {
341
- if (dataItem[optionLabel] === selectedLabel) {
342
- setListIndex({ sectionIndex, itemIndex });
343
- }
344
- });
345
- }
346
- )
347
- : (options as TFlatListItem[] | undefined)?.find(
348
- (item: TFlatListItem, itemIndex: number) => {
349
- if (item[optionLabel] === selectedLabel) {
350
- setListIndex({ itemIndex });
351
- }
352
- }
353
- );
354
- };
147
+ useEffect(() => {
148
+ isMultiple
149
+ ? setSelectedItems(selectedValue as TSelectedItem[])
150
+ : setSelectedItem(selectedValue as TSelectedItem);
151
+
152
+ return () => {};
153
+ }, [
154
+ selectedValue,
155
+ setSelectedItems,
156
+ setSelectedItem,
157
+ isMultiple,
158
+ onValueChange,
159
+ ]);
160
+
161
+ /*===========================================
162
+ * List type
163
+ *==========================================*/
164
+ const ListTypeComponent = isSectionList
165
+ ? DropdownSectionList
166
+ : DropdownFlatList;
167
+ const modifiedSectionData = extractPropertyFromArray(
168
+ filteredOptions,
169
+ 'data'
170
+ )?.flat();
171
+
172
+ /**
173
+ * `options` is the original array, it never changes. (Do not use except you really need the original array) .
174
+ * `filteredOptions` is a copy of options but can be mutated by `setFilteredOptions`, as a result, the value may change.
175
+ * `modifiedOptions` should only be used for computations. It has the same structure for both `FlatList` and `SectionList`
176
+ */
177
+ const modifiedOptions = isSectionList
178
+ ? modifiedSectionData
179
+ : filteredOptions;
180
+
181
+ /*===========================================
182
+ * Select all Hook
183
+ *==========================================*/
184
+ const { selectAll, handleSelectAll } = useSelectAll({
185
+ options: modifiedOptions,
186
+ selectedItems,
187
+ isMultiple,
188
+ onValueChange,
189
+ listControls,
190
+ optionValue,
191
+ });
355
192
 
356
- return (
357
- <>
358
- <Dropdown
359
- testID={testID}
360
- label={label}
361
- placeholder={placeholder}
362
- helperText={helperText}
363
- error={error}
364
- getSelectedItemsLabel={getSelectedItemsLabel}
365
- selectedItem={selectedItem}
366
- selectedItems={selectedItems}
367
- openModal={openModal}
368
- closeModal={closeModal}
369
- labelStyle={labelStyle}
370
- dropdownIcon={dropdownIcon}
371
- dropdownStyle={dropdownStyle}
372
- dropdownIconStyle={dropdownIconStyle}
373
- dropdownContainerStyle={dropdownContainerStyle}
374
- dropdownErrorStyle={dropdownErrorStyle}
375
- dropdownErrorTextStyle={dropdownErrorTextStyle}
376
- dropdownHelperTextStyle={dropdownHelperTextStyle}
377
- selectedItemStyle={selectedItemStyle}
378
- multipleSelectedItemStyle={multipleSelectedItemStyle}
379
- isMultiple={isMultiple}
380
- primaryColor={primaryColor}
381
- disabled={disabled}
382
- placeholderStyle={placeholderStyle}
383
- setIndexOfSelectedItem={setIndexOfSelectedItem}
384
- {...rest}
385
- />
386
- <CustomModal
387
- visible={open}
388
- modalBackgroundStyle={modalBackgroundStyle} // kept for backwards compatibility
389
- modalOptionsContainerStyle={modalOptionsContainerStyle} // kept for backwards compatibility
390
- closeModal={closeModal}
391
- modalControls={modalControls}
392
- modalProps={modalProps} // kept for backwards compatibility
393
- >
394
- <ListTypeComponent
395
- ListHeaderComponent={
396
- <>
397
- {isSearchable && (
398
- <Input
399
- value={searchValue}
400
- onChangeText={(text: string) => onSearch(text)}
401
- style={searchControls?.textInputStyle || searchInputStyle}
402
- primaryColor={primaryColor}
403
- textInputContainerStyle={
404
- searchControls?.textInputContainerStyle
405
- }
406
- placeholder={
407
- searchControls?.textInputProps?.placeholder || 'Search'
408
- }
409
- {...searchControls?.textInputProps}
410
- />
411
- )}
412
- {listHeaderComponent}
413
- {!listControls?.hideSelectAll &&
414
- isMultiple &&
415
- modifiedOptions?.length > 1 && (
416
- <View style={styles.optionsContainerStyle}>
417
- <TouchableOpacity onPress={() => {}}>
418
- <CheckBox
419
- value={selectAll}
420
- label={
421
- selectAll
422
- ? listControls?.unselectAllText || 'Clear all'
423
- : listControls?.selectAllText || 'Select all'
424
- }
425
- onChange={() => handleSelectAll()}
426
- primaryColor={primaryColor}
427
- checkboxControls={checkboxControls}
428
- checkboxSize={checkboxSize}
429
- checkboxStyle={checkboxStyle}
430
- checkboxLabelStyle={checkboxLabelStyle}
431
- checkboxComponentStyles={checkboxComponentStyles}
432
- checkboxComponent={checkboxComponent}
433
- />
434
- </TouchableOpacity>
435
- </View>
436
- )}
437
- </>
438
- }
439
- ListFooterComponent={listFooterComponent}
440
- listComponentStyles={listComponentStyles}
441
- options={newOptions}
442
- optionLabel={optionLabel}
443
- optionValue={optionValue}
444
- isMultiple={isMultiple}
445
- isSearchable={isSearchable}
446
- selectedItems={selectedItems}
193
+ return (
194
+ <>
195
+ <Dropdown
196
+ testID={testID}
197
+ label={label}
198
+ placeholder={placeholder}
199
+ helperText={helperText}
200
+ error={error}
201
+ labelsOfSelectedItems={getLabelsOfSelectedItems({
202
+ isMultiple,
203
+ optionLabel,
204
+ optionValue,
205
+ selectedItem,
206
+ selectedItems,
207
+ modifiedOptions,
208
+ })}
447
209
  selectedItem={selectedItem}
448
- handleMultipleSelections={handleMultipleSelections}
449
- handleSingleSelection={handleSingleSelection}
210
+ selectedItems={selectedItems}
211
+ openModal={() => openModal()}
212
+ closeModal={() => closeModal()}
213
+ labelStyle={labelStyle}
214
+ dropdownIcon={dropdownIcon}
215
+ dropdownStyle={dropdownStyle}
216
+ dropdownIconStyle={dropdownIconStyle}
217
+ dropdownContainerStyle={dropdownContainerStyle}
218
+ dropdownErrorStyle={dropdownErrorStyle}
219
+ dropdownErrorTextStyle={dropdownErrorTextStyle}
220
+ dropdownHelperTextStyle={dropdownHelperTextStyle}
221
+ selectedItemStyle={selectedItemStyle}
222
+ multipleSelectedItemStyle={multipleSelectedItemStyle}
223
+ isMultiple={isMultiple}
450
224
  primaryColor={primaryColor}
451
- checkboxSize={checkboxSize}
452
- checkboxStyle={checkboxStyle}
453
- checkboxLabelStyle={checkboxLabelStyle}
454
- checkboxComponentStyles={checkboxComponentStyles}
455
- checkboxComponent={checkboxComponent}
456
- checkboxControls={checkboxControls}
457
- listIndex={listIndex}
458
- listEmptyComponent={listEmptyComponent}
459
- emptyListMessage={listControls?.emptyListMessage}
225
+ disabled={disabled}
226
+ placeholderStyle={placeholderStyle}
227
+ setIndexOfSelectedItem={setIndexOfSelectedItem}
228
+ {...rest}
460
229
  />
461
- </CustomModal>
462
- </>
463
- );
464
- };
465
-
230
+ <CustomModal
231
+ visible={isVisible}
232
+ onRequestClose={() => closeModal()}
233
+ modalControls={modalControls}
234
+ >
235
+ <ListTypeComponent
236
+ ListHeaderComponent={
237
+ <>
238
+ {isSearchable && (
239
+ <Input
240
+ value={searchValue}
241
+ onChangeText={(text: string) => setSearchValue(text)}
242
+ style={searchControls?.textInputStyle}
243
+ primaryColor={primaryColor}
244
+ textInputContainerStyle={
245
+ searchControls?.textInputContainerStyle
246
+ }
247
+ placeholder={
248
+ searchControls?.textInputProps?.placeholder || 'Search'
249
+ }
250
+ aria-label={
251
+ searchControls?.textInputProps?.placeholder || 'Search'
252
+ }
253
+ {...searchControls?.textInputProps}
254
+ />
255
+ )}
256
+ {listHeaderComponent}
257
+ {!listControls?.hideSelectAll &&
258
+ isMultiple &&
259
+ modifiedOptions?.length > 1 && (
260
+ <View style={styles.optionsContainerStyle}>
261
+ <TouchableOpacity accessible={false}>
262
+ <CheckBox
263
+ value={selectAll}
264
+ label={
265
+ selectAll
266
+ ? listControls?.unselectAllText || 'Clear all'
267
+ : listControls?.selectAllText || 'Select all'
268
+ }
269
+ onChange={() => handleSelectAll()}
270
+ primaryColor={primaryColor}
271
+ checkboxControls={checkboxControls}
272
+ />
273
+ </TouchableOpacity>
274
+ </View>
275
+ )}
276
+ </>
277
+ }
278
+ ListFooterComponent={listFooterComponent}
279
+ listComponentStyles={listComponentStyles}
280
+ options={filteredOptions}
281
+ optionLabel={optionLabel}
282
+ optionValue={optionValue}
283
+ isMultiple={isMultiple}
284
+ isSearchable={isSearchable}
285
+ selectedItems={selectedItems}
286
+ selectedItem={selectedItem}
287
+ handleMultipleSelections={handleMultipleSelections}
288
+ handleSingleSelection={handleSingleSelection}
289
+ primaryColor={primaryColor}
290
+ checkboxControls={checkboxControls}
291
+ listIndex={listIndex}
292
+ listEmptyComponent={listEmptyComponent}
293
+ emptyListMessage={listControls?.emptyListMessage}
294
+ />
295
+ </CustomModal>
296
+ </>
297
+ );
298
+ }
299
+ );
466
300
  const styles = StyleSheet.create({
467
301
  optionsContainerStyle: {
468
302
  paddingHorizontal: 20,