anima-ds-nucleus 1.0.16 → 1.0.18

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 (25) hide show
  1. package/dist/anima-ds-nucleus.css +1 -1
  2. package/dist/anima-ds.cjs.js +150 -124
  3. package/dist/anima-ds.esm.js +6799 -5651
  4. package/package.json +1 -1
  5. package/src/components/DataDisplay/Card/CardTituloCorto.jsx +23 -2
  6. package/src/components/DataDisplay/Card/CardTituloCortoMasEstado.jsx +23 -2
  7. package/src/components/DataDisplay/Card/CardTituloLargo.jsx +23 -2
  8. package/src/components/DataDisplay/Card/CardTituloLargoMasEstado.jsx +23 -2
  9. package/src/components/Inputs/PasswordInput/PasswordInput.jsx +85 -0
  10. package/src/components/Layout/Header/HeaderCompartido.jsx +192 -0
  11. package/src/components/Layout/Header/HeaderCompartido.stories.jsx +66 -0
  12. package/src/components/Layout/Header/HeaderConBuscador.stories.jsx +1 -0
  13. package/src/components/Layout/Header/HeaderCore.jsx +12 -12
  14. package/src/components/Layout/Header/HeaderGeneral.jsx +248 -53
  15. package/src/components/Layout/Header/HeaderGeneral.stories.jsx +34 -0
  16. package/src/components/Layout/Header/HeaderPoint.jsx +3 -3
  17. package/src/components/Layout/NavPoint/NavPoint.jsx +76 -55
  18. package/src/components/Layout/SaludoConFechaDashboard/SaludoConFechaDashboard.jsx +0 -1
  19. package/src/components/Layout/Sidebar/SidebarCore.jsx +82 -30
  20. package/src/components/Views/ForgotPassword/ForgotPassword.jsx +341 -0
  21. package/src/components/Views/ForgotPassword/ForgotPassword.stories.jsx +186 -0
  22. package/src/components/Views/LoginForm/LoginForm.jsx +332 -43
  23. package/src/components/Views/LoginForm/LoginForm.stories.jsx +182 -4
  24. package/src/i18n/config.js +12 -0
  25. package/src/index.js +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anima-ds-nucleus",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Anima Design System - A comprehensive React component library",
5
5
  "author": "Nucleus Labs <ipvasallo@nucleus.com.ar>",
6
6
  "license": "UNLICENSED",
@@ -39,14 +39,35 @@ export const CardTituloCorto = ({
39
39
  >
40
40
  <Typography
41
41
  variant="body-md"
42
- className="color-gray-700"
42
+ style={{
43
+ fontFamily: 'IBM Plex Sans',
44
+ fontWeight: 400,
45
+ fontStyle: 'normal',
46
+ fontSize: '20px',
47
+ lineHeight: '30px',
48
+ letterSpacing: '0%',
49
+ verticalAlign: 'middle',
50
+ color: '#223B40',
51
+ margin: 0
52
+ }}
43
53
  >
44
54
  {title}
45
55
  </Typography>
46
56
  </div>
47
57
  </div>
48
58
  {children && (
49
- <div className="px-4 pb-4">
59
+ <div
60
+ style={{
61
+ width: '379.5px',
62
+ height: '416px',
63
+ paddingRight: '24px',
64
+ paddingLeft: '24px',
65
+ gap: '16px',
66
+ opacity: 1,
67
+ display: 'flex',
68
+ flexDirection: 'column'
69
+ }}
70
+ >
50
71
  {children}
51
72
  </div>
52
73
  )}
@@ -40,7 +40,17 @@ export const CardTituloCortoMasEstado = ({
40
40
  >
41
41
  <Typography
42
42
  variant="body-md"
43
- className="color-gray-700"
43
+ style={{
44
+ fontFamily: 'IBM Plex Sans',
45
+ fontWeight: 400,
46
+ fontStyle: 'normal',
47
+ fontSize: '20px',
48
+ lineHeight: '30px',
49
+ letterSpacing: '0%',
50
+ verticalAlign: 'middle',
51
+ color: '#223B40',
52
+ margin: 0
53
+ }}
44
54
  >
45
55
  {title}
46
56
  </Typography>
@@ -64,7 +74,18 @@ export const CardTituloCortoMasEstado = ({
64
74
  </span>
65
75
  </div>
66
76
  {children && (
67
- <div className="px-4 pb-4">
77
+ <div
78
+ style={{
79
+ width: '379.5px',
80
+ height: '416px',
81
+ paddingRight: '24px',
82
+ paddingLeft: '24px',
83
+ gap: '16px',
84
+ opacity: 1,
85
+ display: 'flex',
86
+ flexDirection: 'column'
87
+ }}
88
+ >
68
89
  {children}
69
90
  </div>
70
91
  )}
@@ -39,14 +39,35 @@ export const CardTituloLargo = ({
39
39
  >
40
40
  <Typography
41
41
  variant="body-md"
42
- className="color-gray-700"
42
+ style={{
43
+ fontFamily: 'IBM Plex Sans',
44
+ fontWeight: 400,
45
+ fontStyle: 'normal',
46
+ fontSize: '20px',
47
+ lineHeight: '30px',
48
+ letterSpacing: '0%',
49
+ verticalAlign: 'middle',
50
+ color: '#223B40',
51
+ margin: 0
52
+ }}
43
53
  >
44
54
  {title}
45
55
  </Typography>
46
56
  </div>
47
57
  </div>
48
58
  {children && (
49
- <div className="px-4 pb-4">
59
+ <div
60
+ style={{
61
+ width: '379.5px',
62
+ height: '416px',
63
+ paddingRight: '24px',
64
+ paddingLeft: '24px',
65
+ gap: '16px',
66
+ opacity: 1,
67
+ display: 'flex',
68
+ flexDirection: 'column'
69
+ }}
70
+ >
50
71
  {children}
51
72
  </div>
52
73
  )}
@@ -40,7 +40,17 @@ export const CardTituloLargoMasEstado = ({
40
40
  >
41
41
  <Typography
42
42
  variant="body-md"
43
- className="color-gray-700"
43
+ style={{
44
+ fontFamily: 'IBM Plex Sans',
45
+ fontWeight: 400,
46
+ fontStyle: 'normal',
47
+ fontSize: '20px',
48
+ lineHeight: '30px',
49
+ letterSpacing: '0%',
50
+ verticalAlign: 'middle',
51
+ color: '#223B40',
52
+ margin: 0
53
+ }}
44
54
  >
45
55
  {title}
46
56
  </Typography>
@@ -64,7 +74,18 @@ export const CardTituloLargoMasEstado = ({
64
74
  </span>
65
75
  </div>
66
76
  {children && (
67
- <div className="px-4 pb-4">
77
+ <div
78
+ style={{
79
+ width: '379.5px',
80
+ height: '416px',
81
+ paddingRight: '24px',
82
+ paddingLeft: '24px',
83
+ gap: '16px',
84
+ opacity: 1,
85
+ display: 'flex',
86
+ flexDirection: 'column'
87
+ }}
88
+ >
68
89
  {children}
69
90
  </div>
70
91
  )}
@@ -0,0 +1,85 @@
1
+ import { useState } from 'react';
2
+ import { Icon } from '../../Atoms/Icon/Icon';
3
+
4
+ export const PasswordInput = ({
5
+ label,
6
+ placeholder,
7
+ value,
8
+ onChange,
9
+ error,
10
+ required = false,
11
+ disabled = false,
12
+ variant,
13
+ className = '',
14
+ inputClassName = '',
15
+ labelClassName = '',
16
+ labelStyle,
17
+ ...props
18
+ }) => {
19
+ const [showPassword, setShowPassword] = useState(false);
20
+ const isHexaLogin = variant === 'hexa-login';
21
+
22
+ const baseInputClasses = isHexaLogin
23
+ ? 'w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm text-gray-900'
24
+ : 'w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed';
25
+
26
+ const resolvedInputClasses = `
27
+ ${baseInputClasses}
28
+ ${isHexaLogin ? '' : (error ? 'border-red-500' : 'border-gray-300')}
29
+ ${inputClassName}
30
+ `.trim().replace(/\s+/g, ' ');
31
+
32
+ return (
33
+ <div className={`w-full ${className}`}>
34
+ {label && (
35
+ <label
36
+ className={labelClassName || 'block text-sm font-medium text-gray-700 mb-1'}
37
+ style={labelStyle}
38
+ >
39
+ {label}
40
+ {required && <span className="text-red-500 ml-1">*</span>}
41
+ </label>
42
+ )}
43
+
44
+ <div className="relative w-full">
45
+ <input
46
+ type={showPassword ? 'text' : 'password'}
47
+ placeholder={placeholder}
48
+ disabled={disabled}
49
+ value={value}
50
+ onChange={onChange}
51
+ className={resolvedInputClasses}
52
+ {...props}
53
+ />
54
+
55
+ <button
56
+ type="button"
57
+ tabIndex={-1}
58
+ onClick={() => setShowPassword((prev) => !prev)}
59
+ className="absolute"
60
+ style={{
61
+ top: '50%',
62
+ transform: 'translateY(-50%)',
63
+ right: '0.75rem',
64
+ color: '#6b7280',
65
+ }}
66
+ aria-label={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
67
+ >
68
+ <Icon
69
+ name={showPassword ? 'EyeSlashIcon' : 'EyeIcon'}
70
+ variant="24-outline"
71
+ size={18}
72
+ />
73
+ </button>
74
+ </div>
75
+
76
+ {error && !isHexaLogin && (
77
+ <p className="mt-1 text-sm text-red-600">{error}</p>
78
+ )}
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export default PasswordInput;
84
+
85
+
@@ -0,0 +1,192 @@
1
+ import { useState } from 'react';
2
+ import { Icon } from '../../Atoms/Icon/Icon';
3
+ import { Avatar } from '../../Atoms/Avatar/Avatar';
4
+ import { Typography } from '../../Atoms/Typography/Typography';
5
+
6
+ // Constantes de diseño reutilizables
7
+ const NOTIFICATION_BADGE_COLOR = '#6D3856';
8
+
9
+ export const HeaderCompartido = ({
10
+ searchPlaceholder = 'Buscar empleados, reportes, configuraciones...',
11
+ userName,
12
+ userAvatar,
13
+ notificationCount = 0,
14
+ onSearch,
15
+ onNotificationClick,
16
+ onUserClick,
17
+ // Borde inferior (subrayado)
18
+ showBottomBorder = false,
19
+ bottomBorderClassName = 'border-b border-gray-200',
20
+ // Overrides de estilo/clases para poder ajustar layout desde el proyecto consumidor
21
+ desktopLayoutClassName = '',
22
+ desktopLayoutStyle,
23
+ desktopSearchContainerClassName = '',
24
+ desktopSearchContainerStyle,
25
+ className = '',
26
+ ...props
27
+ }) => {
28
+ const [searchValue, setSearchValue] = useState('');
29
+
30
+ const formatNotificationCount = (count) => {
31
+ return count > 9 ? '9+' : count;
32
+ };
33
+
34
+ const handleSearchChange = (e) => {
35
+ const value = e.target.value;
36
+ setSearchValue(value);
37
+ if (onSearch) {
38
+ onSearch(value);
39
+ }
40
+ };
41
+
42
+ const handleSearchSubmit = (e) => {
43
+ e.preventDefault();
44
+ if (onSearch) {
45
+ onSearch(searchValue);
46
+ }
47
+ };
48
+
49
+ return (
50
+ <header
51
+ className={`bg-white ${showBottomBorder ? bottomBorderClassName : ''} ${className}`}
52
+ {...props}
53
+ >
54
+ <style>{`
55
+ .header-search-input {
56
+ border-color: #9ca3af;
57
+ }
58
+ .header-search-input::placeholder {
59
+ color: #9ca3af !important;
60
+ opacity: 1 !important;
61
+ }
62
+ .header-search-icon-container {
63
+ border-color: #9ca3af;
64
+ }
65
+ .header-search-form:focus-within .header-search-input {
66
+ border-color: #3b82f6 !important;
67
+ box-shadow: 0 0 0 1px #3b82f6;
68
+ }
69
+ .header-search-form:focus-within .header-search-icon-container {
70
+ border-color: #3b82f6 !important;
71
+ box-shadow: 0 0 0 1px #3b82f6;
72
+ }
73
+ .header-notification-badge {
74
+ background-color: ${NOTIFICATION_BADGE_COLOR};
75
+ border-radius: 12px;
76
+ }
77
+ .header-actions-wrapper {
78
+ flex-shrink: 0;
79
+ }
80
+ `}</style>
81
+
82
+ <div className="w-full" style={{ paddingLeft: '4px', paddingRight: '4px' }}>
83
+ {/* Layout Desktop */}
84
+ <div
85
+ className={`header-desktop-layout flex items-center justify-between h-16 ${desktopLayoutClassName}`}
86
+ style={desktopLayoutStyle}
87
+ >
88
+ {/* Barra de búsqueda con icono a la derecha */}
89
+ <div
90
+ className={`flex-1 mr-2 md:mr-4 ${desktopSearchContainerClassName}`}
91
+ style={{ maxWidth: 'none', minWidth: '0', ...(desktopSearchContainerStyle || {}) }}
92
+ >
93
+ <form onSubmit={handleSearchSubmit} className="header-search-form flex items-center w-full">
94
+ {/* Input de búsqueda */}
95
+ <input
96
+ type="text"
97
+ value={searchValue}
98
+ onChange={handleSearchChange}
99
+ placeholder={searchPlaceholder}
100
+ className="header-search-input flex-1 pl-2 md:pl-4 pr-2 md:pr-4 py-2 md:py-2.5 bg-white border border-gray-400 rounded-l-lg
101
+ focus:outline-none text-sm md:text-base"
102
+ style={{
103
+ height: '40px',
104
+ borderRight: 'none',
105
+ borderTopRightRadius: '0',
106
+ borderBottomRightRadius: '0',
107
+ color: '#374151',
108
+ fontFamily: 'IBM Plex Sans',
109
+ fontWeight: 400,
110
+ fontStyle: 'italic',
111
+ fontSize: '14px',
112
+ lineHeight: '20px',
113
+ letterSpacing: '0px'
114
+ }}
115
+ />
116
+
117
+ {/* Recuadro con icono de buscar a la derecha */}
118
+ <div
119
+ className="header-search-icon-container flex items-center justify-center border border-gray-400 rounded-r-lg bg-white"
120
+ style={{
121
+ width: '40px',
122
+ height: '40px',
123
+ borderTopLeftRadius: '0',
124
+ borderBottomLeftRadius: '0'
125
+ }}
126
+ >
127
+ <Icon
128
+ name="MagnifyingGlassIcon"
129
+ variant="24-outline"
130
+ size={20}
131
+ className="color-gray-600"
132
+ />
133
+ </div>
134
+ </form>
135
+ </div>
136
+
137
+ {/* Notificaciones y Perfil */}
138
+ <div className="header-actions-wrapper flex items-center gap-3 md:gap-6">
139
+ {notificationCount !== undefined && (
140
+ <button
141
+ onClick={onNotificationClick}
142
+ className="relative p-2 hover:bg-gray-100 rounded-lg transition-colors"
143
+ aria-label="Notificaciones"
144
+ >
145
+ <Icon
146
+ name="BellIcon"
147
+ variant="24-outline"
148
+ size={24}
149
+ className="color-gray-600"
150
+ />
151
+ {notificationCount > 0 && (
152
+ <span className="absolute -top-1 -right-1 px-1.5 py-0.5 min-w-[20px] h-5 text-white rounded-full flex items-center justify-center text-body-sm font-medium header-notification-badge">
153
+ {formatNotificationCount(notificationCount)}
154
+ </span>
155
+ )}
156
+ </button>
157
+ )}
158
+
159
+ {userName && (
160
+ <button
161
+ onClick={onUserClick}
162
+ className="flex items-center gap-3 hover:bg-gray-50 rounded-lg px-2 py-1.5 transition-colors"
163
+ aria-label="Perfil de usuario"
164
+ >
165
+ <Avatar
166
+ src={userAvatar}
167
+ name={userName}
168
+ size="medium"
169
+ variant="circle"
170
+ />
171
+ <Typography
172
+ variant="body-lg"
173
+ className="color-gray-700 hidden md:block header-user-name"
174
+ >
175
+ {userName}
176
+ </Typography>
177
+ <Icon
178
+ name="ChevronDownIcon"
179
+ variant="24-outline"
180
+ size={20}
181
+ className="color-gray-500 header-user-chevron hidden md:block"
182
+ />
183
+ </button>
184
+ )}
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </header>
189
+ );
190
+ };
191
+
192
+ export default HeaderCompartido;
@@ -0,0 +1,66 @@
1
+ import { HeaderCompartido } from './HeaderCompartido';
2
+
3
+ export default {
4
+ title: 'Layout/HeaderCompartido',
5
+ component: HeaderCompartido,
6
+ tags: ['autodocs'],
7
+ };
8
+
9
+ export const Default = {
10
+ render: () => (
11
+ <HeaderCompartido
12
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
13
+ userName="Maria García Alonso"
14
+ userAvatar="https://i.pravatar.cc/150?img=12"
15
+ notificationCount={7}
16
+ onSearch={(value) => console.log('Búsqueda:', value)}
17
+ onNotificationClick={() => console.log('Notificaciones clickeadas')}
18
+ onUserClick={() => console.log('Usuario clickeado')}
19
+ />
20
+ ),
21
+ };
22
+
23
+ export const SinNotificaciones = {
24
+ render: () => (
25
+ <HeaderCompartido
26
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
27
+ userName="Juan Pérez"
28
+ userAvatar="https://i.pravatar.cc/150?img=33"
29
+ notificationCount={0}
30
+ />
31
+ ),
32
+ };
33
+
34
+ export const ConNotificaciones = {
35
+ render: () => (
36
+ <HeaderCompartido
37
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
38
+ userName="Maria García Alonso"
39
+ userAvatar="https://i.pravatar.cc/150?img=12"
40
+ notificationCount={7}
41
+ onSearch={(value) => console.log('Búsqueda:', value)}
42
+ onNotificationClick={() => console.log('Notificaciones clickeadas')}
43
+ onUserClick={() => console.log('Usuario clickeado')}
44
+ />
45
+ ),
46
+ };
47
+
48
+ export const ConMuchasNotificaciones = {
49
+ render: () => (
50
+ <HeaderCompartido
51
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
52
+ userName="Ana Martínez"
53
+ userAvatar="https://i.pravatar.cc/150?img=47"
54
+ notificationCount={15}
55
+ />
56
+ ),
57
+ };
58
+
59
+ export const SinUsuario = {
60
+ render: () => (
61
+ <HeaderCompartido
62
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
63
+ notificationCount={3}
64
+ />
65
+ ),
66
+ };
@@ -85,3 +85,4 @@ export const CustomSearchPlaceholder = {
85
85
 
86
86
 
87
87
 
88
+
@@ -40,7 +40,7 @@ export const HeaderCore = ({
40
40
  notificationDesktopButtonStyle,
41
41
  notificationDesktopIconWrapperClassName = '',
42
42
  notificationDesktopIconWrapperStyle,
43
- notificationDesktopIconSize = 18,
43
+ notificationDesktopIconSize = 24,
44
44
  notificationDesktopIconStrokeWidth = 1.5,
45
45
  notificationDesktopIconStyle,
46
46
  notificationDesktopBadgeStyle,
@@ -48,7 +48,7 @@ export const HeaderCore = ({
48
48
  notificationMobileButtonStyle,
49
49
  notificationMobileIconWrapperClassName = '',
50
50
  notificationMobileIconWrapperStyle,
51
- notificationMobileIconSize = 18,
51
+ notificationMobileIconSize = 24,
52
52
  notificationMobileIconStrokeWidth = 1.5,
53
53
  notificationMobileIconStyle,
54
54
  showNotificationBadgeOnMobile = false,
@@ -286,11 +286,11 @@ export const HeaderCore = ({
286
286
  strokeWidth={notificationDesktopIconStrokeWidth}
287
287
  className={`color-gray-600 ${notificationIconClassName}`}
288
288
  style={{
289
- width: '17.75112533569336px',
290
- height: '18px',
289
+ width: '24px',
290
+ height: '24px',
291
291
  position: 'absolute',
292
- top: '3px',
293
- left: '3.12px',
292
+ top: '0px',
293
+ left: '0px',
294
294
  opacity: 1,
295
295
  transform: 'rotate(0deg)',
296
296
  ...(notificationIconStyle || {}),
@@ -310,7 +310,7 @@ export const HeaderCore = ({
310
310
  paddingRight: '8px',
311
311
  paddingBottom: '2px',
312
312
  paddingLeft: '8px',
313
- borderRadius: '8px',
313
+ borderRadius: '16px',
314
314
  opacity: 1,
315
315
  transform: 'rotate(0deg)',
316
316
  ...(notificationBadgeStyle || {}),
@@ -448,11 +448,11 @@ export const HeaderCore = ({
448
448
  strokeWidth={notificationMobileIconStrokeWidth}
449
449
  className={`color-gray-600 ${notificationIconClassName}`}
450
450
  style={{
451
- width: '17.75112533569336px',
452
- height: '18px',
451
+ width: '24px',
452
+ height: '24px',
453
453
  position: 'absolute',
454
- top: '3px',
455
- left: '3.12px',
454
+ top: '0px',
455
+ left: '0px',
456
456
  opacity: 1,
457
457
  transform: 'rotate(0deg)',
458
458
  ...(notificationIconStyle || {}),
@@ -472,7 +472,7 @@ export const HeaderCore = ({
472
472
  paddingRight: '8px',
473
473
  paddingBottom: '2px',
474
474
  paddingLeft: '8px',
475
- borderRadius: '8px',
475
+ borderRadius: '16px',
476
476
  marginLeft: '6px',
477
477
  opacity: 1,
478
478
  transform: 'rotate(0deg)',