aport-tools 4.1.31 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- import { ThemeColors } from 'aport-themes';
1
+ import { ThemeColors, ThemeFonts } from 'aport-themes';
2
2
  import React from 'react';
3
3
  import { TextProps, TextStyle } from 'react-native';
4
4
  interface CustomTextProps extends TextProps {
@@ -31,6 +31,11 @@ interface CustomTextProps extends TextProps {
31
31
  * This restricts type to known color keys like 'primary', 'error', etc.
32
32
  */
33
33
  type?: keyof ThemeColors;
34
+ /**
35
+ * Text font type. Defaults to 'body'. Should match the keys in ThemeFonts.
36
+ * This restricts type to known fonts keys like 'primary', 'secundary', etc.
37
+ */
38
+ typeFont?: keyof ThemeFonts;
34
39
  /**
35
40
  * Header level. Accepts 0 (none), 1, 2, or 3. Defaults to 0.
36
41
  */
@@ -48,6 +53,8 @@ interface CustomTextProps extends TextProps {
48
53
  * @param size - Size of the text. Defaults to 'medium'.
49
54
  * @param b - If true, applies bold styling.
50
55
  * @param i - If true, applies italic styling.
56
+ * @param type - Type of Text component. Defaults to 'text'.
57
+ * @param typeFont - Type of Font component. Defaults to 'body'.
51
58
  * @param u - If true, applies underline styling.
52
59
  * @param align - Paragraph alignment. Defaults to 'left'.
53
60
  * @param h - Header level. Accepts 0 (none), 1, 2, or 3. Defaults to 0.
@@ -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.1.31 | 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;
@@ -150,6 +160,8 @@ var Form = function Form(_a) {
150
160
  * @param size - Size of the text. Defaults to 'medium'.
151
161
  * @param b - If true, applies bold styling.
152
162
  * @param i - If true, applies italic styling.
163
+ * @param type - Type of Text component. Defaults to 'text'.
164
+ * @param typeFont - Type of Font component. Defaults to 'body'.
153
165
  * @param u - If true, applies underline styling.
154
166
  * @param align - Paragraph alignment. Defaults to 'left'.
155
167
  * @param h - Header level. Accepts 0 (none), 1, 2, or 3. Defaults to 0.
@@ -170,16 +182,22 @@ var Text = function Text(_a) {
170
182
  align = _g === void 0 ? 'left' : _g,
171
183
  _h = _a.type,
172
184
  type = _h === void 0 ? 'text' : _h,
173
- _j = _a.h,
174
- h = _j === void 0 ? 0 : _j,
185
+ _j = _a.typeFont,
186
+ typeFont = _j === void 0 ? 'body' : _j,
187
+ _k = _a.h,
188
+ h = _k === void 0 ? 0 : _k,
175
189
  style = _a.style;
176
190
  var theme = useContext(ThemeContext).theme;
177
- var colors = theme.colors;
191
+ var colors = theme.colors,
192
+ fonts = theme.fonts;
193
+ // Determine font family and size based on 'typeFont'
194
+ var fontSettings = fonts[typeFont] || fonts.body;
195
+ var fontFamily = fontSettings.fontFamily;
196
+ var fontSize = fontSettings.fontSize || size;
178
197
  // Calculate header size based on 'h' prop
179
- var fontSize = size;
180
198
  if (h === 1) fontSize = 32;else if (h === 2) fontSize = 24;else if (h === 3) fontSize = 18;
181
199
  // Define font weight based on bold prop
182
- var fontWeight = b ? '700' : '400';
200
+ var fontWeight = b ? '700' : fontSettings.fontWeight || '400';
183
201
  // Define font style based on italic prop
184
202
  var fontStyle = i ? 'italic' : 'normal';
185
203
  // Define text decoration based on underline prop
@@ -192,6 +210,7 @@ var Text = function Text(_a) {
192
210
  var textStyles = {
193
211
  fontSize: fontSize,
194
212
  fontWeight: fontWeight,
213
+ fontFamily: fontFamily,
195
214
  fontStyle: fontStyle,
196
215
  textDecorationLine: textDecorationLine,
197
216
  textAlign: textAlign,
@@ -211,23 +230,23 @@ var ErrorList = function ErrorList(_a) {
211
230
  var theme = useContext(ThemeContext).theme;
212
231
  var colors = theme.colors;
213
232
  return /*#__PURE__*/React.createElement(View, {
214
- style: styles$5.container
233
+ style: styles$6.container
215
234
  }, errors.map(function (error, index) {
216
235
  return /*#__PURE__*/React.createElement(View, {
217
236
  key: index,
218
- style: styles$5.errorItem
237
+ style: styles$6.errorItem
219
238
  }, /*#__PURE__*/React.createElement(Text, {
220
- style: [styles$5.bullet, {
239
+ style: [styles$6.bullet, {
221
240
  color: colors.error.hex
222
241
  }]
223
242
  }, "\u2022"), /*#__PURE__*/React.createElement(Text, {
224
- style: [styles$5.errorText, {
243
+ style: [styles$6.errorText, {
225
244
  color: colors.error.hex
226
245
  }]
227
246
  }, error));
228
247
  }));
229
248
  };
230
- var styles$5 = StyleSheet.create({
249
+ var styles$6 = StyleSheet.create({
231
250
  container: {
232
251
  marginTop: 4
233
252
  },
@@ -305,13 +324,13 @@ var Input = function Input(_a) {
305
324
  setFormValue(name, formattedText);
306
325
  };
307
326
  return /*#__PURE__*/React.createElement(View, {
308
- style: styles$4.container
327
+ style: styles$5.container
309
328
  }, /*#__PURE__*/React.createElement(Text, {
310
- style: [styles$4.label, {
329
+ style: [styles$5.label, {
311
330
  color: colors.text.hex
312
331
  }]
313
332
  }, label), /*#__PURE__*/React.createElement(TextInput, __assign({
314
- style: [styles$4.input, {
333
+ style: [styles$5.input, {
315
334
  backgroundColor: colors.body.hex,
316
335
  borderColor: formErrors[name] ? colors.error.hex : "#CCC",
317
336
  color: colors.text.hex
@@ -324,7 +343,7 @@ var Input = function Input(_a) {
324
343
  errors: formErrors[name]
325
344
  })));
326
345
  };
327
- var styles$4 = StyleSheet.create({
346
+ var styles$5 = StyleSheet.create({
328
347
  container: {
329
348
  marginBottom: 16
330
349
  },
@@ -355,11 +374,11 @@ var TextArea = function TextArea(_a) {
355
374
  setFormValue(name, text);
356
375
  };
357
376
  return /*#__PURE__*/React.createElement(View, {
358
- style: styles$3.container
377
+ style: styles$4.container
359
378
  }, /*#__PURE__*/React.createElement(Text, {
360
- style: styles$3.label
379
+ style: styles$4.label
361
380
  }, label), /*#__PURE__*/React.createElement(TextInput, __assign({
362
- style: [styles$3.textArea, style],
381
+ style: [styles$4.textArea, style],
363
382
  value: formValues[name] || '',
364
383
  onChangeText: handleChange,
365
384
  placeholder: label,
@@ -372,7 +391,7 @@ var TextArea = function TextArea(_a) {
372
391
  errors: formErrors[name]
373
392
  })));
374
393
  };
375
- var styles$3 = StyleSheet.create({
394
+ var styles$4 = StyleSheet.create({
376
395
  container: {
377
396
  marginBottom: 16
378
397
  },
@@ -401,18 +420,191 @@ var Label = function Label(_a) {
401
420
  var theme = useContext(ThemeContext).theme;
402
421
  var colors = theme.colors;
403
422
  return /*#__PURE__*/React.createElement(Text, {
404
- style: [styles$2.label, style, {
423
+ style: [styles$3.label, style, {
405
424
  color: colors.text.hex
406
425
  }]
407
426
  }, text);
408
427
  };
409
- var styles$2 = StyleSheet.create({
428
+ var styles$3 = StyleSheet.create({
410
429
  label: {
411
430
  marginBottom: 4,
412
431
  fontWeight: '500'
413
432
  }
414
433
  });
415
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
+
416
608
  // src/components/Button.tsx
417
609
  /**
418
610
  * Determines the styles based on the button type and whether it is disabled.
@@ -591,5 +783,5 @@ var styles = StyleSheet.create({
591
783
  }
592
784
  });
593
785
 
594
- export { Button, Card, ErrorList, Form, Input, Label, Text, TextArea, useFormContext };
786
+ export { Button, Card, ErrorList, Form, Input, InputList, Label, Text, TextArea, useFormContext };
595
787
  //# sourceMappingURL=index.esm.js.map