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