@bigbinary/neetoui-rn 0.0.120 → 0.0.124

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.
@@ -16,7 +16,7 @@ import {
16
16
  import { ThemeContext } from "styled-components/native";
17
17
  import { ScrollView } from "react-native-gesture-handler";
18
18
 
19
- import { Card, Container, Input, Typography } from "@components";
19
+ import { Card, Container, Input, Touchable, Typography } from "@components";
20
20
 
21
21
  const DropdownItem = ({
22
22
  label,
@@ -25,8 +25,8 @@ const DropdownItem = ({
25
25
  onPress,
26
26
  itemContainerStyle,
27
27
  selectedItemContainerStyle,
28
- itemTextStyle,
29
- selectedItemTextStyle,
28
+ itemLabelStyle,
29
+ selectedItemLabelStyle,
30
30
  }) => (
31
31
  <TouchableWithoutFeedback onPress={onPress}>
32
32
  <Container
@@ -40,8 +40,8 @@ const DropdownItem = ({
40
40
  fontFamily="inter400"
41
41
  fontSize="s"
42
42
  color={isSelectedItem ? "font.white" : "font.grey"}
43
- {...itemTextStyle}
44
- {...(isSelectedItem && selectedItemTextStyle)}
43
+ {...itemLabelStyle}
44
+ {...(isSelectedItem && selectedItemLabelStyle)}
45
45
  >
46
46
  {label}
47
47
  </Typography>
@@ -56,8 +56,8 @@ DropdownItem.propTypes = {
56
56
  onPress: PropTypes.func,
57
57
  itemContainerStyle: PropTypes.object,
58
58
  selectedItemContainerStyle: PropTypes.object,
59
- itemTextStyle: PropTypes.object,
60
- selectedItemTextStyle: PropTypes.object,
59
+ itemLabelStyle: PropTypes.object,
60
+ selectedItemLabelStyle: PropTypes.object,
61
61
  };
62
62
 
63
63
  /**
@@ -114,18 +114,24 @@ export const Select = ({
114
114
  onSelect,
115
115
  isLoading,
116
116
  isSearchable,
117
+ showCreateOption,
118
+ showCreateOptionLoader,
119
+ createOptionLabel,
120
+ onPressCreateOption,
117
121
  labelStyle,
118
122
  containerStyle,
119
123
  inputContainerStyle,
120
124
  dropdownContainerStyle,
121
125
  itemContainerStyle,
122
- itemTextStyle,
126
+ itemLabelStyle,
123
127
  selectedItemContainerStyle,
124
- selectedItemTextStyle,
128
+ selectedItemLabelStyle,
125
129
  searchInputContainerStyle,
126
130
  searchInputStyle,
127
131
  emptyOptionsContainerStyle,
128
- emptyOptionsTextStyle,
132
+ emptyOptionsLabelStyle,
133
+ createSearchedOptionContainerStyle,
134
+ createSearchedOptionLabelStyle,
129
135
  ...rest
130
136
  }) => {
131
137
  const theme = useContext(ThemeContext);
@@ -133,19 +139,31 @@ export const Select = ({
133
139
  const [searchQuery, setSearchQuery] = useState("");
134
140
  const dropdownAnimatedHeight = useSharedValue(0);
135
141
 
142
+ const formatStr = str => str?.toLowerCase()?.trim();
143
+ const filteredOptions = options.filter((item, index) => {
144
+ const label = labelExtractor(item, index);
145
+ if (searchQuery?.length === 0) return true;
146
+ return formatStr(label).includes(formatStr(searchQuery));
147
+ });
148
+
136
149
  const isOptionsEmpty = !options || options?.length === 0;
150
+ const isSearchedOptionsEmpty =
151
+ searchQuery.length > 0 && filteredOptions.length === 0;
137
152
  const emptyOptionsPlaceholderHeight = 40;
153
+ const emptySearchedOptionsHeight = 40;
138
154
  const searchInputHeight = 35;
139
155
  const defaultDropdownItemHeight = itemContainerStyle?.height || 32;
140
156
  const dropdownHeight =
141
157
  dropdownContainerStyle?.height ||
142
158
  dropdownContainerStyle?.maxHeight ||
143
- defaultDropdownItemHeight * Math.min(options?.length, 6) +
159
+ defaultDropdownItemHeight * Math.min(filteredOptions?.length, 6) +
144
160
  (isSearchable ? searchInputHeight + 10 : 0) +
145
- (isOptionsEmpty ? emptyOptionsPlaceholderHeight : 0);
161
+ (isOptionsEmpty ? emptyOptionsPlaceholderHeight : 0) +
162
+ (isSearchedOptionsEmpty && showCreateOption
163
+ ? emptySearchedOptionsHeight
164
+ : 0);
146
165
  const selectedOptionLabel = labelExtractor(value || {});
147
166
  const selectedOptionValue = valueExtractor(value || {});
148
- const formatStr = str => str?.toLowerCase()?.trim();
149
167
 
150
168
  const animatedStyles = useAnimatedStyle(() => {
151
169
  return {
@@ -162,7 +180,7 @@ export const Select = ({
162
180
  }
163
181
  ),
164
182
  };
165
- });
183
+ }, []);
166
184
 
167
185
  const toggleAnimation = () => {
168
186
  dropdownAnimatedHeight.value =
@@ -187,10 +205,10 @@ export const Select = ({
187
205
 
188
206
  useEffect(() => {
189
207
  if (showDropdown) {
190
- toggleAnimation();
208
+ dropdownAnimatedHeight.value = dropdownHeight;
191
209
  }
192
210
  // eslint-disable-next-line react-hooks/exhaustive-deps
193
- }, [showDropdown]);
211
+ }, [showDropdown, dropdownHeight]);
194
212
 
195
213
  return (
196
214
  <Container {...containerStyle}>
@@ -270,43 +288,61 @@ export const Select = ({
270
288
  fontFamily="inter400"
271
289
  fontSize="s"
272
290
  color="font.grey"
273
- {...emptyOptionsTextStyle}
291
+ {...emptyOptionsLabelStyle}
274
292
  >
275
293
  {emptyOptionsPlaceholder || "No Options"}
276
294
  </Typography>
277
295
  </Container>
278
296
  )}
297
+ {isSearchedOptionsEmpty && showCreateOption && (
298
+ <Touchable
299
+ height={emptySearchedOptionsHeight}
300
+ justifyContent="center"
301
+ alignItems="center"
302
+ onPress={() => onPressCreateOption(searchQuery)}
303
+ {...createSearchedOptionContainerStyle}
304
+ >
305
+ {showCreateOptionLoader ? (
306
+ <ActivityIndicator
307
+ size="small"
308
+ color={theme.colors.background.base}
309
+ />
310
+ ) : (
311
+ <Typography
312
+ fontFamily="inter400"
313
+ fontSize="s"
314
+ color="font.grey"
315
+ {...createSearchedOptionLabelStyle}
316
+ >
317
+ {createOptionLabel || `Create ${searchQuery} option`}
318
+ </Typography>
319
+ )}
320
+ </Touchable>
321
+ )}
279
322
  {/* Animation not working without this hidden input */}
280
323
  <Container height={0}>
281
324
  <Input />
282
325
  </Container>
283
326
  <ScrollView>
284
- {options
285
- .filter((item, index) => {
286
- const label = labelExtractor(item, index);
287
- if (searchQuery?.length === 0) return true;
288
- return formatStr(label).includes(formatStr(searchQuery));
289
- })
290
- .map((item, index) => {
291
- const optionLabel = labelExtractor(item, index);
292
- const optionValue = valueExtractor(item, index);
293
- const isSelectedItem =
294
- selectedOptionValue &&
295
- selectedOptionValue === optionValue;
296
- return (
297
- <DropdownItem
298
- key={index}
299
- label={optionLabel}
300
- isSelectedItem={isSelectedItem}
301
- defaultDropdownItemHeight={defaultDropdownItemHeight}
302
- onPress={() => handleItemSelection(item, index)}
303
- itemContainerStyle={itemContainerStyle}
304
- selectedItemContainerStyle={selectedItemContainerStyle}
305
- itemTextStyle={itemTextStyle}
306
- selectedItemTextStyle={selectedItemTextStyle}
307
- />
308
- );
309
- })}
327
+ {filteredOptions.map((item, index) => {
328
+ const optionLabel = labelExtractor(item, index);
329
+ const optionValue = valueExtractor(item, index);
330
+ const isSelectedItem =
331
+ selectedOptionValue && selectedOptionValue === optionValue;
332
+ return (
333
+ <DropdownItem
334
+ key={index}
335
+ label={optionLabel}
336
+ isSelectedItem={isSelectedItem}
337
+ defaultDropdownItemHeight={defaultDropdownItemHeight}
338
+ onPress={() => handleItemSelection(item, index)}
339
+ itemContainerStyle={itemContainerStyle}
340
+ selectedItemContainerStyle={selectedItemContainerStyle}
341
+ itemLabelStyle={itemLabelStyle}
342
+ selectedItemLabelStyle={selectedItemLabelStyle}
343
+ />
344
+ );
345
+ })}
310
346
  </ScrollView>
311
347
  </Card>
312
348
  </Animated.View>
@@ -362,6 +398,22 @@ Select.propTypes = {
362
398
  * Toggle Search bar within the options dropdown to search through the options.
363
399
  */
364
400
  isSearchable: PropTypes.bool,
401
+ /**
402
+ * Show option to create the searched label if not present in the options list
403
+ */
404
+ showCreateOption: PropTypes.bool,
405
+ /**
406
+ * Show loader while creating a searched option not present in the options list
407
+ */
408
+ showCreateOptionLoader: PropTypes.bool,
409
+ /**
410
+ * Custom label for creating searched option not present in the options list
411
+ */
412
+ createOptionLabel: PropTypes.string,
413
+ /**
414
+ * Callback when create searched option is pressed
415
+ */
416
+ onPressCreateOption: PropTypes.func,
365
417
  /**
366
418
  * To customise floating label styles.
367
419
  */
@@ -385,7 +437,7 @@ Select.propTypes = {
385
437
  /**
386
438
  * To customise dropdown item text styles.
387
439
  */
388
- itemTextStyle: PropTypes.object,
440
+ itemLabelStyle: PropTypes.object,
389
441
  /**
390
442
  * To customise dropdown item container styles for selected item.
391
443
  */
@@ -393,7 +445,7 @@ Select.propTypes = {
393
445
  /**
394
446
  * To customise dropdown item text styles for selected item.
395
447
  */
396
- selectedItemTextStyle: PropTypes.object,
448
+ selectedItemLabelStyle: PropTypes.object,
397
449
  /**
398
450
  * To customise search input containerr style.
399
451
  */
@@ -409,16 +461,29 @@ Select.propTypes = {
409
461
  /**
410
462
  * To customise empty options placeholder text style.
411
463
  */
412
- emptyOptionsTextStyle: PropTypes.object,
464
+ emptyOptionsLabelStyle: PropTypes.object,
465
+ /**
466
+ * To customise empty options placeholder container style.
467
+ */
468
+ createSearchedOptionContainerStyle: PropTypes.object,
469
+ /**
470
+ * To customise empty options placeholder text style.
471
+ */
472
+ createSearchedOptionLabelStyle: PropTypes.object,
413
473
  };
414
474
 
415
475
  Select.defaultProps = {
416
476
  label: null,
417
477
  placeholder: "Select Option",
478
+ emptyOptionsPlaceholder: null,
418
479
  labelExtractor: option => option?.label,
419
480
  valueExtractor: option => option?.value,
420
481
  value: null,
421
482
  onSelect: () => {},
422
483
  isLoading: false,
423
484
  isSearchable: false,
485
+ showCreateOption: false,
486
+ showCreateOptionLoader: false,
487
+ createOptionLabel: null,
488
+ onPressCreateOption: () => {},
424
489
  };