@bigbinary/neetoui-rn 0.0.243 → 0.0.245

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.
@@ -1,495 +0,0 @@
1
- import React, { useState, useContext, useEffect } from "react";
2
- import { TouchableWithoutFeedback, Keyboard } from "react-native";
3
-
4
- import PropTypes from "prop-types";
5
- import { ScrollView } from "react-native-gesture-handler";
6
- import Animated, {
7
- useSharedValue,
8
- useAnimatedStyle,
9
- withTiming,
10
- Easing,
11
- runOnJS,
12
- } from "react-native-reanimated";
13
- import Icon from "react-native-remix-icon";
14
- import { moderateScale } from "react-native-size-matters";
15
- import { ThemeContext } from "styled-components/native";
16
-
17
- import {
18
- Card,
19
- Container,
20
- Input,
21
- Touchable,
22
- Typography,
23
- Loader,
24
- } from "@components";
25
-
26
- const DropdownItem = ({
27
- label,
28
- isSelectedItem,
29
- defaultDropdownItemHeight,
30
- onPress,
31
- itemContainerStyle,
32
- selectedItemContainerStyle,
33
- itemLabelStyle,
34
- selectedItemLabelStyle,
35
- }) => (
36
- <TouchableWithoutFeedback onPress={onPress}>
37
- <Container
38
- bg={isSelectedItem ? "background.base" : "background.white"}
39
- height={defaultDropdownItemHeight}
40
- p={moderateScale(2)}
41
- {...itemContainerStyle}
42
- {...(isSelectedItem && selectedItemContainerStyle)}
43
- >
44
- <Typography
45
- color={isSelectedItem ? "font.white" : "font.grey"}
46
- fontFamily="sf400"
47
- fontSize="s"
48
- {...itemLabelStyle}
49
- {...(isSelectedItem && selectedItemLabelStyle)}
50
- >
51
- {label}
52
- </Typography>
53
- </Container>
54
- </TouchableWithoutFeedback>
55
- );
56
-
57
- DropdownItem.propTypes = {
58
- label: PropTypes.string.isRequired,
59
- isSelectedItem: PropTypes.bool,
60
- defaultDropdownItemHeight: PropTypes.number,
61
- onPress: PropTypes.func,
62
- itemContainerStyle: PropTypes.object,
63
- selectedItemContainerStyle: PropTypes.object,
64
- itemLabelStyle: PropTypes.object,
65
- selectedItemLabelStyle: PropTypes.object,
66
- };
67
-
68
- /**
69
- *
70
- * Select can be used to select an option from a list of options.
71
- *
72
- * <div class="screenshots">
73
- * <img src="screenshots/select/select1.png" />
74
- * <img src="screenshots/select/select2.png" />
75
- * </div>
76
- *
77
- * ## Usage
78
- *
79
- * ### Import and use Select component.
80
- *
81
- * ```js
82
- * import * as React, { useState } from 'react';
83
- * import { Select, Container } from '@bigbinary/neetoui-rn';
84
- *
85
- * const OPTIONS = [
86
- * {
87
- * label: "Option 1",
88
- * value: "option_1"
89
- * },
90
- * {
91
- * label: "Option 2",
92
- * value: "option_2"
93
- * },
94
- * ]
95
- *
96
- * export default function Main() {
97
- * const [selectedOption, setSelectedOption] = useState(null)
98
- *
99
- * return (
100
- * <Select
101
- * label="Select"
102
- * options={OPTIONS}
103
- * value={selectedOption}
104
- * onSelect={setSelectedOption}
105
- * />
106
- * );
107
- * }
108
- * ```
109
- */
110
-
111
- export const Select = ({
112
- options,
113
- label,
114
- value,
115
- placeholder,
116
- emptyOptionsPlaceholder,
117
- labelExtractor,
118
- valueExtractor,
119
- onSelect,
120
- isLoading,
121
- isSearchable,
122
- showCreateOption,
123
- showCreateOptionLoader,
124
- createOptionLabel,
125
- onPressCreateOption,
126
- labelStyle,
127
- containerStyle,
128
- inputContainerStyle,
129
- dropdownContainerStyle,
130
- itemContainerStyle,
131
- itemLabelStyle,
132
- selectedItemContainerStyle,
133
- selectedItemLabelStyle,
134
- searchInputContainerStyle,
135
- searchInputStyle,
136
- emptyOptionsContainerStyle,
137
- emptyOptionsLabelStyle,
138
- createSearchedOptionContainerStyle,
139
- createSearchedOptionLabelStyle,
140
- ...rest
141
- }) => {
142
- const theme = useContext(ThemeContext);
143
- const [showDropdown, setShowDropdown] = useState(false);
144
- const [searchQuery, setSearchQuery] = useState("");
145
- const dropdownAnimatedHeight = useSharedValue(0);
146
-
147
- const formatStr = str => str?.toLowerCase()?.trim();
148
- const filteredOptions = options.filter((item, index) => {
149
- const label = labelExtractor(item, index);
150
- if (searchQuery?.length === 0) return true;
151
-
152
- return formatStr(label).includes(formatStr(searchQuery));
153
- });
154
-
155
- const isOptionsEmpty = !options || options?.length === 0;
156
- const isSearchedOptionsEmpty =
157
- searchQuery.length > 0 && filteredOptions.length === 0;
158
- const emptyOptionsPlaceholderHeight = moderateScale(40);
159
- const emptySearchedOptionsHeight = moderateScale(40);
160
- const searchInputHeight = moderateScale(35);
161
- const defaultDropdownItemHeight =
162
- itemContainerStyle?.height || moderateScale(32);
163
-
164
- const dropdownHeight =
165
- dropdownContainerStyle?.height ||
166
- dropdownContainerStyle?.maxHeight ||
167
- defaultDropdownItemHeight *
168
- Math.min(filteredOptions?.length, moderateScale(6)) +
169
- (isSearchable ? searchInputHeight + moderateScale(10) : 0) +
170
- (isOptionsEmpty && !(isSearchedOptionsEmpty && showCreateOption)
171
- ? emptyOptionsPlaceholderHeight
172
- : 0) +
173
- (isSearchedOptionsEmpty && showCreateOption
174
- ? emptySearchedOptionsHeight
175
- : 0);
176
- const selectedOptionLabel = labelExtractor(value || {});
177
- const selectedOptionValue = valueExtractor(value || {});
178
-
179
- const animatedStyles = useAnimatedStyle(
180
- () => ({
181
- height: withTiming(
182
- dropdownAnimatedHeight.value,
183
- {
184
- duration: 100,
185
- easing: Easing.ease,
186
- },
187
- () => {
188
- if (dropdownAnimatedHeight.value === 0) {
189
- runOnJS(setShowDropdown)(false);
190
- }
191
- }
192
- ),
193
- }),
194
- []
195
- );
196
-
197
- const toggleAnimation = () => {
198
- dropdownAnimatedHeight.value =
199
- dropdownAnimatedHeight.value === 0 ? dropdownHeight : 0;
200
- };
201
-
202
- const handleOpenDropdown = () => {
203
- Keyboard.dismiss();
204
- setSearchQuery("");
205
- if (!showDropdown) {
206
- setShowDropdown(true);
207
- }
208
-
209
- if (showDropdown) {
210
- toggleAnimation();
211
- }
212
- };
213
-
214
- const handleItemSelection = (item, index) => {
215
- toggleAnimation();
216
- onSelect(item, index);
217
- };
218
-
219
- useEffect(() => {
220
- if (showDropdown) {
221
- dropdownAnimatedHeight.value = dropdownHeight;
222
- }
223
- }, [showDropdown, dropdownHeight]);
224
-
225
- return (
226
- <Container {...containerStyle}>
227
- <Typography
228
- color="font.base"
229
- fontFamily="sf400"
230
- fontSize="s"
231
- mb={moderateScale(1)}
232
- {...labelStyle}
233
- >
234
- {label}
235
- </Typography>
236
- <TouchableWithoutFeedback
237
- disabled={isLoading}
238
- onPress={handleOpenDropdown}
239
- >
240
- <Container
241
- alignItems="center"
242
- borderColor="border.grey400"
243
- borderWidth={moderateScale(1)}
244
- flexDirection="row"
245
- justifyContent="space-between"
246
- p={moderateScale(2)}
247
- {...inputContainerStyle}
248
- {...rest}
249
- >
250
- <Typography color="font.grey" fontFamily="sf400" fontSize="s">
251
- {selectedOptionLabel || placeholder}
252
- </Typography>
253
- {isLoading ? (
254
- <Loader color={theme.colors.background.base} />
255
- ) : (
256
- <Icon
257
- color="grey"
258
- name={`arrow-${showDropdown ? "up" : "down"}-s-line`}
259
- size={moderateScale(20)}
260
- />
261
- )}
262
- </Container>
263
- </TouchableWithoutFeedback>
264
- {showDropdown && (
265
- <Container overflow="hidden">
266
- <Animated.View style={animatedStyles}>
267
- <Card
268
- bg="background.white"
269
- borderColor="border.grey400"
270
- borderWidth={moderateScale(1)}
271
- maxHeight={dropdownHeight}
272
- {...dropdownContainerStyle}
273
- >
274
- {isSearchable && (
275
- <Container p={moderateScale(1)} {...searchInputContainerStyle}>
276
- <Input
277
- fontSize="s"
278
- placeholder="Search"
279
- containerStyles={{
280
- height: searchInputHeight,
281
- justifyContent: "center",
282
- }}
283
- onChangeText={setSearchQuery}
284
- {...searchInputStyle}
285
- />
286
- </Container>
287
- )}
288
- {isOptionsEmpty && !(isSearchedOptionsEmpty && showCreateOption) && (
289
- <Container
290
- alignItems="center"
291
- height={emptyOptionsPlaceholderHeight}
292
- justifyContent="center"
293
- {...emptyOptionsContainerStyle}
294
- >
295
- <Typography
296
- color="font.grey"
297
- fontFamily="sf400"
298
- fontSize="s"
299
- {...emptyOptionsLabelStyle}
300
- >
301
- {emptyOptionsPlaceholder || "No Options"}
302
- </Typography>
303
- </Container>
304
- )}
305
- {isSearchedOptionsEmpty && showCreateOption && (
306
- <Touchable
307
- alignItems="center"
308
- height={emptySearchedOptionsHeight}
309
- justifyContent="center"
310
- onPress={() => onPressCreateOption(searchQuery)}
311
- {...createSearchedOptionContainerStyle}
312
- >
313
- {showCreateOptionLoader ? (
314
- <Loader color={theme.colors.background.base} size="s" />
315
- ) : (
316
- <Typography
317
- color="font.grey"
318
- fontFamily="sf400"
319
- fontSize="s"
320
- {...createSearchedOptionLabelStyle}
321
- >
322
- {createOptionLabel || `Create ${searchQuery} option`}
323
- </Typography>
324
- )}
325
- </Touchable>
326
- )}
327
- {/* Animation not working without this hidden input */}
328
- <Container height={0}>
329
- <Input />
330
- </Container>
331
- <ScrollView>
332
- {filteredOptions.map((item, index) => {
333
- const optionLabel = labelExtractor(item, index);
334
- const optionValue = valueExtractor(item, index);
335
- const isSelectedItem =
336
- selectedOptionValue && selectedOptionValue === optionValue;
337
-
338
- return (
339
- <DropdownItem
340
- defaultDropdownItemHeight={defaultDropdownItemHeight}
341
- isSelectedItem={isSelectedItem}
342
- itemContainerStyle={itemContainerStyle}
343
- itemLabelStyle={itemLabelStyle}
344
- key={index}
345
- label={optionLabel}
346
- selectedItemContainerStyle={selectedItemContainerStyle}
347
- selectedItemLabelStyle={selectedItemLabelStyle}
348
- onPress={() => handleItemSelection(item, index)}
349
- />
350
- );
351
- })}
352
- </ScrollView>
353
- </Card>
354
- </Animated.View>
355
- </Container>
356
- )}
357
- </Container>
358
- );
359
- };
360
-
361
- Select.propTypes = {
362
- /**
363
- * The text to use for the floating label.
364
- */
365
- label: PropTypes.string,
366
- /**
367
- * Data to populate the options dropdown.
368
- */
369
- options: PropTypes.arrayOf(
370
- PropTypes.shape({
371
- label: PropTypes.string,
372
- value: PropTypes.string,
373
- })
374
- ).isRequired,
375
- /**
376
- * The text to be displayed if no option is selected.
377
- */
378
- placeholder: PropTypes.string,
379
- /**
380
- * The text to be displayed if no options are provided.
381
- */
382
- emptyOptionsPlaceholder: PropTypes.string,
383
- /**
384
- * Use custom key as label.
385
- */
386
- labelExtractor: PropTypes.func,
387
- /**
388
- * Use custom key as value.
389
- */
390
- valueExtractor: PropTypes.func,
391
- /**
392
- * The selected value to show for the Select input.
393
- */
394
- value: PropTypes.object,
395
- /**
396
- * Callback function when an option is selected, receives the select option object.
397
- */
398
- onSelect: PropTypes.func,
399
- /**
400
- * Used to show if the dropdown is loading state, while loading Select input will be disabled.
401
- */
402
- isLoading: PropTypes.bool,
403
- /**
404
- * Toggle Search bar within the options dropdown to search through the options.
405
- */
406
- isSearchable: PropTypes.bool,
407
- /**
408
- * Show option to create the searched label if not present in the options list
409
- */
410
- showCreateOption: PropTypes.bool,
411
- /**
412
- * Show loader while creating a searched option not present in the options list
413
- */
414
- showCreateOptionLoader: PropTypes.bool,
415
- /**
416
- * Custom label for creating searched option not present in the options list
417
- */
418
- createOptionLabel: PropTypes.string,
419
- /**
420
- * Callback when create searched option is pressed
421
- */
422
- onPressCreateOption: PropTypes.func,
423
- /**
424
- * To customize floating label styles.
425
- */
426
- labelStyle: PropTypes.object,
427
- /**
428
- * To customize outermost container style.
429
- */
430
- containerStyle: PropTypes.object,
431
- /**
432
- * To customize Select input container styles.
433
- */
434
- inputContainerStyle: PropTypes.object,
435
- /**
436
- * To customize dropdown container styles.
437
- */
438
- dropdownContainerStyle: PropTypes.object,
439
- /**
440
- * To customize dropdown item container styles.
441
- */
442
- itemContainerStyle: PropTypes.object,
443
- /**
444
- * To customize dropdown item text styles.
445
- */
446
- itemLabelStyle: PropTypes.object,
447
- /**
448
- * To customize dropdown item container styles for selected item.
449
- */
450
- selectedItemContainerStyle: PropTypes.object,
451
- /**
452
- * To customize dropdown item text styles for selected item.
453
- */
454
- selectedItemLabelStyle: PropTypes.object,
455
- /**
456
- * To customize search input containerr style.
457
- */
458
- searchInputContainerStyle: PropTypes.object,
459
- /**
460
- * To customize search input style.
461
- */
462
- searchInputStyle: PropTypes.object,
463
- /**
464
- * To customize empty options placeholder container style.
465
- */
466
- emptyOptionsContainerStyle: PropTypes.object,
467
- /**
468
- * To customize empty options placeholder text style.
469
- */
470
- emptyOptionsLabelStyle: PropTypes.object,
471
- /**
472
- * To customize empty options placeholder container style.
473
- */
474
- createSearchedOptionContainerStyle: PropTypes.object,
475
- /**
476
- * To customize empty options placeholder text style.
477
- */
478
- createSearchedOptionLabelStyle: PropTypes.object,
479
- };
480
-
481
- Select.defaultProps = {
482
- label: null,
483
- placeholder: "Select Option",
484
- emptyOptionsPlaceholder: null,
485
- labelExtractor: option => option?.label,
486
- valueExtractor: option => option?.value,
487
- value: null,
488
- onSelect: () => {},
489
- isLoading: false,
490
- isSearchable: false,
491
- showCreateOption: false,
492
- showCreateOptionLoader: false,
493
- createOptionLabel: null,
494
- onPressCreateOption: () => {},
495
- };
@@ -1,150 +0,0 @@
1
- import React, { useContext } from "react";
2
-
3
- import PropTypes from "prop-types";
4
- import Icon from "react-native-remix-icon";
5
- import { moderateScale } from "react-native-size-matters";
6
- import { ThemeContext } from "styled-components/native";
7
-
8
- import { Typography, Touchable } from "@components";
9
-
10
- /**
11
- *
12
- * <div class="screenshots">
13
- * <img src="screenshots/selectButton/selectButton.png" />
14
- * </div>
15
- *
16
- * This component supports below props categories from [styled-system](/styled-system).
17
- * <ul>
18
- * <li>flexbox</li>
19
- * <li>space</li>
20
- * <li>border</li>
21
- * <li>layout</li>
22
- * <li>color</li>
23
- * <li>buttonStyle</li>
24
- * </ul>
25
- *
26
- * ## Usage
27
- * ```js
28
- * import * as React from "react";
29
- * import { moderateScale } from "react-native-size-matters";
30
- * import { Container, SelectButton } from "@bigbinary/neetoui-rn";
31
- *
32
- * export default function Main() {
33
- * const [selected1, setSelected1] = useState(true);
34
- * const [selected2, setSelected2] = useState(false);
35
- *
36
- * return (
37
- * <Container>
38
- * <SelectButton
39
- * mt={moderateScale(2)}
40
- * selected={selected1}
41
- * onSelect={() => setSelected1(prev => !prev)}
42
- * label={`Button marked as ${!selected1 ? "un" : ""}selected`}
43
- * />
44
- * <SelectButton
45
- * mt={moderateScale(3)}
46
- * selected={selected2}
47
- * onSelect={() => setSelected2(prev => !prev)}
48
- * label={`Button marked as ${!selected2 ? "un" : ""}selected`}
49
- * />
50
- * <SelectButton mt={moderateScale(3)} disabled label="Disabled button" />
51
- * </Container>
52
- * );
53
- * }
54
- * ```
55
- *
56
- */
57
-
58
- export const SelectButton = ({
59
- selected,
60
- onSelect,
61
- disabled,
62
- label,
63
- selectIconStyle,
64
- labelStyle,
65
- ...rest
66
- }) => {
67
- const theme = useContext(ThemeContext);
68
-
69
- const disabledProps = {
70
- labelProps: {
71
- opacity: 0.5,
72
- },
73
- };
74
-
75
- const selectedProps = {
76
- labelProps: {
77
- fontFamily: theme.fonts.sf700,
78
- },
79
- };
80
-
81
- const unselectedProps = {
82
- labelProps: {
83
- fontFamily: theme.fonts.sf400,
84
- },
85
- };
86
-
87
- return (
88
- <Touchable
89
- alignItems="center"
90
- disabled={disabled}
91
- flexDirection="row"
92
- py={moderateScale(8)}
93
- onPress={onSelect}
94
- {...rest}
95
- >
96
- <Typography
97
- color="font.primary"
98
- flex={1}
99
- fontSize="m"
100
- lineHeight={`${moderateScale(22)}px`}
101
- {...(selected && selectedProps.labelProps)}
102
- {...(!selected && unselectedProps.labelProps)}
103
- {...(disabled && disabledProps.labelProps)}
104
- {...labelStyle}
105
- >
106
- {label}
107
- </Typography>
108
- {selected && (
109
- <Icon
110
- color={theme.colors.font.primary}
111
- name="check-fill"
112
- size={moderateScale(20)}
113
- {...selectIconStyle}
114
- />
115
- )}
116
- </Touchable>
117
- );
118
- };
119
-
120
- SelectButton.propTypes = {
121
- /**
122
- * Whether the button is selected or not.
123
- */
124
- selected: PropTypes.bool.isRequired,
125
- /**
126
- * Function to execute on press.
127
- */
128
- onSelect: PropTypes.func.isRequired,
129
- /**
130
- * To disable the component.
131
- */
132
- disabled: PropTypes.bool,
133
- /**
134
- * Text label to be shown with the button.
135
- */
136
- label: PropTypes.string,
137
- /**
138
- * Customize selection icon style.
139
- */
140
- selectIconStyle: PropTypes.object,
141
- /**
142
- * Customize label style.
143
- */
144
- labelStyle: PropTypes.object,
145
- };
146
-
147
- SelectButton.defaultProps = {
148
- selected: false,
149
- onSelect: () => {},
150
- };