react-native-input-select 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.tsx CHANGED
@@ -15,10 +15,7 @@ import type {
15
15
  TSectionList,
16
16
  TSectionListItem,
17
17
  } from './types/index.types';
18
- import {
19
- extractPropertyFromArray,
20
- getMaxLengthOfSectionListProperty,
21
- } from './utils';
18
+ import { extractPropertyFromArray } from './utils';
22
19
 
23
20
  export const DropdownSelect: React.FC<DropdownProps> = ({
24
21
  placeholder,
@@ -45,7 +42,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
45
42
  multipleSelectedItemStyle,
46
43
  modalBackgroundStyle,
47
44
  modalOptionsContainerStyle,
48
- searchInputStyle,
45
+ searchInputStyle, // kept for backwards compatibility
49
46
  primaryColor,
50
47
  disabled,
51
48
  checkboxSize, // kept for backwards compatibility
@@ -59,6 +56,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
59
56
  modalProps,
60
57
  hideModal = false,
61
58
  listControls,
59
+ searchControls,
62
60
  ...rest
63
61
  }) => {
64
62
  const [newOptions, setNewOptions] = useState<TFlatList | TSectionList>([]);
@@ -72,10 +70,12 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
72
70
  itemIndex: number;
73
71
  }>({ itemIndex: 0 }); // for scrollToIndex in Sectionlist and Flatlist
74
72
 
73
+ if (!options || options.length === 0) {
74
+ throw new Error('Options array cannot be empty or undefined');
75
+ }
76
+
75
77
  useEffect(() => {
76
- if (options) {
77
- setNewOptions(options);
78
- }
78
+ setNewOptions(options);
79
79
  return () => {};
80
80
  }, [options]);
81
81
 
@@ -91,6 +91,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
91
91
  * List type
92
92
  *==========================================*/
93
93
 
94
+ // check the structure of the new options array to determine if it is a section list or a
94
95
  const isSectionList = newOptions.some(
95
96
  (item) => item.title && item.data && Array.isArray(item.data)
96
97
  );
@@ -102,11 +103,16 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
102
103
  newOptions,
103
104
  'data'
104
105
  ).flat();
106
+
107
+ /**
108
+ *`modifiedOptions` should only be used for computations newOptions remains the default array.
109
+ * At this point modifiedOptions now has the same structure for both `FlatList` and `SectionList`
110
+ */
105
111
  const modifiedOptions = isSectionList ? modifiedSectionData : newOptions;
106
112
 
107
113
  const optLabel = optionLabel || DEFAULT_OPTION_LABEL;
108
114
  const optValue = optionValue || DEFAULT_OPTION_VALUE;
109
- const optionsCopy = JSON.parse(JSON.stringify(options)); //copy of the original options array
115
+ const optionsCopy = JSON.parse(JSON.stringify(options)); // copy of the original options array
110
116
 
111
117
  /*===========================================
112
118
  * Selection handlers
@@ -114,11 +120,11 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
114
120
  const handleSingleSelection = (value: string | number) => {
115
121
  if (selectedItem === value) {
116
122
  setSelectedItem(null);
117
- onValueChange(null); //send value to parent
123
+ onValueChange(null); // send value to parent
118
124
  } else {
119
125
  setSelectedItem(value);
120
- onValueChange(value); //send value to parent
121
- setOpen(false); //close modal upon selection
126
+ onValueChange(value); // send value to parent
127
+ setOpen(false); // close modal upon selection
122
128
  }
123
129
  };
124
130
 
@@ -131,18 +137,24 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
131
137
  } else {
132
138
  selectedValues.push(value);
133
139
  }
134
- onValueChange(selectedValues); //send value to parent
140
+ onValueChange(selectedValues); // send value to parent
135
141
  return selectedValues;
136
142
  });
137
143
  };
138
144
 
145
+ const removeDisabledItems = (items: TFlatList) => {
146
+ return items.filter((item: TFlatListItem) => !item.disabled);
147
+ };
148
+
139
149
  const handleSelectAll = () => {
140
150
  setSelectAll((prevVal) => {
141
151
  const selectedValues = [];
142
152
 
143
- //don't select disabled items
144
- const filteredOptions = modifiedOptions.filter(
145
- (item: TFlatListItem) => !item.disabled
153
+ // don't select disabled items
154
+ const filteredOptions = removeDisabledItems(
155
+ isSectionList
156
+ ? extractPropertyFromArray(optionsCopy, 'data').flat()
157
+ : optionsCopy
146
158
  );
147
159
 
148
160
  if (!prevVal) {
@@ -152,21 +164,15 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
152
164
  }
153
165
 
154
166
  setSelectedItems(selectedValues);
155
- onValueChange(selectedValues); //send value to parent
167
+ onValueChange(selectedValues); // send value to parent
156
168
  return !prevVal;
157
169
  });
158
170
 
159
- if (
160
- typeof listControls?.selectAllCallback === 'function' &&
161
- !selectAll
162
- ) {
171
+ if (typeof listControls?.selectAllCallback === 'function' && !selectAll) {
163
172
  listControls.selectAllCallback();
164
173
  }
165
174
 
166
- if (
167
- typeof listControls?.unselectAllCallback === 'function' &&
168
- selectAll
169
- ) {
175
+ if (typeof listControls?.unselectAllCallback === 'function' && selectAll) {
170
176
  listControls.unselectAllCallback();
171
177
  }
172
178
  };
@@ -178,8 +184,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
178
184
  (selectedValues: any[]) => {
179
185
  //if the list contains disabled values, those values will not be selected
180
186
  if (
181
- modifiedOptions.filter((item: TFlatListItem) => !item.disabled)
182
- .length === selectedValues.length
187
+ removeDisabledItems(modifiedOptions).length === selectedValues.length
183
188
  ) {
184
189
  setSelectAll(true);
185
190
  } else {
@@ -229,7 +234,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
229
234
 
230
235
  const regexFilter = new RegExp(searchText, 'i');
231
236
 
232
- //Because Search mutates the initial state, we have to search with a copy of the original array
237
+ // Because the options array will be mutated after Search, we have to search with a copy of the original array
233
238
  const searchResults = isSectionList
234
239
  ? searchSectionList(optionsCopy as TSectionList, regexFilter)
235
240
  : searchFlatList(optionsCopy as TFlatList, regexFilter);
@@ -243,7 +248,7 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
243
248
  item[optLabel].toString().toLowerCase().search(regexFilter) !== -1 ||
244
249
  item[optValue].toString().toLowerCase().search(regexFilter) !== -1
245
250
  ) {
246
- return item;
251
+ return true;
247
252
  }
248
253
  return;
249
254
  });
@@ -290,15 +295,6 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
290
295
 
291
296
  let primary = primaryColor || colors.gray;
292
297
 
293
- const sectionListMaxLength = getMaxLengthOfSectionListProperty(
294
- newOptions as TSectionList,
295
- 'data'
296
- );
297
-
298
- const listIsEmpty = isSectionList
299
- ? sectionListMaxLength > 1
300
- : newOptions.length > 1;
301
-
302
298
  /*===========================================
303
299
  * setIndexOfSelectedItem - For ScrollToIndex
304
300
  *==========================================*/
@@ -348,25 +344,30 @@ export const DropdownSelect: React.FC<DropdownProps> = ({
348
344
  />
349
345
  <CustomModal
350
346
  open={open}
351
- handleToggleModal={handleToggleModal}
352
347
  modalBackgroundStyle={modalBackgroundStyle}
353
348
  modalOptionsContainerStyle={modalOptionsContainerStyle}
354
- onRequestClose={() => {}}
349
+ onRequestClose={() => handleToggleModal()}
355
350
  modalProps={modalProps}
356
351
  >
357
352
  <ListTypeComponent
353
+ removeClippedSubviews={false}
358
354
  ListHeaderComponent={
359
355
  <>
360
356
  {isSearchable && (
361
357
  <Input
362
358
  value={searchValue}
363
359
  onChangeText={(text: string) => onSearch(text)}
364
- style={searchInputStyle}
360
+ style={searchControls?.textInputStyle || searchInputStyle}
365
361
  primaryColor={primary}
362
+ textInputContainerStyle={
363
+ searchControls?.textInputContainerStyle
364
+ }
365
+ openModal={() => setOpen(true)} // There seems to a known issue on expo web that closes the modal when the input is focused
366
+ {...searchControls?.textInputProps}
366
367
  />
367
368
  )}
368
369
  {listHeaderComponent}
369
- {isMultiple && listIsEmpty && (
370
+ {isMultiple && modifiedOptions.length > 1 && (
370
371
  <View style={styles.optionsContainerStyle}>
371
372
  <TouchableOpacity onPress={() => {}}>
372
373
  <CheckBox
@@ -3,6 +3,7 @@ import type {
3
3
  ColorValue,
4
4
  TextStyle,
5
5
  ModalProps,
6
+ TextInputProps,
6
7
  } from 'react-native';
7
8
 
8
9
  export type DropdownProps = {
@@ -64,6 +65,11 @@ export type DropdownProps = {
64
65
  selectAllCallback?: () => void;
65
66
  unselectAllCallback?: () => void;
66
67
  };
68
+ searchControls?: {
69
+ textInputStyle?: ViewStyle | TextStyle;
70
+ textInputContainerStyle?: ViewStyle;
71
+ textInputProps?: TextInputProps;
72
+ };
67
73
  };
68
74
 
69
75
  export type TFlatList = TFlatListItem[];
@@ -1,25 +1,9 @@
1
- import { TSectionList } from 'src/types/index.types';
2
-
3
1
  /**
4
2
  * Extract property from array
5
3
  */
4
+
6
5
  export const extractPropertyFromArray = (arr: any, property: string) => {
7
6
  let extractedValue = arr.map((item: any) => item[property]);
8
7
 
9
8
  return extractedValue;
10
9
  };
11
-
12
- export const getMaxLengthOfSectionListProperty = (
13
- sectionList: TSectionList,
14
- property: 'title' | 'data'
15
- ) => {
16
- let maxLength = 0;
17
-
18
- sectionList.forEach((obj) => {
19
- if (obj[property]?.length > maxLength) {
20
- maxLength = obj.data.length;
21
- }
22
- });
23
-
24
- return maxLength;
25
- };