@bigbinary/neetoui-rn 0.0.119 → 0.0.123

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
  /**
@@ -108,19 +108,30 @@ export const Select = ({
108
108
  label,
109
109
  value,
110
110
  placeholder,
111
+ emptyOptionsPlaceholder,
111
112
  labelExtractor,
112
113
  valueExtractor,
113
114
  onSelect,
114
115
  isLoading,
115
116
  isSearchable,
117
+ showCreateOption,
118
+ showCreateOptionLoader,
119
+ createOptionLabel,
120
+ onPressCreateOption,
116
121
  labelStyle,
117
122
  containerStyle,
118
123
  inputContainerStyle,
119
124
  dropdownContainerStyle,
120
125
  itemContainerStyle,
121
- itemTextStyle,
126
+ itemLabelStyle,
122
127
  selectedItemContainerStyle,
123
- selectedItemTextStyle,
128
+ selectedItemLabelStyle,
129
+ searchInputContainerStyle,
130
+ searchInputStyle,
131
+ emptyOptionsContainerStyle,
132
+ emptyOptionsLabelStyle,
133
+ createSearchedOptionContainerStyle,
134
+ createSearchedOptionLabelStyle,
124
135
  ...rest
125
136
  }) => {
126
137
  const theme = useContext(ThemeContext);
@@ -128,16 +139,31 @@ export const Select = ({
128
139
  const [searchQuery, setSearchQuery] = useState("");
129
140
  const dropdownAnimatedHeight = useSharedValue(0);
130
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
+
149
+ const isOptionsEmpty = !options || options?.length === 0;
150
+ const isSearchedOptionsEmpty =
151
+ searchQuery.length > 0 && filteredOptions.length === 0;
152
+ const emptyOptionsPlaceholderHeight = 40;
153
+ const emptySearchedOptionsHeight = 40;
131
154
  const searchInputHeight = 35;
132
155
  const defaultDropdownItemHeight = itemContainerStyle?.height || 32;
133
156
  const dropdownHeight =
134
157
  dropdownContainerStyle?.height ||
135
158
  dropdownContainerStyle?.maxHeight ||
136
- defaultDropdownItemHeight * Math.min(options?.length, 6) +
137
- (isSearchable ? searchInputHeight + 10 : 0);
159
+ defaultDropdownItemHeight * Math.min(filteredOptions?.length, 6) +
160
+ (isSearchable ? searchInputHeight + 10 : 0) +
161
+ (isOptionsEmpty ? emptyOptionsPlaceholderHeight : 0) +
162
+ (isSearchedOptionsEmpty && showCreateOption
163
+ ? emptySearchedOptionsHeight
164
+ : 0);
138
165
  const selectedOptionLabel = labelExtractor(value || {});
139
166
  const selectedOptionValue = valueExtractor(value || {});
140
- const formatStr = str => str?.toLowerCase()?.trim();
141
167
 
142
168
  const animatedStyles = useAnimatedStyle(() => {
143
169
  return {
@@ -154,7 +180,7 @@ export const Select = ({
154
180
  }
155
181
  ),
156
182
  };
157
- });
183
+ }, []);
158
184
 
159
185
  const toggleAnimation = () => {
160
186
  dropdownAnimatedHeight.value =
@@ -179,10 +205,10 @@ export const Select = ({
179
205
 
180
206
  useEffect(() => {
181
207
  if (showDropdown) {
182
- toggleAnimation();
208
+ dropdownAnimatedHeight.value = dropdownHeight;
183
209
  }
184
210
  // eslint-disable-next-line react-hooks/exhaustive-deps
185
- }, [showDropdown]);
211
+ }, [showDropdown, dropdownHeight]);
186
212
 
187
213
  return (
188
214
  <Container {...containerStyle}>
@@ -237,7 +263,7 @@ export const Select = ({
237
263
  {...dropdownContainerStyle}
238
264
  >
239
265
  {isSearchable && (
240
- <Container p={1}>
266
+ <Container p={1} {...searchInputContainerStyle}>
241
267
  <Input
242
268
  placeholder="Search"
243
269
  onChangeText={setSearchQuery}
@@ -247,40 +273,76 @@ export const Select = ({
247
273
  height: searchInputHeight,
248
274
  justifyContent: "center",
249
275
  }}
276
+ {...searchInputStyle}
250
277
  />
251
278
  </Container>
252
279
  )}
280
+ {isOptionsEmpty && (
281
+ <Container
282
+ height={emptyOptionsPlaceholderHeight}
283
+ justifyContent="center"
284
+ alignItems="center"
285
+ {...emptyOptionsContainerStyle}
286
+ >
287
+ <Typography
288
+ fontFamily="inter400"
289
+ fontSize="s"
290
+ color="font.grey"
291
+ {...emptyOptionsLabelStyle}
292
+ >
293
+ {emptyOptionsPlaceholder || "No Options"}
294
+ </Typography>
295
+ </Container>
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
+ )}
253
322
  {/* Animation not working without this hidden input */}
254
323
  <Container height={0}>
255
324
  <Input />
256
325
  </Container>
257
326
  <ScrollView>
258
- {options
259
- .filter((item, index) => {
260
- const label = labelExtractor(item, index);
261
- if (searchQuery?.length === 0) return true;
262
- return formatStr(label).includes(formatStr(searchQuery));
263
- })
264
- .map((item, index) => {
265
- const optionLabel = labelExtractor(item, index);
266
- const optionValue = valueExtractor(item, index);
267
- const isSelectedItem =
268
- selectedOptionValue &&
269
- selectedOptionValue === optionValue;
270
- return (
271
- <DropdownItem
272
- key={index}
273
- label={optionLabel}
274
- isSelectedItem={isSelectedItem}
275
- defaultDropdownItemHeight={defaultDropdownItemHeight}
276
- onPress={() => handleItemSelection(item, index)}
277
- itemContainerStyle={itemContainerStyle}
278
- selectedItemContainerStyle={selectedItemContainerStyle}
279
- itemTextStyle={itemTextStyle}
280
- selectedItemTextStyle={selectedItemTextStyle}
281
- />
282
- );
283
- })}
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
+ })}
284
346
  </ScrollView>
285
347
  </Card>
286
348
  </Animated.View>
@@ -308,6 +370,10 @@ Select.propTypes = {
308
370
  * The text to be displayed if no option is selected.
309
371
  */
310
372
  placeholder: PropTypes.string,
373
+ /**
374
+ * The text to be displayed if no options are provided.
375
+ */
376
+ emptyOptionsPlaceholder: PropTypes.string,
311
377
  /**
312
378
  * Use custom key as label.
313
379
  */
@@ -332,6 +398,22 @@ Select.propTypes = {
332
398
  * Toggle Search bar within the options dropdown to search through the options.
333
399
  */
334
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,
335
417
  /**
336
418
  * To customise floating label styles.
337
419
  */
@@ -355,7 +437,7 @@ Select.propTypes = {
355
437
  /**
356
438
  * To customise dropdown item text styles.
357
439
  */
358
- itemTextStyle: PropTypes.object,
440
+ itemLabelStyle: PropTypes.object,
359
441
  /**
360
442
  * To customise dropdown item container styles for selected item.
361
443
  */
@@ -363,16 +445,45 @@ Select.propTypes = {
363
445
  /**
364
446
  * To customise dropdown item text styles for selected item.
365
447
  */
366
- selectedItemTextStyle: PropTypes.object,
448
+ selectedItemLabelStyle: PropTypes.object,
449
+ /**
450
+ * To customise search input containerr style.
451
+ */
452
+ searchInputContainerStyle: PropTypes.object,
453
+ /**
454
+ * To customise search input style.
455
+ */
456
+ searchInputStyle: PropTypes.object,
457
+ /**
458
+ * To customise empty options placeholder container style.
459
+ */
460
+ emptyOptionsContainerStyle: PropTypes.object,
461
+ /**
462
+ * To customise empty options placeholder text style.
463
+ */
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,
367
473
  };
368
474
 
369
475
  Select.defaultProps = {
370
476
  label: null,
371
477
  placeholder: "Select Option",
478
+ emptyOptionsPlaceholder: null,
372
479
  labelExtractor: option => option?.label,
373
480
  valueExtractor: option => option?.value,
374
481
  value: null,
375
482
  onSelect: () => {},
376
483
  isLoading: false,
377
484
  isSearchable: false,
485
+ showCreateOption: false,
486
+ showCreateOptionLoader: false,
487
+ createOptionLabel: null,
488
+ onPressCreateOption: () => {},
378
489
  };