neogestify-ui-components 1.2.18 → 1.2.19

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.
Files changed (41) hide show
  1. package/README.md +349 -342
  2. package/dist/components/alerts/index.js +1 -1
  3. package/dist/components/alerts/index.js.map +1 -1
  4. package/dist/components/alerts/index.mjs +1 -1
  5. package/dist/components/alerts/index.mjs.map +1 -1
  6. package/dist/components/html/index.js +1 -1
  7. package/dist/components/html/index.js.map +1 -1
  8. package/dist/components/html/index.mjs +1 -1
  9. package/dist/components/html/index.mjs.map +1 -1
  10. package/dist/components/icons/index.js.map +1 -1
  11. package/dist/components/icons/index.mjs.map +1 -1
  12. package/dist/context/theme/index.js +1 -1
  13. package/dist/context/theme/index.js.map +1 -1
  14. package/dist/context/theme/index.mjs +1 -1
  15. package/dist/context/theme/index.mjs.map +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/index.mjs.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/alerts/InfoAlert.tsx +25 -25
  22. package/src/components/alerts/alerta.ts +93 -93
  23. package/src/components/alerts/index.ts +1 -1
  24. package/src/components/html/Button.tsx +71 -71
  25. package/src/components/html/Form.tsx +39 -39
  26. package/src/components/html/Input.tsx +136 -136
  27. package/src/components/html/Loading.tsx +104 -104
  28. package/src/components/html/Modal.tsx +79 -79
  29. package/src/components/html/Select.tsx +81 -81
  30. package/src/components/html/Table.tsx +61 -61
  31. package/src/components/html/TextArea.tsx +70 -70
  32. package/src/components/html/index.ts +7 -7
  33. package/src/components/icons/icons.tsx +550 -550
  34. package/src/components/icons/index.ts +1 -1
  35. package/src/context/theme/ThemeContext.tsx +37 -37
  36. package/src/context/theme/ThemeToggle.tsx +23 -23
  37. package/src/context/theme/index.ts +3 -3
  38. package/src/context/theme/theme.types.ts +11 -11
  39. package/src/context/theme/useTheme.ts +10 -10
  40. package/src/index.ts +5 -5
  41. package/src/types/types.ts +3 -3
@@ -1,26 +1,26 @@
1
- import { AlertaInfo } from './alerta';
2
- import { QuestionIcon } from '../icons/icons';
3
- import { Button } from '../html';
4
-
5
- interface InfoAlertProps {
6
- title: string;
7
- text: string;
8
- }
9
-
10
- export default function InfoAlert({ title, text }: InfoAlertProps) {
11
-
12
- const Question = async () => {
13
- await AlertaInfo(title, text);
14
- }
15
-
16
- return (
17
- <Button
18
- type="button"
19
- variant="custom"
20
- onClick={() => Question()}
21
- className="p-1 text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"
22
- >
23
- <QuestionIcon className="w-4 h-4" />
24
- </Button>
25
- )
1
+ import { AlertaInfo } from './alerta';
2
+ import { QuestionIcon } from '../icons/icons';
3
+ import { Button } from '../html';
4
+
5
+ interface InfoAlertProps {
6
+ title: string;
7
+ text: string;
8
+ }
9
+
10
+ export default function InfoAlert({ title, text }: InfoAlertProps) {
11
+
12
+ const Question = async () => {
13
+ await AlertaInfo(title, text);
14
+ }
15
+
16
+ return (
17
+ <Button
18
+ type="button"
19
+ variant="custom"
20
+ onClick={() => Question()}
21
+ className="p-1 text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"
22
+ >
23
+ <QuestionIcon className="w-4 h-4" />
24
+ </Button>
25
+ )
26
26
  }
@@ -1,94 +1,94 @@
1
- import Swal from "sweetalert2";
2
-
3
- interface AlertaOptions {
4
- title: string;
5
- text: string;
6
- icon: 'success' | 'error' | 'warning' | 'info' | 'question';
7
- confirmButtonText?: string;
8
- showCancelButton?: boolean;
9
- cancelButtonText?: string;
10
- showDenyButton?: boolean;
11
- denyButtonText?: string;
12
- onConfirm?: () => void;
13
- onCancel?: () => void;
14
- onDeny?: () => void;
15
- toast?: boolean;
16
- timer?: number;
17
- position?: 'top' | 'top-start' | 'top-end' | 'center' | 'center-start' | 'center-end' | 'bottom' | 'bottom-start' | 'bottom-end';
18
- allowOutsideClick?: boolean;
19
- allowEscapeKey?: boolean;
20
- input?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'range' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'file' | 'url';
21
- inputLabel?: string;
22
- inputPlaceholder?: string;
23
- inputValue?: string;
24
- inputValidator?: (value: unknown) => string | null | Promise<string | null>;
25
- inputAttributes?: Record<string, string>;
26
- }
27
-
28
- export async function Alerta(options: AlertaOptions) {
29
- const theme = localStorage.getItem('theme');
30
-
31
- const isDark = theme === 'dark';
32
-
33
- const result = await Swal.fire({
34
- title: options.title,
35
- text: options.text,
36
- icon: options.icon,
37
- confirmButtonText: options.confirmButtonText || 'Aceptar',
38
- showCancelButton: options.showCancelButton || false,
39
- cancelButtonText: options.cancelButtonText || 'Cancelar',
40
- showDenyButton: options.showDenyButton || false,
41
- denyButtonText: options.denyButtonText || 'No',
42
- background: isDark ? '#1f2937' : '#f9fafb',
43
- color: isDark ? '#f9fafb' : '#1f2937',
44
- customClass: {
45
- popup: isDark ? 'swal-dark-popup' : 'swal-light-popup',
46
- title: isDark ? 'swal-dark-title' : 'swal-light-title',
47
- confirmButton: isDark ? 'swal-dark-confirm' : 'swal-light-confirm',
48
- cancelButton: isDark ? 'swal-dark-cancel' : 'swal-light-cancel',
49
- denyButton: isDark ? 'swal-dark-deny' : 'swal-light-deny'
50
- },
51
- toast: options.toast || false,
52
- timer: options.timer,
53
- position: options.position || 'center',
54
- showConfirmButton: !options.toast && !options.timer,
55
- timerProgressBar: options.toast || !!options.timer,
56
- allowOutsideClick: options.allowOutsideClick !== false, // Por defecto true
57
- allowEscapeKey: options.allowEscapeKey !== false, // Por defecto true
58
- input: options.input,
59
- inputLabel: options.inputLabel,
60
- inputPlaceholder: options.inputPlaceholder,
61
- inputValue: options.inputValue,
62
- inputValidator: options.inputValidator,
63
- inputAttributes: options.inputAttributes
64
- });
65
-
66
- if (result.isConfirmed && options.onConfirm) {
67
- options.onConfirm();
68
- } else if (result.isDenied && options.onDeny) {
69
- options.onDeny();
70
- } else if (result.isDismissed && options.onCancel) {
71
- options.onCancel();
72
- }
73
-
74
- return result;
75
- }
76
-
77
- // Funciones de conveniencia para casos comunes
78
- export const AlertaExito = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
79
- Alerta({ title, text, icon: 'success', confirmButtonText: 'Aceptar', onConfirm, ...options });
80
-
81
- export const AlertaError = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
82
- Alerta({ title, text, icon: 'error', confirmButtonText: 'Aceptar', onConfirm, ...options });
83
-
84
- export const AlertaInfo = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
85
- Alerta({ title, text, icon: 'info', confirmButtonText: 'Entendido', onConfirm, ...options });
86
-
87
- export const AlertaAdvertencia = (title: string, text: string, onConfirm?: () => void, onCancel?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
88
- Alerta({ title, text, icon: 'warning', confirmButtonText: 'Sí, continuar', cancelButtonText: 'Cancelar', showCancelButton: true, onConfirm, onCancel, ...options });
89
-
90
- export const AlertaConfirmacion = (title: string, text: string, onConfirm?: () => void, onCancel?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
91
- Alerta({ title, text, icon: 'question', confirmButtonText: 'Sí', cancelButtonText: 'No', showCancelButton: true, onConfirm, onCancel, ...options });
92
-
93
- export const AlertaToast = (title: string, text: string, icon: 'success' | 'error' | 'warning' | 'info' = 'info', timer: number = 3000, position: 'top' | 'top-start' | 'top-end' | 'center' | 'center-start' | 'center-end' | 'bottom' | 'bottom-start' | 'bottom-end' = 'top-end') =>
1
+ import Swal from "sweetalert2";
2
+
3
+ interface AlertaOptions {
4
+ title: string;
5
+ text: string;
6
+ icon: 'success' | 'error' | 'warning' | 'info' | 'question';
7
+ confirmButtonText?: string;
8
+ showCancelButton?: boolean;
9
+ cancelButtonText?: string;
10
+ showDenyButton?: boolean;
11
+ denyButtonText?: string;
12
+ onConfirm?: () => void;
13
+ onCancel?: () => void;
14
+ onDeny?: () => void;
15
+ toast?: boolean;
16
+ timer?: number;
17
+ position?: 'top' | 'top-start' | 'top-end' | 'center' | 'center-start' | 'center-end' | 'bottom' | 'bottom-start' | 'bottom-end';
18
+ allowOutsideClick?: boolean;
19
+ allowEscapeKey?: boolean;
20
+ input?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'range' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'file' | 'url';
21
+ inputLabel?: string;
22
+ inputPlaceholder?: string;
23
+ inputValue?: string;
24
+ inputValidator?: (value: unknown) => string | null | Promise<string | null>;
25
+ inputAttributes?: Record<string, string>;
26
+ }
27
+
28
+ export async function Alerta(options: AlertaOptions) {
29
+ const theme = localStorage.getItem('theme');
30
+
31
+ const isDark = theme === 'dark';
32
+
33
+ const result = await Swal.fire({
34
+ title: options.title,
35
+ text: options.text,
36
+ icon: options.icon,
37
+ confirmButtonText: options.confirmButtonText || 'Aceptar',
38
+ showCancelButton: options.showCancelButton || false,
39
+ cancelButtonText: options.cancelButtonText || 'Cancelar',
40
+ showDenyButton: options.showDenyButton || false,
41
+ denyButtonText: options.denyButtonText || 'No',
42
+ background: isDark ? '#1f2937' : '#f9fafb',
43
+ color: isDark ? '#f9fafb' : '#1f2937',
44
+ customClass: {
45
+ popup: isDark ? 'swal-dark-popup' : 'swal-light-popup',
46
+ title: isDark ? 'swal-dark-title' : 'swal-light-title',
47
+ confirmButton: isDark ? 'swal-dark-confirm' : 'swal-light-confirm',
48
+ cancelButton: isDark ? 'swal-dark-cancel' : 'swal-light-cancel',
49
+ denyButton: isDark ? 'swal-dark-deny' : 'swal-light-deny'
50
+ },
51
+ toast: options.toast || false,
52
+ timer: options.timer,
53
+ position: options.position || 'center',
54
+ showConfirmButton: !options.toast && !options.timer,
55
+ timerProgressBar: options.toast || !!options.timer,
56
+ allowOutsideClick: options.allowOutsideClick !== false, // Por defecto true
57
+ allowEscapeKey: options.allowEscapeKey !== false, // Por defecto true
58
+ input: options.input,
59
+ inputLabel: options.inputLabel,
60
+ inputPlaceholder: options.inputPlaceholder,
61
+ inputValue: options.inputValue,
62
+ inputValidator: options.inputValidator,
63
+ inputAttributes: options.inputAttributes
64
+ });
65
+
66
+ if (result.isConfirmed && options.onConfirm) {
67
+ options.onConfirm();
68
+ } else if (result.isDenied && options.onDeny) {
69
+ options.onDeny();
70
+ } else if (result.isDismissed && options.onCancel) {
71
+ options.onCancel();
72
+ }
73
+
74
+ return result;
75
+ }
76
+
77
+ // Funciones de conveniencia para casos comunes
78
+ export const AlertaExito = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
79
+ Alerta({ title, text, icon: 'success', confirmButtonText: 'Aceptar', onConfirm, ...options });
80
+
81
+ export const AlertaError = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
82
+ Alerta({ title, text, icon: 'error', confirmButtonText: 'Aceptar', onConfirm, ...options });
83
+
84
+ export const AlertaInfo = (title: string, text: string, onConfirm?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
85
+ Alerta({ title, text, icon: 'info', confirmButtonText: 'Entendido', onConfirm, ...options });
86
+
87
+ export const AlertaAdvertencia = (title: string, text: string, onConfirm?: () => void, onCancel?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
88
+ Alerta({ title, text, icon: 'warning', confirmButtonText: 'Sí, continuar', cancelButtonText: 'Cancelar', showCancelButton: true, onConfirm, onCancel, ...options });
89
+
90
+ export const AlertaConfirmacion = (title: string, text: string, onConfirm?: () => void, onCancel?: () => void, options?: { allowOutsideClick?: boolean; allowEscapeKey?: boolean }) =>
91
+ Alerta({ title, text, icon: 'question', confirmButtonText: 'Sí', cancelButtonText: 'No', showCancelButton: true, onConfirm, onCancel, ...options });
92
+
93
+ export const AlertaToast = (title: string, text: string, icon: 'success' | 'error' | 'warning' | 'info' = 'info', timer: number = 3000, position: 'top' | 'top-start' | 'top-end' | 'center' | 'center-start' | 'center-end' | 'bottom' | 'bottom-start' | 'bottom-end' = 'top-end') =>
94
94
  Alerta({ title, text, icon, toast: true, timer, position });
@@ -1,2 +1,2 @@
1
- export * from './alerta';
1
+ export * from './alerta';
2
2
  export { default as InfoAlert } from './InfoAlert';
@@ -1,72 +1,72 @@
1
- import { AnimateSpin } from '../icons/icons';
2
- import { type ButtonHTMLAttributes, type FC, type ReactNode } from 'react';
3
-
4
- interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
5
- variant?: 'primary' | 'secondary' | 'icon' | 'danger' | 'success' | 'outline' | 'nav' | 'custom' | 'link' | 'warning' | 'toggle';
6
- children: ReactNode;
7
- isLoading?: boolean;
8
- loadingText?: string;
9
- isActive?: boolean;
10
- }
11
-
12
- export const Button: FC<ButtonProps> = ({
13
- variant = 'primary',
14
- children,
15
- isLoading = false,
16
- loadingText,
17
- isActive = false,
18
- className = '',
19
- disabled,
20
- ...props
21
- }) => {
22
- const baseClasses = 'transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer';
23
-
24
- const variantClasses = {
25
- primary: 'py-2 px-2 border border-indigo-600/20 dark:border-indigo-500/20 text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
26
- secondary: 'p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-md border border-gray-300 dark:border-gray-600 shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
27
- icon: 'p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-full focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
28
- danger: 'py-2 px-2 border border-red-600/20 dark:border-red-500/20 text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 dark:focus:ring-red-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
29
- success: 'py-2 px-2 border border-green-600/20 dark:border-green-500/20 text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 dark:focus:ring-green-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
30
- outline: 'py-2 px-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
31
- nav: 'w-full flex items-center px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 hover:scale-105 text-gray-700 dark:text-gray-300 dark:hover:text-white hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
32
- custom: "",
33
- link: 'text-sm text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
34
- warning: 'py-2 px-2 border border-yellow-600/20 dark:border-yellow-500/20 text-sm font-medium rounded-md text-white bg-yellow-600 hover:bg-yellow-700 dark:bg-yellow-500 dark:hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-yellow-500 dark:focus:ring-yellow-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
35
- toggle: 'px-2 py-2 rounded-lg font-medium transition-all duration-200 disabled:cursor-not-allowed border-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900'
36
- };
37
-
38
- let classes = `${baseClasses} ${variantClasses[variant]} ${className}`;
39
-
40
- if (variant === 'nav' && isActive) {
41
- classes += ' bg-indigo-600 dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600 text-white shadow-lg scale-105';
42
- }
43
-
44
- if (variant === 'nav' && !isActive) {
45
- classes += ' hover:bg-white dark:hover:bg-gray-700 hover:shadow-lg';
46
- }
47
-
48
- if (variant === 'toggle') {
49
- if (isActive) {
50
- classes += ' bg-indigo-600 text-white border-indigo-600/30 dark:border-indigo-500/30 hover:bg-indigo-700';
51
- } else {
52
- classes += ' bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600 hover:bg-gray-300 dark:hover:bg-gray-600 hover:border-gray-400 dark:hover:border-gray-500';
53
- }
54
- }
55
-
56
- return (
57
- <button
58
- className={classes}
59
- disabled={disabled || isLoading}
60
- {...props}
61
- >
62
- {isLoading ? (
63
- <>
64
- <AnimateSpin className="h-5 w-5 mr-2 inline-block text-current" />
65
- {loadingText || 'Cargando...'}
66
- </>
67
- ) : (
68
- children
69
- )}
70
- </button>
71
- );
1
+ import { AnimateSpin } from '../icons/icons';
2
+ import { type ButtonHTMLAttributes, type FC, type ReactNode } from 'react';
3
+
4
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: 'primary' | 'secondary' | 'icon' | 'danger' | 'success' | 'outline' | 'nav' | 'custom' | 'link' | 'warning' | 'toggle';
6
+ children: ReactNode;
7
+ isLoading?: boolean;
8
+ loadingText?: string;
9
+ isActive?: boolean;
10
+ }
11
+
12
+ export const Button: FC<ButtonProps> = ({
13
+ variant = 'primary',
14
+ children,
15
+ isLoading = false,
16
+ loadingText,
17
+ isActive = false,
18
+ className = '',
19
+ disabled,
20
+ ...props
21
+ }) => {
22
+ const baseClasses = 'transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer';
23
+
24
+ const variantClasses = {
25
+ primary: 'py-2 px-2 border border-indigo-600/20 dark:border-indigo-500/20 text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
26
+ secondary: 'p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-md border border-gray-300 dark:border-gray-600 shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
27
+ icon: 'p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-800 rounded-full focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
28
+ danger: 'py-2 px-2 border border-red-600/20 dark:border-red-500/20 text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 dark:focus:ring-red-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
29
+ success: 'py-2 px-2 border border-green-600/20 dark:border-green-500/20 text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 dark:focus:ring-green-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
30
+ outline: 'py-2 px-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
31
+ nav: 'w-full flex items-center px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 hover:scale-105 text-gray-700 dark:text-gray-300 dark:hover:text-white hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
32
+ custom: "",
33
+ link: 'text-sm text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900 rounded-lg px-2',
34
+ warning: 'py-2 px-2 border border-yellow-600/20 dark:border-yellow-500/20 text-sm font-medium rounded-md text-white bg-yellow-600 hover:bg-yellow-700 dark:bg-yellow-500 dark:hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-yellow-500 dark:focus:ring-yellow-400 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900',
35
+ toggle: 'px-2 py-2 rounded-lg font-medium transition-all duration-200 disabled:cursor-not-allowed border-2 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 dark:focus:ring-offset-gray-900'
36
+ };
37
+
38
+ let classes = `${baseClasses} ${variantClasses[variant]} ${className}`;
39
+
40
+ if (variant === 'nav' && isActive) {
41
+ classes += ' bg-indigo-600 dark:bg-indigo-500 hover:bg-indigo-700 dark:hover:bg-indigo-600 text-white shadow-lg scale-105';
42
+ }
43
+
44
+ if (variant === 'nav' && !isActive) {
45
+ classes += ' hover:bg-white dark:hover:bg-gray-700 hover:shadow-lg';
46
+ }
47
+
48
+ if (variant === 'toggle') {
49
+ if (isActive) {
50
+ classes += ' bg-indigo-600 text-white border-indigo-600/30 dark:border-indigo-500/30 hover:bg-indigo-700';
51
+ } else {
52
+ classes += ' bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600 hover:bg-gray-300 dark:hover:bg-gray-600 hover:border-gray-400 dark:hover:border-gray-500';
53
+ }
54
+ }
55
+
56
+ return (
57
+ <button
58
+ className={classes}
59
+ disabled={disabled || isLoading}
60
+ {...props}
61
+ >
62
+ {isLoading ? (
63
+ <>
64
+ <AnimateSpin className="h-5 w-5 mr-2 inline-block text-current" />
65
+ {loadingText || 'Cargando...'}
66
+ </>
67
+ ) : (
68
+ children
69
+ )}
70
+ </button>
71
+ );
72
72
  };
@@ -1,40 +1,40 @@
1
- import { type FormHTMLAttributes, type FC, type FormEvent, type ReactNode } from 'react';
2
-
3
- interface FormProps extends FormHTMLAttributes<HTMLFormElement> {
4
- children: ReactNode;
5
- onSubmit?: (e: FormEvent<HTMLFormElement>) => void;
6
- variant?: 'default' | 'modal' | 'card' | 'inline' | 'compact';
7
- }
8
-
9
- export const Form: FC<FormProps> = ({ onSubmit, children, variant = 'default', className = '', ...props }) => {
10
- const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
11
- e.preventDefault();
12
- if (onSubmit) {
13
- onSubmit(e);
14
- }
15
- };
16
-
17
- const getVariantClasses = () => {
18
- switch (variant) {
19
- case 'modal':
20
- return 'flex-1 px-6 py-4 overflow-y-auto';
21
- case 'card':
22
- return 'p-6 space-y-6';
23
- case 'inline':
24
- return 'flex flex-wrap gap-4 items-end';
25
- case 'compact':
26
- return 'space-y-3';
27
- case 'default':
28
- default:
29
- return 'space-y-4';
30
- }
31
- };
32
-
33
- const combinedClassName = `${getVariantClasses()} ${className}`.trim();
34
-
35
- return (
36
- <form onSubmit={handleSubmit} className={combinedClassName} {...props}>
37
- {children}
38
- </form>
39
- );
1
+ import { type FormHTMLAttributes, type FC, type FormEvent, type ReactNode } from 'react';
2
+
3
+ interface FormProps extends FormHTMLAttributes<HTMLFormElement> {
4
+ children: ReactNode;
5
+ onSubmit?: (e: FormEvent<HTMLFormElement>) => void;
6
+ variant?: 'default' | 'modal' | 'card' | 'inline' | 'compact';
7
+ }
8
+
9
+ export const Form: FC<FormProps> = ({ onSubmit, children, variant = 'default', className = '', ...props }) => {
10
+ const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
11
+ e.preventDefault();
12
+ if (onSubmit) {
13
+ onSubmit(e);
14
+ }
15
+ };
16
+
17
+ const getVariantClasses = () => {
18
+ switch (variant) {
19
+ case 'modal':
20
+ return 'flex-1 px-6 py-4 overflow-y-auto';
21
+ case 'card':
22
+ return 'p-6 space-y-6';
23
+ case 'inline':
24
+ return 'flex flex-wrap gap-4 items-end';
25
+ case 'compact':
26
+ return 'space-y-3';
27
+ case 'default':
28
+ default:
29
+ return 'space-y-4';
30
+ }
31
+ };
32
+
33
+ const combinedClassName = `${getVariantClasses()} ${className}`.trim();
34
+
35
+ return (
36
+ <form onSubmit={handleSubmit} className={combinedClassName} {...props}>
37
+ {children}
38
+ </form>
39
+ );
40
40
  };