@dropi/react-native-design-system 0.2.10 → 0.2.12

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.
package/README.md CHANGED
@@ -35,8 +35,15 @@ El **Design System de Dropi** para aplicaciones **React Native**. Este paquete r
35
35
  - [🧪 Moléculas](#moléculas)
36
36
  - [Alert](#alert)
37
37
  - [Empty State](#empty-state)
38
- - [Title Description](#title-description)
38
+ - [Radio Buttons](#radio-buttons)
39
+ - [Title Description](#title-description)
40
+ - [Search](#search)
39
41
  - [Tooltip](#tooltip)
42
+ - [Tags](#tags)
43
+ - [Order Tag](#order-tag)
44
+ - [Default Tag](#default-tag)
45
+ - [Toasts](#toasts)
46
+ - [Feedback Toast](#feedback-toast)
40
47
 
41
48
  # Instalación
42
49
 
@@ -478,17 +485,86 @@ import { EmptyState } from "@dropi/react-native-design-system";
478
485
  />
479
486
  ```
480
487
 
481
- ## Title Description
488
+ ## Search
489
+
490
+ El `Search` es un componente de campo de búsqueda diseñado para filtrar contenido de manera interactiva. Incluye un ícono de búsqueda a la izquierda, un campo de texto editable y un botón de limpieza que aparece automáticamente cuando hay texto ingresado. Utiliza `forwardRef` para exponer la referencia del `TextInput` nativo, permitiendo control programático del foco y otras funcionalidades del input. El componente mantiene una apariencia limpia y consistente usando los tokens `colors`, `radius`, `sizes` y `spacing` del design system.
491
+
492
+ ### 📦 Importación:
493
+ ```Typescript
494
+ import { Search } from "@dropi/react-native-design-system";
495
+ ```
496
+
497
+ ### ⚙️ Props:
498
+ | Prop | Tipo | Descripción |
499
+ | :------------ | :---------------------- | :--------------------------------------------------------------------------------- |
500
+ | filterText | string | Valor actual del texto de búsqueda. |
501
+ | setFilterText | (text: string) => void | Callback para actualizar el valor del texto. |
502
+ | placeholder | string | *(Opcional)* Texto placeholder. Por defecto es "Buscar". |
503
+ | ref | TextInput | Referencia al TextInput nativo para control programático. |
504
+ | ...rest | TextInputProps | Cualquier prop nativa del componente TextInput de React Native. |
505
+
506
+ ### 🧩 Ejemplos de uso:
507
+ ```Typescript
508
+ import { useRef, useState } from 'react';
509
+ import { TextInput } from 'react-native';
510
+ import { Search } from '@dropi/react-native-design-system';
511
+
512
+ const MyComponent = () => {
513
+ const [searchText, setSearchText] = useState('');
514
+ const searchRef = useRef<TextInput>(null);
515
+
516
+ const handleFocusSearch = () => {
517
+ searchRef.current?.focus();
518
+ };
519
+
520
+ return (
521
+ <Search
522
+ ref={searchRef}
523
+ filterText={searchText}
524
+ setFilterText={setSearchText}
525
+ placeholder="Buscar productos"
526
+ />
527
+ );
528
+ };
529
+
530
+ // Uso básico
531
+ <Search
532
+ filterText={query}
533
+ setFilterText={setQuery}
534
+ />
535
+
536
+ // Con placeholder personalizado
537
+ <Search
538
+ filterText={searchValue}
539
+ setFilterText={setSearchValue}
540
+ placeholder="Buscar por nombre o código"
541
+ />
542
+
543
+ // Con props adicionales de TextInput
544
+ <Search
545
+ ref={inputRef}
546
+ filterText={filter}
547
+ setFilterText={setFilter}
548
+ placeholder="Filtrar resultados"
549
+ autoFocus
550
+ returnKeyType="search"
551
+ onSubmitEditing={handleSearch}
552
+ />
553
+ ```
554
+
555
+ ## Radio Buttons
556
+
557
+ ### Title Description
482
558
 
483
559
  El TitleDescription es un componente de selección diseñado para mostrar opciones con un título principal, una descripción opcional, una imagen y un indicador visual circular que refleja si la opción está activa. Es ideal para flujos donde el usuario debe elegir entre varias alternativas.
484
560
  Adapta automáticamente tamaños en tablets usando isTablet, mantiene una disposición horizontal limpia y un estilo consistente con el design system.
485
561
 
486
- ### 📦 Importación:
562
+ #### 📦 Importación:
487
563
  ```Typescript
488
564
  import { TitleDescription } from "@dropi/react-native-design-system";
489
565
  ```
490
566
 
491
- ### ⚙️ Props:
567
+ #### ⚙️ Props:
492
568
  | Prop | Tipo | Descripción |
493
569
  | :------------- | :------------------------ | :-----------------------------------------------------------------------------|
494
570
  | title | string | Título principal de la opción. |
@@ -499,7 +575,7 @@ import { TitleDescription } from "@dropi/react-native-design-system";
499
575
  | ...rest | TouchableOpacityProps | Props adicionales del contenedor presionable. |
500
576
 
501
577
 
502
- ### 🧩 Ejemplos de uso:
578
+ #### 🧩 Ejemplos de uso:
503
579
  ```Typescript
504
580
  <TitleDescription
505
581
  title="Domicilio"
@@ -561,4 +637,209 @@ import { TitleDescription } from "@dropi/react-native-design-system";
561
637
  </Body>
562
638
  </Tooltip>
563
639
 
640
+ ```
641
+
642
+ ## Tags
643
+
644
+ ### Order Tag
645
+
646
+ El `OrderTag` es un componente visual diseñado para mostrar el estado actual de un pedido mediante una etiqueta con codificación cromática. Cada estado de pedido se representa con un color específico del sistema, facilitando la identificación rápida del estado sin necesidad de leer el texto completo. El componente es compacto, puede limitar su ancho para contextos reducidos, y utiliza los tokens `colors`, `radius` y `spacing` para mantener consistencia visual con el resto del design system.
647
+
648
+ ### 📦 Importación:
649
+ ```Typescript
650
+ import { OrderTag } from "@dropi/react-native-design-system";
651
+ ```
652
+
653
+ ### ⚙️ Props:
654
+ | Prop | Tipo | Descripción |
655
+ | :------------- | :------------------- | :--------------------------------------------------------------------------------------- |
656
+ | status | string | Estado del pedido que determina el color y texto de la etiqueta. |
657
+ | limitedWidth | boolean | *(Opcional)* Limita el ancho máximo a 112px. Por defecto es `false` (ancho completo). |
658
+
659
+ ### 📋 Estados disponibles:
660
+ | Estado | Color |
661
+ | :---------------------------- | :------------------------ |
662
+ | ENTREGADO | Success-700 |
663
+ | EN TRANSITO | Success-600 |
664
+ | GUIA_GENERADA | Info-500 |
665
+ | RECOGIDO POR DROPI | Info-700 |
666
+ | ENTREGADO A TRANSPORTADORA | Success-400 |
667
+ | PENDIENTE | Warning-600 |
668
+ | PENDIENTE CONFIRMACION | Warning-500 |
669
+ | NOVEDAD | Error-600 |
670
+ | DEVOLUCION | Error-800 |
671
+ | CANCELADO | Gray-400 |
672
+
673
+ *Cualquier estado no listado mostrará un fondo negro por defecto.*
674
+
675
+ ### 🧩 Ejemplos de uso:
676
+ ```Typescript
677
+ <OrderTag status="ENTREGADO" />
678
+
679
+ <OrderTag
680
+ status="EN TRANSITO"
681
+ limitedWidth={true}
682
+ />
683
+
684
+ <OrderTag status="PENDIENTE CONFIRMACION" />
685
+
686
+ <OrderTag
687
+ status="NOVEDAD"
688
+ limitedWidth={false}
689
+ />
690
+ ```
691
+
692
+ ### Default Tag
693
+
694
+ El `DefaultTag` es un componente de etiqueta versátil diseñado para categorizar, destacar o marcar contenido dentro de la interfaz. Ofrece dos variantes visuales (`primary` y `secondary`) y seis estados semánticos (`default`, `success`, `info`, `warning`, `red`, `neutral`) que determinan su esquema de color. Además, permite incluir un ícono opcional para reforzar visualmente el significado de la etiqueta. El componente limita su ancho máximo a 160px y se autoajusta al inicio del contenedor, utilizando los tokens `colors`, `radius` y `sizes` para mantener coherencia con el design system.
695
+
696
+ #### 📦 Importación:
697
+ ```Typescript
698
+ import { DefaultTag } from "@dropi/react-native-design-system";
699
+ ```
700
+
701
+ #### ⚙️ Props:
702
+ | Prop | Tipo | Descripción |
703
+ | :------ | :---------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |
704
+ | type | 'primary' \| 'secondary' | Define la variante visual del tag (colores sólidos o suaves). |
705
+ | label | string | Texto visible dentro de la etiqueta. |
706
+ | state | 'default' \| 'success' \| 'info' \| 'warning' \| 'red' \| 'neutral' | *(Opcional)* Estado semántico que determina el color. Por defecto es `'default'`. |
707
+ | icon | IconName | *(Opcional)* Ícono que aparece antes del texto. |
708
+
709
+ #### 🎨 Estados y colores:
710
+
711
+ **Primary (fondo sólido, texto blanco):**
712
+ | Estado | Color de fondo |
713
+ | :------- | :------------- |
714
+ | default | Primary-500 |
715
+ | success | Success-500 |
716
+ | info | Info-500 |
717
+ | warning | Warning-500 |
718
+ | red | Error-500 |
719
+ | neutral | Gray-500 |
720
+
721
+ **Secondary (fondo suave, texto del color primario del estado):**
722
+ | Estado | Color de fondo | Color de texto |
723
+ | :------- | :------------- | :-------------- |
724
+ | default | Primary-100 | Primary-500 |
725
+ | success | Success-50 | Success-500 |
726
+ | info | Info-50 | Info-500 |
727
+ | warning | Warning-50 | Warning-500 |
728
+ | red | Error-50 | Error-500 |
729
+ | neutral | Gray-50 | Gray-500 |
730
+
731
+ #### 🧩 Ejemplos de uso:
732
+ ```Typescript
733
+ <DefaultTag
734
+ type="primary"
735
+ label="Nuevo"
736
+ state="default"
737
+ />
738
+
739
+ <DefaultTag
740
+ type="secondary"
741
+ label="Aprobado"
742
+ state="success"
743
+ icon="check-circle"
744
+ />
745
+
746
+ <DefaultTag
747
+ type="primary"
748
+ label="Urgente"
749
+ state="warning"
750
+ icon="alert-triangle"
751
+ />
752
+
753
+ <DefaultTag
754
+ type="secondary"
755
+ label="Información"
756
+ state="info"
757
+ />
758
+ ```
759
+
760
+ ## Toasts
761
+
762
+ ### Feedback Toast
763
+
764
+ El `FeedbackToast` es un componente de notificación temporal que aparece desde la parte superior de la pantalla para comunicar el resultado de una acción o mostrar información importante al usuario. Incluye una animación Lottie contextual, una banda lateral de color semántico y botón de cierre. El componente se anima automáticamente al mostrarse con un efecto de "rebote" y puede cerrarse manualmente o mediante programación. Utiliza `forwardRef` para exponer métodos imperativos que permiten controlar su comportamiento desde componentes padres.
765
+
766
+ #### 📦 Importación:
767
+ ```Typescript
768
+ import { FeedbackToast } from "@dropi/react-native-design-system";
769
+ ```
770
+
771
+ #### ⚙️ Props:
772
+ | Prop | Tipo | Descripción |
773
+ | :------------ | :------------------------------------------- | :------------------------------------------------------------------------------------- |
774
+ | type | 'success' \| 'error' \| 'warning' \| 'info' | Define el tipo de notificación, determina color de banda y animación Lottie. |
775
+ | title | string | *(Opcional)* Título principal del toast. |
776
+ | message | string | *(Opcional)* Mensaje descriptivo del toast. |
777
+ | setShowToast | (show: boolean) => void | Callback para controlar la visibilidad del toast desde el componente padre. |
778
+ | ref | ToastRef | Referencia que expone el método `animateOut()` para cerrar el toast programáticamente. |
779
+
780
+ #### 🎨 Tipos y sus características:
781
+ | Tipo | Color de banda | Animación Lottie |
782
+ | :------- | :------------- | :------------------ |
783
+ | success | Success-500 | afirmacion.json |
784
+ | error | Error-500 | buscando.json |
785
+ | warning | Warning-500 | alerta.json |
786
+ | info | Info-500 | pregunta.json |
787
+
788
+ #### 🧩 Ejemplos de uso:
789
+ ```Typescript
790
+ import { useRef, useState } from 'react';
791
+ import { FeedbackToast, ToastRef } from '@dropi/react-native-design-system';
792
+
793
+ const MyComponent = () => {
794
+ const [showToast, setShowToast] = useState(false);
795
+ const toastRef = useRef<ToastRef>(null);
796
+
797
+ const handleSuccess = () => {
798
+ setShowToast(true);
799
+ };
800
+
801
+ const handleCloseToast = () => {
802
+ toastRef.current?.animateOut();
803
+ };
804
+
805
+ return (
806
+ <>
807
+ {showToast && (
808
+ <FeedbackToast
809
+ ref={toastRef}
810
+ type="success"
811
+ title="¡Operación exitosa!"
812
+ message="Los cambios se guardaron correctamente"
813
+ setShowToast={setShowToast}
814
+ />
815
+ )}
816
+ </>
817
+ );
818
+ };
819
+
820
+ // Toast de error sin título
821
+ <FeedbackToast
822
+ ref={toastRef}
823
+ type="error"
824
+ message="No se pudo completar la operación"
825
+ setShowToast={setShowToast}
826
+ />
827
+
828
+ // Toast de advertencia
829
+ <FeedbackToast
830
+ ref={toastRef}
831
+ type="warning"
832
+ title="Atención"
833
+ message="Esta acción no se puede deshacer"
834
+ setShowToast={setShowToast}
835
+ />
836
+
837
+ // Toast informativo
838
+ <FeedbackToast
839
+ ref={toastRef}
840
+ type="info"
841
+ title="Información"
842
+ message="Hay una nueva actualización disponible"
843
+ setShowToast={setShowToast}
844
+ />
564
845
  ```
@@ -0,0 +1,14 @@
1
+ import { TextInput, KeyboardTypeOptions, TextInputProps } from "react-native";
2
+ import { IconName } from "dropi-lib-icons";
3
+ export declare const BaseInput: import("react").ForwardRefExoticComponent<TextInputProps & {
4
+ type?: KeyboardTypeOptions;
5
+ preIcon?: IconName;
6
+ label?: string;
7
+ helper?: string;
8
+ placeholder?: string;
9
+ tooltip?: string;
10
+ value: string;
11
+ hasError: boolean;
12
+ errorMessage?: string;
13
+ isFocus: boolean;
14
+ } & import("react").RefAttributes<TextInput>>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.BaseInput = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _molecules = require("./molecules");
9
+ var _styles = _interopRequireDefault(require("./styles"));
10
+ var _react = require("react");
11
+ var _constants = require("../../constants");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ const BaseInput = exports.BaseInput = /*#__PURE__*/(0, _react.forwardRef)(({
15
+ type = "default",
16
+ preIcon,
17
+ label,
18
+ helper,
19
+ placeholder,
20
+ tooltip,
21
+ value,
22
+ hasError,
23
+ errorMessage,
24
+ isFocus,
25
+ /** TextInput props */
26
+ ...rest
27
+ }, ref) => {
28
+ const getBorderColor = () => {
29
+ if (hasError) {
30
+ return _constants.colors["Error-500"].light;
31
+ }
32
+ if (isFocus) {
33
+ return _constants.colors["Info-500"].light;
34
+ }
35
+ return _constants.colors["Gray-200"].light;
36
+ };
37
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
38
+ style: _styles.default.fieldContainer,
39
+ children: [label && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputLabel, {
40
+ text: label
41
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
42
+ style: [_styles.default.searchbarContainer, {
43
+ borderColor: getBorderColor()
44
+ }],
45
+ children: [preIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputIcon, {
46
+ icon: preIcon
47
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
48
+ style: [_styles.default.searchContainer, {
49
+ marginLeft: preIcon ? _constants.spacing["size-2"] : 0
50
+ }],
51
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
52
+ ref: ref,
53
+ style: _styles.default.usernameInput,
54
+ placeholder: placeholder,
55
+ placeholderTextColor: _constants.colors["Gray-500"].light,
56
+ value: value,
57
+ keyboardType: type,
58
+ ...rest
59
+ })
60
+ })]
61
+ }), helper && !hasError && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputHelper, {
62
+ helperText: helper
63
+ }), hasError && errorMessage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputError, {
64
+ errorMessage: errorMessage
65
+ })]
66
+ });
67
+ });
@@ -0,0 +1,14 @@
1
+ import { IconName } from "dropi-lib-icons";
2
+ type InputProps = {
3
+ preIcon?: IconName;
4
+ helper?: string;
5
+ tooltip?: string;
6
+ value: string;
7
+ onChange: (value: string) => void;
8
+ hasError: boolean;
9
+ errorMessage?: string;
10
+ readOnly: boolean;
11
+ };
12
+ export declare const validateEmail: (value: string) => boolean;
13
+ export declare const EmailInput: ({ preIcon, helper, tooltip, value, onChange, hasError, errorMessage, readOnly, }: InputProps) => import("react/jsx-runtime").JSX.Element;
14
+ export {};
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.validateEmail = exports.EmailInput = void 0;
7
+ var _BaseInput = require("./BaseInput");
8
+ var _react = require("react");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ const validateEmail = value => {
11
+ // Regular expression for validating email addresses
12
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
13
+ return emailRegex.test(value);
14
+ };
15
+ exports.validateEmail = validateEmail;
16
+ const EmailInput = ({
17
+ preIcon,
18
+ helper,
19
+ tooltip,
20
+ value,
21
+ onChange,
22
+ hasError,
23
+ errorMessage,
24
+ readOnly
25
+ }) => {
26
+ const [incorrectEmail, setIncorrectEmail] = (0, _react.useState)(false);
27
+ const [focus, setFocus] = (0, _react.useState)(false);
28
+ const [wasVisited, setWasVisited] = (0, _react.useState)(false);
29
+ const onFocus = () => {
30
+ setFocus(true);
31
+ };
32
+ const onBlur = () => {
33
+ setFocus(false);
34
+ if (!wasVisited) {
35
+ setWasVisited(true);
36
+ if (!validateEmail(value)) {
37
+ setIncorrectEmail(true);
38
+ }
39
+ }
40
+ };
41
+ const getErrorMessage = () => {
42
+ if (hasError) {
43
+ return errorMessage;
44
+ }
45
+ if (incorrectEmail) {
46
+ return "Ingresa un correo electrónico válido";
47
+ }
48
+ };
49
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_BaseInput.BaseInput, {
50
+ type: "email-address",
51
+ label: "Correo electrónico",
52
+ placeholder: "Ingresa tu correo electrónico",
53
+ value: value,
54
+ preIcon: preIcon,
55
+ helper: helper,
56
+ tooltip: tooltip,
57
+ onChangeText: text => {
58
+ onChange(text);
59
+ if (wasVisited) {
60
+ if (validateEmail(value)) {
61
+ setIncorrectEmail(false);
62
+ } else {
63
+ setIncorrectEmail(true);
64
+ }
65
+ }
66
+ },
67
+ hasError: hasError || incorrectEmail,
68
+ errorMessage: getErrorMessage(),
69
+ autoCorrect: false,
70
+ autoCapitalize: "none",
71
+ readOnly: readOnly,
72
+ onBlur: onBlur,
73
+ onFocus: onFocus,
74
+ isFocus: focus
75
+ });
76
+ };
77
+ exports.EmailInput = EmailInput;
@@ -0,0 +1,26 @@
1
+ type InputType = "text" | "number" | "email" | "password";
2
+ type InputFactoryProps = {
3
+ type: InputType;
4
+ };
5
+ export declare const Input: ({ type, ...props }: InputFactoryProps) => import("react").ForwardRefExoticComponent<import("react-native").TextInputProps & {
6
+ type?: import("react-native").KeyboardTypeOptions;
7
+ preIcon?: import("dropi-lib-icons").IconName;
8
+ label?: string;
9
+ helper?: string;
10
+ placeholder?: string;
11
+ tooltip?: string;
12
+ value: string;
13
+ hasError: boolean;
14
+ errorMessage?: string;
15
+ isFocus: boolean;
16
+ } & import("react").RefAttributes<import("react-native").TextInput>> | (({ preIcon, helper, tooltip, value, onChange, hasError, errorMessage, readOnly, }: {
17
+ preIcon?: import("dropi-lib-icons").IconName;
18
+ helper?: string;
19
+ tooltip?: string;
20
+ value: string;
21
+ onChange: (value: string) => void;
22
+ hasError: boolean;
23
+ errorMessage?: string;
24
+ readOnly: boolean;
25
+ }) => import("react/jsx-runtime").JSX.Element);
26
+ export {};
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Input = void 0;
7
+ var _BaseInput = require("./BaseInput");
8
+ var _EmailInput = require("./EmailInput");
9
+ // import { PasswordInput } from "./PasswordInput"
10
+
11
+ const InputComponents = {
12
+ text: _BaseInput.BaseInput,
13
+ number: _BaseInput.BaseInput,
14
+ email: _EmailInput.EmailInput,
15
+ password: _EmailInput.EmailInput
16
+ };
17
+ const Input = ({
18
+ type,
19
+ ...props
20
+ }) => {
21
+ return InputComponents[type];
22
+ };
23
+ exports.Input = Input;
@@ -0,0 +1,11 @@
1
+ import { TextInput, TextInputProps } from "react-native";
2
+ import { IconName } from "dropi-lib-icons";
3
+ export declare const PasswordInput: import("react").ForwardRefExoticComponent<TextInputProps & {
4
+ preIcon?: IconName;
5
+ helper?: string;
6
+ tooltip?: string;
7
+ value: string;
8
+ onChangeFunction: (value: string) => void;
9
+ hasError: boolean;
10
+ errorMessage?: string;
11
+ } & import("react").RefAttributes<TextInput>>;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PasswordInput = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _constants = require("./../../constants");
9
+ var _molecules = require("./molecules");
10
+ var _styles = _interopRequireDefault(require("./styles"));
11
+ var _react = require("react");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ const PasswordInput = exports.PasswordInput = /*#__PURE__*/(0, _react.forwardRef)(({
15
+ preIcon,
16
+ helper,
17
+ tooltip,
18
+ value,
19
+ onChangeFunction,
20
+ hasError,
21
+ errorMessage,
22
+ /** TextInput props */
23
+ ...rest
24
+ }, ref) => {
25
+ const [passwordVisibility, setPasswordVisibility] = (0, _react.useState)(false);
26
+ const [incorrectPasswordLength, setIncorrectPasswordLength] = (0, _react.useState)(false);
27
+ const [focus, setFocus] = (0, _react.useState)(false);
28
+ const [wasVisited, setWasVisited] = (0, _react.useState)(false);
29
+ const onFocus = () => {
30
+ setFocus(true);
31
+ };
32
+ const onBlur = () => {
33
+ setFocus(false);
34
+ if (!wasVisited) {
35
+ setWasVisited(true);
36
+ if (value.length < 4) {
37
+ setIncorrectPasswordLength(true);
38
+ }
39
+ }
40
+ };
41
+ const getBorderColor = () => {
42
+ if (hasError || incorrectPasswordLength) {
43
+ return _constants.colors["Error-500"].light;
44
+ }
45
+ if (focus) {
46
+ return _constants.colors["Info-500"].light;
47
+ }
48
+ return _constants.colors["Gray-200"].light;
49
+ };
50
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
51
+ style: _styles.default.fieldContainer,
52
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputLabel, {
53
+ text: "Contraseña"
54
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
55
+ style: [_styles.default.searchbarContainer, {
56
+ borderColor: getBorderColor()
57
+ }],
58
+ children: [preIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputIcon, {
59
+ icon: preIcon
60
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
61
+ style: [_styles.default.searchContainer, {
62
+ marginLeft: preIcon ? _constants.spacing["size-2"] : 0
63
+ }],
64
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
65
+ ref: ref,
66
+ style: _styles.default.usernameInput,
67
+ placeholder: "Ingresa tu contraseña",
68
+ placeholderTextColor: _constants.colors["Gray-500"].light,
69
+ value: value,
70
+ secureTextEntry: !passwordVisibility,
71
+ onChangeText: text => {
72
+ onChangeFunction(text);
73
+ if (wasVisited) {
74
+ if (text.length < 4) {
75
+ setIncorrectPasswordLength(true);
76
+ } else {
77
+ setIncorrectPasswordLength(false);
78
+ }
79
+ }
80
+ },
81
+ onFocus: onFocus,
82
+ onBlur: onBlur,
83
+ ...rest
84
+ })
85
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputIcon, {
86
+ icon: passwordVisibility ? "eye-crossed" : "eye",
87
+ onClick: () => setPasswordVisibility(!passwordVisibility)
88
+ })]
89
+ }), helper && !hasError && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputHelper, {
90
+ helperText: helper
91
+ }), incorrectPasswordLength && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputError, {
92
+ errorMessage: "La contraseña debe tener al menos 4 caracteres"
93
+ }), hasError && errorMessage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_molecules.InputError, {
94
+ errorMessage: errorMessage
95
+ })]
96
+ });
97
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./EmailInput";
2
+ export * from "./PasswordInput";
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _EmailInput = require("./EmailInput");
7
+ Object.keys(_EmailInput).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _EmailInput[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _EmailInput[key];
14
+ }
15
+ });
16
+ });
17
+ var _PasswordInput = require("./PasswordInput");
18
+ Object.keys(_PasswordInput).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _PasswordInput[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _PasswordInput[key];
25
+ }
26
+ });
27
+ });
@@ -0,0 +1,5 @@
1
+ type ErrorProps = {
2
+ errorMessage: string;
3
+ };
4
+ export declare const InputError: ({ errorMessage }: ErrorProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InputError = void 0;
7
+ var _reactNative = _interopRequireDefault(require("dropi-lib-icons/react-native"));
8
+ var _reactNative2 = require("react-native");
9
+ var _constants = require("../../../constants");
10
+ var _atoms = require("../../../atoms");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ const InputError = ({
14
+ errorMessage
15
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative2.View, {
16
+ style: styles.errorContainer,
17
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.View, {
18
+ style: styles.errorIcon,
19
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.default, {
20
+ name: "warning-circle-outline",
21
+ size: _constants.sizes["s"],
22
+ color: _constants.colors["Error-500"].light
23
+ })
24
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_atoms.Body, {
25
+ type: "s-regular",
26
+ style: styles.errorText,
27
+ children: errorMessage
28
+ })]
29
+ });
30
+ exports.InputError = InputError;
31
+ const styles = _reactNative2.StyleSheet.create({
32
+ errorContainer: {
33
+ marginTop: _constants.spacing["size-2"],
34
+ flexDirection: "row",
35
+ width: "100%"
36
+ },
37
+ errorIcon: {
38
+ alignItems: "center",
39
+ paddingTop: _constants.spacing["size-1"]
40
+ },
41
+ errorText: {
42
+ color: _constants.colors["Error-500"].light,
43
+ marginLeft: _constants.spacing["size-1"],
44
+ flex: 1
45
+ }
46
+ });
@@ -0,0 +1,5 @@
1
+ type HelperProps = {
2
+ helperText: string;
3
+ };
4
+ export declare const InputHelper: ({ helperText }: HelperProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InputHelper = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _atoms = require("../../../atoms");
9
+ var _constants = require("../../../constants");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ const InputHelper = ({
12
+ helperText
13
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
14
+ style: {
15
+ marginTop: _constants.spacing["size-2"]
16
+ },
17
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_atoms.Body, {
18
+ type: "s-regular",
19
+ style: {
20
+ color: _constants.colors["Gray-600"].light
21
+ },
22
+ children: helperText
23
+ })
24
+ });
25
+ exports.InputHelper = InputHelper;
@@ -0,0 +1,7 @@
1
+ import { IconName } from "dropi-lib-icons";
2
+ type IconProps = {
3
+ icon: IconName;
4
+ onClick?: () => void;
5
+ };
6
+ export declare const InputIcon: ({ icon, onClick }: IconProps) => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InputIcon = void 0;
7
+ var _reactNative = _interopRequireDefault(require("dropi-lib-icons/react-native"));
8
+ var _reactNative2 = require("react-native");
9
+ var _constants = require("../../../constants");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ const InputIcon = ({
13
+ icon,
14
+ onClick
15
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.TouchableOpacity, {
16
+ style: styles.userAvatarContainer,
17
+ onPress: onClick,
18
+ activeOpacity: onClick ? 0 : 1,
19
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.default, {
20
+ name: icon,
21
+ size: _constants.sizes["xl"],
22
+ color: _constants.colors["Gray-400"].light
23
+ })
24
+ });
25
+ exports.InputIcon = InputIcon;
26
+ const styles = _reactNative2.StyleSheet.create({
27
+ userAvatarContainer: {
28
+ justifyContent: "center",
29
+ alignItems: "center"
30
+ }
31
+ });
@@ -0,0 +1,5 @@
1
+ type LabelProps = {
2
+ text: string;
3
+ };
4
+ export declare const InputLabel: ({ text }: LabelProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InputLabel = void 0;
7
+ var _atoms = require("../../../atoms");
8
+ var _constants = require("../../../constants");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ const InputLabel = ({
11
+ text
12
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_atoms.Body, {
13
+ type: "m-regular",
14
+ style: {
15
+ color: _constants.colors["Gray-600"].light
16
+ },
17
+ children: text
18
+ });
19
+ exports.InputLabel = InputLabel;
@@ -0,0 +1,4 @@
1
+ export * from "./InputLabel";
2
+ export * from "./InputIcon";
3
+ export * from "./InputHelper";
4
+ export * from "./InputError";
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _InputLabel = require("./InputLabel");
7
+ Object.keys(_InputLabel).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _InputLabel[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _InputLabel[key];
14
+ }
15
+ });
16
+ });
17
+ var _InputIcon = require("./InputIcon");
18
+ Object.keys(_InputIcon).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _InputIcon[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _InputIcon[key];
25
+ }
26
+ });
27
+ });
28
+ var _InputHelper = require("./InputHelper");
29
+ Object.keys(_InputHelper).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _InputHelper[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _InputHelper[key];
36
+ }
37
+ });
38
+ });
39
+ var _InputError = require("./InputError");
40
+ Object.keys(_InputError).forEach(function (key) {
41
+ if (key === "default" || key === "__esModule") return;
42
+ if (key in exports && exports[key] === _InputError[key]) return;
43
+ Object.defineProperty(exports, key, {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _InputError[key];
47
+ }
48
+ });
49
+ });
@@ -0,0 +1,27 @@
1
+ declare const _default: {
2
+ fieldContainer: {
3
+ marginBottom: number;
4
+ width: "100%";
5
+ };
6
+ searchbarContainer: {
7
+ width: "100%";
8
+ borderRadius: number;
9
+ borderWidth: number;
10
+ justifyContent: "space-between";
11
+ flexDirection: "row";
12
+ marginTop: number;
13
+ height: number;
14
+ paddingHorizontal: number;
15
+ paddingVertical: number;
16
+ };
17
+ searchContainer: {
18
+ flex: number;
19
+ justifyContent: "center";
20
+ };
21
+ usernameInput: {
22
+ fontWeight: "400";
23
+ color: "#475066";
24
+ fontSize: number;
25
+ };
26
+ };
27
+ export default _default;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _constants = require("./../../constants");
8
+ var _reactNative = require("react-native");
9
+ var _default = exports.default = _reactNative.StyleSheet.create({
10
+ fieldContainer: {
11
+ marginBottom: _constants.spacing["size-4"],
12
+ width: "100%"
13
+ },
14
+ searchbarContainer: {
15
+ width: "100%",
16
+ borderRadius: _constants.radius["border-2"],
17
+ borderWidth: 1,
18
+ justifyContent: "space-between",
19
+ flexDirection: "row",
20
+ marginTop: _constants.spacing["size-2"],
21
+ height: 48,
22
+ paddingHorizontal: _constants.spacing["size-3"],
23
+ paddingVertical: _constants.spacing["size-2"]
24
+ },
25
+ searchContainer: {
26
+ flex: 1,
27
+ justifyContent: "center"
28
+ },
29
+ usernameInput: {
30
+ fontWeight: _constants.weights.regular,
31
+ color: _constants.colors["Gray-600"].light,
32
+ fontSize: _constants.sizes.s
33
+ }
34
+ });
@@ -1,7 +1,8 @@
1
- export * from './Alert';
2
- export * from './EmptyState';
3
- export * from './RadioButtons';
4
- export * from './Search';
5
- export * from './Tooltip';
6
- export * from './Toasts';
7
- export * from './Tags';
1
+ export * from "./Alert";
2
+ export * from "./EmptyState";
3
+ export * from "./RadioButtons";
4
+ export * from "./Search";
5
+ export * from "./Tooltip";
6
+ export * from "./Toasts";
7
+ export * from "./Tags";
8
+ export * from "./InputField";
@@ -79,4 +79,15 @@ Object.keys(_Tags).forEach(function (key) {
79
79
  return _Tags[key];
80
80
  }
81
81
  });
82
+ });
83
+ var _InputField = require("./InputField");
84
+ Object.keys(_InputField).forEach(function (key) {
85
+ if (key === "default" || key === "__esModule") return;
86
+ if (key in exports && exports[key] === _InputField[key]) return;
87
+ Object.defineProperty(exports, key, {
88
+ enumerable: true,
89
+ get: function () {
90
+ return _InputField[key];
91
+ }
92
+ });
82
93
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dropi/react-native-design-system",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "A React Native package built from scratch",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -20,12 +20,12 @@
20
20
  ],
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "react": ">=19.0.0",
24
- "react-native": ">=0.79.5",
25
- "dropi-lib-icons": ">=1.2.5",
23
+ "dropi-lib-icons": ">=1.3.4",
24
+ "expo-constants": ">=17.1.7",
26
25
  "expo-image": ">=2.4.0",
27
26
  "lottie-react-native": ">=7.2.2",
28
- "expo-constants": ">=17.1.7"
27
+ "react": ">=19.0.0",
28
+ "react-native": ">=0.79.5"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@babel/cli": "^7.28.3",
@@ -34,12 +34,12 @@
34
34
  "@babel/preset-react": "^7.28.5",
35
35
  "@babel/preset-typescript": "^7.28.5",
36
36
  "@types/react": "^19.2.3",
37
- "react": "^19.2.0",
38
- "react-native": "^0.82.1",
39
- "typescript": "^5.6.0",
40
- "dropi-lib-icons": "^1.2.5",
37
+ "dropi-lib-icons": "^1.3.4",
38
+ "expo-constants": ">=17.1.7",
41
39
  "expo-image": ">=2.4.0",
42
40
  "lottie-react-native": ">=7.2.2",
43
- "expo-constants": ">=17.1.7"
41
+ "react": "^19.2.0",
42
+ "react-native": "^0.82.1",
43
+ "typescript": "^5.6.0"
44
44
  }
45
45
  }