react-native-input-select 1.3.18 → 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 -224
  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 -226
  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 +54 -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 +300 -443
  114. package/src/types/index.types.ts +67 -40
  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,468 +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,
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
+ 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
195
78
  },
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;
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
+ ),
257
107
  });
258
- return searchResults;
259
- };
260
108
 
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;
109
+ /*===========================================
110
+ * setIndexOfSelectedItem - For ScrollToIndex
111
+ *==========================================*/
112
+ const { listIndex, setListIndex, setIndexOfSelectedItem } =
113
+ useIndexOfSelectedItem({
114
+ options,
115
+ optionLabel,
116
+ isSectionList,
275
117
  });
276
118
 
277
- 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,
278
136
  });
279
137
 
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]);
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
+ });
332
156
 
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
- };
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
+ });
355
202
 
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}
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
+ })}
447
219
  selectedItem={selectedItem}
448
- handleMultipleSelections={handleMultipleSelections}
449
- 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}
450
234
  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}
235
+ disabled={disabled}
236
+ placeholderStyle={placeholderStyle}
237
+ setIndexOfSelectedItem={setIndexOfSelectedItem}
238
+ {...rest}
460
239
  />
461
- </CustomModal>
462
- </>
463
- );
464
- };
465
-
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
+ );
466
323
  const styles = StyleSheet.create({
467
324
  optionsContainerStyle: {
468
325
  paddingHorizontal: 20,