aport-tools 4.2.0 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ interface Option {
3
+ id: number | string;
4
+ label: string;
5
+ value: any;
6
+ }
7
+ interface InputListProps {
8
+ name: string;
9
+ /**
10
+ * Placeholder text displayed in the input box when no selection is made.
11
+ * @type {string}
12
+ * @default "Choose value/s"
13
+ */
14
+ placeholder?: string;
15
+ /**
16
+ * Custom styles for the component.
17
+ * @type {object}
18
+ */
19
+ style?: object;
20
+ /**
21
+ * Array of options to display in the dropdown. Each option should have an id, label, and value.
22
+ * @type {Option[]}
23
+ */
24
+ options: Option[];
25
+ /**
26
+ * Enables multi-selection mode when true. If enabled, users can select multiple values.
27
+ * @type {boolean}
28
+ * @default false
29
+ */
30
+ multi?: boolean;
31
+ /**
32
+ * Disables the dropdown input when true.
33
+ * @type {boolean}
34
+ * @default false
35
+ */
36
+ disabled?: boolean;
37
+ /**
38
+ * Key used to sort options in the dropdown (e.g., by 'id', 'label').
39
+ * @type {keyof Option}
40
+ */
41
+ sortBy?: keyof Option;
42
+ /**
43
+ * If true, displays a separator line between each option.
44
+ * @type {boolean}
45
+ * @default false
46
+ */
47
+ separator?: boolean;
48
+ /**
49
+ * Closes the dropdown if the user scrolls the list.
50
+ * @type {boolean}
51
+ * @default false
52
+ */
53
+ closeOnScroll?: boolean;
54
+ /**
55
+ * Closes the dropdown after selecting an item if true (only relevant when multi is false).
56
+ * @type {boolean}
57
+ * @default true
58
+ */
59
+ closeOnSelect?: boolean;
60
+ /**
61
+ * Limits the maximum number of items that can be selected when multi is true.
62
+ * Once the limit is reached, the dropdown closes, and no further selections can be made until
63
+ * an item is deselected.
64
+ * @type {number}
65
+ */
66
+ maxSelection?: number;
67
+ }
68
+ /**
69
+ * InputList component - A custom dropdown list component for React Native with multi-selection support,
70
+ * customizable styling, sorting, and configurable close behavior on selection or scrolling.
71
+ *
72
+ * @param {string} placeholder - Placeholder text for the input.
73
+ * @param {object} style - Custom styles for the component.
74
+ * @param {Option[]} options - Array of options to display in the dropdown.
75
+ * @param {boolean} multi - Enables multi-selection mode.
76
+ * @param {boolean} disabled - Disables the dropdown input.
77
+ * @param {keyof Option} sortBy - Key to sort options by (e.g., 'id').
78
+ * @param {boolean} separator - If true, adds a separator line between options.
79
+ * @param {boolean} closeOnScroll - Closes the dropdown if the user scrolls the list.
80
+ * @param {boolean} closeOnSelect - Closes the dropdown on selection in single-select mode.
81
+ * @param {number} maxSelection - Maximum number of items selectable in multi-select mode.
82
+ */
83
+ export declare const InputList: React.FC<InputListProps>;
84
+ export {};
@@ -3,3 +3,4 @@ export { Form, useFormContext } from './FormContext';
3
3
  export { default as TextArea } from './TextArea';
4
4
  export { default as Label } from './Label';
5
5
  export { default as ErrorList } from './ErrorList';
6
+ export { InputList } from './InputList';
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
- /*! aport-tools v4.2.0 | ISC */
2
- import React, { useContext, useState, createContext, useMemo } from 'react';
3
- import { StyleSheet, Text as Text$1, View, TextInput, TouchableOpacity, ActivityIndicator, Platform } from 'react-native';
1
+ /*! aport-tools v4.2.1 | ISC */
2
+ import React, { useContext, useState, createContext, useCallback, useMemo } from 'react';
3
+ import { StyleSheet, Text as Text$1, View, TextInput, TouchableOpacity, Modal, Pressable, FlatList, Keyboard, ActivityIndicator, Platform } from 'react-native';
4
4
  import { ThemeContext } from 'aport-themes';
5
5
 
6
6
  /******************************************************************************
@@ -81,6 +81,16 @@ function __generator(thisArg, body) {
81
81
  }
82
82
  }
83
83
 
84
+ function __spreadArray(to, from, pack) {
85
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
86
+ if (ar || !(i in from)) {
87
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
88
+ ar[i] = from[i];
89
+ }
90
+ }
91
+ return to.concat(ar || Array.prototype.slice.call(from));
92
+ }
93
+
84
94
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
85
95
  var e = new Error(message);
86
96
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
@@ -220,23 +230,23 @@ var ErrorList = function ErrorList(_a) {
220
230
  var theme = useContext(ThemeContext).theme;
221
231
  var colors = theme.colors;
222
232
  return /*#__PURE__*/React.createElement(View, {
223
- style: styles$5.container
233
+ style: styles$6.container
224
234
  }, errors.map(function (error, index) {
225
235
  return /*#__PURE__*/React.createElement(View, {
226
236
  key: index,
227
- style: styles$5.errorItem
237
+ style: styles$6.errorItem
228
238
  }, /*#__PURE__*/React.createElement(Text, {
229
- style: [styles$5.bullet, {
239
+ style: [styles$6.bullet, {
230
240
  color: colors.error.hex
231
241
  }]
232
242
  }, "\u2022"), /*#__PURE__*/React.createElement(Text, {
233
- style: [styles$5.errorText, {
243
+ style: [styles$6.errorText, {
234
244
  color: colors.error.hex
235
245
  }]
236
246
  }, error));
237
247
  }));
238
248
  };
239
- var styles$5 = StyleSheet.create({
249
+ var styles$6 = StyleSheet.create({
240
250
  container: {
241
251
  marginTop: 4
242
252
  },
@@ -314,13 +324,13 @@ var Input = function Input(_a) {
314
324
  setFormValue(name, formattedText);
315
325
  };
316
326
  return /*#__PURE__*/React.createElement(View, {
317
- style: styles$4.container
327
+ style: styles$5.container
318
328
  }, /*#__PURE__*/React.createElement(Text, {
319
- style: [styles$4.label, {
329
+ style: [styles$5.label, {
320
330
  color: colors.text.hex
321
331
  }]
322
332
  }, label), /*#__PURE__*/React.createElement(TextInput, __assign({
323
- style: [styles$4.input, {
333
+ style: [styles$5.input, {
324
334
  backgroundColor: colors.body.hex,
325
335
  borderColor: formErrors[name] ? colors.error.hex : "#CCC",
326
336
  color: colors.text.hex
@@ -333,7 +343,7 @@ var Input = function Input(_a) {
333
343
  errors: formErrors[name]
334
344
  })));
335
345
  };
336
- var styles$4 = StyleSheet.create({
346
+ var styles$5 = StyleSheet.create({
337
347
  container: {
338
348
  marginBottom: 16
339
349
  },
@@ -364,11 +374,11 @@ var TextArea = function TextArea(_a) {
364
374
  setFormValue(name, text);
365
375
  };
366
376
  return /*#__PURE__*/React.createElement(View, {
367
- style: styles$3.container
377
+ style: styles$4.container
368
378
  }, /*#__PURE__*/React.createElement(Text, {
369
- style: styles$3.label
379
+ style: styles$4.label
370
380
  }, label), /*#__PURE__*/React.createElement(TextInput, __assign({
371
- style: [styles$3.textArea, style],
381
+ style: [styles$4.textArea, style],
372
382
  value: formValues[name] || '',
373
383
  onChangeText: handleChange,
374
384
  placeholder: label,
@@ -381,7 +391,7 @@ var TextArea = function TextArea(_a) {
381
391
  errors: formErrors[name]
382
392
  })));
383
393
  };
384
- var styles$3 = StyleSheet.create({
394
+ var styles$4 = StyleSheet.create({
385
395
  container: {
386
396
  marginBottom: 16
387
397
  },
@@ -410,18 +420,191 @@ var Label = function Label(_a) {
410
420
  var theme = useContext(ThemeContext).theme;
411
421
  var colors = theme.colors;
412
422
  return /*#__PURE__*/React.createElement(Text, {
413
- style: [styles$2.label, style, {
423
+ style: [styles$3.label, style, {
414
424
  color: colors.text.hex
415
425
  }]
416
426
  }, text);
417
427
  };
418
- var styles$2 = StyleSheet.create({
428
+ var styles$3 = StyleSheet.create({
419
429
  label: {
420
430
  marginBottom: 4,
421
431
  fontWeight: '500'
422
432
  }
423
433
  });
424
434
 
435
+ /**
436
+ * InputList component - A custom dropdown list component for React Native with multi-selection support,
437
+ * customizable styling, sorting, and configurable close behavior on selection or scrolling.
438
+ *
439
+ * @param {string} placeholder - Placeholder text for the input.
440
+ * @param {object} style - Custom styles for the component.
441
+ * @param {Option[]} options - Array of options to display in the dropdown.
442
+ * @param {boolean} multi - Enables multi-selection mode.
443
+ * @param {boolean} disabled - Disables the dropdown input.
444
+ * @param {keyof Option} sortBy - Key to sort options by (e.g., 'id').
445
+ * @param {boolean} separator - If true, adds a separator line between options.
446
+ * @param {boolean} closeOnScroll - Closes the dropdown if the user scrolls the list.
447
+ * @param {boolean} closeOnSelect - Closes the dropdown on selection in single-select mode.
448
+ * @param {number} maxSelection - Maximum number of items selectable in multi-select mode.
449
+ */
450
+ var InputList = function InputList(_a) {
451
+ var name = _a.name,
452
+ _b = _a.placeholder,
453
+ placeholder = _b === void 0 ? "Choose value/s" : _b,
454
+ style = _a.style,
455
+ options = _a.options,
456
+ _c = _a.multi,
457
+ multi = _c === void 0 ? false : _c,
458
+ _d = _a.disabled,
459
+ disabled = _d === void 0 ? false : _d,
460
+ sortBy = _a.sortBy,
461
+ _e = _a.separator,
462
+ separator = _e === void 0 ? false : _e,
463
+ _f = _a.closeOnScroll,
464
+ closeOnScroll = _f === void 0 ? false : _f,
465
+ _g = _a.closeOnSelect,
466
+ closeOnSelect = _g === void 0 ? true : _g,
467
+ maxSelection = _a.maxSelection;
468
+ var _h = useFormContext(),
469
+ formValues = _h.formValues,
470
+ setFormValue = _h.setFormValue;
471
+ var _j = useState(false),
472
+ isDropdownVisible = _j[0],
473
+ setIsDropdownVisible = _j[1];
474
+ var selectedOptions = formValues[name] || (multi ? [] : null);
475
+ var sortedOptions = sortBy ? __spreadArray([], options, true).sort(function (a, b) {
476
+ return a[sortBy] > b[sortBy] ? 1 : -1;
477
+ }) : options;
478
+ var theme = useContext(ThemeContext).theme;
479
+ var colors = theme.colors;
480
+ /**
481
+ * Handles selection of an option. Adds or removes the option from selectedOptions based on
482
+ * multi-selection and maxSelection criteria.
483
+ * @param {Option} option - The selected option object.
484
+ */
485
+ var handleSelectOption = function handleSelectOption(option) {
486
+ if (multi) {
487
+ var alreadySelected = selectedOptions.some(function (opt) {
488
+ return opt.id === option.id;
489
+ });
490
+ var updatedSelections = alreadySelected ? selectedOptions.filter(function (opt) {
491
+ return opt.id !== option.id;
492
+ }) : __spreadArray(__spreadArray([], selectedOptions, true), [option], false);
493
+ // Close dropdown if max selection reached
494
+ if (!alreadySelected && maxSelection && updatedSelections.length >= maxSelection) {
495
+ setIsDropdownVisible(false);
496
+ }
497
+ // Update form value with selected items
498
+ setFormValue(name, updatedSelections);
499
+ } else {
500
+ setFormValue(name, option);
501
+ if (closeOnSelect) setIsDropdownVisible(false);
502
+ }
503
+ };
504
+ /**
505
+ * Renders selected options as a comma-separated string or the placeholder if none selected.
506
+ * @returns {string} - The display text for selected options or placeholder.
507
+ */
508
+ var renderSelectedText = function renderSelectedText() {
509
+ if (multi) return selectedOptions.map(function (opt) {
510
+ return opt.label;
511
+ }).join(', ') || placeholder;
512
+ return (selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.label) || placeholder;
513
+ };
514
+ /**
515
+ * Toggles dropdown visibility. Disables toggle if the component is disabled.
516
+ */
517
+ var toggleDropdown = function toggleDropdown() {
518
+ if (!disabled) {
519
+ setIsDropdownVisible(!isDropdownVisible);
520
+ if (!isDropdownVisible) Keyboard.dismiss();
521
+ }
522
+ };
523
+ /**
524
+ * Closes the dropdown when pressing outside.
525
+ */
526
+ var handleCloseDropdown = useCallback(function () {
527
+ if (isDropdownVisible) setIsDropdownVisible(false);
528
+ }, [isDropdownVisible]);
529
+ return /*#__PURE__*/React.createElement(View, {
530
+ style: [styles$2.container, style]
531
+ }, /*#__PURE__*/React.createElement(TouchableOpacity, {
532
+ style: styles$2.inputContainer,
533
+ onPress: toggleDropdown,
534
+ disabled: disabled
535
+ }, /*#__PURE__*/React.createElement(Text$1, {
536
+ style: {
537
+ color: colors.text.hex
538
+ }
539
+ }, renderSelectedText())), /*#__PURE__*/React.createElement(Modal, {
540
+ visible: isDropdownVisible,
541
+ transparent: true,
542
+ animationType: "fade"
543
+ }, /*#__PURE__*/React.createElement(Pressable, {
544
+ style: styles$2.overlay,
545
+ onPress: handleCloseDropdown
546
+ }), /*#__PURE__*/React.createElement(View, {
547
+ style: [styles$2.dropdownContainer, {
548
+ backgroundColor: colors.body.hex
549
+ }]
550
+ }, /*#__PURE__*/React.createElement(FlatList, {
551
+ data: sortedOptions,
552
+ keyExtractor: function keyExtractor(item) {
553
+ return item.id.toString();
554
+ },
555
+ renderItem: function renderItem(_a) {
556
+ var item = _a.item;
557
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
558
+ onPress: function onPress() {
559
+ return handleSelectOption(item);
560
+ },
561
+ style: styles$2.optionItem
562
+ }, /*#__PURE__*/React.createElement(Text$1, {
563
+ style: {
564
+ color: colors.text.hex
565
+ }
566
+ }, item.label));
567
+ },
568
+ ItemSeparatorComponent: function ItemSeparatorComponent() {
569
+ return separator ? /*#__PURE__*/React.createElement(View, {
570
+ style: styles$2.separator
571
+ }) : null;
572
+ },
573
+ scrollEnabled: !closeOnScroll
574
+ }))));
575
+ };
576
+ var styles$2 = StyleSheet.create({
577
+ container: {
578
+ padding: 8
579
+ },
580
+ inputContainer: {
581
+ padding: 12,
582
+ borderWidth: 1,
583
+ borderColor: '#ccc',
584
+ borderRadius: 5
585
+ },
586
+ dropdownContainer: {
587
+ position: 'absolute',
588
+ top: 60,
589
+ width: '90%',
590
+ borderRadius: 8,
591
+ elevation: 5,
592
+ alignSelf: 'center'
593
+ },
594
+ optionItem: {
595
+ padding: 12
596
+ },
597
+ separator: {
598
+ height: 1,
599
+ backgroundColor: '#ddd',
600
+ marginHorizontal: 8
601
+ },
602
+ overlay: {
603
+ flex: 1,
604
+ backgroundColor: 'rgba(0,0,0,0.3)'
605
+ }
606
+ });
607
+
425
608
  // src/components/Button.tsx
426
609
  /**
427
610
  * Determines the styles based on the button type and whether it is disabled.
@@ -600,5 +783,5 @@ var styles = StyleSheet.create({
600
783
  }
601
784
  });
602
785
 
603
- export { Button, Card, ErrorList, Form, Input, Label, Text, TextArea, useFormContext };
786
+ export { Button, Card, ErrorList, Form, Input, InputList, Label, Text, TextArea, useFormContext };
604
787
  //# sourceMappingURL=index.esm.js.map